Просмотр исходного кода

qcacmn: 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: I6a414e0da883250a90451824367c12fcca33c27e
Padma Raghunathan 5 лет назад
Родитель
Сommit
c68c9e44b3
2 измененных файлов с 43 добавлено и 17 удалено
  1. 41 16
      target_if/cfr/src/target_if_cfr_6018.c
  2. 2 1
      umac/cfr/dispatcher/inc/wlan_cfr_utils_api.h

+ 41 - 16
target_if/cfr/src/target_if_cfr_6018.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * any purpose with or without fee is hereby granted, provided that the
@@ -107,6 +107,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)
@@ -124,6 +126,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);
@@ -750,7 +757,10 @@ void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
 	} else {
 	} else {
 		cfr_err("Correlation returned invalid status!!");
 		cfr_err("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);
 }
 }
@@ -856,9 +866,12 @@ 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;
 	}
 	}
 
 
@@ -919,6 +932,7 @@ bool enh_cfr_dbr_event_handler(struct wlan_objmgr_pdev *pdev,
 		status = true;
 		status = true;
 	}
 	}
 
 
+	qdf_spin_unlock_bh(&pcfr->lut_lock);
 	return status;
 	return status;
 }
 }
 
 
@@ -1123,7 +1137,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) {
@@ -1139,14 +1153,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",
 			  ether_sprintf(&tx_evt_param.peer_mac_addr.bytes[0]));
 			  ether_sprintf(&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) {
@@ -1154,7 +1168,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,
 			  ether_sprintf(&tx_evt_param.peer_mac_addr.bytes[0]));
 			  ether_sprintf(&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);
@@ -1166,7 +1180,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",
@@ -1174,11 +1188,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++;
@@ -1252,10 +1268,11 @@ target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
 	} else {
 	} else {
 		cfr_err("Correlation returned invalid status!!");
 		cfr_err("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);
@@ -1366,6 +1383,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)
@@ -1387,6 +1406,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);
@@ -1563,6 +1584,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;
 }
 }
 
 
@@ -1616,6 +1639,8 @@ 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;
 }
 }
 
 

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

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * any purpose with or without fee is hereby granted, provided that the
@@ -495,6 +495,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