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
This commit is contained in:
Padma Raghunathan
2020-03-10 11:07:53 +05:30
committed by nshrivas
parent 407870de43
commit 07ed407a56
2 changed files with 47 additions and 20 deletions

View File

@@ -105,6 +105,8 @@ void target_if_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev)
return; return;
} }
qdf_spin_lock_bh(&pcfr->lut_lock);
for (i = 0; i < NUM_LUT_ENTRIES; i++) { for (i = 0; i < NUM_LUT_ENTRIES; i++) {
lut = get_lut_entry(pcfr, i); lut = get_lut_entry(pcfr, i);
if (!lut) 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); 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); WLAN_UMAC_COMP_CFR);
if (qdf_unlikely(!pcfr)) { if (qdf_unlikely(!pcfr)) {
cfr_err("pdev object for CFR is NULL"); cfr_err("pdev object for CFR is NULL");
goto done; goto relref;
} }
cdp_rx_ppdu = (struct cdp_rx_indication_ppdu *)qdf_nbuf_data(nbuf); cdp_rx_ppdu = (struct cdp_rx_indication_ppdu *)qdf_nbuf_data(nbuf);
cfr_info = &cdp_rx_ppdu->cfr_info; cfr_info = &cdp_rx_ppdu->cfr_info;
if (!cfr_info->bb_captured_channel) if (!cfr_info->bb_captured_channel)
goto done; goto relref;
psoc = wlan_pdev_get_psoc(pdev); psoc = wlan_pdev_get_psoc(pdev);
if (qdf_unlikely(!psoc)) { if (qdf_unlikely(!psoc)) {
cfr_err("psoc is null\n"); cfr_err("psoc is null\n");
goto done; goto relref;
} }
cfr_rx_ops = &psoc->soc_cb.rx_ops.cfr_rx_ops; 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)) { &cookie, 0)) {
cfr_debug("Cookie lookup failure for addr: 0x%pK", cfr_debug("Cookie lookup failure for addr: 0x%pK",
(void *)((uintptr_t)buf_addr)); (void *)((uintptr_t)buf_addr));
goto done; goto relref;
} }
cfr_debug("<RXTLV><%u>:buffer address: 0x%pK \n" 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->rtt_che_buffer_pointer_high8,
cfr_info->chan_capture_status); cfr_info->chan_capture_status);
qdf_spin_lock_bh(&pcfr->lut_lock);
lut = get_lut_entry(pcfr, cookie); lut = get_lut_entry(pcfr, cookie);
if (qdf_unlikely(!lut)) { if (qdf_unlikely(!lut)) {
cfr_err("lut is NULL"); cfr_err("lut is NULL");
goto done; goto unlock;
} }
vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_CFR_ID); vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_CFR_ID);
if (qdf_unlikely(!vdev)) { if (qdf_unlikely(!vdev)) {
cfr_debug("vdev is null\n"); cfr_debug("vdev is null\n");
goto done; goto unlock;
} }
bss_chan = wlan_vdev_mlme_get_bss_chan(vdev); 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", cfr_debug("HOLD for buffer address: 0x%pK cookie: %u",
(void *)((uintptr_t)buf_addr), cookie); (void *)((uintptr_t)buf_addr), cookie);
} else { } 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); qdf_nbuf_free(nbuf);
wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); 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.length * 4;
length += dma_hdr.total_bytes; /* size of cfr data */ length += dma_hdr.total_bytes; /* size of cfr data */
qdf_spin_lock_bh(&pcfr->lut_lock);
lut = get_lut_entry(pcfr, cookie); lut = get_lut_entry(pcfr, cookie);
if (!lut) { if (!lut) {
cfr_err("lut is NULL"); cfr_err("lut is NULL");
qdf_spin_unlock_bh(&pcfr->lut_lock);
return true; return true;
} }
@@ -916,10 +929,11 @@ static bool enh_cfr_dbr_event_handler(struct wlan_objmgr_pdev *pdev,
"Buffer is not released"); "Buffer is not released");
status = false; status = false;
} else { } else {
cfr_err("Correlation returned invalid status!!"); cfr_debug("Correlation returned invalid status!!");
status = true; status = true;
} }
qdf_spin_unlock_bh(&pcfr->lut_lock);
return status; return status;
} }
@@ -1128,7 +1142,7 @@ target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
if (!pcfr) { if (!pcfr) {
cfr_err("pdev object for CFR is NULL"); cfr_err("pdev object for CFR is NULL");
retval = -EINVAL; retval = -EINVAL;
goto end; goto relref;
} }
if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_PS_STATUS_MASK) == 1) { 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); NULL, 0, &end_magic, 4);
retval = -EINVAL; retval = -EINVAL;
goto end; goto relref;
} }
if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_STATUS_MASK) == 0) { if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_STATUS_MASK) == 0) {
cfr_debug("CFR capture failed for peer : %s", cfr_debug("CFR capture failed for peer : %s",
mac2str(&tx_evt_param.peer_mac_addr.bytes[0])); mac2str(&tx_evt_param.peer_mac_addr.bytes[0]));
retval = -EINVAL; retval = -EINVAL;
goto end; goto relref;
} }
if (tx_evt_param.status & CFR_TX_EVT_STATUS_MASK) { 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, tx_evt_param.status & CFR_TX_EVT_STATUS_MASK,
mac2str(&tx_evt_param.peer_mac_addr.bytes[0])); mac2str(&tx_evt_param.peer_mac_addr.bytes[0]));
retval = -EINVAL; retval = -EINVAL;
goto end; goto relref;
} }
buf_addr_temp = (tx_evt_param.correlation_info_2 & 0x0f); 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", cfr_debug("Cookie lookup failure for addr: 0x%pK status: 0x%x",
(void *)((uintptr_t)buf_addr), tx_evt_param.status); (void *)((uintptr_t)buf_addr), tx_evt_param.status);
retval = -EINVAL; retval = -EINVAL;
goto end; goto relref;
} }
cfr_debug("buffer address: 0x%pK cookie: %u", 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); dump_cfr_peer_tx_event_enh(&tx_evt_param, cookie);
qdf_spin_lock_bh(&pcfr->lut_lock);
lut = get_lut_entry(pcfr, cookie); lut = get_lut_entry(pcfr, cookie);
if (!lut) { if (!lut) {
cfr_err("lut is NULL\n"); cfr_err("lut is NULL\n");
retval = -EINVAL; retval = -EINVAL;
goto end; goto unlock;
} }
pcfr->tx_evt_cnt++; 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", cfr_debug("HOLD for buffer address: 0x%pK cookie: %u",
(void *)((uintptr_t)buf_addr), cookie); (void *)((uintptr_t)buf_addr), cookie);
} else { } else {
cfr_err("Correlation returned invalid status!!"); cfr_debug("Correlation returned invalid status!!");
retval = -EINVAL; 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_psoc_release_ref(psoc, WLAN_CFR_ID);
wlan_objmgr_vdev_release_ref(vdev, 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()); cur_tstamp = qdf_ktime_to_ms(qdf_ktime_get());
qdf_spin_lock_bh(&pcfr->lut_lock);
for (i = 0; i < NUM_LUT_ENTRIES; i++) { for (i = 0; i < NUM_LUT_ENTRIES; i++) {
lut = get_lut_entry(pcfr, i); lut = get_lut_entry(pcfr, i);
if (!lut) 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) if (pcfr->lut_timer_init)
qdf_timer_mod(&pcfr->lut_age_timer, LUT_AGE_TIMER); qdf_timer_mod(&pcfr->lut_age_timer, LUT_AGE_TIMER);
wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); 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; pcfr->lut_timer_init = 1;
} }
qdf_spinlock_create(&pcfr->lut_lock);
return status; return status;
} }
@@ -1622,5 +1645,7 @@ QDF_STATUS cfr_6018_deinit_pdev(struct wlan_objmgr_psoc *psoc,
if (status != QDF_STATUS_SUCCESS) if (status != QDF_STATUS_SUCCESS)
cfr_err("Failed to register with dbr"); cfr_err("Failed to register with dbr");
qdf_spinlock_destroy(&pcfr->lut_lock);
return status; return status;
} }

View File

@@ -452,11 +452,12 @@ struct cfr_rcc_param {
* data length was invalid * data length was invalid
* flush_timeout_dbr_cnt: No. of DBR completion flushed out in ageout logic * 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 * 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 * last_success_tstamp: DBR timestamp which indicates that both DBR and TX/RX
* events have been received successfully. * events have been received successfully.
* cfr_dma_aborts: No. of CFR DMA aborts in ucode * 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 * To be extended if we get more capbality info
@@ -495,6 +496,7 @@ struct pdev_cfr {
uint64_t cfr_dma_aborts; uint64_t cfr_dma_aborts;
#endif #endif
struct unassoc_pool_entry unassoc_pool[MAX_CFR_ENABLED_CLIENTS]; struct unassoc_pool_entry unassoc_pool[MAX_CFR_ENABLED_CLIENTS];
qdf_spinlock_t lut_lock;
}; };
#define PEER_CFR_CAPTURE_ENABLE 1 #define PEER_CFR_CAPTURE_ENABLE 1