diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 4ecd6c8e6b..0f08c9a7bc 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -6502,6 +6502,10 @@ dp_print_soc_rx_stats(struct dp_soc *soc) DP_PRINT_STATS("RX frag wait: %d", soc->stats.rx.rx_frag_wait); DP_PRINT_STATS("RX frag err: %d", soc->stats.rx.rx_frag_err); DP_PRINT_STATS("RX HP out_of_sync: %d", soc->stats.rx.hp_oos); + DP_PRINT_STATS("RX DUP DESC: %d", + soc->stats.rx.err.hal_reo_dest_dup); + DP_PRINT_STATS("RX REL DUP DESC: %d", + soc->stats.rx.err.hal_wbm_rel_dup); for (i = 0; i < HAL_RXDMA_ERR_MAX; i++) { index += qdf_snprint(&rxdma_error[index], diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index 8f6b10ddfd..39fc125abb 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -56,6 +56,28 @@ static inline bool dp_rx_check_ap_bridge(struct dp_vdev *vdev) return false; } #endif + +/* + * dp_rx_dump_info_and_assert() - dump RX Ring info and Rx Desc info + * + * @soc: core txrx main context + * @hal_ring: opaque pointer to the HAL Rx Ring, which will be serviced + * @ring_desc: opaque pointer to the RX ring descriptor + * @rx_desc: host rs descriptor + * + * Return: void + */ +void dp_rx_dump_info_and_assert(struct dp_soc *soc, void *hal_ring, + void *ring_desc, struct dp_rx_desc *rx_desc) +{ + void *hal_soc = soc->hal_soc; + + dp_rx_desc_dump(rx_desc); + hal_srng_dump_ring_desc(hal_soc, hal_ring, ring_desc); + hal_srng_dump_ring(hal_soc, hal_ring); + qdf_assert_always(rx_desc->in_use); +} + /* * dp_rx_buffers_replenish() - replenish rxdma ring with rx nbufs * called during dp rx initialization @@ -1448,9 +1470,21 @@ uint32_t dp_rx_process(struct dp_intr *int_ctx, void *hal_ring, rx_buf_cookie = HAL_RX_REO_BUF_COOKIE_GET(ring_desc); rx_desc = dp_rx_cookie_2_va_rxdma_buf(soc, rx_buf_cookie); - - qdf_assert(rx_desc); + + /* + * 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_rx_dump_info_and_assert(soc, hal_ring, + ring_desc, rx_desc); + } + rx_bufs_reaped[rx_desc->pool_id]++; /* TODO */ diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index dd74412079..2d7ee818a5 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -846,6 +846,19 @@ static inline QDF_STATUS dp_rx_ast_set_active(struct dp_soc *soc, uint16_t sa_id } #endif +/* + * dp_rx_desc_dump() - dump the sw rx descriptor + * + * @rx_desc: sw rx descriptor + */ +static inline void dp_rx_desc_dump(struct dp_rx_desc *rx_desc) +{ + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, + "rx_desc->nbuf: %pK, rx_desc->cookie: %d, rx_desc->pool_id: %d, rx_desc->in_use: %d, rx_desc->unmapped: %d", + rx_desc->nbuf, rx_desc->cookie, rx_desc->pool_id, + rx_desc->in_use, rx_desc->unmapped); +} + /* * check_qwrap_multicast_loopback() - Check if rx packet is a loopback packet. * In qwrap mode, packets originated from @@ -962,4 +975,7 @@ int dp_wds_rx_policy_check(uint8_t *rx_tlv_hdr, struct dp_vdev *vdev, qdf_nbuf_t dp_rx_nbuf_prepare(struct dp_soc *soc, struct dp_pdev *pdev); +void dp_rx_dump_info_and_assert(struct dp_soc *soc, void *hal_ring, + void *ring_desc, struct dp_rx_desc *rx_desc); + #endif /* _DP_RX_H */ diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index f11bd13fc8..6aeb44886c 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -1253,6 +1253,19 @@ dp_rx_wbm_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) continue; } + /* + * 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_wbm_rel_dup, 1); + dp_rx_dump_info_and_assert(soc, hal_ring, + ring_desc, rx_desc); + } + nbuf = rx_desc->nbuf; qdf_nbuf_unmap_single(soc->osdev, nbuf, QDF_DMA_BIDIRECTIONAL); diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index ca3284c408..bbcd9beff4 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -617,6 +617,10 @@ struct dp_soc_stats { uint32_t reo_error[HAL_REO_ERR_MAX]; /* HAL REO ERR Count */ uint32_t hal_reo_error[MAX_REO_DEST_RINGS]; + /* HAL REO DEST Duplicate count */ + uint32_t hal_reo_dest_dup; + /* HAL WBM RELEASE Duplicate count */ + uint32_t hal_wbm_rel_dup; } err; /* packet count per core - per ring */ diff --git a/hal/wifi3.0/hal_api.h b/hal/wifi3.0/hal_api.h index d5427d6344..3d759a885f 100644 --- a/hal/wifi3.0/hal_api.h +++ b/hal/wifi3.0/hal_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1334,4 +1334,48 @@ static inline void hal_setup_link_idle_list(void *halsoc, num_entries); } + +/** + * hal_srng_dump_ring_desc() - Dump ring descriptor info + * + * @hal_soc: Opaque HAL SOC handle + * @hal_ring: Source ring pointer + * @ring_desc: Opaque ring descriptor handle + */ +static inline void hal_srng_dump_ring_desc(struct hal_soc *hal, void *hal_ring, + void *ring_desc) +{ + struct hal_srng *srng = (struct hal_srng *)hal_ring; + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, + ring_desc, (srng->entry_size << 2)); +} + +/** + * hal_srng_dump_ring() - Dump last 128 descs of the ring + * + * @hal_soc: Opaque HAL SOC handle + * @hal_ring: Source ring pointer + */ +static inline void hal_srng_dump_ring(struct hal_soc *hal, void *hal_ring) +{ + struct hal_srng *srng = (struct hal_srng *)hal_ring; + uint32_t *desc; + uint32_t tp, i; + + tp = srng->u.dst_ring.tp; + + for (i = 0; i < 128; i++) { + if (!tp) + tp = srng->ring_size; + + desc = &srng->ring_base_vaddr[tp - srng->entry_size]; + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_DP, + QDF_TRACE_LEVEL_FATAL, + desc, (srng->entry_size << 2)); + + tp -= srng->entry_size; + } +} + #endif /* _HAL_APIH_ */ diff --git a/hal/wifi3.0/hal_rx.h b/hal/wifi3.0/hal_rx.h index 24efe00305..94f694f758 100644 --- a/hal/wifi3.0/hal_rx.h +++ b/hal/wifi3.0/hal_rx.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the