From b86ddaf2057bf8c1c488ce18af532d8cb325cdab Mon Sep 17 00:00:00 2001 From: Pavankumar Nandeshwar Date: Mon, 7 Oct 2019 12:55:16 +0530 Subject: [PATCH] qcacmn: Handle wbm_internal_error in tx completions Handle wbm_internal_error in tx completions by releasing associated descriptors and buffers. Change-Id: I94d334c90c0514674323430fe53da72fb5424576 --- dp/wifi3.0/dp_rx_err.c | 150 +++++++++++++++++++++++++++++++++++++++++ dp/wifi3.0/dp_stats.c | 8 ++- dp/wifi3.0/dp_tx.c | 11 ++- dp/wifi3.0/dp_tx.h | 4 ++ dp/wifi3.0/dp_types.h | 9 ++- hal/wifi3.0/hal_tx.h | 3 + 6 files changed, 181 insertions(+), 4 deletions(-) diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 218e8dbbc1..ef3b368e31 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -1834,3 +1834,153 @@ dp_rxdma_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, return work_done; } + +static inline uint32_t +dp_wbm_int_err_mpdu_pop(struct dp_soc *soc, uint32_t mac_id, + hal_rxdma_desc_t rxdma_dst_ring_desc, + union dp_rx_desc_list_elem_t **head, + union dp_rx_desc_list_elem_t **tail) +{ + void *rx_msdu_link_desc; + qdf_nbuf_t msdu; + qdf_nbuf_t last; + struct hal_rx_msdu_list msdu_list; + uint16_t num_msdus; + struct hal_buf_info buf_info; + void *p_buf_addr_info; + void *p_last_buf_addr_info; + uint32_t rx_bufs_used = 0; + uint32_t msdu_cnt; + uint32_t i; + + msdu = 0; + + last = NULL; + + hal_rx_reo_ent_buf_paddr_get(rxdma_dst_ring_desc, &buf_info, + &p_last_buf_addr_info, &msdu_cnt); + + do { + rx_msdu_link_desc = + dp_rx_cookie_2_link_desc_va(soc, &buf_info); + + if (!rx_msdu_link_desc) { + DP_STATS_INC(soc, tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_LINK_DESC], 1); + break; + } + + hal_rx_msdu_list_get(soc->hal_soc, rx_msdu_link_desc, + &msdu_list, &num_msdus); + + if (msdu_list.sw_cookie[0] != HAL_RX_COOKIE_SPECIAL) { + for (i = 0; i < num_msdus; i++) { + struct dp_rx_desc *rx_desc = + dp_rx_cookie_2_va_rxdma_buf( + soc, + msdu_list.sw_cookie[i]); + qdf_assert_always(rx_desc); + msdu = rx_desc->nbuf; + + qdf_nbuf_unmap_single(soc->osdev, msdu, + QDF_DMA_FROM_DEVICE); + + qdf_nbuf_free(msdu); + rx_bufs_used++; + dp_rx_add_to_free_desc_list(head, + tail, rx_desc); + } + } + + hal_rx_mon_next_link_desc_get(rx_msdu_link_desc, &buf_info, + &p_buf_addr_info); + + dp_rx_link_desc_return(soc, p_last_buf_addr_info, + HAL_BM_ACTION_PUT_IN_IDLE_LIST); + p_last_buf_addr_info = p_buf_addr_info; + + } while (buf_info.paddr); + + return rx_bufs_used; +} + +/* + * + * dp_handle_wbm_internal_error() - handles wbm_internal_error case + * + * @soc: core DP main context + * @hal_desc: hal descriptor + * @buf_type: indicates if the buffer is of type link disc or msdu + * Return: None + * + * wbm_internal_error is seen in following scenarios : + * + * 1. Null pointers detected in WBM_RELEASE_RING descriptors + * 2. Null pointers detected during delinking process + * + * Some null pointer cases: + * + * a. MSDU buffer pointer is NULL + * b. Next_MSDU_Link_Desc pointer is NULL, with no last msdu flag + * c. MSDU buffer pointer is NULL or Next_Link_Desc pointer is NULL + */ +void +dp_handle_wbm_internal_error(struct dp_soc *soc, void *hal_desc, + uint32_t buf_type) +{ + struct hal_buf_info buf_info = {0}; + struct dp_pdev *dp_pdev; + struct dp_rx_desc *rx_desc = NULL; + uint32_t rx_buf_cookie; + uint32_t rx_bufs_reaped = 0; + union dp_rx_desc_list_elem_t *head = NULL; + union dp_rx_desc_list_elem_t *tail = NULL; + uint8_t pool_id; + + hal_rx_reo_buf_paddr_get(hal_desc, &buf_info); + + if (!buf_info.paddr) { + DP_STATS_INC(soc, tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_BUFFER], 1); + return; + } + + rx_buf_cookie = HAL_RX_REO_BUF_COOKIE_GET(hal_desc); + pool_id = DP_RX_DESC_COOKIE_POOL_ID_GET(rx_buf_cookie); + + if (buf_type == HAL_WBM_RELEASE_RING_2_BUFFER_TYPE) { + DP_STATS_INC(soc, tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_MSDU_BUFF], 1); + rx_desc = dp_rx_cookie_2_va_rxdma_buf(soc, rx_buf_cookie); + + if (rx_desc && rx_desc->nbuf) { + qdf_nbuf_unmap_single(soc->osdev, rx_desc->nbuf, + QDF_DMA_FROM_DEVICE); + + rx_desc->unmapped = 1; + + qdf_nbuf_free(rx_desc->nbuf); + dp_rx_add_to_free_desc_list(&head, + &tail, + rx_desc); + + rx_bufs_reaped++; + } + } else if (buf_type == HAL_WBM_RELEASE_RING_2_DESC_TYPE) { + rx_bufs_reaped = dp_wbm_int_err_mpdu_pop(soc, pool_id, + hal_desc, + &head, &tail); + } + + if (rx_bufs_reaped) { + struct rx_desc_pool *rx_desc_pool; + struct dp_srng *dp_rxdma_srng; + + DP_STATS_INC(soc, tx.wbm_internal_error[WBM_INT_ERROR_REO_BUFF_REAPED], 1); + dp_pdev = soc->pdev_list[pool_id]; + dp_rxdma_srng = &dp_pdev->rx_refill_buf_ring; + rx_desc_pool = &soc->rx_desc_buf[pool_id]; + + dp_rx_buffers_replenish(soc, pool_id, dp_rxdma_srng, + rx_desc_pool, + rx_bufs_reaped, + &head, &tail); + } +} diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c index 3c21c8bddb..71d7f46918 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/dp/wifi3.0/dp_stats.c @@ -5597,8 +5597,12 @@ 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 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], + soc->stats.tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_LINK_DESC], + soc->stats.tx.wbm_internal_error[WBM_INT_ERROR_REO_NULL_MSDU_BUFF], + soc->stats.tx.wbm_internal_error[WBM_INT_ERROR_REO_BUFF_REAPED]); 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 deb5334951..86e59ddc86 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -3472,7 +3472,16 @@ more_data: 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); + DP_STATS_INC(soc, tx.wbm_internal_error[WBM_INT_ERROR_ALL], 1); + + if (HAL_TX_COMP_RELEASE_SOURCE_REO == + buffer_src) + dp_handle_wbm_internal_error( + soc, + tx_comp_hal_desc, + hal_tx_comp_get_buffer_type( + tx_comp_hal_desc)); + continue; } else { qdf_assert_always(0); diff --git a/dp/wifi3.0/dp_tx.h b/dp/wifi3.0/dp_tx.h index 32466ff082..e6fe1fe085 100644 --- a/dp/wifi3.0/dp_tx.h +++ b/dp/wifi3.0/dp_tx.h @@ -330,6 +330,10 @@ void dp_iterate_update_peer_list(struct cdp_pdev *pdev_hdl); #define DP_TX_TID_OVERRIDE(_msdu_info, _nbuf) #endif +void +dp_handle_wbm_internal_error(struct dp_soc *soc, void *hal_desc, + uint32_t buf_type); + /* TODO TX_FEATURE_NOT_YET */ static inline void dp_tx_comp_process_exception(struct dp_tx_desc_s *tx_desc) { diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 3870ac6ab7..cb32f058b3 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -88,6 +88,13 @@ #define DP_MAX_IRQ_PER_CONTEXT 12 #define DEFAULT_HW_PEER_ID 0xffff +#define WBM_INT_ERROR_ALL 0 +#define WBM_INT_ERROR_REO_NULL_BUFFER 1 +#define WBM_INT_ERROR_REO_NULL_LINK_DESC 2 +#define WBM_INT_ERROR_REO_NULL_MSDU_BUFF 3 +#define WBM_INT_ERROR_REO_BUFF_REAPED 4 +#define MAX_WBM_INT_ERROR_REASONS 5 + #define MAX_TX_HW_QUEUES MAX_TCL_DATA_RINGS /* Maximum retries for Delba per tid per peer */ #define DP_MAX_DELBA_RETRY 3 @@ -662,7 +669,7 @@ struct dp_soc_stats { /* tx completion release_src != TQM or FW */ uint32_t invalid_release_source; /* tx completion wbm_internal_error */ - uint32_t wbm_internal_error; + uint32_t wbm_internal_error[MAX_WBM_INT_ERROR_REASONS]; /* 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_tx.h b/hal/wifi3.0/hal_tx.h index 0d263dead9..ea343ff830 100644 --- a/hal/wifi3.0/hal_tx.h +++ b/hal/wifi3.0/hal_tx.h @@ -29,6 +29,8 @@ #define WBM_RELEASE_RING_5_TX_RATE_STATS_LSB 0 #define WBM_RELEASE_RING_5_TX_RATE_STATS_MASK 0xffffffff +#define HAL_WBM_RELEASE_RING_2_BUFFER_TYPE 0 +#define HAL_WBM_RELEASE_RING_2_DESC_TYPE 1 /*--------------------------------------------------------------------------- Preprocessor definitions and constants @@ -91,6 +93,7 @@ do { \ #define HAL_TX_COMPLETION_DESC_BASE_LEN 12 #define HAL_TX_COMP_RELEASE_SOURCE_TQM 0 +#define HAL_TX_COMP_RELEASE_SOURCE_REO 2 #define HAL_TX_COMP_RELEASE_SOURCE_FW 3 /* Define a place-holder release reason for FW */