diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index 72333e6ec4..22c205ee31 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -1177,6 +1177,7 @@ static inline bool dp_rx_adjust_nbuf_len(qdf_nbuf_t nbuf, uint16_t *mpdu_len) /** * dp_rx_sg_create() - create a frag_list for MSDUs which are spread across * multiple nbufs. + * @soc: DP SOC handle * @nbuf: pointer to the first msdu of an amsdu. * * This function implements the creation of RX frag_list for cases @@ -1184,7 +1185,7 @@ static inline bool dp_rx_adjust_nbuf_len(qdf_nbuf_t nbuf, uint16_t *mpdu_len) * * Return: returns the head nbuf which contains complete frag_list. */ -qdf_nbuf_t dp_rx_sg_create(qdf_nbuf_t nbuf) +qdf_nbuf_t dp_rx_sg_create(struct dp_soc *soc, qdf_nbuf_t nbuf) { qdf_nbuf_t parent, frag_list, next = NULL; uint16_t frag_list_len = 0; @@ -1230,6 +1231,18 @@ qdf_nbuf_t dp_rx_sg_create(qdf_nbuf_t nbuf) qdf_nbuf_set_rx_chfrag_start(parent, 1); last_nbuf = dp_rx_adjust_nbuf_len(parent, &mpdu_len); + /* + * HW issue: MSDU cont bit is set but reported MPDU length can fit + * in to single buffer + * + * Increment error stats and avoid SG list creation + */ + if (last_nbuf) { + DP_STATS_INC(soc, rx.err.msdu_continuation_err, 1); + qdf_nbuf_pull_head(parent, RX_PKT_TLVS_LEN); + return parent; + } + /* * this is where we set the length of the fragments which are * associated to the parent nbuf. We iterate through the frag_list @@ -2668,7 +2681,7 @@ done: qdf_nbuf_pull_head(nbuf, RX_PKT_TLVS_LEN); } else if (qdf_nbuf_is_rx_chfrag_cont(nbuf)) { msdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf); - nbuf = dp_rx_sg_create(nbuf); + nbuf = dp_rx_sg_create(soc, nbuf); next = nbuf->next; if (qdf_nbuf_is_raw_frame(nbuf)) { diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index 435d6c548b..4fd1baa7af 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -645,6 +645,7 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, /** * dp_rx_sg_create() - create a frag_list for MSDUs which are spread across * multiple nbufs. + * @soc: core txrx main context * @nbuf: pointer to the first msdu of an amsdu. * * This function implements the creation of RX frag_list for cases @@ -652,7 +653,7 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, * * Return: returns the head nbuf which contains complete frag_list. */ -qdf_nbuf_t dp_rx_sg_create(qdf_nbuf_t nbuf); +qdf_nbuf_t dp_rx_sg_create(struct dp_soc *soc, qdf_nbuf_t nbuf); /* diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 6260b7c7ef..6db3ef381b 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -602,7 +602,7 @@ more_msdu_link_desc: rx_tlv_hdr_last = qdf_nbuf_data(tail_nbuf); if (qdf_unlikely(head_nbuf != tail_nbuf)) { - nbuf = dp_rx_sg_create(head_nbuf); + nbuf = dp_rx_sg_create(soc, head_nbuf); qdf_nbuf_set_is_frag(nbuf, 1); DP_STATS_INC(soc, rx.err.reo_err_oor_sg_count, 1); } @@ -2182,7 +2182,7 @@ done: * QCN9000 has this support */ if (qdf_nbuf_is_rx_chfrag_cont(nbuf)) { - nbuf = dp_rx_sg_create(nbuf); + nbuf = dp_rx_sg_create(soc, nbuf); next = nbuf->next; /* * SG error handling is not done correctly, diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c index 1c3b48bd8f..d09995ef03 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/dp/wifi3.0/dp_stats.c @@ -6622,6 +6622,9 @@ dp_print_soc_rx_stats(struct dp_soc *soc) DP_PRINT_STATS("Rx nbuf sanity fail: %d", soc->stats.rx.err.nbuf_sanity_fail); + DP_PRINT_STATS("Rx err msdu continuation err: %d", + soc->stats.rx.err.msdu_continuation_err); + for (i = 0; i < HAL_RXDMA_ERR_MAX; i++) { index += qdf_snprint(&rxdma_error[index], DP_RXDMA_ERR_LENGTH - index, diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 42d0faaa09..f6a63763b7 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -977,6 +977,8 @@ struct dp_soc_stats { uint32_t nbuf_sanity_fail; /* Duplicate link desc refilled */ uint32_t dup_refill_link_desc; + /* Incorrect msdu continuation bit in MSDU desc */ + uint32_t msdu_continuation_err; } err; /* packet count per core - per ring */