From 7e58813e0e2e3b3a0d5481ffc3f20f7cdea6a79a Mon Sep 17 00:00:00 2001 From: Manikanta Pubbisetty Date: Mon, 5 Feb 2024 15:17:38 +0530 Subject: [PATCH] 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 --- dp/wifi3.0/dp_ipa.c | 22 +++++++++++++++++++++- dp/wifi3.0/dp_ipa.h | 18 +++++++++++++++++- dp/wifi3.0/dp_main.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/dp/wifi3.0/dp_ipa.c b/dp/wifi3.0/dp_ipa.c index 6c1359c610..84f701b5a6 100644 --- a/dp/wifi3.0/dp_ipa.c +++ b/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 diff --git a/dp/wifi3.0/dp_ipa.h b/dp/wifi3.0/dp_ipa.h index 2d96dea0a1..57d5c78f49 100644 --- a/dp/wifi3.0/dp_ipa.h +++ b/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_ */ diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index a93678f2ff..a913515d7b 100644 --- a/dp/wifi3.0/dp_main.c +++ b/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) ||