From 217d9785111359c98d2800486c8450e5667808e1 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Fri, 28 Apr 2017 23:49:11 +0530 Subject: [PATCH] qcacld-3.0: Wait for all peer unmap events Currently even though all peer unmaps events of last associated peer are not received, driver still goes ahead for new connection with a diffrent peer. Now if firmware uses same peer id for new peer also this causes synchronization issue of peer ref counts and will eventually lead of kernel panic. Add changes to wait for last peer's all unmap events before proceeding with new connection CRs-Fixed: 2040627 Change-Id: I30e74d9bebe66fec55d7682d3cec581a078f5e75 --- core/dp/txrx/ol_txrx.c | 40 ++++++++++++++++++++++++++++++++++++ core/dp/txrx/ol_txrx_types.h | 1 + 2 files changed, 41 insertions(+) diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index fac9cc1da518..6ea5718a03aa 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -2025,6 +2025,8 @@ ol_txrx_vdev_attach(struct cdp_pdev *ppdev, vdev->tx_fl_hwm = 0; vdev->rx = NULL; vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + qdf_mem_zero(&vdev->last_peer_mac_addr, + sizeof(union ol_txrx_align_mac_addr_t)); qdf_spinlock_create(&vdev->flow_control_lock); vdev->osif_flow_control_cb = NULL; vdev->osif_fc_ctx = NULL; @@ -2379,6 +2381,8 @@ ol_txrx_peer_attach(struct cdp_vdev *pvdev, uint8_t *peer_mac_addr) bool wait_on_deletion = false; unsigned long rc; struct ol_txrx_pdev_t *pdev; + bool cmp_wait_mac = false; + uint8_t zero_mac_addr[QDF_MAC_ADDR_SIZE] = { 0, 0, 0, 0, 0, 0 }; /* preconditions */ TXRX_ASSERT2(vdev); @@ -2387,6 +2391,10 @@ ol_txrx_peer_attach(struct cdp_vdev *pvdev, uint8_t *peer_mac_addr) pdev = vdev->pdev; TXRX_ASSERT2(pdev); + if (qdf_mem_cmp(&zero_mac_addr, &vdev->last_peer_mac_addr, + QDF_MAC_ADDR_SIZE)) + cmp_wait_mac = true; + qdf_spin_lock_bh(&pdev->peer_ref_mutex); /* check for duplicate exsisting peer */ TAILQ_FOREACH(temp_peer, &vdev->peer_list, peer_list_elem) { @@ -2402,14 +2410,40 @@ ol_txrx_peer_attach(struct cdp_vdev *pvdev, uint8_t *peer_mac_addr) vdev->wait_on_peer_id = temp_peer->local_id; qdf_event_reset(&vdev->wait_delete_comp); wait_on_deletion = true; + break; } else { qdf_spin_unlock_bh(&pdev->peer_ref_mutex); return NULL; } } + if (cmp_wait_mac && !ol_txrx_peer_find_mac_addr_cmp( + &temp_peer->mac_addr, + &vdev->last_peer_mac_addr)) { + ol_txrx_info( + "vdev_id %d (%02x:%02x:%02x:%02x:%02x:%02x) old peer exsist.\n", + vdev->vdev_id, + vdev->last_peer_mac_addr.raw[0], + vdev->last_peer_mac_addr.raw[1], + vdev->last_peer_mac_addr.raw[2], + vdev->last_peer_mac_addr.raw[3], + vdev->last_peer_mac_addr.raw[4], + vdev->last_peer_mac_addr.raw[5]); + if (qdf_atomic_read(&temp_peer->delete_in_progress)) { + vdev->wait_on_peer_id = temp_peer->local_id; + qdf_event_reset(&vdev->wait_delete_comp); + wait_on_deletion = true; + break; + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + ol_txrx_err("peer not found"); + return NULL; + } + } } qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + qdf_mem_zero(&vdev->last_peer_mac_addr, + sizeof(union ol_txrx_align_mac_addr_t)); if (wait_on_deletion) { /* wait for peer deletion */ rc = qdf_wait_single_event(&vdev->wait_delete_comp, @@ -3387,6 +3421,12 @@ static void ol_txrx_peer_detach(void *ppeer) */ qdf_atomic_set(&peer->delete_in_progress, 1); + if (vdev->opmode == wlan_op_mode_sta) { + qdf_mem_copy(&peer->vdev->last_peer_mac_addr, + &peer->mac_addr, + sizeof(union ol_txrx_align_mac_addr_t)); + } + /* * Create a timer to track unmap events when the sta peer gets deleted. */ diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h index c948eaa36625..9b7eadfc6f25 100644 --- a/core/dp/txrx/ol_txrx_types.h +++ b/core/dp/txrx/ol_txrx_types.h @@ -1066,6 +1066,7 @@ struct ol_txrx_vdev_t { #endif uint16_t wait_on_peer_id; + union ol_txrx_align_mac_addr_t last_peer_mac_addr; qdf_event_t wait_delete_comp; #if defined(FEATURE_TSO) struct {