Explorar o código

qcacmn: Reset tx desc as part of flow pool delete

Tx desc flow pool for the vdev is not deleted as part
of disconnection due to tx_desc pending to be processed
in tx comp ring. Hdd_stop is triggered immediately after
this causing dp vdev detach. In parallel, the tx desc
from the tx comp ring is processed, wherein stale vdev
address is derefernced to get dp soc causing page fault.

Fix is to reset tx desc by setting the vdev to NULL as
part of dp_tx_delete_flow_pool and also reset count to
zero in dp_tx_comp_handler before ring desc process loop.

Change-Id: I66f718668ba84f89106d09e624d9593f89479e55
CRs-Fixed: 2683874
Yeshwanth Sriram Guntuka %!s(int64=5) %!d(string=hai) anos
pai
achega
6159db7efa
Modificáronse 3 ficheiros con 15 adicións e 7 borrados
  1. 6 7
      dp/wifi3.0/dp_tx.c
  2. 2 0
      dp/wifi3.0/dp_tx.h
  3. 7 0
      dp/wifi3.0/dp_tx_flow_control.c

+ 6 - 7
dp/wifi3.0/dp_tx.c

@@ -3738,7 +3738,7 @@ uint32_t dp_tx_comp_handler(struct dp_intr *int_ctx, struct dp_soc *soc,
 	struct dp_tx_desc_s *head_desc = NULL;
 	struct dp_tx_desc_s *tail_desc = NULL;
 	uint32_t num_processed = 0;
-	uint32_t count = 0;
+	uint32_t count;
 	uint32_t num_avail_for_reap = 0;
 	bool force_break = false;
 
@@ -3748,6 +3748,7 @@ more_data:
 	/* Re-initialize local variables to be re-used */
 	head_desc = NULL;
 	tail_desc = NULL;
+	count = 0;
 
 	if (qdf_unlikely(dp_srng_access_start(int_ctx, soc, hal_ring_hdl))) {
 		dp_err("HAL RING Access Failed -- %pK", hal_ring_hdl);
@@ -4086,9 +4087,8 @@ dp_is_tx_desc_flush_match(struct dp_pdev *pdev,
  * the outstanding TX data or reset Vdev to NULL in associated TX
  * Desc.
  */
-static void dp_tx_desc_flush(struct dp_pdev *pdev,
-			     struct dp_vdev *vdev,
-			     bool force_free)
+void dp_tx_desc_flush(struct dp_pdev *pdev, struct dp_vdev *vdev,
+		      bool force_free)
 {
 	uint8_t i;
 	uint32_t j;
@@ -4171,9 +4171,8 @@ dp_tx_desc_reset_vdev(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 	TX_DESC_LOCK_UNLOCK(&soc->tx_desc[desc_pool_id].lock);
 }
 
-static void dp_tx_desc_flush(struct dp_pdev *pdev,
-			     struct dp_vdev *vdev,
-			     bool force_free)
+void dp_tx_desc_flush(struct dp_pdev *pdev, struct dp_vdev *vdev,
+		      bool force_free)
 {
 	uint8_t i, num_pool;
 	uint32_t j;

+ 2 - 0
dp/wifi3.0/dp_tx.h

@@ -503,4 +503,6 @@ QDF_STATUS dp_peer_set_tx_capture_enabled(struct dp_pdev *pdev,
 	return QDF_STATUS_SUCCESS;
 }
 #endif
+void dp_tx_desc_flush(struct dp_pdev *pdev, struct dp_vdev *vdev,
+		      bool force_free);
 #endif

+ 7 - 0
dp/wifi3.0/dp_tx_flow_control.c

@@ -313,6 +313,8 @@ struct dp_tx_desc_pool_s *dp_tx_create_flow_pool(struct dp_soc *soc,
 int dp_tx_delete_flow_pool(struct dp_soc *soc, struct dp_tx_desc_pool_s *pool,
 	bool force)
 {
+	struct dp_vdev *vdev;
+
 	if (!soc || !pool) {
 		dp_err("pool or soc is NULL");
 		QDF_ASSERT(0);
@@ -339,6 +341,11 @@ int dp_tx_delete_flow_pool(struct dp_soc *soc, struct dp_tx_desc_pool_s *pool,
 	if (pool->avail_desc < pool->pool_size) {
 		pool->status = FLOW_POOL_INVALID;
 		qdf_spin_unlock_bh(&pool->flow_pool_lock);
+		/* Reset TX desc associated to this Vdev as NULL */
+		vdev = dp_get_vdev_from_soc_vdev_id_wifi3(soc,
+							  pool->flow_pool_id);
+		if (vdev)
+			dp_tx_desc_flush(vdev->pdev, vdev, false);
 		dp_err("avail desc less than pool size");
 		return -EAGAIN;
 	}