Browse Source

qcacmn: WAR to avoid SG process with wrong continuation bit

If a continuation bit is set in msdu desc info and reported
length can fit in single buffer avoid SG processing

Change-Id: I6e8c3e1e657c372d5d915450dda20ba26bac495f
Chaithanya Garrepalli 4 years ago
parent
commit
3888d0824e
5 changed files with 24 additions and 5 deletions
  1. 15 2
      dp/wifi3.0/dp_rx.c
  2. 2 1
      dp/wifi3.0/dp_rx.h
  3. 2 2
      dp/wifi3.0/dp_rx_err.c
  4. 3 0
      dp/wifi3.0/dp_stats.c
  5. 2 0
      dp/wifi3.0/dp_types.h

+ 15 - 2
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)) {

+ 2 - 1
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);
 
 
 /*

+ 2 - 2
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,

+ 3 - 0
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,

+ 2 - 0
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 */