From be9f588e34fbaf9d0276a97d50f8f0c4351df824 Mon Sep 17 00:00:00 2001 From: Mohit Khanna Date: Thu, 27 May 2021 10:26:43 -0700 Subject: [PATCH] qcacmn: Handle BUF_ADDR ring desc in dp_rx_err Currently dp_rx_err_process expects ring descriptor to be only LINK_DESC_TYPE. In certain cases BUF_ADDR_TYPE ring descriptor is observed in reo_exception ring. Add logic to handle the same. Change-Id: I5baecc3f8eafc0830672b91bc9d9607b568a6cda CRs-Fixed: 2954653 --- dp/wifi3.0/dp_internal.h | 1 + dp/wifi3.0/dp_rx_err.c | 130 ++++++++++++++++++++++++++++++++++++++- dp/wifi3.0/dp_types.h | 10 +++ qdf/inc/qdf_types.h | 2 + 4 files changed, 141 insertions(+), 2 deletions(-) diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h index 8534e95160f7..180bd12b250c 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -426,6 +426,7 @@ static inline void dp_wds_ext_peer_init(struct dp_peer *peer) * 2.4GHz band uses lmac_id = 1 * 5GHz/6GHz band uses lmac_id=0 */ +#define DP_INVALID_LMAC_ID (-1) #define DP_MON_INVALID_LMAC_ID (-1) #define DP_MON_2G_LMAC_ID 1 #define DP_MON_5G_LMAC_ID 0 diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index bf9012f669d2..690e29e01e13 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -36,6 +36,11 @@ /* Max buffer in invalid peer SG list*/ #define DP_MAX_INVALID_BUFFERS 10 +/* Max regular Rx packet routing error */ +#define DP_MAX_REG_RX_ROUTING_ERRS_THRESHOLD 20 +#define DP_MAX_REG_RX_ROUTING_ERRS_IN_TIMEOUT 10 +#define DP_RX_ERR_ROUTE_TIMEOUT_US (5 * 1000 * 1000) /* micro seconds */ + /** * dp_rx_mcast_echo_check() - check if the mcast pkt is a loop * back on same vap or a different vap. @@ -905,10 +910,11 @@ dp_rx_bar_frame_handle(struct dp_soc *soc, next: dp_rx_link_desc_return(soc, ring_desc, HAL_BM_ACTION_PUT_IN_IDLE_LIST); + dp_rx_buffer_pool_nbuf_free(soc, rx_desc->nbuf, + rx_desc->pool_id); dp_rx_add_to_free_desc_list(&pdev->free_list_head, &pdev->free_list_tail, rx_desc); - qdf_nbuf_free(nbuf); } /** @@ -1653,6 +1659,119 @@ dp_rx_err_ring_record_entry(struct dp_soc *soc, uint64_t paddr, } #endif +#ifdef HANDLE_RX_REROUTE_ERR +static int dp_rx_err_handle_msdu_buf(struct dp_soc *soc, + hal_ring_desc_t ring_desc) +{ + int lmac_id = DP_INVALID_LMAC_ID; + uint32_t cookie = 0; + struct dp_rx_desc *rx_desc = NULL; + struct hal_buf_info hbi; + struct dp_pdev *pdev; + + cookie = HAL_RX_REO_BUF_COOKIE_GET(ring_desc); + rx_desc = dp_rx_cookie_2_va_rxdma_buf(soc, cookie); + + /* sanity */ + if (!rx_desc) { + DP_STATS_INC(soc, rx.err.reo_err_msdu_buf_invalid_cookie, 1); + goto assert_return; + } + + if (!rx_desc->nbuf) + goto assert_return; + + hal_rx_reo_buf_paddr_get(ring_desc, &hbi); + dp_rx_err_ring_record_entry(soc, hbi.paddr, + hbi.sw_cookie, + hal_rx_ret_buf_manager_get(ring_desc)); + if (hbi.paddr != qdf_nbuf_get_frag_paddr(rx_desc->nbuf, 0)) { + DP_STATS_INC(soc, rx.err.nbuf_sanity_fail, 1); + rx_desc->in_err_state = 1; + goto assert_return; + } + + /* After this point the rx_desc and nbuf are valid */ + dp_ipa_rx_buf_smmu_mapping_lock(soc); + qdf_assert_always(rx_desc->unmapped); + dp_ipa_handle_rx_buf_smmu_mapping(soc, + rx_desc->nbuf, + RX_DATA_BUFFER_SIZE, + false); + qdf_nbuf_unmap_nbytes_single(soc->osdev, + rx_desc->nbuf, + QDF_DMA_FROM_DEVICE, + RX_DATA_BUFFER_SIZE); + rx_desc->unmapped = 1; + dp_ipa_rx_buf_smmu_mapping_unlock(soc); + dp_rx_buffer_pool_nbuf_free(soc, rx_desc->nbuf, + rx_desc->pool_id); + + pdev = dp_get_pdev_for_lmac_id(soc, rx_desc->pool_id); + lmac_id = rx_desc->pool_id; + dp_rx_add_to_free_desc_list(&pdev->free_list_head, + &pdev->free_list_tail, + rx_desc); + return lmac_id; + +assert_return: + qdf_assert(0); + return lmac_id; +} + +static int dp_rx_err_exception(struct dp_soc *soc, hal_ring_desc_t ring_desc) +{ + int ret; + uint64_t cur_time_stamp; + + DP_STATS_INC(soc, rx.err.reo_err_msdu_buf_rcved, 1); + + /* Recover if overall error count exceeds threshold */ + if (soc->stats.rx.err.reo_err_msdu_buf_rcved > + DP_MAX_REG_RX_ROUTING_ERRS_THRESHOLD) { + dp_err("pkt threshold breached! reo_err_msdu_buf_rcved %u first err pkt time_stamp %llu", + soc->stats.rx.err.reo_err_msdu_buf_rcved, + soc->rx_route_err_start_pkt_ts); + qdf_trigger_self_recovery(NULL, QDF_RX_REG_PKT_ROUTE_ERR); + } + + cur_time_stamp = qdf_get_log_timestamp_usecs(); + if (!soc->rx_route_err_start_pkt_ts) + soc->rx_route_err_start_pkt_ts = cur_time_stamp; + + /* Recover if threshold number of packets received in threshold time */ + if ((cur_time_stamp - soc->rx_route_err_start_pkt_ts) > + DP_RX_ERR_ROUTE_TIMEOUT_US) { + soc->rx_route_err_start_pkt_ts = cur_time_stamp; + + if (soc->rx_route_err_in_window > + DP_MAX_REG_RX_ROUTING_ERRS_IN_TIMEOUT) { + qdf_trigger_self_recovery(NULL, + QDF_RX_REG_PKT_ROUTE_ERR); + dp_err("rate threshold breached! reo_err_msdu_buf_rcved %u first err pkt time_stamp %llu", + soc->stats.rx.err.reo_err_msdu_buf_rcved, + soc->rx_route_err_start_pkt_ts); + } else { + soc->rx_route_err_in_window = 1; + } + } else { + soc->rx_route_err_in_window++; + } + + ret = dp_rx_err_handle_msdu_buf(soc, ring_desc); + + return ret; +} +#else /* HANDLE_RX_REROUTE_ERR */ + +static int dp_rx_err_exception(struct dp_soc *soc, hal_ring_desc_t ring_desc) +{ + qdf_assert_always(0); + + return DP_INVALID_LMAC_ID; +} +#endif /* HANDLE_RX_REROUTE_ERR */ + uint32_t dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, hal_ring_handle_t hal_ring_hdl, uint32_t quota) @@ -1718,7 +1837,14 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, /* * For REO error ring, expect only MSDU LINK DESC */ - qdf_assert_always(buf_type == HAL_RX_REO_MSDU_LINK_DESC_TYPE); + if (qdf_unlikely(buf_type != HAL_RX_REO_MSDU_LINK_DESC_TYPE)) { + int lmac_id; + + lmac_id = dp_rx_err_exception(soc, ring_desc); + if (lmac_id >= 0) + rx_bufs_reaped[lmac_id] += 1; + goto next_entry; + } cookie = HAL_RX_REO_BUF_COOKIE_GET(ring_desc); /* diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 43f862ae1bb9..767337c9f67f 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1006,6 +1006,10 @@ struct dp_soc_stats { uint32_t rx_2k_jump_to_stack; /* RX 2k jump msdu dropped count */ uint32_t rx_2k_jump_drop; + /* REO ERR msdu buffer received */ + uint32_t reo_err_msdu_buf_rcved; + /* REO ERR msdu buffer with invalid coookie received */ + uint32_t reo_err_msdu_buf_invalid_cookie; /* REO OOR msdu drop count */ uint32_t reo_err_oor_drop; /* REO OOR msdu indicated to stack count */ @@ -1669,6 +1673,12 @@ struct dp_soc { /* SoC level data path statistics */ struct dp_soc_stats stats; + /* timestamp to keep track of msdu buffers received on reo err ring */ + uint64_t rx_route_err_start_pkt_ts; + + /* Num RX Route err in a given window to keep track of rate of errors */ + uint32_t rx_route_err_in_window; + /* Enable processing of Tx completion status words */ bool process_tx_status; bool process_rx_status; diff --git a/qdf/inc/qdf_types.h b/qdf/inc/qdf_types.h index 0eb01bdb1520..6c3acb499dc5 100644 --- a/qdf/inc/qdf_types.h +++ b/qdf/inc/qdf_types.h @@ -1352,6 +1352,7 @@ enum qdf_suspend_type { * @QDF_HAL_REG_WRITE_FAILURE: HAL register writing failures * @QDF_SUSPEND_NO_CREDIT: host lack of credit after suspend * @QDF_TASKLET_CREDIT_LATENCY_DETECT: tasklet or credit latency happened + * @QDF_RX_REG_PKT_ROUTE_ERR: MSDU buf errors exceed thresh in REO err path */ enum qdf_hang_reason { QDF_REASON_UNSPECIFIED, @@ -1378,6 +1379,7 @@ enum qdf_hang_reason { QDF_HAL_REG_WRITE_FAILURE, QDF_SUSPEND_NO_CREDIT, QDF_TASKLET_CREDIT_LATENCY_DETECT, + QDF_RX_REG_PKT_ROUTE_ERR, }; /**