Przeglądaj źródła

qcacmn: Force free leaking TX completion in PERF build

When TX completion entires are pending over 60 seconds,
Perform force free for these entries that belong to invalid
vdev. This could allow system to continue to go to suspend.

Change-Id: I34a39b8c7a9385fea0bed087e0644564f426bf90
CRs-Fixed: 3252807
Yu Tian 2 lat temu
rodzic
commit
c58feb9240
3 zmienionych plików z 58 dodań i 0 usunięć
  1. 54 0
      dp/wifi3.0/dp_main.c
  2. 2 0
      dp/wifi3.0/dp_stats.c
  3. 2 0
      dp/wifi3.0/dp_types.h

+ 54 - 0
dp/wifi3.0/dp_main.c

@@ -13124,6 +13124,7 @@ static bool dp_tx_comp_delay_check(struct dp_tx_desc_s *tx_desc)
 	return false;
 }
 
+#if defined(CONFIG_SLUB_DEBUG_ON)
 /**
  * dp_find_missing_tx_comp() - check for leaked descriptor in tx path
  * @soc - DP SOC context
@@ -13196,6 +13197,59 @@ static void dp_find_missing_tx_comp(struct dp_soc *soc)
 	}
 }
 #else
+static void dp_find_missing_tx_comp(struct dp_soc *soc)
+{
+	uint8_t i;
+	uint32_t j;
+	uint32_t num_desc, page_id, offset;
+	uint16_t num_desc_per_page;
+	struct dp_tx_desc_s *tx_desc = NULL;
+	struct dp_tx_desc_pool_s *tx_desc_pool = NULL;
+
+	for (i = 0; i < MAX_TXDESC_POOLS; i++) {
+		tx_desc_pool = &soc->tx_desc[i];
+		if (!(tx_desc_pool->pool_size) ||
+		    IS_TX_DESC_POOL_STATUS_INACTIVE(tx_desc_pool) ||
+		    !(tx_desc_pool->desc_pages.cacheable_pages))
+			continue;
+
+		num_desc = tx_desc_pool->pool_size;
+		num_desc_per_page =
+			tx_desc_pool->desc_pages.num_element_per_page;
+		for (j = 0; j < num_desc; j++) {
+			page_id = j / num_desc_per_page;
+			offset = j % num_desc_per_page;
+
+			if (qdf_unlikely(!(tx_desc_pool->
+					 desc_pages.cacheable_pages)))
+				break;
+
+			tx_desc = dp_tx_desc_find(soc, i, page_id, offset);
+			if (tx_desc->magic == DP_TX_MAGIC_PATTERN_FREE) {
+				continue;
+			} else if (tx_desc->magic ==
+				   DP_TX_MAGIC_PATTERN_INUSE) {
+				if (dp_tx_comp_delay_check(tx_desc)) {
+					dp_err_rl("Tx completion not rcvd for id: %u",
+						  tx_desc->id);
+					if (tx_desc->vdev_id == DP_INVALID_VDEV_ID) {
+						tx_desc->flags |= DP_TX_DESC_FLAG_FLUSH;
+						dp_tx_comp_free_buf(soc, tx_desc);
+						dp_tx_desc_release(tx_desc, i);
+						DP_STATS_INC(soc,
+							     tx.tx_comp_force_freed, 1);
+						dp_err_rl("Tx completion force freed");
+					}
+				}
+			} else {
+				dp_err_rl("tx desc %u corrupted, flags: 0x%x",
+					  tx_desc->id, tx_desc->flags);
+			}
+		}
+	}
+}
+#endif /* CONFIG_SLUB_DEBUG_ON */
+#else
 static inline void dp_find_missing_tx_comp(struct dp_soc *soc)
 {
 }

+ 2 - 0
dp/wifi3.0/dp_stats.c

@@ -7101,6 +7101,8 @@ void dp_txrx_path_stats(struct dp_soc *soc)
 			       pdev->soc->stats.tx.tx_invalid_peer.num);
 		DP_PRINT_STATS("Tx desc freed in non-completion path: %u",
 			       pdev->soc->stats.tx.tx_comp_exception);
+		DP_PRINT_STATS("Tx desc force freed: %u",
+			       pdev->soc->stats.tx.tx_comp_force_freed);
 
 		DP_PRINT_STATS("Tx packets sent per interrupt:");
 		DP_PRINT_STATS("Single Packet: %u",

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

@@ -1072,6 +1072,8 @@ struct dp_soc_stats {
 		uint64_t tqm_drop_no_peer;
 		/* Number of tx completions reaped per WBM2SW release ring */
 		uint32_t tx_comp[MAX_TCL_DATA_RINGS];
+		/* Number of tx completions force freed */
+		uint32_t tx_comp_force_freed;
 	} tx;
 
 	/* SOC level RX stats */