qcacmn: Support enhanced Rx capture

Support Rx capture mode to deliver first 128 bytes of
each MSDU, along with some meta data.

Change-Id: I1ffa8b1a029d46f68aa78520bacc019de8af7a82
diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h
index eb97da5..a66235c 100644
--- a/dp/inc/cdp_txrx_cmn_struct.h
+++ b/dp/inc/cdp_txrx_cmn_struct.h
@@ -39,6 +39,9 @@
 #endif /* CONFIG_WIN */
 #include <cdp_txrx_handle.h>
 #include <cdp_txrx_stats_struct.h>
+#ifdef WLAN_RX_PKT_CAPTURE_ENH
+#include "cdp_txrx_extd_struct.h"
+#endif
 
 #ifndef OL_TXRX_NUM_LOCAL_PEER_IDS
 /*
@@ -825,6 +828,7 @@
  * @CDP_CONFIG_CAPTURE_LATENCY: Capture time latency
  * @CDP_INGRESS_STATS: Accumulate ingress statistics
  * @CDP_OSIF_DROP: Accumulate drops in OSIF layer
+ * @CDP_CONFIG_ENH_RX_CAPTURE: Enable enhanced RX capture
  */
 enum cdp_pdev_param_type {
 	CDP_CONFIG_DEBUG_SNIFFER,
@@ -837,6 +841,19 @@
 	CDP_CONFIG_CAPTURE_LATENCY,
 	CDP_INGRESS_STATS,
 	CDP_OSIF_DROP,
+	CDP_CONFIG_ENH_RX_CAPTURE,
+};
+
+/**
+ * cdp_rx_enh_capture_mode - Rx enhanced capture modes
+ * @CDP_RX_ENH_CAPTURE_DISABLED: Disable Rx enhance capture
+ * @CDP_RX_ENH_CAPTURE_MPDU: Enable capture of 128 bytes of each MPDU
+ * @CDP_RX_ENH_CAPTURE_MPDU_MSDU: Enable capture of 128 bytes of each MSDU
+ */
+enum cdp_rx_enh_capture_mode {
+	CDP_RX_ENH_CAPTURE_DISABLED = 0,
+	CDP_RX_ENH_CAPTURE_MPDU,
+	CDP_RX_ENH_CAPTURE_MPDU_MSDU,
 };
 
 /*
diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h
index 993e533..6434392 100644
--- a/dp/inc/cdp_txrx_stats_struct.h
+++ b/dp/inc/cdp_txrx_stats_struct.h
@@ -1730,6 +1730,8 @@
 	OL_ATH_PARAM_PERIODIC_CFR_CAPTURE = 404,
 	OL_ATH_PARAM_FLUSH_PEER_RATE_STATS = 405,
 	OL_ATH_PARAM_DCS_RE_ENABLE_TIMER = 406,
+	/* Enable/disable Rx lite monitor mode */
+	OL_ATH_PARAM_RX_MON_LITE = 407,
 };
 
 /* Enumeration of PDEV Configuration parameter */
diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c
index 6faf60f..9b4730a 100644
--- a/dp/wifi3.0/dp_main.c
+++ b/dp/wifi3.0/dp_main.c
@@ -33,6 +33,7 @@
 #include "dp_tx.h"
 #include "dp_tx_desc.h"
 #include "dp_rx.h"
+#include "dp_rx_mon.h"
 #ifdef DP_RATETABLE_SUPPORT
 #include "dp_ratetable.h"
 #endif
@@ -65,6 +66,24 @@
 #include <pktlog_ac.h>
 #endif
 #endif
+
+#ifdef WLAN_RX_PKT_CAPTURE_ENH
+#include "dp_rx_mon_feature.h"
+#else
+/*
+ * dp_config_enh_rx_capture()- API to enable/disable enhanced rx capture
+ * @pdev_handle: DP_PDEV handle
+ * @val: user provided value
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+dp_config_enh_rx_capture(struct cdp_pdev *pdev_handle, int val)
+{
+	return QDF_STATUS_E_INVAL;
+}
+#endif
+
 void *dp_soc_init(void *dpsoc, HTC_HANDLE htc_handle, void *hif_handle);
 static void dp_pdev_detach(struct cdp_pdev *txrx_pdev, int force);
 static struct dp_soc *
@@ -5822,9 +5841,9 @@
  * dp_reset_monitor_mode() - Disable monitor mode
  * @pdev_handle: Datapath PDEV handle
  *
- * Return: 0 on success, not 0 on failure
+ * Return: QDF_STATUS
  */
-static QDF_STATUS dp_reset_monitor_mode(struct cdp_pdev *pdev_handle)
+QDF_STATUS dp_reset_monitor_mode(struct cdp_pdev *pdev_handle)
 {
 	struct dp_pdev *pdev = (struct dp_pdev *)pdev_handle;
 	struct htt_rx_ring_tlv_filter htt_tlv_filter;
@@ -5921,9 +5940,9 @@
  * dp_pdev_configure_monitor_rings() - configure monitor rings
  * @vdev_handle: Datapath VDEV handle
  *
- * Return: void
+ * Return: QDF_STATUS
  */
-static QDF_STATUS dp_pdev_configure_monitor_rings(struct dp_pdev *pdev)
+QDF_STATUS dp_pdev_configure_monitor_rings(struct dp_pdev *pdev)
 {
 	struct htt_rx_ring_tlv_filter htt_tlv_filter;
 	struct dp_soc *soc;
@@ -5975,6 +5994,16 @@
 	htt_tlv_filter.mo_ctrl_filter = pdev->mo_ctrl_filter;
 	htt_tlv_filter.offset_valid = false;
 
+	if ((pdev->rx_enh_capture_mode == CDP_RX_ENH_CAPTURE_MPDU) ||
+	    (pdev->rx_enh_capture_mode == CDP_RX_ENH_CAPTURE_MPDU_MSDU)) {
+		htt_tlv_filter.fp_mgmt_filter = 0;
+		htt_tlv_filter.fp_ctrl_filter = 0;
+		htt_tlv_filter.fp_data_filter = 0;
+		htt_tlv_filter.mo_mgmt_filter = 0;
+		htt_tlv_filter.mo_ctrl_filter = 0;
+		htt_tlv_filter.mo_data_filter = 0;
+	}
+
 	for (mac_id = 0; mac_id < NUM_RXDMA_RINGS_PER_PDEV; mac_id++) {
 		int mac_for_pdev = dp_get_mac_id_for_pdev(mac_id, pdev_id);
 
@@ -5995,6 +6024,10 @@
 	htt_tlv_filter.packet = 0;
 	htt_tlv_filter.msdu_end = 0;
 	htt_tlv_filter.mpdu_end = 0;
+	if ((pdev->rx_enh_capture_mode == CDP_RX_ENH_CAPTURE_MPDU) ||
+	    (pdev->rx_enh_capture_mode == CDP_RX_ENH_CAPTURE_MPDU_MSDU)) {
+		htt_tlv_filter.mpdu_end = 1;
+	}
 	htt_tlv_filter.attention = 0;
 	htt_tlv_filter.ppdu_start = 1;
 	htt_tlv_filter.ppdu_end = 1;
@@ -6004,9 +6037,19 @@
 	htt_tlv_filter.enable_fp = 1;
 	htt_tlv_filter.enable_md = 0;
 	htt_tlv_filter.enable_mo = 1;
-	if (pdev->mcopy_mode) {
+	if (pdev->mcopy_mode ||
+	    (pdev->rx_enh_capture_mode != CDP_RX_ENH_CAPTURE_DISABLED)) {
 		htt_tlv_filter.packet_header = 1;
+		if (pdev->rx_enh_capture_mode == CDP_RX_ENH_CAPTURE_MPDU) {
+			htt_tlv_filter.header_per_msdu = 0;
+			htt_tlv_filter.enable_mo = 0;
+		} else if (pdev->rx_enh_capture_mode ==
+			   CDP_RX_ENH_CAPTURE_MPDU_MSDU) {
+			htt_tlv_filter.header_per_msdu = 1;
+			htt_tlv_filter.enable_mo = 0;
+		}
 	}
+
 	htt_tlv_filter.fp_mgmt_filter = FILTER_MGMT_ALL;
 	htt_tlv_filter.fp_ctrl_filter = FILTER_CTRL_ALL;
 	htt_tlv_filter.fp_data_filter = FILTER_DATA_ALL;
@@ -8188,6 +8231,7 @@
 			dp_h2t_cfg_stats_msg_send(pdev,
 				DP_PPDU_STATS_CFG_SNIFFER, pdev->pdev_id);
 		break;
+
 	default:
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
 			"Invalid value");
@@ -8376,6 +8420,8 @@
 	case CDP_OSIF_DROP:
 		dp_pdev_tid_stats_osif_drop(pdev_handle, val);
 		break;
+	case CDP_CONFIG_ENH_RX_CAPTURE:
+		return dp_config_enh_rx_capture(pdev_handle, val);
 	default:
 		return QDF_STATUS_E_INVAL;
 	}
diff --git a/dp/wifi3.0/dp_rx_mon.h b/dp/wifi3.0/dp_rx_mon.h
index 78c844b..44a3fd3 100644
--- a/dp/wifi3.0/dp_rx_mon.h
+++ b/dp/wifi3.0/dp_rx_mon.h
@@ -40,6 +40,22 @@
 QDF_STATUS dp_rx_pdev_mon_status_detach(struct dp_pdev *pdev, int mac_id);
 
 /**
+ * dp_reset_monitor_mode() - Disable monitor mode
+ * @pdev_handle: Datapath PDEV handle
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS dp_reset_monitor_mode(struct cdp_pdev *pdev_handle);
+
+/**
+ * dp_pdev_configure_monitor_rings() - configure monitor rings
+ * @vdev_handle: Datapath VDEV handle
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS dp_pdev_configure_monitor_rings(struct dp_pdev *pdev);
+
+/**
  * dp_mon_link_free() - free monitor link desc pool
  * @pdev: core txrx pdev context
  *
diff --git a/dp/wifi3.0/dp_rx_mon_status.c b/dp/wifi3.0/dp_rx_mon_status.c
index 2e871da..72a5f7e 100644
--- a/dp/wifi3.0/dp_rx_mon_status.c
+++ b/dp/wifi3.0/dp_rx_mon_status.c
@@ -32,6 +32,26 @@
 #include "dp_ratetable.h"
 #endif
 
+#ifdef WLAN_RX_PKT_CAPTURE_ENH
+#include "dp_rx_mon_feature.h"
+#else
+static QDF_STATUS
+dp_rx_handle_enh_capture(struct dp_soc *soc, struct dp_pdev *pdev,
+			 struct hal_rx_ppdu_info *ppdu_info)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static void
+dp_rx_mon_enh_capture_process(struct dp_pdev *pdev, uint32_t tlv_status,
+			      qdf_nbuf_t status_nbuf,
+			      struct hal_rx_ppdu_info *ppdu_info,
+			      bool *nbuf_used,
+			      uint32_t rx_enh_capture_mode)
+{
+}
+#endif
+
 /**
 * dp_rx_populate_cdp_indication_ppdu() - Populate cdp rx indication structure
 * @pdev: pdev ctx
@@ -531,9 +551,13 @@
 	uint8_t *rx_tlv_start;
 	uint32_t tlv_status = HAL_TLV_STATUS_BUF_DONE;
 	QDF_STATUS m_copy_status = QDF_STATUS_SUCCESS;
+	QDF_STATUS enh_log_status = QDF_STATUS_SUCCESS;
 	struct cdp_pdev_mon_stats *rx_mon_stats;
 	int smart_mesh_status;
 	enum WDI_EVENT pktlog_mode = WDI_NO_VAL;
+	bool nbuf_used;
+	uint32_t rx_enh_capture_mode;
+
 
 	ppdu_info = &pdev->ppdu_info;
 	rx_mon_stats = &pdev->rx_mon_stats;
@@ -541,16 +565,19 @@
 	if (pdev->mon_ppdu_status != DP_PPDU_STATUS_START)
 		return;
 
+	rx_enh_capture_mode = pdev->rx_enh_capture_mode;
+
 	while (!qdf_nbuf_is_queue_empty(&pdev->rx_status_q)) {
 
 		status_nbuf = qdf_nbuf_queue_remove(&pdev->rx_status_q);
 
 		rx_tlv = qdf_nbuf_data(status_nbuf);
 		rx_tlv_start = rx_tlv;
+		nbuf_used = false;
 
 		if ((pdev->monitor_vdev) || (pdev->enhanced_stats_en) ||
-				pdev->mcopy_mode) {
-
+		    pdev->mcopy_mode ||
+		    (rx_enh_capture_mode != CDP_RX_ENH_CAPTURE_DISABLED)) {
 			do {
 				tlv_status = hal_rx_status_get_tlv_info(rx_tlv,
 						ppdu_info, pdev->soc->hal_soc);
@@ -558,12 +585,18 @@
 				dp_rx_mon_update_dbg_ppdu_stats(ppdu_info,
 								rx_mon_stats);
 
+				dp_rx_mon_enh_capture_process(pdev, tlv_status,
+					status_nbuf, ppdu_info,
+					&nbuf_used, rx_enh_capture_mode);
+
 				rx_tlv = hal_rx_status_get_next_tlv(rx_tlv);
 
 				if ((rx_tlv - rx_tlv_start) >= RX_BUFFER_SIZE)
 					break;
 
-			} while (tlv_status == HAL_TLV_STATUS_PPDU_NOT_DONE);
+			} while ((tlv_status == HAL_TLV_STATUS_PPDU_NOT_DONE) ||
+				 (tlv_status == HAL_TLV_STATUS_HEADER) ||
+				 (tlv_status == HAL_TLV_STATUS_MPDU_END));
 		}
 		if (pdev->dp_peer_based_pktlog) {
 			dp_rx_process_peer_based_pktlog(soc, ppdu_info,
@@ -593,6 +626,14 @@
 						pdev, ppdu_info, status_nbuf);
 			if (m_copy_status == QDF_STATUS_SUCCESS)
 				qdf_nbuf_free(status_nbuf);
+		} else if (rx_enh_capture_mode != CDP_RX_ENH_CAPTURE_DISABLED) {
+			if (!nbuf_used)
+				qdf_nbuf_free(status_nbuf);
+
+			if (tlv_status == HAL_TLV_STATUS_PPDU_DONE)
+				enh_log_status =
+				dp_rx_handle_enh_capture(soc,
+							 pdev, ppdu_info);
 		} else {
 			qdf_nbuf_free(status_nbuf);
 		}
@@ -1022,6 +1063,7 @@
 	union dp_rx_desc_list_elem_t *tail = NULL;
 	struct dp_srng *mon_status_ring;
 	uint32_t num_entries;
+	uint32_t i;
 	struct rx_desc_pool *rx_desc_pool;
 	QDF_STATUS status;
 	int mac_for_pdev = dp_get_mac_id_for_mac(soc, ring_id);
@@ -1065,5 +1107,13 @@
 	dp_rx_mon_init_dbg_ppdu_stats(&pdev->ppdu_info,
 				      &pdev->rx_mon_stats);
 
+	for (i = 0; i < MAX_MU_USERS; i++) {
+		qdf_nbuf_queue_init(&pdev->mpdu_q[i]);
+		pdev->is_mpdu_hdr[i] = true;
+	}
+	qdf_mem_zero(pdev->msdu_list, sizeof(pdev->msdu_list[MAX_MU_USERS]));
+
+	pdev->rx_enh_capture_mode = CDP_RX_ENH_CAPTURE_DISABLED;
+
 	return QDF_STATUS_SUCCESS;
 }
diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h
index 9d2145c..27207ee 100644
--- a/dp/wifi3.0/dp_types.h
+++ b/dp/wifi3.0/dp_types.h
@@ -92,6 +92,7 @@
 #define DP_MAX_DELBA_RETRY 3
 
 #define PCP_TID_MAP_MAX 8
+#define MAX_MU_USERS 37
 
 #ifndef REMOVE_PKT_LOG
 enum rx_pktlog_mode {
@@ -101,6 +102,12 @@
 };
 #endif
 
+struct msdu_list {
+	qdf_nbuf_t head;
+	qdf_nbuf_t tail;
+	uint32 sum_len;
+};
+
 struct dp_soc_cmn;
 struct dp_pdev;
 struct dp_vdev;
@@ -1291,7 +1298,18 @@
 	uint64_t mon_last_linkdesc_paddr;
 	/* to track duplicate buffer indications by HW for a WAR */
 	uint32_t mon_last_buf_cookie;
-
+	/* 128 bytes mpdu header queue per user for ppdu */
+	qdf_nbuf_queue_t mpdu_q[MAX_MU_USERS];
+	/* is this a mpdu header TLV and not msdu header TLV */
+	bool is_mpdu_hdr[MAX_MU_USERS];
+	/* per user 128 bytes msdu header list for MPDU */
+	struct msdu_list msdu_list[MAX_MU_USERS];
+	/* RX enhanced capture mode */
+	uint32_t rx_enh_capture_mode;
+#ifdef WLAN_RX_PKT_CAPTURE_ENH
+	/* RX per MPDU/PPDU information */
+	struct cdp_rx_indication_mpdu mpdu_ind[MAX_MU_USERS];
+#endif
 	/* pool addr for mcast enhance buff */
 	struct {
 		int size;
diff --git a/hal/wifi3.0/hal_api_mon.h b/hal/wifi3.0/hal_api_mon.h
index 9a1c281..34fe236 100644
--- a/hal/wifi3.0/hal_api_mon.h
+++ b/hal/wifi3.0/hal_api_mon.h
@@ -61,11 +61,15 @@
 		HAL_RX_USER_TLV32_USERID_MASK) >> \
 		HAL_RX_USER_TLV32_USERID_LSB)
 
-#define HAL_TLV_STATUS_PPDU_NOT_DONE		0
-#define HAL_TLV_STATUS_PPDU_DONE		1
-#define HAL_TLV_STATUS_BUF_DONE			2
-#define HAL_TLV_STATUS_PPDU_NON_STD_DONE	3
-
+#define HAL_TLV_STATUS_PPDU_NOT_DONE 0
+#define HAL_TLV_STATUS_PPDU_DONE 1
+#define HAL_TLV_STATUS_BUF_DONE 2
+#define HAL_TLV_STATUS_PPDU_NON_STD_DONE 3
+#define HAL_TLV_STATUS_PPDU_START 4
+#define HAL_TLV_STATUS_HEADER 5
+#define HAL_TLV_STATUS_MPDU_END 6
+#define HAL_TLV_STATUS_MSDU_START 7
+#define HAL_TLV_STATUS_MSDU_END 8
 
 #define HAL_MAX_UL_MU_USERS			8
 
@@ -386,10 +390,6 @@
 	HAL_RX_MON_PPDU_END,
 };
 
-struct hal_rx_ppdu_user_info {
-
-};
-
 struct hal_rx_ppdu_common_info {
 	uint32_t ppdu_id;
 	uint32_t ppdu_timestamp;
@@ -418,12 +418,20 @@
 
 struct hal_rx_ppdu_info {
 	struct hal_rx_ppdu_common_info com_info;
-	struct hal_rx_ppdu_user_info user_info[HAL_MAX_UL_MU_USERS];
 	struct mon_rx_status rx_status;
+	struct mon_rx_user_status rx_user_status[HAL_MAX_UL_MU_USERS];
 	struct hal_rx_msdu_payload_info msdu_info;
 	struct hal_rx_nac_info nac_info;
 	/* status ring PPDU start and end state */
 	uint32_t rx_state;
+	/* MU user id for status ring TLV */
+	uint32_t user_id;
+	/* MPDU/MSDU truncated to 128 bytes header start addr in status skb */
+	unsigned char *data;
+	/* MPDU/MSDU truncated to 128 bytes header real length */
+	uint32_t hdr_len;
+	/* MPDU FCS error */
+	bool fcs_err;
 };
 
 static inline uint32_t
diff --git a/hal/wifi3.0/hal_generic_api.h b/hal/wifi3.0/hal_generic_api.h
index c64de89..5aa4cb2 100644
--- a/hal/wifi3.0/hal_generic_api.h
+++ b/hal/wifi3.0/hal_generic_api.h
@@ -263,6 +263,30 @@
 }
 #endif /* CONFIG_MCL && QCA_WIFI_QCA6290_11AX */
 
+#if defined(RX_PPDU_END_USER_STATS_1_OFDMA_INFO_VALID_OFFSET)
+static inline void
+hal_rx_handle_ofdma_info(
+	void *rx_tlv,
+	struct mon_rx_user_status *mon_rx_user_status)
+{
+		mon_rx_user_status->ofdma_info_valid =
+			HAL_RX_GET(rx_tlv, RX_PPDU_END_USER_STATS_1,
+				   OFDMA_INFO_VALID);
+		mon_rx_user_status->dl_ofdma_ru_start_index =
+			HAL_RX_GET(rx_tlv, RX_PPDU_END_USER_STATS_1,
+				   DL_OFDMA_RU_START_INDEX);
+		mon_rx_user_status->dl_ofdma_ru_width =
+			HAL_RX_GET(rx_tlv, RX_PPDU_END_USER_STATS_2,
+				   DL_OFDMA_RU_WIDTH);
+}
+#else
+static inline void
+hal_rx_handle_ofdma_info(void *rx_tlv,
+			 struct mon_rx_user_status *mon_rx_user_status)
+{
+}
+#endif
+
 /**
  * hal_rx_status_get_tlv_info() - process receive info TLV
  * @rx_tlv_hdr: pointer to TLV header
@@ -283,6 +307,7 @@
 	uint16_t he_ltf = 0;
 	void *rx_tlv;
 	bool unhandled = false;
+	struct mon_rx_user_status *mon_rx_user_status;
 	struct hal_rx_ppdu_info *ppdu_info =
 			(struct hal_rx_ppdu_info *)ppduinfo;
 
@@ -291,6 +316,10 @@
 	tlv_len = HAL_RX_GET_USER_TLV32_LEN(rx_tlv_hdr);
 
 	rx_tlv = (uint8_t *)rx_tlv_hdr + HAL_RX_TLV32_HDR_SIZE;
+
+	qdf_trace_hex_dump(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			   rx_tlv, tlv_len);
+
 	switch (tlv_tag) {
 
 	case WIFIRX_PPDU_START_E:
@@ -396,6 +425,17 @@
 			break;
 		}
 
+		mon_rx_user_status = &ppdu_info->rx_user_status[user_id];
+
+		mon_rx_user_status->mcs =
+			HAL_RX_GET(rx_tlv, RX_PPDU_END_USER_STATS_1,
+				   MCS);
+		mon_rx_user_status->nss =
+			HAL_RX_GET(rx_tlv, RX_PPDU_END_USER_STATS_1,
+				   NSS);
+
+		hal_rx_handle_ofdma_info(rx_tlv, mon_rx_user_status);
+
 		ppdu_info->com_info.mpdu_cnt_fcs_ok =
 			HAL_RX_GET(rx_tlv, RX_PPDU_END_USER_STATS_3,
 					MPDU_CNT_FCS_OK);
@@ -1061,8 +1101,8 @@
 	{
 		uint8_t reception_type;
 		uint8_t *rssi_info_tlv = (uint8_t *)rx_tlv +
-			HAL_RX_OFFSET(UNIFIED_PHYRX_RSSI_LEGACY_3,
-			RECEIVE_RSSI_INFO_PRE_RSSI_INFO_DETAILS);
+			HAL_RX_OFFSET(UNIFIED_PHYRX_RSSI_LEGACY_19,
+				RECEIVE_RSSI_INFO_PREAMBLE_RSSI_INFO_DETAILS);
 
 		ppdu_info->rx_status.rssi_comb = HAL_RX_GET(rx_tlv,
 			PHYRX_RSSI_LEGACY_35, RSSI_COMB);
@@ -1087,44 +1127,51 @@
 		}
 		value = HAL_RX_GET(rssi_info_tlv,
 			RECEIVE_RSSI_INFO_0, RSSI_PRI20_CHAIN0);
+		ppdu_info->rx_status.rssi[0] = value;
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
 			"RSSI_PRI20_CHAIN0: %d\n", value);
 
 		value = HAL_RX_GET(rssi_info_tlv,
-			RECEIVE_RSSI_INFO_0, RSSI_EXT20_CHAIN0);
+			RECEIVE_RSSI_INFO_2, RSSI_PRI20_CHAIN1);
+		ppdu_info->rx_status.rssi[1] = value;
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			"RSSI_EXT20_CHAIN0: %d\n", value);
+			"RSSI_PRI20_CHAIN1: %d\n", value);
 
 		value = HAL_RX_GET(rssi_info_tlv,
-			RECEIVE_RSSI_INFO_0, RSSI_EXT40_LOW20_CHAIN0);
+			RECEIVE_RSSI_INFO_4, RSSI_PRI20_CHAIN2);
+		ppdu_info->rx_status.rssi[2] = value;
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			"RSSI_EXT40_LOW20_CHAIN0: %d\n", value);
+			"RSSI_PRI20_CHAIN2: %d\n", value);
 
 		value = HAL_RX_GET(rssi_info_tlv,
-			RECEIVE_RSSI_INFO_0, RSSI_EXT40_HIGH20_CHAIN0);
+			RECEIVE_RSSI_INFO_6, RSSI_PRI20_CHAIN3);
+		ppdu_info->rx_status.rssi[3] = value;
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			"RSSI_EXT40_HIGH20_CHAIN0: %d\n", value);
+			"RSSI_PRI20_CHAIN3: %d\n", value);
 
 		value = HAL_RX_GET(rssi_info_tlv,
-			RECEIVE_RSSI_INFO_1, RSSI_EXT80_LOW20_CHAIN0);
+			RECEIVE_RSSI_INFO_8, RSSI_PRI20_CHAIN4);
+		ppdu_info->rx_status.rssi[4] = value;
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			"RSSI_EXT80_LOW20_CHAIN0: %d\n", value);
+			"RSSI_PRI20_CHAIN4: %d\n", value);
 
 		value = HAL_RX_GET(rssi_info_tlv,
-			RECEIVE_RSSI_INFO_1, RSSI_EXT80_LOW_HIGH20_CHAIN0);
+			RECEIVE_RSSI_INFO_10, RSSI_PRI20_CHAIN5);
+		ppdu_info->rx_status.rssi[5] = value;
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			"RSSI_EXT80_LOW_HIGH20_CHAIN0: %d\n", value);
+			"RSSI_PRI20_CHAIN5: %d\n", value);
 
 		value = HAL_RX_GET(rssi_info_tlv,
-			RECEIVE_RSSI_INFO_1, RSSI_EXT80_HIGH_LOW20_CHAIN0);
+			RECEIVE_RSSI_INFO_12, RSSI_PRI20_CHAIN6);
+		ppdu_info->rx_status.rssi[6] = value;
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			"RSSI_EXT80_HIGH_LOW20_CHAIN0: %d\n", value);
+			"RSSI_PRI20_CHAIN1: %d\n", value);
 
 		value = HAL_RX_GET(rssi_info_tlv,
-				   RECEIVE_RSSI_INFO_1,
-				   RSSI_EXT80_HIGH20_CHAIN0);
+			RECEIVE_RSSI_INFO_14, RSSI_PRI20_CHAIN7);
+		ppdu_info->rx_status.rssi[7] = value;
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-			"RSSI_EXT80_HIGH20_CHAIN0: %d\n", value);
+			"RSSI_PRI20_CHAIN7: %d\n", value);
 		break;
 	}
 	case WIFIPHYRX_OTHER_RECEIVE_INFO_E:
@@ -1134,7 +1181,11 @@
 	case WIFIRX_HEADER_E:
 		ppdu_info->msdu_info.first_msdu_payload = rx_tlv;
 		ppdu_info->msdu_info.payload_len = tlv_len;
-		break;
+		ppdu_info->user_id = user_id;
+		ppdu_info->hdr_len = tlv_len;
+		ppdu_info->data = rx_tlv;
+		ppdu_info->data += 4;
+		return HAL_TLV_STATUS_HEADER;
 	case WIFIRX_MPDU_START_E:
 	{
 		uint8_t *rx_mpdu_start =
@@ -1186,6 +1237,12 @@
 			ppdu_info->rx_status.monitor_direct_used = 1;
 		break;
 	}
+	case WIFIRX_MPDU_END_E:
+		ppdu_info->user_id = user_id;
+		ppdu_info->fcs_err =
+			HAL_RX_GET(rx_tlv, RX_MPDU_END_1,
+				   FCS_ERR);
+		return HAL_TLV_STATUS_MPDU_END;
 	case 0:
 		return HAL_TLV_STATUS_PPDU_DONE;
 
diff --git a/hal/wifi3.0/qca6018/hal_6018.c b/hal/wifi3.0/qca6018/hal_6018.c
index 37a010f..697f2d1 100644
--- a/hal/wifi3.0/qca6018/hal_6018.c
+++ b/hal/wifi3.0/qca6018/hal_6018.c
@@ -48,6 +48,8 @@
 	PHYRX_HE_SIG_B2_OFDMA_0_PHYRX_HE_SIG_B2_OFDMA_INFO_DETAILS_STA_ID_OFFSET
 #define UNIFIED_PHYRX_RSSI_LEGACY_3_RECEIVE_RSSI_INFO_PRE_RSSI_INFO_DETAILS_OFFSET \
 	PHYRX_RSSI_LEGACY_3_PRE_RSSI_INFO_DETAILS_RSSI_PRI20_CHAIN0_OFFSET
+#define UNIFIED_PHYRX_RSSI_LEGACY_19_RECEIVE_RSSI_INFO_PREAMBLE_RSSI_INFO_DETAILS_OFFSET \
+	PHYRX_RSSI_LEGACY_19_PREAMBLE_RSSI_INFO_DETAILS_RSSI_PRI20_CHAIN0_OFFSET
 #define UNIFIED_RX_MPDU_START_0_RX_MPDU_INFO_RX_MPDU_INFO_DETAILS_OFFSET \
 	RX_MPDU_START_0_RX_MPDU_INFO_DETAILS_RXPCU_MPDU_FILTER_IN_CATEGORY_OFFSET
 #define UNIFIED_RX_MSDU_LINK_8_RX_MSDU_DETAILS_MSDU_0_OFFSET \
diff --git a/hal/wifi3.0/qca6290/hal_6290.c b/hal/wifi3.0/qca6290/hal_6290.c
index 709ef2f..928426f 100644
--- a/hal/wifi3.0/qca6290/hal_6290.c
+++ b/hal/wifi3.0/qca6290/hal_6290.c
@@ -54,6 +54,8 @@
 	PHYRX_HE_SIG_B2_OFDMA_0_HE_SIG_B2_OFDMA_INFO_PHYRX_HE_SIG_B2_OFDMA_INFO_DETAILS_OFFSET
 #define UNIFIED_PHYRX_RSSI_LEGACY_3_RECEIVE_RSSI_INFO_PRE_RSSI_INFO_DETAILS_OFFSET \
 	PHYRX_RSSI_LEGACY_3_RECEIVE_RSSI_INFO_PRE_RSSI_INFO_DETAILS_OFFSET
+#define UNIFIED_PHYRX_RSSI_LEGACY_19_RECEIVE_RSSI_INFO_PREAMBLE_RSSI_INFO_DETAILS_OFFSET \
+	PHYRX_RSSI_LEGACY_19_RECEIVE_RSSI_INFO_PREAMBLE_RSSI_INFO_DETAILS_OFFSET
 #define UNIFIED_RX_MPDU_START_0_RX_MPDU_INFO_RX_MPDU_INFO_DETAILS_OFFSET \
 	RX_MPDU_START_0_RX_MPDU_INFO_RX_MPDU_INFO_DETAILS_OFFSET
 #define UNIFIED_RX_MSDU_LINK_8_RX_MSDU_DETAILS_MSDU_0_OFFSET \
diff --git a/hal/wifi3.0/qca6390/hal_6390.c b/hal/wifi3.0/qca6390/hal_6390.c
index 0b7a919..03bd044 100644
--- a/hal/wifi3.0/qca6390/hal_6390.c
+++ b/hal/wifi3.0/qca6390/hal_6390.c
@@ -54,6 +54,8 @@
 	PHYRX_HE_SIG_B2_OFDMA_0_HE_SIG_B2_OFDMA_INFO_PHYRX_HE_SIG_B2_OFDMA_INFO_DETAILS_OFFSET
 #define UNIFIED_PHYRX_RSSI_LEGACY_3_RECEIVE_RSSI_INFO_PRE_RSSI_INFO_DETAILS_OFFSET \
 	PHYRX_RSSI_LEGACY_3_RECEIVE_RSSI_INFO_PRE_RSSI_INFO_DETAILS_OFFSET
+#define UNIFIED_PHYRX_RSSI_LEGACY_19_RECEIVE_RSSI_INFO_PREAMBLE_RSSI_INFO_DETAILS_OFFSET \
+	PHYRX_RSSI_LEGACY_19_RECEIVE_RSSI_INFO_PREAMBLE_RSSI_INFO_DETAILS_OFFSET
 #define UNIFIED_RX_MPDU_START_0_RX_MPDU_INFO_RX_MPDU_INFO_DETAILS_OFFSET \
 	RX_MPDU_START_0_RX_MPDU_INFO_RX_MPDU_INFO_DETAILS_OFFSET
 #define UNIFIED_RX_MSDU_LINK_8_RX_MSDU_DETAILS_MSDU_0_OFFSET \
diff --git a/hal/wifi3.0/qca8074v1/hal_8074v1.c b/hal/wifi3.0/qca8074v1/hal_8074v1.c
index e836751..6162fb4 100644
--- a/hal/wifi3.0/qca8074v1/hal_8074v1.c
+++ b/hal/wifi3.0/qca8074v1/hal_8074v1.c
@@ -48,6 +48,8 @@
 	PHYRX_HE_SIG_B2_OFDMA_0_HE_SIG_B2_OFDMA_INFO_PHYRX_HE_SIG_B2_OFDMA_INFO_DETAILS_OFFSET
 #define UNIFIED_PHYRX_RSSI_LEGACY_3_RECEIVE_RSSI_INFO_PRE_RSSI_INFO_DETAILS_OFFSET \
 	PHYRX_RSSI_LEGACY_3_RECEIVE_RSSI_INFO_PRE_RSSI_INFO_DETAILS_OFFSET
+#define UNIFIED_PHYRX_RSSI_LEGACY_19_RECEIVE_RSSI_INFO_PREAMBLE_RSSI_INFO_DETAILS_OFFSET \
+	PHYRX_RSSI_LEGACY_19_RECEIVE_RSSI_INFO_PREAMBLE_RSSI_INFO_DETAILS_OFFSET
 #define UNIFIED_RX_MPDU_START_0_RX_MPDU_INFO_RX_MPDU_INFO_DETAILS_OFFSET \
 	RX_MPDU_START_0_RX_MPDU_INFO_RX_MPDU_INFO_DETAILS_OFFSET
 #define UNIFIED_RX_MSDU_LINK_8_RX_MSDU_DETAILS_MSDU_0_OFFSET \
diff --git a/hal/wifi3.0/qca8074v2/hal_8074v2.c b/hal/wifi3.0/qca8074v2/hal_8074v2.c
index 536fd05..9ffd177 100644
--- a/hal/wifi3.0/qca8074v2/hal_8074v2.c
+++ b/hal/wifi3.0/qca8074v2/hal_8074v2.c
@@ -48,6 +48,8 @@
 	PHYRX_HE_SIG_B2_OFDMA_0_PHYRX_HE_SIG_B2_OFDMA_INFO_DETAILS_STA_ID_OFFSET
 #define UNIFIED_PHYRX_RSSI_LEGACY_3_RECEIVE_RSSI_INFO_PRE_RSSI_INFO_DETAILS_OFFSET \
 	PHYRX_RSSI_LEGACY_3_PRE_RSSI_INFO_DETAILS_RSSI_PRI20_CHAIN0_OFFSET
+#define UNIFIED_PHYRX_RSSI_LEGACY_19_RECEIVE_RSSI_INFO_PREAMBLE_RSSI_INFO_DETAILS_OFFSET \
+	PHYRX_RSSI_LEGACY_19_PREAMBLE_RSSI_INFO_DETAILS_RSSI_PRI20_CHAIN0_OFFSET
 #define UNIFIED_RX_MPDU_START_0_RX_MPDU_INFO_RX_MPDU_INFO_DETAILS_OFFSET \
 	RX_MPDU_START_0_RX_MPDU_INFO_DETAILS_RXPCU_MPDU_FILTER_IN_CATEGORY_OFFSET
 #define UNIFIED_RX_MSDU_LINK_8_RX_MSDU_DETAILS_MSDU_0_OFFSET \
diff --git a/qdf/inc/qdf_nbuf.h b/qdf/inc/qdf_nbuf.h
index c4f2a5c..893fa4b 100644
--- a/qdf/inc/qdf_nbuf.h
+++ b/qdf/inc/qdf_nbuf.h
@@ -154,6 +154,8 @@
 #define IEEE80211_AMSDU_FLAG    0x02
 #endif
 
+#define MAX_CHAIN 8
+
 /**
  * struct mon_rx_status - This will have monitor mode rx_status extracted from
  * htt_rx_desc used later to update radiotap information.
@@ -191,6 +193,7 @@
  * @beamformed: Is frame beamformed.
  * @he_sig_b_common_RU[4]: HE (11ax) common RU assignment index
  * @rssi_comb: Combined RSSI
+ * @rssi[MAX_CHAIN]: 8 bits RSSI per 20Mhz per chain
  * @duration: 802.11 Duration
  * @frame_control_info_valid: field indicates if fc value is valid
  * @frame_control: frame control field
@@ -266,6 +269,7 @@
 	uint8_t  beamformed;
 	uint8_t  he_sig_b_common_RU[4];
 	int8_t   rssi_comb;
+	uint64_t rssi[MAX_CHAIN];
 	uint8_t  reception_type;
 	uint16_t duration;
 	uint8_t frame_control_info_valid;
@@ -303,6 +307,23 @@
 };
 
 /**
+ * struct mon_rx_status - This will have monitor mode per user rx_status
+ * extracted from hardware TLV.
+ * @mcs: MCS index of Rx frame
+ * @nss: Number of spatial streams
+ * @ofdma_info_valid: OFDMA info below is valid
+ * @dl_ofdma_ru_start_index: OFDMA RU start index
+ * @dl_ofdma_ru_width: OFDMA total RU width
+ */
+struct mon_rx_user_status {
+	uint32_t mcs:4,
+		 nss:3,
+		 ofdma_info_valid:1,
+		 dl_ofdma_ru_start_index:7,
+		 dl_ofdma_ru_width:7;
+};
+
+/**
  * struct qdf_radiotap_vendor_ns - Vendor Namespace header as per
  * Radiotap spec: https://www.radiotap.org/fields/Vendor%20Namespace.html
  * @oui: Vendor OUI
@@ -1707,6 +1728,41 @@
 }
 
 /**
+ * qdf_nbuf_set_data_pointer() - set data pointer
+ * @buf: Network buf instance
+ * @data: data pointer
+ *
+ * Return: none
+ */
+static inline void qdf_nbuf_set_data_pointer(qdf_nbuf_t buf, uint8_t *data)
+{
+	__qdf_nbuf_set_data_pointer(buf, data);
+}
+
+/**
+ * qdf_nbuf_set_len() - set data length
+ * @buf: Network buf instance
+ * @len: data length
+ * Return: none
+ */
+static inline void qdf_nbuf_set_len(qdf_nbuf_t buf, uint32_t len)
+{
+	__qdf_nbuf_set_len(buf, len);
+}
+
+/**
+ * qdf_nbuf_set_tail_pointer() - set data tail pointer
+ * @buf: Network buf instance
+ * @len: length of data
+ *
+ * Return: none
+ */
+static inline void qdf_nbuf_set_tail_pointer(qdf_nbuf_t buf, int len)
+{
+	__qdf_nbuf_set_tail_pointer(buf, len);
+}
+
+/**
  * qdf_nbuf_reset() - reset the buffer data and pointer
  * @buf: Network buf instance
  * @reserve: reserve
@@ -1870,6 +1926,12 @@
 	return __qdf_nbuf_queue_first(head);
 }
 
+static inline qdf_nbuf_t
+qdf_nbuf_queue_last(qdf_nbuf_queue_t *head)
+{
+	return __qdf_nbuf_queue_last(head);
+}
+
 /**
  * qdf_nbuf_get_protocol() - return the protocol value of the skb
  * @skb: Pointer to network buffer
diff --git a/qdf/linux/src/i_qdf_nbuf.h b/qdf/linux/src/i_qdf_nbuf.h
index ff7365e..8c3af1e 100644
--- a/qdf/linux/src/i_qdf_nbuf.h
+++ b/qdf/linux/src/i_qdf_nbuf.h
@@ -147,6 +147,7 @@
  *
  * @rx.ftype: mcast2ucast, TSO, SG, MESH
  * @rx.is_raw_frame: RAW frame
+ * @rx.fcs_err: FCS error
  * @rx.reserved: reserved
  *
  * @tx.dev.priv_cb_w.fctx: ctx to handle special pkts defined by ftype
@@ -259,7 +260,8 @@
 			} trace;
 			uint8_t ftype;
 			uint8_t is_raw_frame:1,
-				reserved:7;
+				fcs_err:1,
+				reserved:6;
 		} rx;
 
 		/* Note: MAX: 40 bytes */
@@ -406,6 +408,10 @@
 	(((struct qdf_nbuf_cb *) \
 	((skb)->cb))->u.rx.flag_is_frag)
 
+#define QDF_NBUF_CB_RX_FCS_ERR(skb) \
+	(((struct qdf_nbuf_cb *) \
+	((skb)->cb))->u.rx.fcs_err)
+
 #define QDF_NBUF_UPDATE_TX_PKT_COUNT(skb, PACKET_STATE) \
 	qdf_nbuf_set_state(skb, PACKET_STATE)
 
@@ -1013,6 +1019,45 @@
 #define __qdf_nbuf_reserve      skb_reserve
 
 /**
+ * __qdf_nbuf_set_data_pointer() - set buffer data pointer
+ * @skb: Pointer to network buffer
+ * @data: data pointer
+ *
+ * Return: none
+ */
+static inline void
+__qdf_nbuf_set_data_pointer(struct sk_buff *skb, uint8_t *data)
+{
+	skb->data = data;
+}
+
+/**
+ * __qdf_nbuf_set_len() - set buffer data length
+ * @skb: Pointer to network buffer
+ * @len: data length
+ *
+ * Return: none
+ */
+static inline void
+__qdf_nbuf_set_len(struct sk_buff *skb, uint32_t len)
+{
+	skb->len = len;
+}
+
+/**
+ * __qdf_nbuf_set_tail_pointer() - set buffer data tail pointer
+ * @skb: Pointer to network buffer
+ * @len: skb data length
+ *
+ * Return: none
+ */
+static inline void
+__qdf_nbuf_set_tail_pointer(struct sk_buff *skb, int len)
+{
+	skb_set_tail_pointer(skb, len);
+}
+
+/**
  * __qdf_nbuf_reset() - reset the buffer data and pointer
  * @buf: Network buf instance
  * @reserve: reserve
@@ -1623,6 +1668,18 @@
 }
 
 /**
+ * __qdf_nbuf_queue_last() - returns the last skb in the queue
+ * @qhead: head of queue
+ *
+ * Return: NULL if the queue is empty
+ */
+static inline struct sk_buff *
+__qdf_nbuf_queue_last(__qdf_nbuf_queue_t *qhead)
+{
+	return qhead->tail;
+}
+
+/**
  * __qdf_nbuf_queue_len() - return the queue length
  * @qhead: Queue head
  *
diff --git a/spectral/Kbuild b/spectral/Kbuild
index df29021..af0f7fd 100644
--- a/spectral/Kbuild
+++ b/spectral/Kbuild
@@ -34,6 +34,7 @@
 INCS += -I$(obj)/$(DEPTH)/ini_cfg/inc/
 INCS += -I$(obj)/$(DEPTH)/component_dev/wmi/inc
 INCS += -I$(obj)/$(DEPTH)/pld/inc
+INCS += -I$(obj)/$(DEPTH)/component_dev/dp/inc
 
 ifeq ($(WLAN_CONV_CRYPTO_SUPPORTED), 1)
 INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/crypto/inc