From da4d1b37e3207d55ecab6227cc50949c5e3d3bb7 Mon Sep 17 00:00:00 2001 From: Ruben Columbus Date: Tue, 17 Sep 2019 02:31:37 -0700 Subject: [PATCH] qcacmn: tx completion handler with invalid release source added stats counter to check invalid release reason other than FW and TQM in tx completion path. added assert to make sure host is not releasing descriptors with NULL address. Change-Id: I3a30bd0f0c3954ed6435489d9b21f16201d1b840 --- dp/wifi3.0/dp_stats.c | 2 ++ dp/wifi3.0/dp_tx.c | 24 +++++++++++++++++++++++- dp/wifi3.0/dp_types.h | 2 ++ hal/wifi3.0/hal_rx.h | 43 +++++++++++++++++++++++++++++++++++++++++++ hal/wifi3.0/hal_tx.h | 18 ++++++++++++++++++ 5 files changed, 88 insertions(+), 1 deletion(-) diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c index a5056ad972..3c21c8bddb 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/dp/wifi3.0/dp_stats.c @@ -5597,6 +5597,8 @@ dp_print_soc_tx_stats(struct dp_soc *soc) soc->stats.tx.tcl_ring_full[2]); DP_PRINT_STATS("Tx invalid completion release = %d", soc->stats.tx.invalid_release_source); + DP_PRINT_STATS("Tx comp wbm internal error = %d", + soc->stats.tx.wbm_internal_error); DP_PRINT_STATS("Tx comp loop pkt limit hit = %d", soc->stats.tx.tx_comp_loop_pkt_limit_hit); DP_PRINT_STATS("Tx comp HP out of sync2 = %d", diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index c6538e3e19..1a7eda2811 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -3437,6 +3437,7 @@ more_data: * Tx completion indication, assert */ if ((buffer_src != HAL_TX_COMP_RELEASE_SOURCE_TQM) && (buffer_src != HAL_TX_COMP_RELEASE_SOURCE_FW)) { + uint8_t wbm_internal_error; QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, @@ -3444,7 +3445,28 @@ more_data: buffer_src); hal_dump_comp_desc(tx_comp_hal_desc); DP_STATS_INC(soc, tx.invalid_release_source, 1); - qdf_assert_always(0); + + /* When WBM sees NULL buffer_addr_info in any of + * ingress rings it sends an error indication, + * with wbm_internal_error=1, to a specific ring. + * The WBM2SW ring used to indicate these errors is + * fixed in HW, and that ring is being used as Tx + * completion ring. These errors are not related to + * Tx completions, and should just be ignored + */ + + wbm_internal_error = + hal_get_wbm_internal_error(tx_comp_hal_desc); + + if (wbm_internal_error) { + QDF_TRACE(QDF_MODULE_ID_DP, + QDF_TRACE_LEVEL_ERROR, + "Tx comp wbm_internal_error!!!\n"); + DP_STATS_INC(soc, tx.wbm_internal_error, 1); + continue; + } else { + qdf_assert_always(0); + } } /* Get descriptor id */ diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 974a98a3c0..a9b4b91673 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -661,6 +661,8 @@ struct dp_soc_stats { uint32_t dropped_fw_removed; /* tx completion release_src != TQM or FW */ uint32_t invalid_release_source; + /* tx completion wbm_internal_error */ + uint32_t wbm_internal_error; /* TX Comp loop packet limit hit */ uint32_t tx_comp_loop_pkt_limit_hit; /* Head pointer Out of sync at the end of dp_tx_comp_handler */ diff --git a/hal/wifi3.0/hal_rx.h b/hal/wifi3.0/hal_rx.h index 0e7478df75..c3d2bafe12 100644 --- a/hal/wifi3.0/hal_rx.h +++ b/hal/wifi3.0/hal_rx.h @@ -2379,6 +2379,29 @@ static inline bool hal_rx_reo_is_2k_jump(hal_ring_desc_t rx_desc) true : false; } +#define HAL_WBM_RELEASE_RING_DESC_LEN_DWORDS (NUM_OF_DWORDS_WBM_RELEASE_RING) +/** + * hal_dump_wbm_rel_desc() - dump wbm release descriptor + * @hal_desc: hardware descriptor pointer + * + * This function will print wbm release descriptor + * + * Return: none + */ +static inline void hal_dump_wbm_rel_desc(void *src_srng_desc) +{ + uint32_t *wbm_comp = (uint32_t *)src_srng_desc; + uint32_t i; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "Current Rx wbm release descriptor is"); + + for (i = 0; i < HAL_WBM_RELEASE_RING_DESC_LEN_DWORDS; i++) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "DWORD[i] = 0x%x", wbm_comp[i]); + } +} + /** * hal_rx_msdu_link_desc_set: Retrieves MSDU Link Descriptor to WBM * @@ -2398,16 +2421,36 @@ void hal_rx_msdu_link_desc_set(hal_soc_handle_t hal_soc_hdl, { struct wbm_release_ring *wbm_rel_srng = (struct wbm_release_ring *)src_srng_desc; + uint32_t addr_31_0; + uint8_t addr_39_32; /* Structure copy !!! */ wbm_rel_srng->released_buff_or_desc_addr_info = *((struct buffer_addr_info *)buf_addr_info); + + addr_31_0 = + wbm_rel_srng->released_buff_or_desc_addr_info.buffer_addr_31_0; + addr_39_32 = + wbm_rel_srng->released_buff_or_desc_addr_info.buffer_addr_39_32; + HAL_DESC_SET_FIELD(src_srng_desc, WBM_RELEASE_RING_2, RELEASE_SOURCE_MODULE, HAL_RX_WBM_ERR_SRC_SW); HAL_DESC_SET_FIELD(src_srng_desc, WBM_RELEASE_RING_2, BM_ACTION, bm_action); HAL_DESC_SET_FIELD(src_srng_desc, WBM_RELEASE_RING_2, BUFFER_OR_DESC_TYPE, HAL_RX_WBM_BUF_TYPE_MSDU_LINK_DESC); + + /* WBM error is indicated when any of the link descriptors given to + * WBM has a NULL address, and one those paths is the link descriptors + * released from host after processing RXDMA errors, + * or from Rx defrag path, and we want to add an assert here to ensure + * host is not releasing descriptors with NULL address. + */ + + if (qdf_unlikely(!addr_31_0 && !addr_39_32)) { + hal_dump_wbm_rel_desc(src_srng_desc); + qdf_assert_always(0); + } } /* diff --git a/hal/wifi3.0/hal_tx.h b/hal/wifi3.0/hal_tx.h index 5062c47dad..ee386b3f4d 100644 --- a/hal/wifi3.0/hal_tx.h +++ b/hal/wifi3.0/hal_tx.h @@ -1109,4 +1109,22 @@ void hal_tx_set_tidmap_prty(hal_soc_handle_t hal_soc_hdl, uint8_t val) hal_soc->ops->hal_tx_set_tidmap_prty(hal_soc, val); } + +/** + * hal_get_wbm_internal_error() - wbm internal error + * @hal_desc: completion ring descriptor pointer + * + * This function will return the type of pointer - buffer or descriptor + * + * Return: buffer type + */ +static inline uint8_t hal_get_wbm_internal_error(void *hal_desc) +{ + uint32_t comp_desc = + *(uint32_t *)(((uint8_t *)hal_desc) + + WBM_RELEASE_RING_2_WBM_INTERNAL_ERROR_OFFSET); + + return (comp_desc & WBM_RELEASE_RING_2_WBM_INTERNAL_ERROR_MASK) >> + WBM_RELEASE_RING_2_WBM_INTERNAL_ERROR_LSB; +} #endif /* HAL_TX_H */