Prechádzať zdrojové kódy

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
Abhishek Singh 8 rokov pred
rodič
commit
217d978511
2 zmenil súbory, kde vykonal 41 pridanie a 0 odobranie
  1. 40 0
      core/dp/txrx/ol_txrx.c
  2. 1 0
      core/dp/txrx/ol_txrx_types.h

+ 40 - 0
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.
 	 */

+ 1 - 0
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 {