From 1bf08f3566f65323b20a56cf44cc59d0deaf6be1 Mon Sep 17 00:00:00 2001 From: Jinwei Chen Date: Wed, 30 Nov 2022 02:14:31 -0800 Subject: [PATCH] qcacmn: Add TX completion ring desc sanity check Suspect HW update WBM2SW ring HP, but the ring entry contents are not updated accordingly which then host will fetch one stale ring entry, this makes other TX packet are freed unexpectedlly. Add change to detect this situation earlier, if HW cookie conversion is done, then invalidate 2nd dword for upper 32bits of VA, so next time when reap this ring entry contents to know if this desc is updated by HW or not. if HW cookie conversion is not done, then compare the PA in buff_addr_info with PA in current TX desc to check. Change-Id: I351eb4f860216fc618ff28736d4832fcec45dcc5 CRs-Fixed: 3345935 --- dp/inc/cdp_txrx_stats_struct.h | 2 + dp/wifi3.0/be/dp_be_tx.c | 113 ++++++++++++++++++++++++--------- dp/wifi3.0/be/dp_be_tx.h | 27 ++++++++ dp/wifi3.0/dp_stats.c | 6 ++ dp/wifi3.0/dp_tx.c | 4 +- dp/wifi3.0/dp_types.h | 8 ++- hal/wifi3.0/be/hal_be_tx.h | 18 +++++- 7 files changed, 141 insertions(+), 37 deletions(-) diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h index c4f20cae85..cc27f0c072 100644 --- a/dp/inc/cdp_txrx_stats_struct.h +++ b/dp/inc/cdp_txrx_stats_struct.h @@ -2634,6 +2634,7 @@ struct cdp_per_cpu_packets { * @tx.desc_in_use: Descriptors in use at soc * @tx.dropped_fw_removed: HW_release_reason == FW removed * @tx.invalid_release_source: tx completion release_src != HW or FW + * @tx.invalid_tx_comp_desc: TX Desc from completion ring Desc is not valid * @tx.wifi_internal_error: tx completion wifi_internal_error * @tx.non_wifi_internal_err: tx completion non_wifi_internal_error * @tx.tx_comp_loop_pkt_limit_hit: TX Comp loop packet limit hit @@ -2717,6 +2718,7 @@ struct cdp_soc_stats { uint32_t desc_in_use; uint32_t dropped_fw_removed; uint32_t invalid_release_source; + uint32_t invalid_tx_comp_desc; uint32_t wifi_internal_error[CDP_MAX_WIFI_INT_ERROR_REASONS]; uint32_t non_wifi_internal_err; uint32_t tx_comp_loop_pkt_limit_hit; diff --git a/dp/wifi3.0/be/dp_be_tx.c b/dp/wifi3.0/be/dp_be_tx.c index 7d9263eb1b..b6811b4c79 100644 --- a/dp/wifi3.0/be/dp_be_tx.c +++ b/dp/wifi3.0/be/dp_be_tx.c @@ -79,29 +79,60 @@ struct dp_mlo_mpass_buf { extern uint8_t sec_type_map[MAX_CDP_SEC_TYPE]; -#ifdef DP_USE_REDUCED_PEER_ID_FIELD_WIDTH -static inline uint16_t dp_tx_comp_get_peer_id(struct dp_soc *soc, - void *tx_comp_hal_desc) -{ - uint16_t peer_id = hal_tx_comp_get_peer_id(tx_comp_hal_desc); - struct dp_tx_comp_peer_id *tx_peer_id = - (struct dp_tx_comp_peer_id *)&peer_id; +#ifdef DP_TX_COMP_RING_DESC_SANITY_CHECK +/* + * Value to mark ring desc is invalidated by buffer_virt_addr_63_32 field + * of WBM2SW ring Desc. + */ +#define DP_TX_COMP_DESC_BUFF_VA_32BITS_HI_INVALIDATE 0x12121212 - return (tx_peer_id->peer_id | - (tx_peer_id->ml_peer_valid << soc->peer_id_shift)); +/** + * dp_tx_comp_desc_check_and_invalidate() - sanity check for ring desc and + * invalidate it after each reaping + * @tx_comp_hal_desc: ring desc virtual address + * @r_tx_desc: pointer to current dp TX Desc pointer + * @tx_desc_va: the original 64 bits Desc VA got from ring Desc + * @hw_cc_done: HW cookie conversion done or not + * + * If HW CC is done, check the buffer_virt_addr_63_32 value to know if + * ring Desc is stale or not. if HW CC is not done, then compare PA between + * ring Desc and current TX desc. + * + * Return: None. + */ +static inline +void dp_tx_comp_desc_check_and_invalidate(void *tx_comp_hal_desc, + struct dp_tx_desc_s **r_tx_desc, + uint64_t tx_desc_va, + bool hw_cc_done) +{ + qdf_dma_addr_t desc_dma_addr; + + if (qdf_likely(hw_cc_done)) { + /* Check upper 32 bits */ + if (DP_TX_COMP_DESC_BUFF_VA_32BITS_HI_INVALIDATE == + (tx_desc_va >> 32)) + *r_tx_desc = NULL; + + /* Invalidate the ring desc for 32 ~ 63 bits of VA */ + hal_tx_comp_set_desc_va_63_32( + tx_comp_hal_desc, + DP_TX_COMP_DESC_BUFF_VA_32BITS_HI_INVALIDATE); + } else { + /* Compare PA between ring desc and current TX desc stored */ + desc_dma_addr = hal_tx_comp_get_paddr(tx_comp_hal_desc); + + if (desc_dma_addr != (*r_tx_desc)->dma_addr) + *r_tx_desc = NULL; + } } #else -/* Combine ml_peer_valid and peer_id field */ -#define DP_BE_TX_COMP_PEER_ID_MASK 0x00003fff -#define DP_BE_TX_COMP_PEER_ID_SHIFT 0 - -static inline uint16_t dp_tx_comp_get_peer_id(struct dp_soc *soc, - void *tx_comp_hal_desc) +static inline +void dp_tx_comp_desc_check_and_invalidate(void *tx_comp_hal_desc, + struct dp_tx_desc_s **r_tx_desc, + uint64_t tx_desc_va, + bool hw_cc_done) { - uint16_t peer_id = hal_tx_comp_get_peer_id(tx_comp_hal_desc); - - return ((peer_id & DP_BE_TX_COMP_PEER_ID_MASK) >> - DP_BE_TX_COMP_PEER_ID_SHIFT); } #endif @@ -112,12 +143,15 @@ void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc, struct dp_tx_desc_s **r_tx_desc) { uint32_t tx_desc_id; + uint64_t tx_desc_va = 0; + bool hw_cc_done = + hal_tx_comp_get_cookie_convert_done(tx_comp_hal_desc); - if (qdf_likely( - hal_tx_comp_get_cookie_convert_done(tx_comp_hal_desc))) { + if (qdf_likely(hw_cc_done)) { /* HW cookie conversion done */ - *r_tx_desc = (struct dp_tx_desc_s *) - hal_tx_comp_get_desc_va(tx_comp_hal_desc); + tx_desc_va = hal_tx_comp_get_desc_va(tx_comp_hal_desc); + *r_tx_desc = (struct dp_tx_desc_s *)(uintptr_t)tx_desc_va; + } else { /* SW do cookie conversion to VA */ tx_desc_id = hal_tx_comp_get_desc_id(tx_comp_hal_desc); @@ -125,21 +159,33 @@ void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc, (struct dp_tx_desc_s *)dp_cc_desc_find(soc, tx_desc_id); } + dp_tx_comp_desc_check_and_invalidate(tx_comp_hal_desc, + r_tx_desc, tx_desc_va, + hw_cc_done); + if (*r_tx_desc) - (*r_tx_desc)->peer_id = dp_tx_comp_get_peer_id(soc, - tx_comp_hal_desc); + (*r_tx_desc)->peer_id = + dp_tx_comp_get_peer_id_be(soc, + tx_comp_hal_desc); } #else void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc, void *tx_comp_hal_desc, struct dp_tx_desc_s **r_tx_desc) { - *r_tx_desc = (struct dp_tx_desc_s *) - hal_tx_comp_get_desc_va(tx_comp_hal_desc); + uint64_t tx_desc_va; + tx_desc_va = hal_tx_comp_get_desc_va(tx_comp_hal_desc); + *r_tx_desc = (struct dp_tx_desc_s *)(uintptr_t)tx_desc_va; + + dp_tx_comp_desc_check_and_invalidate(tx_comp_hal_desc, + r_tx_desc, + tx_desc_va, + true); if (*r_tx_desc) - (*r_tx_desc)->peer_id = dp_tx_comp_get_peer_id(soc, - tx_comp_hal_desc); + (*r_tx_desc)->peer_id = + dp_tx_comp_get_peer_id_be(soc, + tx_comp_hal_desc); } #endif /* DP_HW_COOKIE_CONVERT_EXCEPTION */ #else @@ -155,9 +201,14 @@ void dp_tx_comp_get_params_from_hal_desc_be(struct dp_soc *soc, *r_tx_desc = (struct dp_tx_desc_s *)dp_cc_desc_find(soc, tx_desc_id); + dp_tx_comp_desc_check_and_invalidate(tx_comp_hal_desc, + r_tx_desc, 0, + false); + if (*r_tx_desc) - (*r_tx_desc)->peer_id = dp_tx_comp_get_peer_id(soc, - tx_comp_hal_desc); + (*r_tx_desc)->peer_id = + dp_tx_comp_get_peer_id_be(soc, + tx_comp_hal_desc); } #endif /* DP_FEATURE_HW_COOKIE_CONVERSION */ diff --git a/dp/wifi3.0/be/dp_be_tx.h b/dp/wifi3.0/be/dp_be_tx.h index 902c34b99a..6492dab71e 100644 --- a/dp/wifi3.0/be/dp_be_tx.h +++ b/dp/wifi3.0/be/dp_be_tx.h @@ -49,6 +49,33 @@ struct __attribute__((__packed__)) dp_tx_comp_peer_id { #define DP_TX_FAST_DESC_SIZE 24 #define DP_TX_L3_L4_CSUM_ENABLE 0x1f +#ifdef DP_USE_REDUCED_PEER_ID_FIELD_WIDTH +/** + * dp_tx_comp_get_peer_id_be() - Get peer ID from TX Comp Desc + * @soc: Handle to DP Soc structure + * @tx_comp_hal_desc: TX comp ring descriptor + * + * Return: Peer ID + */ +static inline uint16_t dp_tx_comp_get_peer_id_be(struct dp_soc *soc, + void *tx_comp_hal_desc) +{ + uint16_t peer_id = hal_tx_comp_get_peer_id(tx_comp_hal_desc); + struct dp_tx_comp_peer_id *tx_peer_id = + (struct dp_tx_comp_peer_id *)&peer_id; + + return (tx_peer_id->peer_id | + (tx_peer_id->ml_peer_valid << soc->peer_id_shift)); +} +#else +static inline uint16_t dp_tx_comp_get_peer_id_be(struct dp_soc *soc, + void *tx_comp_hal_desc) +{ + return hal_tx_comp_get_peer_id(tx_comp_hal_desc); + +} +#endif + /** * dp_tx_hw_enqueue_be() - Enqueue to TCL HW for transmit for BE target * @soc: DP Soc Handle diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c index d3020948c8..aeba7f15cf 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/dp/wifi3.0/dp_stats.c @@ -7165,6 +7165,8 @@ void dp_txrx_path_stats(struct dp_soc *soc) DP_PRINT_STATS("Invalid release source: %u", soc->stats.tx.invalid_release_source); + DP_PRINT_STATS("Invalid TX desc from completion ring: %u", + soc->stats.tx.invalid_tx_comp_desc); DP_PRINT_STATS("Dropped in host:"); DP_PRINT_STATS("Total packets dropped: %u,", pdev->stats.tx_i.dropped.dropped_pkt.num); @@ -7714,6 +7716,8 @@ dp_print_soc_tx_stats(struct dp_soc *soc) soc->stats.tx.tcl_ring_full[3]); DP_PRINT_STATS("Tx invalid completion release = %u", soc->stats.tx.invalid_release_source); + DP_PRINT_STATS("TX invalid Desc from completion ring = %u", + soc->stats.tx.invalid_tx_comp_desc); DP_PRINT_STATS("Tx comp wbm internal error = %d : [%d %d %d %d]", soc->stats.tx.wbm_internal_error[WBM_INT_ERROR_ALL], soc->stats.tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_BUFFER], @@ -8860,6 +8864,8 @@ QDF_STATUS dp_txrx_get_soc_stats(struct cdp_soc_t *soc_hdl, soc_stats->tx.dropped_fw_removed = soc->stats.tx.dropped_fw_removed; soc_stats->tx.invalid_release_source = soc->stats.tx.invalid_release_source; + soc_stats->tx.invalid_tx_comp_desc = + soc->stats.tx.invalid_tx_comp_desc; for (inx = 0; inx < CDP_MAX_WIFI_INT_ERROR_REASONS; inx++) soc_stats->tx.wifi_internal_error[inx] = soc->stats.tx.wbm_internal_error[inx]; diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 152ca5cc4c..d6cd1be410 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -5825,8 +5825,10 @@ more_data: soc->arch_ops.tx_comp_get_params_from_hal_desc(soc, tx_comp_hal_desc, &tx_desc); - if (!tx_desc) { + if (qdf_unlikely(!tx_desc)) { dp_err("unable to retrieve tx_desc!"); + hal_dump_comp_desc(tx_comp_hal_desc); + DP_STATS_INC(soc, tx.invalid_tx_comp_desc, 1); QDF_BUG(0); continue; } diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 017d27cf9a..c9383bf8c5 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1097,6 +1097,8 @@ struct dp_soc_stats { uint32_t dropped_fw_removed; /* tx completion release_src != TQM or FW */ uint32_t invalid_release_source; + /* TX descriptor from completion ring Desc is not valid */ + uint32_t invalid_tx_comp_desc; /* tx completion wbm_internal_error */ uint32_t wbm_internal_error[MAX_WBM_INT_ERROR_REASONS]; /* tx completion non_wbm_internal_error */ @@ -1885,9 +1887,9 @@ struct dp_arch_ops { struct cdp_tx_exception_metadata *metadata, struct dp_tx_msdu_info_s *msdu_info); - void (*tx_comp_get_params_from_hal_desc)(struct dp_soc *soc, - void *tx_comp_hal_desc, - struct dp_tx_desc_s **desc); + void (*tx_comp_get_params_from_hal_desc)(struct dp_soc *soc, + void *tx_comp_hal_desc, + struct dp_tx_desc_s **desc); void (*dp_tx_process_htt_completion)(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc, uint8_t *status, diff --git a/hal/wifi3.0/be/hal_be_tx.h b/hal/wifi3.0/be/hal_be_tx.h index b8ba5e5447..5621b173cc 100644 --- a/hal/wifi3.0/be/hal_be_tx.h +++ b/hal/wifi3.0/be/hal_be_tx.h @@ -570,6 +570,20 @@ static inline uint8_t hal_tx_comp_get_cookie_convert_done(void *hal_desc) } #endif +/** + * hal_tx_comp_set_desc_va_63_32() - Set bit 32~63 value for 64 bit VA + * @hal_desc: completion ring descriptor pointer + * @val: value to be set + * + * Return: None + */ +static inline void hal_tx_comp_set_desc_va_63_32(void *hal_desc, uint32_t val) +{ + HAL_SET_FLD(hal_desc, + WBM2SW_COMPLETION_RING_TX, + BUFFER_VIRT_ADDR_63_32) = val; +} + /** * hal_tx_comp_get_desc_va() - Get Desc virtual address within completion Desc * @hal_desc: completion ring descriptor pointer @@ -578,7 +592,7 @@ static inline uint8_t hal_tx_comp_get_cookie_convert_done(void *hal_desc) * * Return: TX desc virtual address */ -static inline uintptr_t hal_tx_comp_get_desc_va(void *hal_desc) +static inline uint64_t hal_tx_comp_get_desc_va(void *hal_desc) { uint64_t va_from_desc; @@ -590,7 +604,7 @@ static inline uintptr_t hal_tx_comp_get_desc_va(void *hal_desc) WBM2SW_COMPLETION_RING_TX, BUFFER_VIRT_ADDR_63_32)) << 32); - return (uintptr_t)va_from_desc; + return va_from_desc; } /*---------------------------------------------------------------------------