Преглед изворни кода

qcacmn: Optimize force free logic in dp_find_missing_tx_comp()

Currently during runtime suspend, in dp_find_missing_tx_comp(),
TX descriptors are freed forcefully if the TX completions for
those descriptors do not arrive within 60 seconds.

In certain rare corner cases, there is a chance of TX buffer (that is
in the enqueue path) getting freed in the TX completion path due to
delayed completions. This results in NULL pointer dereference.
Following is the sequence of events for such a case,

1. dp_find_missing_tx_comp() frees a TX descriptor
2. Different buffer gets attached to the same TX descriptor
3. Delayed completion for the previous TX arrives and frees
   the buffer in point 2.

Defer the free in dp_find_missing_tx_comp() when there is a delta in
HP/TP for the TX/COMP rings. If HP & TP are not same, then there is
high chance of processing the delayed completion beforehand, thus
avoiding the aforementioned race.

Change-Id: Ia835928f85ea0f79d0187a55333cb8959d0a72e9
CRs-Fixed: 3721341
Manikanta Pubbisetty пре 1 година
родитељ
комит
7e58813e0e
3 измењених фајлова са 77 додато и 2 уклоњено
  1. 21 1
      dp/wifi3.0/dp_ipa.c
  2. 17 1
      dp/wifi3.0/dp_ipa.h
  3. 39 0
      dp/wifi3.0/dp_main.c

+ 21 - 1
dp/wifi3.0/dp_ipa.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -4357,4 +4357,24 @@ void dp_ipa_get_wdi_version(struct cdp_soc_t *soc_hdl, uint8_t *wdi_ver)
 	else
 		*wdi_ver = IPA_WDI_3;
 }
+
+#ifdef IPA_WDI3_TX_TWO_PIPES
+bool dp_ipa_is_ring_ipa_tx(struct dp_soc *soc, uint8_t ring_id)
+{
+	if (!soc->wlan_cfg_ctx->ipa_enabled)
+		return false;
+
+	return (ring_id == IPA_TCL_DATA_RING_IDX) ||
+		((ring_id == IPA_TX_ALT_RING_IDX) &&
+		 wlan_cfg_is_ipa_two_tx_pipes_enabled(soc->wlan_cfg_ctx));
+}
+#else
+bool dp_ipa_is_ring_ipa_tx(struct dp_soc *soc, uint8_t ring_id)
+{
+	if (!soc->wlan_cfg_ctx->ipa_enabled)
+		return false;
+
+	return (ring_id == IPA_TCL_DATA_RING_IDX);
+}
+#endif /* IPA_WDI3_TX_TWO_PIPES */
 #endif

+ 17 - 1
dp/wifi3.0/dp_ipa.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -627,6 +627,16 @@ QDF_STATUS dp_ipa_update_peer_rx_stats(struct cdp_soc_t *soc, uint8_t vdev_id,
  * Return: None
  */
 void dp_ipa_get_wdi_version(struct cdp_soc_t *soc_hdl, uint8_t *wdi_ver);
+
+/**
+ * dp_ipa_is_ring_ipa_tx() - Check if the TX ring is used by IPA
+ *
+ * @soc: DP SoC
+ * @ring_id: TX ring id
+ *
+ * Return: bool
+ */
+bool dp_ipa_is_ring_ipa_tx(struct dp_soc *soc, uint8_t ring_id);
 #else
 static inline int dp_ipa_uc_detach(struct dp_soc *soc, struct dp_pdev *pdev)
 {
@@ -729,5 +739,11 @@ static inline void dp_ipa_get_wdi_version(struct cdp_soc_t *soc_hdl,
 					  uint8_t *wdi_ver)
 {
 }
+
+static inline bool
+dp_ipa_is_ring_ipa_tx(struct dp_soc *soc, uint8_t ring_id)
+{
+	return false;
+}
 #endif
 #endif /* _DP_IPA_H_ */

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

@@ -12689,6 +12689,42 @@ static struct cdp_sawf_ops dp_ops_sawf = {
 #ifdef DP_TX_TRACKING
 
 #define DP_TX_COMP_MAX_LATENCY_MS 60000
+
+static bool dp_check_pending_tx(struct dp_soc *soc)
+{
+	hal_soc_handle_t hal_soc = soc->hal_soc;
+	uint32_t hp, tp, i;
+
+	for (i = 0; i < soc->num_tcl_data_rings; i++) {
+		if (dp_ipa_is_ring_ipa_tx(soc, i))
+			continue;
+
+		hal_get_sw_hptp(hal_soc, soc->tcl_data_ring[i].hal_srng,
+				&tp, &hp);
+
+		if (hp != tp) {
+			dp_info_rl("Pending transactions in TCL DATA Ring[%d] hp=0x%x, tp=0x%x",
+				   i, hp, tp);
+			return true;
+		}
+
+		if (wlan_cfg_get_wbm_ring_num_for_index(soc->wlan_cfg_ctx, i) ==
+		    INVALID_WBM_RING_NUM)
+			continue;
+
+		hal_get_sw_hptp(hal_soc, soc->tx_comp_ring[i].hal_srng,
+				&tp, &hp);
+
+		if (hp != tp) {
+			dp_info_rl("Pending transactions in TX comp Ring[%d] hp=0x%x, tp=0x%x",
+				   i, hp, tp);
+			return true;
+		}
+	}
+
+	return false;
+}
+
 /**
  * dp_tx_comp_delay_check() - calculate time latency for tx completion per pkt
  * @tx_desc: tx descriptor
@@ -12742,6 +12778,9 @@ void dp_find_missing_tx_comp(struct dp_soc *soc)
 	struct dp_tx_desc_s *tx_desc = NULL;
 	struct dp_tx_desc_pool_s *tx_desc_pool = NULL;
 
+	if (dp_check_pending_tx(soc))
+		return;
+
 	for (i = 0; i < MAX_TXDESC_POOLS; i++) {
 		tx_desc_pool = &soc->tx_desc[i];
 		if (!(tx_desc_pool->pool_size) ||