浏览代码

qcacmn: Handle scattered msdu in OOR error scenario

In OOR error handling scenario, msdu is spread across
two nbufs. Due to this, there is a mismatch between
msdu count fetched from MPDU desc detatils and count
fetched from rx link descriptor.

Fix is to create frag list for the case where msdu
is spread across multiple nbufs.

Change-Id: I1d600a0988b373e68aad6ef815fb2d775763b7cb
CRs-Fixed: 2665963
Yeshwanth Sriram Guntuka 5 年之前
父节点
当前提交
7dad533e6c
共有 4 个文件被更改,包括 77 次插入28 次删除
  1. 31 12
      dp/wifi3.0/dp_rx.c
  2. 5 2
      dp/wifi3.0/dp_rx.h
  3. 39 14
      dp/wifi3.0/dp_rx_err.c
  4. 2 0
      dp/wifi3.0/dp_types.h

+ 31 - 12
dp/wifi3.0/dp_rx.c

@@ -1792,11 +1792,29 @@ void dp_rx_skip_tlvs(qdf_nbuf_t nbuf, uint32_t l3_padding)
 	QDF_NBUF_CB_RX_PACKET_L3_HDR_PAD(nbuf) = l3_padding;
 	qdf_nbuf_pull_head(nbuf, l3_padding + RX_PKT_TLVS_LEN);
 }
+
+/**
+ * dp_rx_set_hdr_pad() - set l3 padding in nbuf cb
+ * @nbuf: pkt skb pointer
+ * @l3_padding: l3 padding
+ *
+ * Return: None
+ */
+static inline
+void dp_rx_set_hdr_pad(qdf_nbuf_t nbuf, uint32_t l3_padding)
+{
+	QDF_NBUF_CB_RX_PACKET_L3_HDR_PAD(nbuf) = l3_padding;
+}
 #else
 void dp_rx_skip_tlvs(qdf_nbuf_t nbuf, uint32_t l3_padding)
 {
 	qdf_nbuf_pull_head(nbuf, l3_padding + RX_PKT_TLVS_LEN);
 }
+
+static inline
+void dp_rx_set_hdr_pad(qdf_nbuf_t nbuf, uint32_t l3_padding)
+{
+}
 #endif
 
 
@@ -2911,26 +2929,27 @@ dp_rx_nbuf_prepare(struct dp_soc *soc, struct dp_pdev *pdev)
 
 #ifdef DP_RX_SPECIAL_FRAME_NEED
 bool dp_rx_deliver_special_frame(struct dp_soc *soc, struct dp_peer *peer,
-				 qdf_nbuf_t nbuf, uint32_t frame_mask)
+				 qdf_nbuf_t nbuf, uint32_t frame_mask,
+				 uint8_t *rx_tlv_hdr)
 {
 	uint32_t l2_hdr_offset = 0;
 	uint16_t msdu_len = 0;
-	uint32_t pkt_len = 0;
-	uint8_t *rx_tlv_hdr;
+	uint32_t skip_len;
 
-	if (qdf_unlikely(qdf_nbuf_is_frag(nbuf)))
-		return false;
-
-	rx_tlv_hdr = qdf_nbuf_data(nbuf);
 	l2_hdr_offset =
 		hal_rx_msdu_end_l3_hdr_padding_get(soc->hal_soc, rx_tlv_hdr);
 
-	msdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf);
-	pkt_len = msdu_len + l2_hdr_offset + RX_PKT_TLVS_LEN;
-	QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(nbuf) = 1;
+	if (qdf_unlikely(qdf_nbuf_is_frag(nbuf))) {
+		skip_len = l2_hdr_offset;
+	} else {
+		msdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf);
+		skip_len = l2_hdr_offset + RX_PKT_TLVS_LEN;
+		qdf_nbuf_set_pktlen(nbuf, msdu_len + skip_len);
+	}
 
-	qdf_nbuf_set_pktlen(nbuf, pkt_len);
-	dp_rx_skip_tlvs(nbuf, l2_hdr_offset);
+	QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(nbuf) = 1;
+	dp_rx_set_hdr_pad(nbuf, l2_hdr_offset);
+	qdf_nbuf_pull_head(nbuf, skip_len);
 
 	if (dp_rx_is_special_frame(nbuf, frame_mask)) {
 		dp_rx_deliver_to_stack(soc, peer->vdev, peer,

+ 5 - 2
dp/wifi3.0/dp_rx.h

@@ -172,6 +172,7 @@ bool dp_rx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask)
  * @peer: pointer to DP peer
  * @nbuf: pointer to the skb of RX frame
  * @frame_mask: the mask for speical frame needed
+ * @rx_tlv_hdr: start of rx tlv header
  *
  * note: Msdu_len must have been stored in QDF_NBUF_CB_RX_PKT_LEN(nbuf) and
  * single nbuf is expected.
@@ -179,7 +180,8 @@ bool dp_rx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask)
  * return: true - nbuf has been delivered to stack, false - not.
  */
 bool dp_rx_deliver_special_frame(struct dp_soc *soc, struct dp_peer *peer,
-				 qdf_nbuf_t nbuf, uint32_t frame_mask);
+				 qdf_nbuf_t nbuf, uint32_t frame_mask,
+				 uint8_t *rx_tlv_hdr);
 #else
 static inline
 bool dp_rx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask)
@@ -189,7 +191,8 @@ bool dp_rx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask)
 
 static inline
 bool dp_rx_deliver_special_frame(struct dp_soc *soc, struct dp_peer *peer,
-				 qdf_nbuf_t nbuf, uint32_t frame_mask)
+				 qdf_nbuf_t nbuf, uint32_t frame_mask,
+				 uint8_t *rx_tlv_hdr)
 {
 	return false;
 }

+ 39 - 14
dp/wifi3.0/dp_rx_err.c

@@ -390,6 +390,7 @@ dp_rx_pn_error_handle(struct dp_soc *soc, hal_ring_desc_t ring_desc,
  * @soc: core txrx main context
  * @nbuf: pointer to msdu skb
  * @peer_id: dp peer ID
+ * @rx_tlv_hdr: start of rx tlv header
  *
  * This function process the msdu delivered from REO2TCL
  * ring with error type OOR
@@ -399,7 +400,8 @@ dp_rx_pn_error_handle(struct dp_soc *soc, hal_ring_desc_t ring_desc,
 static void
 dp_rx_oor_handle(struct dp_soc *soc,
 		 qdf_nbuf_t nbuf,
-		 uint16_t peer_id)
+		 uint16_t peer_id,
+		 uint8_t *rx_tlv_hdr)
 {
 	uint32_t frame_mask = FRAME_MASK_IPV4_ARP | FRAME_MASK_IPV4_DHCP |
 				FRAME_MASK_IPV4_EAPOL | FRAME_MASK_IPV6_DHCP;
@@ -411,7 +413,8 @@ dp_rx_oor_handle(struct dp_soc *soc,
 		goto free_nbuf;
 	}
 
-	if (dp_rx_deliver_special_frame(soc, peer, nbuf, frame_mask)) {
+	if (dp_rx_deliver_special_frame(soc, peer, nbuf, frame_mask,
+					rx_tlv_hdr)) {
 		DP_STATS_INC(soc, rx.err.reo_err_oor_to_stack, 1);
 		dp_peer_unref_del_find_by_id(peer);
 		return;
@@ -449,7 +452,8 @@ dp_rx_reo_err_entry_process(struct dp_soc *soc,
 	uint32_t rx_bufs_used = 0;
 	struct dp_pdev *pdev;
 	int i;
-	uint8_t *rx_tlv_hdr;
+	uint8_t *rx_tlv_hdr_first;
+	uint8_t *rx_tlv_hdr_last;
 	uint32_t tid = DP_MAX_TIDS;
 	uint16_t peer_id;
 	struct dp_rx_desc *rx_desc;
@@ -461,6 +465,9 @@ dp_rx_reo_err_entry_process(struct dp_soc *soc,
 	struct buffer_addr_info next_link_desc_addr_info = { 0 };
 	/* First field in REO Dst ring Desc is buffer_addr_info */
 	void *buf_addr_info = ring_desc;
+	qdf_nbuf_t head_nbuf = NULL;
+	qdf_nbuf_t tail_nbuf = NULL;
+	uint16_t msdu_processed = 0;
 
 	peer_id = DP_PEER_METADATA_PEER_ID_GET(
 					mpdu_desc_info->peer_meta_data);
@@ -482,8 +489,25 @@ more_msdu_link_desc:
 		qdf_nbuf_unmap_single(soc->osdev,
 				      nbuf, QDF_DMA_FROM_DEVICE);
 
-		rx_tlv_hdr = qdf_nbuf_data(nbuf);
 		QDF_NBUF_CB_RX_PKT_LEN(nbuf) = msdu_list.msdu_info[i].msdu_len;
+		rx_bufs_used++;
+		dp_rx_add_to_free_desc_list(&pdev->free_list_head,
+					    &pdev->free_list_tail, rx_desc);
+
+		DP_RX_LIST_APPEND(head_nbuf, tail_nbuf, nbuf);
+
+		if (qdf_unlikely(msdu_list.msdu_info[i].msdu_flags &
+				 HAL_MSDU_F_MSDU_CONTINUATION))
+			continue;
+
+		rx_tlv_hdr_first = qdf_nbuf_data(head_nbuf);
+		rx_tlv_hdr_last = qdf_nbuf_data(tail_nbuf);
+
+		if (qdf_unlikely(head_nbuf != tail_nbuf)) {
+			nbuf = dp_rx_sg_create(head_nbuf);
+			qdf_nbuf_set_is_frag(nbuf, 1);
+			DP_STATS_INC(soc, rx.err.reo_err_oor_sg_count, 1);
+		}
 
 		switch (err_code) {
 		case HAL_REO_ERR_REGULAR_FRAME_2K_JUMP:
@@ -492,28 +516,28 @@ more_msdu_link_desc:
 			 * and use it for following msdu.
 			 */
 			if (hal_rx_msdu_end_first_msdu_get(soc->hal_soc,
-							   rx_tlv_hdr))
+							   rx_tlv_hdr_last))
 				tid = hal_rx_mpdu_start_tid_get(soc->hal_soc,
-								rx_tlv_hdr);
+							      rx_tlv_hdr_first);
 
-			dp_2k_jump_handle(soc, nbuf, rx_tlv_hdr,
+			dp_2k_jump_handle(soc, nbuf, rx_tlv_hdr_last,
 					  peer_id, tid);
 			break;
 
 		case HAL_REO_ERR_REGULAR_FRAME_OOR:
-			dp_rx_oor_handle(soc, nbuf, peer_id);
+			dp_rx_oor_handle(soc, nbuf, peer_id, rx_tlv_hdr_last);
 			break;
 		default:
 			dp_err_rl("Non-support error code %d", err_code);
 			qdf_nbuf_free(nbuf);
 		}
 
-		dp_rx_add_to_free_desc_list(&pdev->free_list_head,
-					    &pdev->free_list_tail, rx_desc);
-		rx_bufs_used++;
+		msdu_processed++;
+		head_nbuf = NULL;
+		tail_nbuf = NULL;
 	}
 
-	if (rx_bufs_used < mpdu_desc_info->msdu_count) {
+	if (msdu_processed < mpdu_desc_info->msdu_count) {
 		hal_rx_get_next_msdu_link_desc_buf_addr_info(
 						link_desc_va,
 						&next_link_desc_addr_info);
@@ -539,7 +563,7 @@ more_msdu_link_desc:
 
 	dp_rx_link_desc_return_by_addr(soc, buf_addr_info,
 				       HAL_BM_ACTION_PUT_IN_IDLE_LIST);
-	QDF_BUG(rx_bufs_used == mpdu_desc_info->msdu_count);
+	QDF_BUG(msdu_processed == mpdu_desc_info->msdu_count);
 
 	return rx_bufs_used;
 }
@@ -755,7 +779,8 @@ dp_2k_jump_handle(struct dp_soc *soc,
 	}
 
 nbuf_deliver:
-	if (dp_rx_deliver_special_frame(soc, peer, nbuf, frame_mask)) {
+	if (dp_rx_deliver_special_frame(soc, peer, nbuf, frame_mask,
+					rx_tlv_hdr)) {
 		DP_STATS_INC(soc, rx.err.rx_2k_jump_to_stack, 1);
 		dp_peer_unref_del_find_by_id(peer);
 		return;

+ 2 - 0
dp/wifi3.0/dp_types.h

@@ -832,6 +832,8 @@ struct dp_soc_stats {
 			uint32_t reo_err_oor_drop;
 			/* REO OOR msdu indicated to stack count */
 			uint32_t reo_err_oor_to_stack;
+			/* REO OOR scattered msdu count */
+			uint32_t reo_err_oor_sg_count;
 		} err;
 
 		/* packet count per core - per ring */