瀏覽代碼

qcacmn: Support RX 2K jump/OOR frame handling from REO2TCL ring

Support RX 2K jump/OOR frame handling from REO2TCL ring.
(a) configure REO error destination ring register to route 2K jump
/OOR frame to REO2TCL ring.
(b) for 2K jump RX frame, only accept ARP frame and drop others,
meanwhile, send delba action frame to remote peer once receive first
2K jump data.
(c) for OOR RX frame, accept ARP/EAPOL/DHCP/IPV6_DHCP frame, otherwise
drop it.

Change-Id: I7cb33279a8ba543686da4eba547e40f86813e057
CRs-Fixed: 2631949
Jinwei Chen 5 年之前
父節點
當前提交
b3e587db52

+ 3 - 1
dp/wifi3.0/dp_main.c

@@ -2787,7 +2787,7 @@ static void dp_reo_frag_dst_set(struct dp_soc *soc, uint8_t *frag_dst_ring)
 
 	switch (offload_radio) {
 	case dp_nss_cfg_default:
-		*frag_dst_ring = HAL_SRNG_REO_EXCEPTION;
+		*frag_dst_ring = REO_REMAP_TCL;
 		break;
 	case dp_nss_cfg_first_radio:
 		/*
@@ -3169,6 +3169,8 @@ out:
 
 	hal_reo_setup(soc->hal_soc, &reo_params);
 
+	hal_reo_set_err_dst_remap(soc->hal_soc);
+
 	qdf_atomic_set(&soc->cmn_init_done, 1);
 
 	dp_soc_wds_attach(soc);

+ 48 - 34
dp/wifi3.0/dp_rx.c

@@ -1676,25 +1676,6 @@ static inline bool dp_rx_enable_eol_data_check(struct dp_soc *soc)
 
 #endif /* WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT */
 
-/**
- * dp_is_special_data() - check is the pkt special like eapol, dhcp, etc
- *
- * @nbuf: pkt skb pointer
- *
- * Return: true if matched, false if not
- */
-static inline
-bool dp_is_special_data(qdf_nbuf_t nbuf)
-{
-	if (qdf_nbuf_is_ipv4_arp_pkt(nbuf) ||
-	    qdf_nbuf_is_ipv4_dhcp_pkt(nbuf) ||
-	    qdf_nbuf_is_ipv4_eapol_pkt(nbuf) ||
-	    qdf_nbuf_is_ipv6_dhcp_pkt(nbuf))
-		return true;
-	else
-		return false;
-}
-
 #ifdef DP_RX_PKT_NO_PEER_DELIVER
 /**
  * dp_rx_deliver_to_stack_no_peer() - try deliver rx data even if
@@ -1718,6 +1699,8 @@ void dp_rx_deliver_to_stack_no_peer(struct dp_soc *soc, qdf_nbuf_t nbuf)
 	uint16_t msdu_len = 0;
 	uint32_t pkt_len = 0;
 	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;
 
 	peer_id = QDF_NBUF_CB_RX_PEER_ID(nbuf);
 	if (peer_id > soc->max_peers)
@@ -1728,29 +1711,27 @@ void dp_rx_deliver_to_stack_no_peer(struct dp_soc *soc, qdf_nbuf_t nbuf)
 	if (!vdev || vdev->delete.pending || !vdev->osif_rx)
 		goto deliver_fail;
 
+	if (qdf_unlikely(qdf_nbuf_is_frag(nbuf)))
+		goto deliver_fail;
+
 	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))) {
-		qdf_nbuf_pull_head(nbuf, RX_PKT_TLVS_LEN);
-	} else {
-		qdf_nbuf_set_pktlen(nbuf, pkt_len);
-		qdf_nbuf_pull_head(nbuf,
-				   RX_PKT_TLVS_LEN +
-				   l2_hdr_offset);
-	}
+	qdf_nbuf_set_pktlen(nbuf, pkt_len);
+	qdf_nbuf_pull_head(nbuf,
+			   RX_PKT_TLVS_LEN +
+			   l2_hdr_offset);
 
-	/* only allow special frames */
-	if (!dp_is_special_data(nbuf))
-		goto deliver_fail;
-
-	vdev->osif_rx(vdev->osif_vdev, nbuf);
-	DP_STATS_INC(soc, rx.err.pkt_delivered_no_peer, 1);
-	return;
+	if (dp_rx_is_special_frame(nbuf, frame_mask)) {
+		vdev->osif_rx(vdev->osif_vdev, nbuf);
+		DP_STATS_INC(soc, rx.err.pkt_delivered_no_peer, 1);
+		return;
+	}
 
 deliver_fail:
 	DP_STATS_INC_PKT(soc, rx.err.rx_invalid_peer, 1,
@@ -2790,3 +2771,36 @@ dp_rx_nbuf_prepare(struct dp_soc *soc, struct dp_pdev *pdev)
 
 	return nbuf;
 }
+
+#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)
+{
+	uint32_t l2_hdr_offset = 0;
+	uint16_t msdu_len = 0;
+	uint32_t pkt_len = 0;
+	uint8_t *rx_tlv_hdr;
+
+	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;
+
+	qdf_nbuf_set_pktlen(nbuf, pkt_len);
+	dp_rx_skip_tlvs(nbuf, l2_hdr_offset);
+
+	if (dp_rx_is_special_frame(nbuf, frame_mask)) {
+		dp_rx_deliver_to_stack(soc, peer->vdev, peer,
+				       nbuf, NULL);
+		return true;
+	}
+
+	return false;
+}
+#endif

+ 63 - 0
dp/wifi3.0/dp_rx.h

@@ -132,6 +132,69 @@ struct dp_rx_desc {
 	(((_cookie) & RX_DESC_COOKIE_INDEX_MASK) >>	\
 			RX_DESC_COOKIE_INDEX_SHIFT)
 
+#define FRAME_MASK_IPV4_ARP   1
+#define FRAME_MASK_IPV4_DHCP  2
+#define FRAME_MASK_IPV4_EAPOL 4
+#define FRAME_MASK_IPV6_DHCP  8
+
+#ifdef DP_RX_SPECIAL_FRAME_NEED
+/**
+ * dp_rx_is_special_frame() - check is RX frame special needed
+ *
+ * @nbuf: RX skb pointer
+ * @frame_mask: the mask for speical frame needed
+ *
+ * Check is RX frame wanted matched with mask
+ *
+ * Return: true - special frame needed, false - no
+ */
+static inline
+bool dp_rx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask)
+{
+	if (((frame_mask & FRAME_MASK_IPV4_ARP) &&
+	     qdf_nbuf_is_ipv4_arp_pkt(nbuf)) ||
+	    ((frame_mask & FRAME_MASK_IPV4_DHCP) &&
+	     qdf_nbuf_is_ipv4_dhcp_pkt(nbuf)) ||
+	    ((frame_mask & FRAME_MASK_IPV4_EAPOL) &&
+	     qdf_nbuf_is_ipv4_eapol_pkt(nbuf)) ||
+	    ((frame_mask & FRAME_MASK_IPV6_DHCP) &&
+	     qdf_nbuf_is_ipv6_dhcp_pkt(nbuf)))
+		return true;
+
+	return false;
+}
+
+/**
+ * dp_rx_deliver_special_frame() - Deliver the RX special frame to stack
+ *				   if matches mask
+ *
+ * @soc: Datapath soc handler
+ * @peer: pointer to DP peer
+ * @nbuf: pointer to the skb of RX frame
+ * @frame_mask: the mask for speical frame needed
+ *
+ * note: Msdu_len must have been stored in QDF_NBUF_CB_RX_PKT_LEN(nbuf) and
+ * single nbuf is expected.
+ *
+ * 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);
+#else
+static inline
+bool dp_rx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask)
+{
+	return false;
+}
+
+static inline
+bool dp_rx_deliver_special_frame(struct dp_soc *soc, struct dp_peer *peer,
+				 qdf_nbuf_t nbuf, uint32_t frame_mask)
+{
+	return false;
+}
+#endif
+
 /* DOC: Offset to obtain LLC hdr
  *
  * In the case of Wifi parse error

+ 207 - 43
dp/wifi3.0/dp_rx_err.c

@@ -379,32 +379,163 @@ dp_rx_pn_error_handle(struct dp_soc *soc, hal_ring_desc_t ring_desc,
 }
 
 /**
- * dp_rx_2k_jump_handle() - Handles Sequence Number Jump by 2K
+ * dp_rx_oor_handle() - Handles the msdu which is OOR error
+ *
+ * @soc: core txrx main context
+ * @nbuf: pointer to msdu skb
+ * @peer_id: dp peer ID
+ *
+ * This function process the msdu delivered from REO2TCL
+ * ring with error type OOR
+ *
+ * Return: None
+ */
+static void
+dp_rx_oor_handle(struct dp_soc *soc,
+		 qdf_nbuf_t nbuf,
+		 uint16_t peer_id)
+{
+	uint32_t frame_mask = FRAME_MASK_IPV4_ARP | FRAME_MASK_IPV4_DHCP |
+				FRAME_MASK_IPV4_EAPOL | FRAME_MASK_IPV6_DHCP;
+	struct dp_peer *peer = NULL;
+
+	peer = dp_peer_find_by_id(soc, peer_id);
+	if (!peer) {
+		dp_info_rl("peer not found");
+		goto free_nbuf;
+	}
+
+	if (dp_rx_deliver_special_frame(soc, peer, nbuf, frame_mask)) {
+		DP_STATS_INC(soc, rx.err.reo_err_oor_to_stack, 1);
+		dp_peer_unref_del_find_by_id(peer);
+		return;
+	}
+
+free_nbuf:
+	if (peer)
+		dp_peer_unref_del_find_by_id(peer);
+
+	DP_STATS_INC(soc, rx.err.reo_err_oor_drop, 1);
+	qdf_nbuf_free(nbuf);
+}
+
+/**
+ * dp_rx_reo_err_entry_process() - Handles for REO error entry processing
  *
  * @soc: core txrx main context
  * @ring_desc: opaque pointer to the REO error ring descriptor
- * @mpdu_desc_info: MPDU descriptor information from ring descriptor
- * @head: head of the local descriptor free-list
- * @tail: tail of the local descriptor free-list
- * @quota: No. of units (packets) that can be serviced in one shot.
+ * @mpdu_desc_info: pointer to mpdu level description info
+ * @link_desc_va: pointer to msdu_link_desc virtual address
+ * @err_code: reo erro code fetched from ring entry
  *
- * This function implements the error handling when sequence number
- * of the MPDU jumps suddenly by 2K.Today there are 2 cases that
- * need to be handled:
- *	A) CSN (Current Sequence Number) = Last Valid SN (LSN) + 2K
- *	B) CSN = LSN + 2K, but falls within a "BA sized window" of the SSN
- * For case A) the protocol stack is invoked to generate DELBA/DEAUTH frame
- * For case B), the frame is normally dropped, no more action is taken
+ * Function to handle msdus fetched from msdu link desc, currently
+ * only support 2K jump, OOR error.
  *
- * Return: uint32_t: No. of elements processed
+ * Return: msdu count processed.
  */
 static uint32_t
-dp_rx_2k_jump_handle(struct dp_soc *soc, hal_ring_desc_t ring_desc,
-		     struct hal_rx_mpdu_desc_info *mpdu_desc_info,
-		     uint8_t *mac_id, uint32_t quota)
+dp_rx_reo_err_entry_process(struct dp_soc *soc,
+			    void *ring_desc,
+			    struct hal_rx_mpdu_desc_info *mpdu_desc_info,
+			    void *link_desc_va,
+			    enum hal_reo_error_code err_code)
 {
-	return dp_rx_msdus_drop(soc, ring_desc, mpdu_desc_info,
-				mac_id, quota);
+	uint32_t rx_bufs_used = 0;
+	struct dp_pdev *pdev;
+	int i;
+	uint8_t *rx_tlv_hdr;
+	uint32_t tid = DP_MAX_TIDS;
+	uint16_t peer_id;
+	struct dp_rx_desc *rx_desc;
+	qdf_nbuf_t nbuf;
+	struct hal_buf_info buf_info;
+	struct hal_rx_msdu_list msdu_list;
+	uint16_t num_msdus;
+	struct buffer_addr_info cur_link_desc_addr_info = { 0 };
+	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;
+
+	peer_id = DP_PEER_METADATA_PEER_ID_GET(
+					mpdu_desc_info->peer_meta_data);
+
+more_msdu_link_desc:
+	hal_rx_msdu_list_get(soc->hal_soc, link_desc_va, &msdu_list,
+			     &num_msdus);
+	for (i = 0; i < num_msdus; i++) {
+		rx_desc = dp_rx_cookie_2_va_rxdma_buf(
+					soc,
+					msdu_list.sw_cookie[i]);
+
+		qdf_assert_always(rx_desc);
+
+		/* all buffers from a MSDU link belong to same pdev */
+		pdev = dp_get_pdev_for_lmac_id(soc, rx_desc->pool_id);
+
+		nbuf = rx_desc->nbuf;
+		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;
+
+		switch (err_code) {
+		case HAL_REO_ERR_REGULAR_FRAME_2K_JUMP:
+			/*
+			 * only first msdu, mpdu start description tlv valid?
+			 * and use it for following msdu.
+			 */
+			if (hal_rx_msdu_end_first_msdu_get(soc->hal_soc,
+							   rx_tlv_hdr))
+				tid = hal_rx_mpdu_start_tid_get(soc->hal_soc,
+								rx_tlv_hdr);
+
+			dp_2k_jump_handle(soc, nbuf, rx_tlv_hdr,
+					  peer_id, tid);
+			break;
+
+		case HAL_REO_ERR_REGULAR_FRAME_OOR:
+			dp_rx_oor_handle(soc, nbuf, peer_id);
+			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++;
+	}
+
+	if (rx_bufs_used < mpdu_desc_info->msdu_count) {
+		hal_rx_get_next_msdu_link_desc_buf_addr_info(
+						link_desc_va,
+						&next_link_desc_addr_info);
+
+		if (hal_rx_is_buf_addr_info_valid(
+				&next_link_desc_addr_info)) {
+			dp_rx_link_desc_return_by_addr(
+					soc,
+					buf_addr_info,
+					HAL_BM_ACTION_PUT_IN_IDLE_LIST);
+
+			hal_rx_buffer_addr_info_get_paddr(
+						&next_link_desc_addr_info,
+						&buf_info);
+			link_desc_va =
+				dp_rx_cookie_2_link_desc_va(soc, &buf_info);
+			cur_link_desc_addr_info = next_link_desc_addr_info;
+			buf_addr_info = &cur_link_desc_addr_info;
+
+			goto 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);
+
+	return rx_bufs_used;
 }
 
 #ifdef DP_INVALID_PEER_ASSERT
@@ -574,58 +705,62 @@ dp_2k_jump_handle(struct dp_soc *soc,
 		  uint16_t peer_id,
 		  uint8_t tid)
 {
-	uint32_t ppdu_id;
 	struct dp_peer *peer = NULL;
 	struct dp_rx_tid *rx_tid = NULL;
+	uint32_t frame_mask = FRAME_MASK_IPV4_ARP;
 
 	peer = dp_peer_find_by_id(soc, peer_id);
-	if (!peer || peer->delete_in_progress) {
-		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
-			  "peer not found");
+	if (!peer) {
+		dp_info_rl("peer not found");
 		goto free_nbuf;
 	}
-	rx_tid = &peer->rx_tid[tid];
-	if (qdf_unlikely(!rx_tid)) {
-		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
-			  "rx_tid is NULL!!");
-		goto free_nbuf;
+
+	if (tid >= DP_MAX_TIDS) {
+		dp_info_rl("invalid tid");
+		goto nbuf_deliver;
 	}
+
+	rx_tid = &peer->rx_tid[tid];
 	qdf_spin_lock_bh(&rx_tid->tid_lock);
-	ppdu_id = hal_rx_attn_phy_ppdu_id_get(rx_tlv_hdr);
 
-	/*
-	 * If BA session is created and a non-aggregate packet is
-	 * landing here then the issue is with sequence number mismatch.
-	 * Proceed with delba even in that case
-	 */
-	if (rx_tid->ppdu_id_2k != ppdu_id &&
-	    rx_tid->ba_status != DP_RX_BA_ACTIVE) {
-		rx_tid->ppdu_id_2k = ppdu_id;
+	/* only if BA session is active, allow send Delba */
+	if (rx_tid->ba_status != DP_RX_BA_ACTIVE) {
 		qdf_spin_unlock_bh(&rx_tid->tid_lock);
-		goto free_nbuf;
+		goto nbuf_deliver;
 	}
+
 	if (!rx_tid->delba_tx_status) {
 		rx_tid->delba_tx_retry++;
 		rx_tid->delba_tx_status = 1;
 		rx_tid->delba_rcode =
 			IEEE80211_REASON_QOS_SETUP_REQUIRED;
 		qdf_spin_unlock_bh(&rx_tid->tid_lock);
-		if (soc->cdp_soc.ol_ops->send_delba)
+		if (soc->cdp_soc.ol_ops->send_delba) {
+			DP_STATS_INC(soc, rx.err.rx_2k_jump_delba_sent, 1);
 			soc->cdp_soc.ol_ops->send_delba(
 					peer->vdev->pdev->soc->ctrl_psoc,
 					peer->vdev->vdev_id,
 					peer->mac_addr.raw,
 					tid,
 					rx_tid->delba_rcode);
+		}
 	} else {
 		qdf_spin_unlock_bh(&rx_tid->tid_lock);
 	}
 
+nbuf_deliver:
+	if (dp_rx_deliver_special_frame(soc, peer, nbuf, frame_mask)) {
+		DP_STATS_INC(soc, rx.err.rx_2k_jump_to_stack, 1);
+		dp_peer_unref_del_find_by_id(peer);
+		return;
+	}
+
 free_nbuf:
 	if (peer)
 		dp_peer_unref_del_find_by_id(peer);
+
+	DP_STATS_INC(soc, rx.err.rx_2k_jump_drop, 1);
 	qdf_nbuf_free(nbuf);
-	return;
 }
 
 #if defined(QCA_WIFI_QCA6390) || defined(QCA_WIFI_QCA6490) || \
@@ -1371,9 +1506,33 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
 			if (dp_pdev)
 				DP_STATS_INC(dp_pdev, err.reo_error, 1);
 
-			count = dp_rx_2k_jump_handle(soc,
-						     ring_desc, &mpdu_desc_info,
-						     &mac_id, quota);
+			count = dp_rx_reo_err_entry_process(
+					soc,
+					ring_desc,
+					&mpdu_desc_info,
+					link_desc_va,
+					HAL_REO_ERR_REGULAR_FRAME_2K_JUMP);
+
+			rx_bufs_reaped[mac_id] += count;
+			continue;
+		}
+
+		if (hal_rx_reo_is_oor_error(ring_desc)) {
+			DP_STATS_INC(
+				soc,
+				rx.err.
+				reo_error[HAL_REO_ERR_REGULAR_FRAME_OOR],
+				1);
+			/* increment @pdev level */
+			dp_pdev = dp_get_pdev_for_lmac_id(soc, mac_id);
+			if (dp_pdev)
+				DP_STATS_INC(dp_pdev, err.reo_error, 1);
+			count = dp_rx_reo_err_entry_process(
+					soc,
+					ring_desc,
+					&mpdu_desc_info,
+					link_desc_va,
+					HAL_REO_ERR_REGULAR_FRAME_OOR);
 
 			rx_bufs_reaped[mac_id] += count;
 			continue;
@@ -1707,7 +1866,12 @@ done:
 						tid =
 						hal_rx_mpdu_start_tid_get(hal_soc, rx_tlv_hdr);
 					}
-					dp_2k_jump_handle(soc, nbuf, rx_tlv_hdr,
+					QDF_NBUF_CB_RX_PKT_LEN(nbuf) =
+					hal_rx_msdu_start_msdu_len_get(
+								rx_tlv_hdr);
+					nbuf->next = NULL;
+					dp_2k_jump_handle(soc, nbuf,
+							  rx_tlv_hdr,
 							  peer_id, tid);
 					nbuf = next;
 					if (peer)

+ 25 - 0
dp/wifi3.0/dp_stats.c

@@ -5574,6 +5574,16 @@ void dp_txrx_path_stats(struct dp_soc *soc)
 			       pdev->soc->stats.rx.err.pkt_delivered_no_peer);
 		DP_PRINT_STATS("RX invalid cookie: %d",
 			       soc->stats.rx.err.invalid_cookie);
+		DP_PRINT_STATS("2k jump delba sent: %u",
+			       pdev->soc->stats.rx.err.rx_2k_jump_delba_sent);
+		DP_PRINT_STATS("2k jump msdu to stack: %u",
+			       pdev->soc->stats.rx.err.rx_2k_jump_to_stack);
+		DP_PRINT_STATS("2k jump msdu drop: %u",
+			       pdev->soc->stats.rx.err.rx_2k_jump_drop);
+		DP_PRINT_STATS("REO err oor msdu to stack %u",
+			       pdev->soc->stats.rx.err.reo_err_oor_to_stack);
+		DP_PRINT_STATS("REO err oor msdu drop: %u",
+			       pdev->soc->stats.rx.err.reo_err_oor_drop);
 
 		DP_PRINT_STATS("Reo Statistics");
 		DP_PRINT_STATS("near_full: %u ", soc->stats.rx.near_full);
@@ -6088,6 +6098,21 @@ dp_print_soc_rx_stats(struct dp_soc *soc)
 	DP_PRINT_STATS("RX wait completed msdu break: %d",
 		       soc->stats.rx.msdu_scatter_wait_break);
 
+	DP_PRINT_STATS("2k jump delba sent: %d",
+		       soc->stats.rx.err.rx_2k_jump_delba_sent);
+
+	DP_PRINT_STATS("2k jump msdu to stack: %d",
+		       soc->stats.rx.err.rx_2k_jump_to_stack);
+
+	DP_PRINT_STATS("2k jump msdu drop: %d",
+		       soc->stats.rx.err.rx_2k_jump_drop);
+
+	DP_PRINT_STATS("REO err oor msdu to stack %d",
+		       soc->stats.rx.err.reo_err_oor_to_stack);
+
+	DP_PRINT_STATS("REO err oor msdu drop: %d",
+		       soc->stats.rx.err.reo_err_oor_drop);
+
 	for (i = 0; i < HAL_RXDMA_ERR_MAX; i++) {
 		index += qdf_snprint(&rxdma_error[index],
 				DP_RXDMA_ERR_LENGTH - index,

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

@@ -795,6 +795,16 @@ struct dp_soc_stats {
 			uint32_t scatter_msdu;
 			/* RX msdu drop count due to invalid cookie */
 			uint32_t invalid_cookie;
+			/* Delba sent count due to RX 2k jump */
+			uint32_t rx_2k_jump_delba_sent;
+			/* RX 2k jump msdu indicated to stack count */
+			uint32_t rx_2k_jump_to_stack;
+			/* RX 2k jump msdu dropped count */
+			uint32_t rx_2k_jump_drop;
+			/* REO OOR msdu drop count */
+			uint32_t reo_err_oor_drop;
+			/* REO OOR msdu indicated to stack count */
+			uint32_t reo_err_oor_to_stack;
 		} err;
 
 		/* packet count per core - per ring */

+ 25 - 0
hal/wifi3.0/hal_api.h

@@ -815,6 +815,15 @@ extern void *hal_srng_setup(void *hal_soc, int ring_type, int ring_num,
 #define REO_REMAP_FW 6
 #define REO_REMAP_UNUSED 7
 
+/*
+ * Macro to access HWIO_REO_R0_ERROR_DESTINATION_RING_CTRL_IX_0
+ * to map destination to rings
+ */
+#define HAL_REO_ERR_REMAP_IX0(_VALUE, _OFFSET) \
+	((_VALUE) << \
+	 (HWIO_REO_R0_ERROR_DESTINATION_MAPPING_IX_0_ERROR_ ## \
+	  DESTINATION_RING_ ## _OFFSET ## _SHFT))
+
 /*
  * Macro to access HWIO_REO_R0_DESTINATION_RING_CTRL_IX_0
  * to map destination to rings
@@ -2052,4 +2061,20 @@ hal_rx_sw_mon_desc_info_get(struct hal_soc *hal,
 {
 	return hal->ops->hal_rx_sw_mon_desc_info_get(ring_desc, desc_info);
 }
+
+/**
+ * hal_reo_set_err_dst_remap() - Set REO error destination ring remap
+ *				 register value.
+ *
+ * @hal_soc_hdl: Opaque HAL soc handle
+ *
+ * Return: None
+ */
+static inline void hal_reo_set_err_dst_remap(hal_soc_handle_t hal_soc_hdl)
+{
+	struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl;
+
+	if (hal_soc->ops->hal_reo_set_err_dst_remap)
+		hal_soc->ops->hal_reo_set_err_dst_remap(hal_soc);
+}
 #endif /* _HAL_APIH_ */

+ 0 - 1
hal/wifi3.0/hal_generic_api.h

@@ -1630,7 +1630,6 @@ static void hal_reo_setup_generic(struct hal_soc *soc,
 				       SEQ_WCSS_UMAC_REO_REG_OFFSET)));
 	}
 
-
 	/* TODO: Check if the following registers shoould be setup by host:
 	 * AGING_CONTROL
 	 * HIGH_MEMORY_THRESHOLD

+ 1 - 0
hal/wifi3.0/hal_internal.h

@@ -469,6 +469,7 @@ struct hal_hw_txrx_ops {
 				uint32_t num_entries);
 	qdf_iomem_t (*hal_get_window_address)(struct hal_soc *hal_soc,
 					      qdf_iomem_t addr);
+	void (*hal_reo_set_err_dst_remap)(void *hal_soc);
 
 	/* tx */
 	void (*hal_tx_desc_set_dscp_tid_table_id)(void *desc, uint8_t id);

+ 75 - 0
hal/wifi3.0/hal_rx.h

@@ -2121,6 +2121,22 @@ static inline bool hal_rx_reo_is_2k_jump(hal_ring_desc_t rx_desc)
 			true : false;
 }
 
+/**
+ * hal_rx_reo_is_oor_error() - Indicate if this error was caused by OOR
+ *
+ * @ring_desc: opaque pointer used by HAL to get the REO destination entry
+ *
+ * Return: true: error caused by OOR, false: other error
+ */
+static inline bool hal_rx_reo_is_oor_error(void *rx_desc)
+{
+	struct reo_destination_ring *reo_desc =
+			(struct reo_destination_ring *)rx_desc;
+
+	return (HAL_RX_REO_ERROR_GET(reo_desc) ==
+		HAL_REO_ERR_REGULAR_FRAME_OOR) ? true : false;
+}
+
 #define HAL_WBM_RELEASE_RING_DESC_LEN_DWORDS (NUM_OF_DWORDS_WBM_RELEASE_RING)
 /**
  * hal_dump_wbm_rel_desc() - dump wbm release descriptor
@@ -3656,4 +3672,63 @@ hal_rx_mpdu_start_tlv_tag_valid(hal_soc_handle_t hal_soc_hdl,
 
 	return hal->ops->hal_rx_mpdu_start_tlv_tag_valid(rx_tlv_hdr);
 }
+
+/**
+ * hal_rx_buffer_addr_info_get_paddr(): get paddr/sw_cookie from
+ *					<struct buffer_addr_info> structure
+ * @buf_addr_info: pointer to <struct buffer_addr_info> structure
+ * @buf_info: structure to return the buffer information including
+ *		paddr/cookie
+ *
+ * return: None
+ */
+static inline
+void hal_rx_buffer_addr_info_get_paddr(void *buf_addr_info,
+				       struct hal_buf_info *buf_info)
+{
+	buf_info->paddr =
+	 (HAL_RX_BUFFER_ADDR_31_0_GET(buf_addr_info) |
+	  ((uint64_t)(HAL_RX_BUFFER_ADDR_39_32_GET(buf_addr_info)) << 32));
+
+	buf_info->sw_cookie = HAL_RX_BUF_COOKIE_GET(buf_addr_info);
+}
+
+/**
+ * hal_rx_get_next_msdu_link_desc_buf_addr_info(): get next msdu link desc
+ *						   buffer addr info
+ * @link_desc_va: pointer to current msdu link Desc
+ * @next_addr_info: buffer to save next msdu link Desc buffer addr info
+ *
+ * return: None
+ */
+static inline
+void hal_rx_get_next_msdu_link_desc_buf_addr_info(
+				void *link_desc_va,
+				struct buffer_addr_info *next_addr_info)
+{
+	struct rx_msdu_link *msdu_link = link_desc_va;
+
+	if (!msdu_link) {
+		qdf_mem_zero(next_addr_info,
+			     sizeof(struct buffer_addr_info));
+		return;
+	}
+
+	*next_addr_info = msdu_link->next_msdu_link_desc_addr_info;
+}
+
+/**
+ * hal_rx_is_buf_addr_info_valid(): check is the buf_addr_info valid
+ *
+ * @buf_addr_info: pointer to buf_addr_info structure
+ *
+ * return: true: has valid paddr, false: not.
+ */
+static inline
+bool hal_rx_is_buf_addr_info_valid(
+				struct buffer_addr_info *buf_addr_info)
+{
+	return (HAL_RX_BUFFER_ADDR_31_0_GET(buf_addr_info) == 0) ?
+						false : true;
+}
 #endif /* _HAL_RX_H */

+ 1 - 0
hal/wifi3.0/qca5018/hal_5018.c

@@ -1352,6 +1352,7 @@ struct hal_hw_txrx_ops qca5018_hal_hw_txrx_ops = {
 	hal_reo_setup_generic,
 	hal_setup_link_idle_list_generic,
 	hal_get_window_address_5018,
+	NULL,
 
 	/* tx */
 	hal_tx_desc_set_dscp_tid_table_id_5018,

+ 1 - 0
hal/wifi3.0/qca6290/hal_6290.c

@@ -1000,6 +1000,7 @@ struct hal_hw_txrx_ops qca6290_hal_hw_txrx_ops = {
 	hal_reo_setup_generic,
 	hal_setup_link_idle_list_generic,
 	hal_get_window_address_6290,
+	NULL,
 
 	/* tx */
 	hal_tx_desc_set_dscp_tid_table_id_6290,

+ 39 - 0
hal/wifi3.0/qca6390/hal_6390.c

@@ -988,6 +988,44 @@ static inline qdf_iomem_t hal_get_window_address_6390(struct hal_soc *hal_soc,
 	return addr;
 }
 
+/**
+ * hal_reo_set_err_dst_remap_6390(): Function to set REO error destination
+ *				     ring remap register
+ * @hal_soc: Pointer to hal_soc
+ *
+ * Return: none.
+ */
+static void
+hal_reo_set_err_dst_remap_6390(void *hal_soc)
+{
+	/*
+	 * Set REO error 2k jump (error code 5) / OOR (error code 7)
+	 * frame routed to REO2TCL ring.
+	 */
+	uint32_t dst_remap_ix0 =
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 0) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 1) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 2) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 3) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 4) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_TCL, 5) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 6) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_TCL, 7) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 8) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 9);
+
+		HAL_REG_WRITE(hal_soc,
+			      HWIO_REO_R0_ERROR_DESTINATION_MAPPING_IX_0_ADDR(
+			      SEQ_WCSS_UMAC_REO_REG_OFFSET),
+			      dst_remap_ix0);
+
+		hal_info("HWIO_REO_R0_ERROR_DESTINATION_MAPPING_IX_0 0x%x",
+			 HAL_REG_READ(
+			 hal_soc,
+			 HWIO_REO_R0_ERROR_DESTINATION_MAPPING_IX_0_ADDR(
+			 SEQ_WCSS_UMAC_REO_REG_OFFSET)));
+}
+
 struct hal_hw_txrx_ops qca6390_hal_hw_txrx_ops = {
 	/* init and setup */
 	hal_srng_dst_hw_init_generic,
@@ -996,6 +1034,7 @@ struct hal_hw_txrx_ops qca6390_hal_hw_txrx_ops = {
 	hal_reo_setup_generic,
 	hal_setup_link_idle_list_generic,
 	hal_get_window_address_6390,
+	hal_reo_set_err_dst_remap_6390,
 
 	/* tx */
 	hal_tx_desc_set_dscp_tid_table_id_6390,

+ 37 - 0
hal/wifi3.0/qca6490/hal_6490.c

@@ -1411,6 +1411,42 @@ bool hal_rx_get_fisa_timeout_6490(uint8_t *buf)
 	return HAL_RX_TLV_GET_FISA_TIMEOUT(buf);
 }
 
+/**
+ * hal_reo_set_err_dst_remap_6490(): Function to set REO error destination
+ *				     ring remap register
+ * @hal_soc: Pointer to hal_soc
+ *
+ * Return: none.
+ */
+static void
+hal_reo_set_err_dst_remap_6490(void *hal_soc)
+{
+	/*
+	 * Set REO error 2k jump (error code 5) / OOR (error code 7)
+	 * frame routed to REO2TCL ring.
+	 */
+	uint32_t dst_remap_ix0 =
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 0) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 1) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 2) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 3) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 4) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_TCL, 5) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_RELEASE, 6) |
+		HAL_REO_ERR_REMAP_IX0(REO_REMAP_TCL, 7);
+
+		HAL_REG_WRITE(hal_soc,
+			      HWIO_REO_R0_ERROR_DESTINATION_MAPPING_IX_0_ADDR(
+			      SEQ_WCSS_UMAC_REO_REG_OFFSET),
+			      dst_remap_ix0);
+
+		hal_info("HWIO_REO_R0_ERROR_DESTINATION_MAPPING_IX_0 0x%x",
+			 HAL_REG_READ(
+			 hal_soc,
+			 HWIO_REO_R0_ERROR_DESTINATION_MAPPING_IX_0_ADDR(
+			 SEQ_WCSS_UMAC_REO_REG_OFFSET)));
+}
+
 struct hal_hw_txrx_ops qca6490_hal_hw_txrx_ops = {
 	/* init and setup */
 	hal_srng_dst_hw_init_generic,
@@ -1419,6 +1455,7 @@ struct hal_hw_txrx_ops qca6490_hal_hw_txrx_ops = {
 	hal_reo_setup_generic,
 	hal_setup_link_idle_list_generic,
 	hal_get_window_address_6490,
+	hal_reo_set_err_dst_remap_6490,
 
 	/* tx */
 	hal_tx_desc_set_dscp_tid_table_id_6490,

+ 1 - 0
hal/wifi3.0/qca6750/hal_6750.c

@@ -1330,6 +1330,7 @@ struct hal_hw_txrx_ops qca6750_hal_hw_txrx_ops = {
 	hal_reo_setup_generic,
 	hal_setup_link_idle_list_generic,
 	hal_get_window_address_6750,
+	NULL,
 
 	/* tx */
 	hal_tx_desc_set_dscp_tid_table_id_6750,

+ 1 - 0
hal/wifi3.0/qca8074v1/hal_8074v1.c

@@ -1021,6 +1021,7 @@ struct hal_hw_txrx_ops qca8074_hal_hw_txrx_ops = {
 	hal_reo_setup_generic,
 	hal_setup_link_idle_list_generic,
 	hal_get_window_address_8074,
+	NULL,
 
 	/* tx */
 	hal_tx_desc_set_dscp_tid_table_id_8074,

+ 1 - 0
hal/wifi3.0/qca8074v2/hal_8074v2.c

@@ -1018,6 +1018,7 @@ struct hal_hw_txrx_ops qca8074v2_hal_hw_txrx_ops = {
 	hal_reo_setup_generic,
 	hal_setup_link_idle_list_generic,
 	hal_get_window_address_8074v2,
+	NULL,
 
 	/* tx */
 	hal_tx_desc_set_dscp_tid_table_id_8074v2,

+ 1 - 0
hal/wifi3.0/qcn9000/hal_9000.c

@@ -1473,6 +1473,7 @@ struct hal_hw_txrx_ops qcn9000_hal_hw_txrx_ops = {
 	hal_reo_setup_generic,
 	hal_setup_link_idle_list_generic,
 	hal_get_window_address_9000,
+	NULL,
 
 	/* tx */
 	hal_tx_desc_set_dscp_tid_table_id_9000,