From c58feb9240357f1e7ce0537c1f9c11eabb10fcd2 Mon Sep 17 00:00:00 2001 From: Yu Tian Date: Mon, 25 Jul 2022 14:42:12 +0800 Subject: [PATCH] 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 --- dp/wifi3.0/dp_main.c | 54 +++++++++++++++++++++++++++++++++++++++++++ dp/wifi3.0/dp_stats.c | 2 ++ dp/wifi3.0/dp_types.h | 2 ++ 3 files changed, 58 insertions(+) diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 323703fa7a..92ee69d682 100644 --- a/dp/wifi3.0/dp_main.c +++ b/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) { } diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c index d52fb7d616..e29cdafd3e 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/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", diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 0032436d7f..3fd96a69c3 100644 --- a/dp/wifi3.0/dp_types.h +++ b/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 */