From 1de57c2150535b368b4abcc8f6eeca6c8b867932 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Thu, 23 Jul 2020 11:33:35 +0530 Subject: [PATCH] qcacmn: Handle the duplicate entries in reo exception ring We have come across scenarios where rxdma is pushing a certain entry more than once to the reo exception ring. In this scenario, when we try to unmap a buffer, it can lead to multiple unmap of the same buffer. Handle this case, by skipping the process of this duplicate entry, if alrady unmapped, and proceed to the next entry. Change-Id: Iae66f27e432f795ba4730911029fa1d63a75cb06 CRs-Fixed: 2739176 --- dp/wifi3.0/dp_rx.c | 3 +-- dp/wifi3.0/dp_rx.h | 21 +++++++++++++++++++++ dp/wifi3.0/dp_rx_defrag.c | 4 ++++ dp/wifi3.0/dp_rx_err.c | 27 +++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index ed1784f45c..86fd330544 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -1840,8 +1840,7 @@ QDF_STATUS dp_rx_desc_nbuf_sanity_check(hal_ring_desc_t ring_desc, hal_rx_reo_buf_paddr_get(ring_desc, &hbi); /* Sanity check for possible buffer paddr corruption */ - if ((&hbi)->paddr == - qdf_nbuf_get_frag_paddr(rx_desc->nbuf, 0)) + if (dp_rx_desc_paddr_sanity_check(rx_desc, (&hbi)->paddr)) return QDF_STATUS_SUCCESS; return QDF_STATUS_E_FAILURE; diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index ffa449c596..b240bb2aa7 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -721,6 +721,20 @@ void dp_rx_deliver_raw(struct dp_vdev *vdev, qdf_nbuf_t nbuf_list, struct dp_peer *peer); #ifdef RX_DESC_DEBUG_CHECK +/** + * dp_rx_desc_paddr_sanity_check() - paddr sanity for ring desc vs rx_desc + * @rx_desc: rx descriptor + * @ring_paddr: paddr obatined from the ring + * + * Returns: QDF_STATUS + */ +static inline +bool dp_rx_desc_paddr_sanity_check(struct dp_rx_desc *rx_desc, + uint64_t ring_paddr) +{ + return (ring_paddr == qdf_nbuf_get_frag_paddr(rx_desc->nbuf, 0)); +} + /* * dp_rx_desc_alloc_dbg_info() - Alloc memory for rx descriptor debug * structure @@ -775,6 +789,13 @@ void dp_rx_desc_update_dbg_info(struct dp_rx_desc *rx_desc, } #else +static inline +bool dp_rx_desc_paddr_sanity_check(struct dp_rx_desc *rx_desc, + uint64_t ring_paddr) +{ + return true; +} + static inline void dp_rx_desc_alloc_dbg_info(struct dp_rx_desc *rx_desc) { diff --git a/dp/wifi3.0/dp_rx_defrag.c b/dp/wifi3.0/dp_rx_defrag.c index 435e599bf5..3deb68de2d 100644 --- a/dp/wifi3.0/dp_rx_defrag.c +++ b/dp/wifi3.0/dp_rx_defrag.c @@ -1905,6 +1905,10 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, hal_ring_desc_t ring_desc, msdu = rx_desc->nbuf; rx_desc_pool = &soc->rx_desc_buf[rx_desc->pool_id]; + + if (rx_desc->unmapped) + return rx_bufs_used; + dp_ipa_handle_rx_buf_smmu_mapping(soc, rx_desc->nbuf, rx_desc_pool->buf_size, false); diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 3ec41dc3d9..2a8deb393c 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -1524,6 +1524,7 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, uint16_t num_msdus; struct dp_rx_desc *rx_desc = NULL; QDF_STATUS status; + bool ret; /* Debug -- Remove later */ qdf_assert(soc && hal_ring_hdl); @@ -1630,6 +1631,32 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, goto next_entry; } + /* + * this is a unlikely scenario where the host is reaping + * a descriptor which it already reaped just a while ago + * but is yet to replenish it back to HW. + * In this case host will dump the last 128 descriptors + * including the software descriptor rx_desc and assert. + */ + + if (qdf_unlikely(!rx_desc->in_use)) { + DP_STATS_INC(soc, rx.err.hal_reo_dest_dup, 1); + dp_info_rl("Reaping rx_desc not in use!"); + dp_rx_dump_info_and_assert(soc, hal_ring_hdl, + ring_desc, rx_desc); + /* ignore duplicate RX desc and continue */ + /* Pop out the descriptor */ + goto next_entry; + } + + ret = dp_rx_desc_paddr_sanity_check(rx_desc, + msdu_list.paddr[0]); + if (!ret) { + DP_STATS_INC(soc, rx.err.nbuf_sanity_fail, 1); + rx_desc->in_err_state = 1; + goto next_entry; + } + count = dp_rx_frag_handle(soc, ring_desc, &mpdu_desc_info, rx_desc, &mac_id, quota);