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 */