Merge "qca-wifi: Fix for tx capture softlockup on mode change"
diff --git a/dp/wifi3.0/dp_tx_capture.c b/dp/wifi3.0/dp_tx_capture.c
index 5cb8105..390a12f 100644
--- a/dp/wifi3.0/dp_tx_capture.c
+++ b/dp/wifi3.0/dp_tx_capture.c
@@ -525,7 +525,7 @@
 	bool found = false;
 
 	found = dp_peer_tx_cap_search(pdev, peer_id, mac_addr);
-	QDF_TRACE(QDF_MODULE_ID_TX_CAPTURE, QDF_TRACE_LEVEL_INFO_LOW,
+	QDF_TRACE(QDF_MODULE_ID_TX_CAPTURE, QDF_TRACE_LEVEL_INFO_HIGH,
 		  "%s: %d peer_id[%d] mac_addr[%pM] found[%d]!",
 		  __func__, __LINE__, peer_id, mac_addr, found);
 
@@ -545,6 +545,7 @@
 	int i, j;
 
 	tx_capture = &pdev->tx_capture;
+	tx_capture->tx_cap_mode_flag = true;
 	/* Work queue setup for HTT stats and tx capture handling */
 	qdf_create_work(0, &pdev->tx_capture.ppdu_stats_work,
 			dp_tx_ppdu_stats_process,
@@ -937,6 +938,44 @@
 }
 
 /*
+ * dp_enh_tx_capture_disable()- API to disable enhanced tx capture
+ * @pdev_handle: DP_PDEV handle
+ *
+ * Return: void
+ */
+void
+dp_enh_tx_capture_disable(struct dp_pdev *pdev)
+{
+	int i, j;
+
+	dp_soc_set_txrx_ring_map(pdev->soc);
+	dp_h2t_cfg_stats_msg_send(pdev,
+				  DP_PPDU_STATS_CFG_ENH_STATS,
+				  pdev->pdev_id);
+	dp_iterate_free_peer_msdu_q(pdev);
+	for (i = 0; i < TXCAP_MAX_TYPE; i++) {
+		for (j = 0; j < TXCAP_MAX_SUBTYPE; j++) {
+			qdf_nbuf_queue_t *retries_q;
+
+			qdf_spin_lock_bh(
+				&pdev->tx_capture.ctl_mgmt_lock[i][j]);
+			qdf_nbuf_queue_free(
+				&pdev->tx_capture.ctl_mgmt_q[i][j]);
+			qdf_spin_unlock_bh(
+				&pdev->tx_capture.ctl_mgmt_lock[i][j]);
+			retries_q = &pdev->tx_capture.retries_ctl_mgmt_q[i][j];
+			if (!qdf_nbuf_is_queue_empty(retries_q))
+				qdf_nbuf_queue_free(retries_q);
+		}
+	}
+	dp_peer_tx_cap_del_all_filter(pdev);
+	pdev->tx_capture.tx_cap_mode_flag = true;
+	QDF_TRACE(QDF_MODULE_ID_TX_CAPTURE, QDF_TRACE_LEVEL_INFO_LOW,
+		  "Mode change request done cur mode - %d\n",
+		  pdev->tx_capture_enabled);
+}
+
+/*
  * dp_config_enh_tx_capture()- API to enable/disable enhanced tx capture
  * @pdev_handle: DP_PDEV handle
  * @val: user provided value
@@ -946,10 +985,28 @@
 QDF_STATUS
 dp_config_enh_tx_capture(struct dp_pdev *pdev, uint8_t val)
 {
-	int i, j;
-
 	qdf_spin_lock(&pdev->tx_capture.config_lock);
-	pdev->tx_capture_enabled = val;
+	if (pdev->tx_capture.tx_cap_mode_flag) {
+		pdev->tx_capture.tx_cap_mode_flag = false;
+		pdev->tx_capture_enabled = val;
+		QDF_TRACE(QDF_MODULE_ID_TX_CAPTURE, QDF_TRACE_LEVEL_INFO_LOW,
+			  "Mode change requested - %d\n",
+			  pdev->tx_capture_enabled);
+	} else if (!pdev->tx_capture.tx_cap_mode_flag &&
+		   !val && !!pdev->tx_capture_enabled) {
+		/* here the val is always 0 which is disable */
+		pdev->tx_capture_enabled = val;
+		pdev->tx_capture.tx_cap_mode_flag = false;
+		QDF_TRACE(QDF_MODULE_ID_TX_CAPTURE, QDF_TRACE_LEVEL_INFO_LOW,
+			  "Mode change requested - %d\n",
+			  pdev->tx_capture_enabled);
+	} else {
+		QDF_TRACE(QDF_MODULE_ID_TX_CAPTURE, QDF_TRACE_LEVEL_INFO_LOW,
+			  "Mode change request pending prev mode - %d\n",
+			  pdev->tx_capture_enabled);
+		qdf_spin_unlock(&pdev->tx_capture.config_lock);
+		return QDF_STATUS_E_BUSY;
+	}
 
 	if (pdev->tx_capture_enabled == CDP_TX_ENH_CAPTURE_ENABLE_ALL_PEERS ||
 	    pdev->tx_capture_enabled == CDP_TX_ENH_CAPTURE_ENDIS_PER_PEER) {
@@ -958,26 +1015,13 @@
 			dp_h2t_cfg_stats_msg_send(pdev,
 						  DP_PPDU_STATS_CFG_SNIFFER,
 						  pdev->pdev_id);
-	} else {
-		dp_soc_set_txrx_ring_map(pdev->soc);
-		dp_h2t_cfg_stats_msg_send(pdev,
-					  DP_PPDU_STATS_CFG_ENH_STATS,
-					  pdev->pdev_id);
-		dp_iterate_free_peer_msdu_q(pdev);
-		for (i = 0; i < TXCAP_MAX_TYPE; i++) {
-			for (j = 0; j < TXCAP_MAX_SUBTYPE; j++) {
-				qdf_spin_lock_bh(
-					&pdev->tx_capture.ctl_mgmt_lock[i][j]);
-				qdf_nbuf_queue_free(
-					&pdev->tx_capture.ctl_mgmt_q[i][j]);
-				qdf_spin_unlock_bh(
-					&pdev->tx_capture.ctl_mgmt_lock[i][j]);
-			}
-		}
-		dp_peer_tx_cap_del_all_filter(pdev);
+		pdev->tx_capture.tx_cap_mode_flag = true;
+		QDF_TRACE(QDF_MODULE_ID_TX_CAPTURE, QDF_TRACE_LEVEL_INFO_LOW,
+			  "Mode change request done cur mode - %d\n",
+			  pdev->tx_capture_enabled);
 	}
-
 	qdf_spin_unlock(&pdev->tx_capture.config_lock);
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -3168,6 +3212,9 @@
 			/* send WDI event */
 			if (pdev->tx_capture_enabled ==
 			    CDP_TX_ENH_CAPTURE_DISABLED) {
+				if (!pdev->tx_capture.tx_cap_mode_flag)
+					dp_enh_tx_capture_disable(pdev);
+
 				/**
 				 * Deliver PPDU stats only for valid (acked)
 				 * data frames if sniffer mode is not enabled.
@@ -3360,6 +3407,11 @@
 
 		qdf_spin_unlock(&ptr_tx_cap->config_lock);
 		qdf_mem_free(nbuf_ppdu_desc_list);
+
+		qdf_spin_lock(&pdev->tx_capture.config_lock);
+		if (!pdev->tx_capture.tx_cap_mode_flag)
+			dp_enh_tx_capture_disable(pdev);
+		qdf_spin_unlock(&pdev->tx_capture.config_lock);
 	}
 }
 
diff --git a/dp/wifi3.0/dp_tx_capture.h b/dp/wifi3.0/dp_tx_capture.h
index 016675c..52bc8c4 100644
--- a/dp/wifi3.0/dp_tx_capture.h
+++ b/dp/wifi3.0/dp_tx_capture.h
@@ -71,6 +71,7 @@
 	uint32_t htt_frame_type[TX_CAP_HTT_MAX_FTYPE];
 	struct cdp_tx_completion_ppdu dummy_ppdu_desc;
 	struct dp_peer_mgmt_list *ptr_peer_mgmt_list;
+	bool tx_cap_mode_flag;
 };
 
 /* Tx TID */