소스 검색

qcacmn: CFR: Add protection while accessing cfr lookup table

Protect access to cfr lookup table, since error handling
mechanism attempts to cleanup CFR entries in timer context,
this leads to contention between bottom-half and timer.

Change-Id: I32a095fc82545ab117ab43a81ef8a3a5602741fc
CRs-Fixed: 2649714
Padma Raghunathan 5 년 전
부모
커밋
07ed407a56
2개의 변경된 파일47개의 추가작업 그리고 20개의 파일을 삭제
  1. 43 18
      target_if/cfr/src/target_if_cfr_6018.c
  2. 4 2
      umac/cfr/dispatcher/inc/wlan_cfr_utils_api.h

+ 43 - 18
target_if/cfr/src/target_if_cfr_6018.c

@@ -105,6 +105,8 @@ void target_if_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev)
 		return;
 	}
 
+	qdf_spin_lock_bh(&pcfr->lut_lock);
+
 	for (i = 0; i < NUM_LUT_ENTRIES; i++) {
 		lut = get_lut_entry(pcfr, i);
 		if (!lut)
@@ -122,6 +124,9 @@ void target_if_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev)
 		}
 
 	}
+
+	qdf_spin_unlock_bh(&pcfr->lut_lock);
+
 	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
 }
 
@@ -617,19 +622,19 @@ void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
 						     WLAN_UMAC_COMP_CFR);
 	if (qdf_unlikely(!pcfr)) {
 		cfr_err("pdev object for CFR is NULL");
-		goto done;
+		goto relref;
 	}
 
 	cdp_rx_ppdu = (struct cdp_rx_indication_ppdu *)qdf_nbuf_data(nbuf);
 	cfr_info = &cdp_rx_ppdu->cfr_info;
 
 	if (!cfr_info->bb_captured_channel)
-		goto done;
+		goto relref;
 
 	psoc = wlan_pdev_get_psoc(pdev);
 	if (qdf_unlikely(!psoc)) {
 		cfr_err("psoc is null\n");
-		goto done;
+		goto relref;
 	}
 
 	cfr_rx_ops = &psoc->soc_cb.rx_ops.cfr_rx_ops;
@@ -642,7 +647,7 @@ void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
 					&cookie, 0)) {
 		cfr_debug("Cookie lookup failure for addr: 0x%pK",
 			  (void *)((uintptr_t)buf_addr));
-		goto done;
+		goto relref;
 	}
 
 	cfr_debug("<RXTLV><%u>:buffer address: 0x%pK \n"
@@ -661,16 +666,18 @@ void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
 		  cfr_info->rtt_che_buffer_pointer_high8,
 		  cfr_info->chan_capture_status);
 
+	qdf_spin_lock_bh(&pcfr->lut_lock);
+
 	lut = get_lut_entry(pcfr, cookie);
 	if (qdf_unlikely(!lut)) {
 		cfr_err("lut is NULL");
-		goto done;
+		goto unlock;
 	}
 
 	vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_CFR_ID);
 	if (qdf_unlikely(!vdev)) {
 		cfr_debug("vdev is null\n");
-		goto done;
+		goto unlock;
 	}
 
 	bss_chan = wlan_vdev_mlme_get_bss_chan(vdev);
@@ -745,9 +752,12 @@ void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
 		cfr_debug("HOLD for buffer address: 0x%pK cookie: %u",
 			  (void *)((uintptr_t)buf_addr), cookie);
 	} else {
-		cfr_err("Correlation returned invalid status!!");
+		cfr_debug("Correlation returned invalid status!!");
 	}
-done:
+
+unlock:
+	qdf_spin_unlock_bh(&pcfr->lut_lock);
+relref:
 	qdf_nbuf_free(nbuf);
 	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
 }
@@ -853,9 +863,12 @@ static bool enh_cfr_dbr_event_handler(struct wlan_objmgr_pdev *pdev,
 	length  = dma_hdr.length * 4;
 	length += dma_hdr.total_bytes; /* size of cfr data */
 
+	qdf_spin_lock_bh(&pcfr->lut_lock);
+
 	lut = get_lut_entry(pcfr, cookie);
 	if (!lut) {
 		cfr_err("lut is NULL");
+		qdf_spin_unlock_bh(&pcfr->lut_lock);
 		return true;
 	}
 
@@ -916,10 +929,11 @@ static bool enh_cfr_dbr_event_handler(struct wlan_objmgr_pdev *pdev,
 			  "Buffer is not released");
 		status = false;
 	} else {
-		cfr_err("Correlation returned invalid status!!");
+		cfr_debug("Correlation returned invalid status!!");
 		status = true;
 	}
 
+	qdf_spin_unlock_bh(&pcfr->lut_lock);
 	return status;
 }
 
@@ -1128,7 +1142,7 @@ target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
 	if (!pcfr) {
 		cfr_err("pdev object for CFR is NULL");
 		retval = -EINVAL;
-		goto end;
+		goto relref;
 	}
 
 	if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_PS_STATUS_MASK) == 1) {
@@ -1144,14 +1158,14 @@ target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
 						  NULL, 0, &end_magic, 4);
 
 		retval = -EINVAL;
-		goto end;
+		goto relref;
 	}
 
 	if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_STATUS_MASK) == 0) {
 		cfr_debug("CFR capture failed for peer : %s",
 			  mac2str(&tx_evt_param.peer_mac_addr.bytes[0]));
 		retval = -EINVAL;
-		goto end;
+		goto relref;
 	}
 
 	if (tx_evt_param.status & CFR_TX_EVT_STATUS_MASK) {
@@ -1159,7 +1173,7 @@ target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
 			  tx_evt_param.status & CFR_TX_EVT_STATUS_MASK,
 			  mac2str(&tx_evt_param.peer_mac_addr.bytes[0]));
 		retval = -EINVAL;
-		goto end;
+		goto relref;
 	}
 
 	buf_addr_temp = (tx_evt_param.correlation_info_2 & 0x0f);
@@ -1171,7 +1185,7 @@ target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
 		cfr_debug("Cookie lookup failure for addr: 0x%pK status: 0x%x",
 			  (void *)((uintptr_t)buf_addr), tx_evt_param.status);
 		retval = -EINVAL;
-		goto end;
+		goto relref;
 	}
 
 	cfr_debug("buffer address: 0x%pK cookie: %u",
@@ -1179,11 +1193,13 @@ target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
 
 	dump_cfr_peer_tx_event_enh(&tx_evt_param, cookie);
 
+	qdf_spin_lock_bh(&pcfr->lut_lock);
+
 	lut = get_lut_entry(pcfr, cookie);
 	if (!lut) {
 		cfr_err("lut is NULL\n");
 		retval = -EINVAL;
-		goto end;
+		goto unlock;
 	}
 
 	pcfr->tx_evt_cnt++;
@@ -1255,12 +1271,13 @@ target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
 		cfr_debug("HOLD for buffer address: 0x%pK cookie: %u",
 			  (void *)((uintptr_t)buf_addr), cookie);
 	} else {
-		cfr_err("Correlation returned invalid status!!");
+		cfr_debug("Correlation returned invalid status!!");
 		retval = -EINVAL;
-		goto end;
 	}
 
-end:
+unlock:
+	qdf_spin_unlock_bh(&pcfr->lut_lock);
+relref:
 
 	wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID);
@@ -1371,6 +1388,8 @@ static os_timer_func(lut_ageout_timer_task)
 
 	cur_tstamp = qdf_ktime_to_ms(qdf_ktime_get());
 
+	qdf_spin_lock_bh(&pcfr->lut_lock);
+
 	for (i = 0; i < NUM_LUT_ENTRIES; i++) {
 		lut = get_lut_entry(pcfr, i);
 		if (!lut)
@@ -1392,6 +1411,8 @@ static os_timer_func(lut_ageout_timer_task)
 		}
 	}
 
+	qdf_spin_unlock_bh(&pcfr->lut_lock);
+
 	if (pcfr->lut_timer_init)
 		qdf_timer_mod(&pcfr->lut_age_timer, LUT_AGE_TIMER);
 	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
@@ -1568,6 +1589,8 @@ QDF_STATUS cfr_6018_init_pdev(struct wlan_objmgr_psoc *psoc,
 		pcfr->lut_timer_init = 1;
 	}
 
+	qdf_spinlock_create(&pcfr->lut_lock);
+
 	return status;
 }
 
@@ -1622,5 +1645,7 @@ QDF_STATUS cfr_6018_deinit_pdev(struct wlan_objmgr_psoc *psoc,
 	if (status != QDF_STATUS_SUCCESS)
 		cfr_err("Failed to register with dbr");
 
+	qdf_spinlock_destroy(&pcfr->lut_lock);
+
 	return status;
 }

+ 4 - 2
umac/cfr/dispatcher/inc/wlan_cfr_utils_api.h

@@ -452,11 +452,12 @@ struct cfr_rcc_param {
  * data length was invalid
  * flush_timeout_dbr_cnt: No. of DBR completion flushed out in ageout logic
  * clear_txrx_event: No. of PPDU status TLVs over-written in LUT
- * unassoc_pool: Pool of un-associated clients used when capture method is
- * CFR_CAPTURE_METHOD_PROBE_RESPONSE
  * last_success_tstamp: DBR timestamp which indicates that both DBR and TX/RX
  * events have been received successfully.
  * cfr_dma_aborts: No. of CFR DMA aborts in ucode
+ * unassoc_pool: Pool of un-associated clients used when capture method is
+ * CFR_CAPTURE_METHOD_PROBE_RESPONSE
+ * lut_lock: Lock to protect access to cfr lookup table
  */
 /*
  * To be extended if we get more capbality info
@@ -495,6 +496,7 @@ struct pdev_cfr {
 	uint64_t cfr_dma_aborts;
 #endif
 	struct unassoc_pool_entry unassoc_pool[MAX_CFR_ENABLED_CLIENTS];
+	qdf_spinlock_t lut_lock;
 };
 
 #define PEER_CFR_CAPTURE_ENABLE   1