qcacmn: support enhance TX capture

support TX capture mode to deliver msdu along with meta data.

Change-Id: Ic84416cc4892e37bfb831dada136a4ff6b615a61
diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h
index 7da523d..0b683ef 100644
--- a/dp/inc/cdp_txrx_cmn_struct.h
+++ b/dp/inc/cdp_txrx_cmn_struct.h
@@ -843,6 +843,7 @@
 	CDP_INGRESS_STATS,
 	CDP_OSIF_DROP,
 	CDP_CONFIG_ENH_RX_CAPTURE,
+	CDP_CONFIG_TX_CAPTURE,
 };
 
 /**
@@ -1211,6 +1212,81 @@
 };
 
 /**
+ * struct cdp_tx_indication_mpdu_info - Tx MPDU completion information
+ * @ppdu_id: PPDU id
+ * @duration: user duration in ppdu
+ * @frame_type: frame type MGMT/CTRL/DATA/BAR
+ * @frame_ctrl: frame control field in 802.11 header
+ * @qos_ctrl: QoS control field in 802.11 header
+ * @tid: TID number
+ * @num_msdu: number of msdu in MPDU
+ * @seq_no: Sequence number of first MPDU
+ * @ltf_size: ltf_size
+ * @stbc: stbc
+ * @he_re: he_re (range extension)
+ * @txbf: txbf
+ * @bw: Transmission bandwidth
+ *       <enum 2 transmit_bw_20_MHz>
+ *       <enum 3 transmit_bw_40_MHz>
+ *       <enum 4 transmit_bw_80_MHz>
+ *       <enum 5 transmit_bw_160_MHz>
+ * @nss: NSS 1,2, ...8
+ * @mcs: MCS index
+ * @preamble: preamble
+ * @gi: guard interval 800/400/1600/3200 ns
+ * @channel: frequency
+ * @channel_num: channel number
+ * @ack_rssi: ack rssi
+ * @ldpc: ldpc
+ * @tx_rate: Transmission Rate
+ * @mac_address: peer mac address
+ * @bss_mac_address: bss mac address
+ * @ppdu_start_timestamp: TSF at PPDU start
+ * @ppdu_end_timestamp: TSF at PPDU end
+ * @ba_start_seq: Block Ack sequence number
+ * @ba_bitmap: Block Ack bitmap
+ */
+struct cdp_tx_indication_mpdu_info {
+	uint32_t ppdu_id;
+	uint32_t tx_duration;
+	uint16_t frame_type;
+	uint16_t frame_ctrl;
+	uint16_t qos_ctrl;
+	uint8_t tid;
+	uint32_t num_msdu;
+	uint32_t seq_no;
+	uint32_t ltf_size:2,
+		 he_re:1,
+		 txbf:4,
+		 bw:4,
+		 nss:4,
+		 mcs:4,
+		 preamble:4,
+		 gi:4;
+	uint32_t channel;
+	uint8_t channel_num;
+	uint32_t ack_rssi;
+	uint32_t ldpc;
+	uint32_t tx_rate;
+	uint8_t mac_address[QDF_MAC_ADDR_SIZE];
+	uint8_t bss_mac_address[QDF_MAC_ADDR_SIZE];
+	uint32_t ppdu_start_timestamp;
+	uint32_t ppdu_end_timestamp;
+	uint32_t ba_start_seq;
+	uint32_t ba_bitmap[CDP_BA_256_BIT_MAP_SIZE_DWORDS];
+};
+
+/**
+ * struct cdp_tx_indication_info - Tx capture information
+ * @mpdu_info: Tx MPDU completion information
+ * @mpdu_nbuf: reconstructed mpdu packet
+ */
+struct cdp_tx_indication_info {
+	struct cdp_tx_indication_mpdu_info mpdu_info;
+	qdf_nbuf_t mpdu_nbuf;
+};
+
+/**
  * struct cdp_tx_completion_ppdu - Tx PPDU completion information
  * @completion_status: completion status - OK/Filter/Abort/Timeout
  * @ppdu_id: PPDU Id
@@ -1228,6 +1304,7 @@
  * @ppdu_end_timestamp: TSF at PPDU end
  * @ack_timestamp: TSF at the reception of ACK
  * @user: per-User stats (array of per-user structures)
+ * @mpdu_q: queue of mpdu in a ppdu
  */
 struct cdp_tx_completion_ppdu {
 	uint32_t ppdu_id;
@@ -1247,6 +1324,7 @@
 	uint32_t ppdu_end_timestamp;
 	uint32_t ack_timestamp;
 	struct cdp_tx_completion_ppdu_user user[CDP_MU_MAX_USERS];
+	qdf_nbuf_queue_t mpdu_q;
 };
 
 /**
diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h
index 6b27eaf..44284df 100644
--- a/dp/inc/cdp_txrx_stats_struct.h
+++ b/dp/inc/cdp_txrx_stats_struct.h
@@ -1751,6 +1751,7 @@
 	OL_ATH_PARAM_RX_MON_LITE = 407,
 	/* wifi down indication used in MBSS feature */
 	OL_ATH_PARAM_WIFI_DOWN_IND = 408,
+	OL_ATH_PARAM_TX_CAPTURE = 409,
 };
 
 /* Enumeration of PDEV Configuration parameter */
diff --git a/dp/wifi3.0/dp_htt.c b/dp/wifi3.0/dp_htt.c
index 4e9c654..f0f4301 100644
--- a/dp/wifi3.0/dp_htt.c
+++ b/dp/wifi3.0/dp_htt.c
@@ -19,13 +19,13 @@
 #include <htt.h>
 #include <hal_hw_headers.h>
 #include <hal_api.h>
-#include "dp_htt.h"
 #include "dp_peer.h"
 #include "dp_types.h"
 #include "dp_internal.h"
 #include "dp_rx_mon.h"
 #include "htt_stats.h"
 #include "htt_ppdu_stats.h"
+#include "dp_htt.h"
 #include "qdf_mem.h"   /* qdf_mem_malloc,free */
 #include "cdp_txrx_cmn_struct.h"
 
@@ -53,47 +53,6 @@
 
 #define HTT_MGMT_CTRL_TLV_HDR_RESERVERD_LEN 16
 
-/**
- * Bitmap of HTT PPDU TLV types for Default mode
- */
-#define HTT_PPDU_DEFAULT_TLV_BITMAP \
-	(1 << HTT_PPDU_STATS_COMMON_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_RATE_TLV) | \
-	(1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV)
-
-/**
- * Bitmap of HTT PPDU TLV types for Sniffer mode bitmap 64
- */
-#define HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP_64 \
-	((1 << HTT_PPDU_STATS_COMMON_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_RATE_TLV) | \
-	(1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_64_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_64_TLV))
-
-/**
- * Bitmap of HTT PPDU TLV types for Sniffer mode bitmap 256
- */
-#define HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP_256 \
-	((1 << HTT_PPDU_STATS_COMMON_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_RATE_TLV) | \
-	(1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_256_TLV) | \
-	(1 << HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_256_TLV))
-
-#define HTT_FRAMECTRL_DATATYPE 0x08
-#define HTT_PPDU_DESC_MAX_DEPTH 16
-#define DP_SCAN_PEER_ID 0xFFFF
-
 /*
  * dp_htt_get_ppdu_sniffer_ampdu_tlv_bitmap() - Get ppdu stats tlv
  * bitmap for sniffer mode
@@ -102,8 +61,7 @@
  * Return: expected bitmap value, returns zero if doesn't match with
  * either 64-bit Tx window or 256-bit window tlv bitmap
  */
-
-static inline int
+int
 dp_htt_get_ppdu_sniffer_ampdu_tlv_bitmap(uint32_t bitmap)
 {
 	if (bitmap == (HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP_64))
@@ -114,17 +72,15 @@
 	return 0;
 }
 
+#ifdef FEATURE_PERPKT_INFO
 /*
- * dp_tx_stats_update() - Update per-peer statistics
- * @soc: Datapath soc handle
+ * dp_tx_rate_stats_update() - Update rate per-peer statistics
  * @peer: Datapath peer handle
  * @ppdu: PPDU Descriptor
- * @ack_rssi: RSSI of last ack received
  *
  * Return: None
  */
-#ifdef FEATURE_PERPKT_INFO
-static inline void
+static void
 dp_tx_rate_stats_update(struct dp_peer *peer,
 			struct cdp_tx_completion_ppdu_user *ppdu)
 {
@@ -135,7 +91,6 @@
 	if (!peer || !ppdu)
 		return;
 
-
 	ratekbps = dp_getrateindex(ppdu->gi,
 				   ppdu->mcs,
 				   ppdu->nss,
@@ -166,8 +121,19 @@
 	}
 }
 
-static void dp_tx_stats_update(struct dp_soc *soc, struct dp_peer *peer,
-		struct cdp_tx_completion_ppdu_user *ppdu, uint32_t ack_rssi)
+/*
+ * dp_tx_stats_update() - Update per-peer statistics
+ * @soc: Datapath soc handle
+ * @peer: Datapath peer handle
+ * @ppdu: PPDU Descriptor
+ * @ack_rssi: RSSI of last ack received
+ *
+ * Return: None
+ */
+static void
+dp_tx_stats_update(struct dp_soc *soc, struct dp_peer *peer,
+		   struct cdp_tx_completion_ppdu_user *ppdu,
+		   uint32_t ack_rssi)
 {
 	struct dp_pdev *pdev = peer->vdev->pdev;
 	uint8_t preamble, mcs;
@@ -283,6 +249,18 @@
 }
 #endif
 
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+#include "dp_tx_capture.h"
+#else
+static inline void
+dp_process_ppdu_stats_update_failed_bitmap(struct dp_pdev *pdev,
+					   void *data,
+					   uint32_t ppdu_id,
+					   uint32_t size)
+{
+}
+#endif
+
 /*
  * htt_htc_pkt_alloc() - Allocate HTC packet buffer
  * @htt_soc:	HTT SOC handle
@@ -1848,19 +1826,33 @@
 	ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
 
 	tag_buf += 2;
+	ppdu_info->sched_cmdid =
+		HTT_PPDU_STATS_COMMON_TLV_SCH_CMDID_GET(*tag_buf);
 	ppdu_desc->num_users =
 		HTT_PPDU_STATS_COMMON_TLV_NUM_USERS_GET(*tag_buf);
 	tag_buf++;
 	frame_type = HTT_PPDU_STATS_COMMON_TLV_FRM_TYPE_GET(*tag_buf);
 
-	if ((frame_type == HTT_STATS_FTYPE_TIDQ_DATA_SU) ||
-			(frame_type == HTT_STATS_FTYPE_TIDQ_DATA_MU))
-		ppdu_desc->frame_type = CDP_PPDU_FTYPE_DATA;
-	else if ((frame_type == HTT_STATS_FTYPE_SGEN_MU_BAR) ||
-		 (frame_type == HTT_STATS_FTYPE_SGEN_BAR))
+	switch (frame_type) {
+	case HTT_STATS_FTYPE_TIDQ_DATA_SU:
+	case HTT_STATS_FTYPE_TIDQ_DATA_MU:
+		/*
+		 * for management packet, frame type come as DATA_SU
+		 * need to check frame_ctrl before setting frame_type
+		 */
+		if (HTT_GET_FRAME_CTRL_TYPE(frame_type) <= FRAME_CTRL_TYPE_CTRL)
+			ppdu_desc->frame_type = CDP_PPDU_FTYPE_CTRL;
+		else
+			ppdu_desc->frame_type = CDP_PPDU_FTYPE_DATA;
+	break;
+	case HTT_STATS_FTYPE_SGEN_MU_BAR:
+	case HTT_STATS_FTYPE_SGEN_BAR:
 		ppdu_desc->frame_type = CDP_PPDU_FTYPE_BAR;
-	else
+	break;
+	default:
 		ppdu_desc->frame_type = CDP_PPDU_FTYPE_CTRL;
+	break;
+	}
 
 	tag_buf += 2;
 	ppdu_desc->tx_duration = *tag_buf;
@@ -2067,6 +2059,7 @@
 	struct cdp_tx_completion_ppdu_user *ppdu_user_desc;
 	uint8_t curr_user_index = 0;
 	uint16_t peer_id;
+	uint32_t size = CDP_BA_64_BIT_MAP_SIZE_DWORDS;
 
 	ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
 
@@ -2085,7 +2078,12 @@
 
 	ppdu_user_desc->start_seq = dp_stats_buf->start_seq;
 	qdf_mem_copy(&ppdu_user_desc->enq_bitmap, &dp_stats_buf->enq_bitmap,
-					CDP_BA_64_BIT_MAP_SIZE_DWORDS);
+		     sizeof(uint32_t) * CDP_BA_64_BIT_MAP_SIZE_DWORDS);
+
+	dp_process_ppdu_stats_update_failed_bitmap(pdev,
+						   (void *)ppdu_user_desc,
+						   ppdu_info->ppdu_id,
+						   size);
 }
 
 /*
@@ -2108,6 +2106,7 @@
 	struct cdp_tx_completion_ppdu_user *ppdu_user_desc;
 	uint8_t curr_user_index = 0;
 	uint16_t peer_id;
+	uint32_t size = CDP_BA_256_BIT_MAP_SIZE_DWORDS;
 
 	ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
 
@@ -2126,7 +2125,12 @@
 
 	ppdu_user_desc->start_seq = dp_stats_buf->start_seq;
 	qdf_mem_copy(&ppdu_user_desc->enq_bitmap, &dp_stats_buf->enq_bitmap,
-					CDP_BA_256_BIT_MAP_SIZE_DWORDS);
+		     sizeof(uint32_t) * CDP_BA_256_BIT_MAP_SIZE_DWORDS);
+
+	dp_process_ppdu_stats_update_failed_bitmap(pdev,
+						   (void *)ppdu_user_desc,
+						   ppdu_info->ppdu_id,
+						   size);
 }
 
 /*
@@ -2238,7 +2242,7 @@
 
 	ppdu_user_desc->ba_seq_no = dp_stats_buf->ba_seq_no;
 	qdf_mem_copy(&ppdu_user_desc->ba_bitmap, &dp_stats_buf->ba_bitmap,
-			CDP_BA_64_BIT_MAP_SIZE_DWORDS);
+		     sizeof(uint32_t) * CDP_BA_64_BIT_MAP_SIZE_DWORDS);
 }
 
 /*
@@ -2278,7 +2282,7 @@
 
 	ppdu_user_desc->ba_seq_no = dp_stats_buf->ba_seq_no;
 	qdf_mem_copy(&ppdu_user_desc->ba_bitmap, &dp_stats_buf->ba_bitmap,
-			CDP_BA_256_BIT_MAP_SIZE_DWORDS);
+		     sizeof(uint32_t) * CDP_BA_256_BIT_MAP_SIZE_DWORDS);
 }
 
 /*
@@ -2421,6 +2425,24 @@
 	dp_peer_unref_del_find_by_id(peer);
 }
 
+#ifndef WLAN_TX_PKT_CAPTURE_ENH
+/*
+ * dp_deliver_mgmt_frm: Process
+ * @pdev: DP PDEV handle
+ * @nbuf: buffer containing the htt_ppdu_stats_tx_mgmtctrl_payload_tlv
+ *
+ * return: void
+ */
+static void dp_deliver_mgmt_frm(struct dp_pdev *pdev, qdf_nbuf_t nbuf)
+{
+	if (pdev->tx_sniffer_enable || pdev->mcopy_mode) {
+		dp_wdi_event_handler(WDI_EVENT_TX_MGMT_CTRL, pdev->soc,
+				     nbuf, HTT_INVALID_PEER,
+				     WDI_NO_VAL, pdev->pdev_id);
+	}
+}
+#endif
+
 /*
  * dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv: Process
  * htt_ppdu_stats_tx_mgmtctrl_payload_tlv
@@ -2439,7 +2461,7 @@
 	uint8_t trim_size;
 
 	if ((!pdev->tx_sniffer_enable) && (!pdev->mcopy_mode) &&
-	    (!pdev->bpr_enable))
+	    (!pdev->bpr_enable) && (!pdev->tx_capture_enabled))
 		return QDF_STATUS_SUCCESS;
 
 	trim_size = ((pdev->mgmtctrl_frm_info.mgmt_buf +
@@ -2461,11 +2483,8 @@
 				     tag_buf, HTT_INVALID_PEER,
 				     WDI_NO_VAL, pdev->pdev_id);
 	}
-	if (pdev->tx_sniffer_enable || pdev->mcopy_mode) {
-		dp_wdi_event_handler(WDI_EVENT_TX_MGMT_CTRL, pdev->soc,
-				     tag_buf, HTT_INVALID_PEER,
-				     WDI_NO_VAL, pdev->pdev_id);
-	}
+
+	dp_deliver_mgmt_frm(pdev, tag_buf);
 
 	return QDF_STATUS_E_ALREADY;
 }
@@ -2555,23 +2574,21 @@
 }
 
 /**
- * dp_ppdu_desc_deliver(): Function to deliver Tx PPDU status descriptor
- * to upper layer
+ * dp_ppdu_desc_user_stats_update(): Function to update TX user stats
  * @pdev: DP pdev handle
  * @ppdu_info: per PPDU TLV descriptor
  *
  * return: void
  */
-static
-void dp_ppdu_desc_deliver(struct dp_pdev *pdev,
-			  struct ppdu_info *ppdu_info)
+void
+dp_ppdu_desc_user_stats_update(struct dp_pdev *pdev,
+			       struct ppdu_info *ppdu_info)
 {
 	struct cdp_tx_completion_ppdu *ppdu_desc = NULL;
 	struct dp_peer *peer = NULL;
-	qdf_nbuf_t nbuf;
-	uint16_t i;
 	uint32_t tlv_bitmap_expected;
 	uint32_t tlv_bitmap_default;
+	uint16_t i;
 
 	ppdu_desc = (struct cdp_tx_completion_ppdu *)
 		qdf_nbuf_data(ppdu_info->nbuf);
@@ -2589,7 +2606,6 @@
 
 	tlv_bitmap_default = tlv_bitmap_expected;
 	for (i = 0; i < ppdu_desc->num_users; i++) {
-
 		ppdu_desc->num_mpdu += ppdu_desc->user[i].num_mpdu;
 		ppdu_desc->num_msdu += ppdu_desc->user[i].num_msdu;
 
@@ -2620,14 +2636,37 @@
 		      (ppdu_desc->frame_type == CDP_PPDU_FTYPE_DATA)) {
 
 			dp_tx_stats_update(pdev->soc, peer,
-					&ppdu_desc->user[i],
-					ppdu_desc->ack_rssi);
+					   &ppdu_desc->user[i],
+					   ppdu_desc->ack_rssi);
 		}
 
 		dp_tx_rate_stats_update(peer, &ppdu_desc->user[i]);
 		dp_peer_unref_del_find_by_id(peer);
 		tlv_bitmap_expected = tlv_bitmap_default;
 	}
+}
+
+#ifndef WLAN_TX_PKT_CAPTURE_ENH
+
+/**
+ * dp_ppdu_desc_deliver(): Function to deliver Tx PPDU status descriptor
+ * to upper layer
+ * @pdev: DP pdev handle
+ * @ppdu_info: per PPDU TLV descriptor
+ *
+ * return: void
+ */
+static
+void dp_ppdu_desc_deliver(struct dp_pdev *pdev,
+			  struct ppdu_info *ppdu_info)
+{
+	struct cdp_tx_completion_ppdu *ppdu_desc = NULL;
+	qdf_nbuf_t nbuf;
+
+	ppdu_desc = (struct cdp_tx_completion_ppdu *)
+		qdf_nbuf_data(ppdu_info->nbuf);
+
+	dp_ppdu_desc_user_stats_update(pdev, ppdu_info);
 
 	/*
 	 * Remove from the list
@@ -2665,6 +2704,8 @@
 	return;
 }
 
+#endif
+
 /**
  * dp_get_ppdu_desc(): Function to allocate new PPDU status
  * desc for new ppdu id
@@ -2898,9 +2939,11 @@
 		    QDF_STATUS_SUCCESS)
 			free_buf = false;
 
-		pdev->mgmtctrl_frm_info.mgmt_buf = NULL;
-		pdev->mgmtctrl_frm_info.mgmt_buf_len = 0;
-		pdev->mgmtctrl_frm_info.ppdu_id = 0;
+		if (free_buf) {
+			pdev->mgmtctrl_frm_info.mgmt_buf = NULL;
+			pdev->mgmtctrl_frm_info.mgmt_buf_len = 0;
+			pdev->mgmtctrl_frm_info.ppdu_id = 0;
+		}
 	}
 
 	if (ppdu_info)
diff --git a/dp/wifi3.0/dp_htt.h b/dp/wifi3.0/dp_htt.h
index 87a1492..84e10ab 100644
--- a/dp/wifi3.0/dp_htt.h
+++ b/dp/wifi3.0/dp_htt.h
@@ -24,6 +24,9 @@
 #include <qdf_nbuf.h>
 #include <htc_api.h>
 
+#include "cdp_txrx_cmn_struct.h"
+#include "dp_types.h"
+
 #define HTT_TX_MUTEX_TYPE qdf_spinlock_t
 
 #define HTT_TX_MUTEX_INIT(_mutex)				\
@@ -40,6 +43,22 @@
 
 #define DP_HTT_MAX_SEND_QUEUE_DEPTH 64
 
+#ifndef HTT_MAC_ADDR_LEN
+#define HTT_MAC_ADDR_LEN 6
+#endif
+
+#define HTT_FRAMECTRL_TYPE_MASK 0x0C
+#define HTT_GET_FRAME_CTRL_TYPE(_val)	\
+		(((_val) & HTT_FRAMECTRL_TYPE_MASK) >> 2)
+#define FRAME_CTRL_TYPE_MGMT	0x0
+#define FRAME_CTRL_TYPE_CTRL	0x1
+#define FRAME_CTRL_TYPE_DATA	0x2
+#define FRAME_CTRL_TYPE_RESV	0x3
+
+#define HTT_FRAMECTRL_DATATYPE 0x08
+#define HTT_PPDU_DESC_MAX_DEPTH 16
+#define DP_SCAN_PEER_ID 0xFFFF
+
 #define DP_HTT_HTC_PKT_MISCLIST_SIZE          256
 
 #define HTT_T2H_EXT_STATS_TLV_START_OFFSET    3
@@ -223,4 +242,18 @@
 	uint32_t msg_len;
 };
 
+int
+dp_htt_get_ppdu_sniffer_ampdu_tlv_bitmap(uint32_t bitmap);
+
+/**
+ * dp_ppdu_desc_user_stats_update(): Function to update TX user stats
+ * @pdev: DP pdev handle
+ * @ppdu_info: per PPDU TLV descriptor
+ *
+ * return: void
+ */
+void
+dp_ppdu_desc_user_stats_update(struct dp_pdev *pdev,
+			       struct ppdu_info *ppdu_info);
+
 #endif /* _DP_HTT_H_ */
diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h
index 4a6d98b..3996073 100644
--- a/dp/wifi3.0/dp_internal.h
+++ b/dp/wifi3.0/dp_internal.h
@@ -35,6 +35,64 @@
 /* Macro For NYSM value received in VHT TLV */
 #define VHT_SGI_NYSM 3
 
+/* PPDU STATS CFG */
+#define DP_PPDU_STATS_CFG_ALL 0xFFFF
+
+/* PPDU stats mask sent to FW to enable enhanced stats */
+#define DP_PPDU_STATS_CFG_ENH_STATS 0xE67
+/* PPDU stats mask sent to FW to support debug sniffer feature */
+#define DP_PPDU_STATS_CFG_SNIFFER 0x2FFF
+/* PPDU stats mask sent to FW to support BPR feature*/
+#define DP_PPDU_STATS_CFG_BPR 0x2000
+/* PPDU stats mask sent to FW to support BPR and enhanced stats feature */
+#define DP_PPDU_STATS_CFG_BPR_ENH (DP_PPDU_STATS_CFG_BPR | \
+				   DP_PPDU_STATS_CFG_ENH_STATS)
+/* PPDU stats mask sent to FW to support BPR and pcktlog stats feature */
+#define DP_PPDU_STATS_CFG_BPR_PKTLOG (DP_PPDU_STATS_CFG_BPR | \
+				      DP_PPDU_TXLITE_STATS_BITMASK_CFG)
+
+/**
+ * Bitmap of HTT PPDU TLV types for Default mode
+ */
+#define HTT_PPDU_DEFAULT_TLV_BITMAP \
+	(1 << HTT_PPDU_STATS_COMMON_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_RATE_TLV) | \
+	(1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV)
+
+/**
+ * Bitmap of HTT PPDU TLV types for Sniffer mode bitmap 64
+ */
+#define HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP_64 \
+	((1 << HTT_PPDU_STATS_COMMON_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_RATE_TLV) | \
+	(1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_64_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_64_TLV))
+
+/**
+ * Bitmap of HTT PPDU TLV types for Sniffer mode bitmap 256
+ */
+#define HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP_256 \
+	((1 << HTT_PPDU_STATS_COMMON_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_RATE_TLV) | \
+	(1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_256_TLV) | \
+	(1 << HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_256_TLV))
+
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+extern uint8_t
+dp_cpu_ring_map[DP_NSS_CPU_RING_MAP_MAX][WLAN_CFG_INT_NUM_CONTEXTS];
+#endif
+
 #if DP_PRINT_ENABLE
 #include <stdarg.h>       /* va_list */
 #include <qdf_types.h> /* qdf_vprint */
@@ -676,6 +734,7 @@
 extern void dp_peer_find_hash_remove(struct dp_soc *soc, struct dp_peer *peer);
 extern void dp_peer_find_hash_erase(struct dp_soc *soc);
 extern void dp_peer_rx_init(struct dp_pdev *pdev, struct dp_peer *peer);
+void dp_peer_tx_init(struct dp_pdev *pdev, struct dp_peer *peer);
 extern void dp_peer_cleanup(struct dp_vdev *vdev, struct dp_peer *peer);
 extern void dp_peer_rx_cleanup(struct dp_vdev *vdev, struct dp_peer *peer);
 extern void dp_peer_unref_delete(void *peer_handle);
@@ -1006,4 +1065,57 @@
  */
 void dp_pdev_print_tid_stats(struct dp_pdev *pdev);
 #endif /* CONFIG_WIN */
+
+void dp_soc_set_txrx_ring_map(struct dp_soc *soc);
+
+#ifndef WLAN_TX_PKT_CAPTURE_ENH
+/**
+ * dp_tx_ppdu_stats_attach - Initialize Tx PPDU stats and enhanced capture
+ * @pdev: DP PDEV
+ *
+ * Return: none
+ */
+static inline void dp_tx_ppdu_stats_attach(struct dp_pdev *pdev)
+{
+}
+
+/**
+ * dp_tx_ppdu_stats_detach - Cleanup Tx PPDU stats and enhanced capture
+ * @pdev: DP PDEV
+ *
+ * Return: none
+ */
+static inline void dp_tx_ppdu_stats_detach(struct dp_pdev *pdev)
+{
+}
+
+/**
+ * dp_tx_ppdu_stats_process - Deferred PPDU stats handler
+ * @context: Opaque work context (PDEV)
+ *
+ * Return: none
+ */
+static  inline void dp_tx_ppdu_stats_process(void *context)
+{
+}
+
+/**
+ * dp_tx_add_to_comp_queue() - add completion msdu to queue
+ * @soc: DP Soc handle
+ * @tx_desc: software Tx descriptor
+ * @ts : Tx completion status from HAL/HTT descriptor
+ * @peer: DP peer
+ *
+ * Return: none
+ */
+static inline
+QDF_STATUS dp_tx_add_to_comp_queue(struct dp_soc *soc,
+				   struct dp_tx_desc_s *desc,
+				   struct hal_tx_completion_status *ts,
+				   struct dp_peer *peer)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+#endif
+
 #endif /* #ifndef _DP_INTERNAL_H_ */
diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c
index 9593480..e0a0a74 100644
--- a/dp/wifi3.0/dp_main.c
+++ b/dp/wifi3.0/dp_main.c
@@ -27,7 +27,6 @@
 #include <htt.h>
 #include <wdi_event.h>
 #include <queue.h>
-#include "dp_htt.h"
 #include "dp_types.h"
 #include "dp_internal.h"
 #include "dp_tx.h"
@@ -46,6 +45,8 @@
 #include "dp_peer.h"
 #include "dp_rx_mon.h"
 #include "htt_stats.h"
+#include "htt_ppdu_stats.h"
+#include "dp_htt.h"
 #include "qdf_mem.h"   /* qdf_mem_malloc,free */
 #include "cfg_ucfg_api.h"
 #ifdef QCA_LL_TX_FLOW_CONTROL_V2
@@ -84,6 +85,23 @@
 }
 #endif
 
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+#include "dp_tx_capture.h"
+#else
+/*
+ * dp_config_enh_tx_capture()- API to enable/disable enhanced tx capture
+ * @pdev_handle: DP_PDEV handle
+ * @val: user provided value
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+dp_config_enh_tx_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 *
@@ -136,21 +154,6 @@
 
 #define STR_MAXLEN	64
 
-#define DP_PPDU_STATS_CFG_ALL 0xFFFF
-
-/* PPDU stats mask sent to FW to enable enhanced stats */
-#define DP_PPDU_STATS_CFG_ENH_STATS 0xE67
-/* PPDU stats mask sent to FW to support debug sniffer feature */
-#define DP_PPDU_STATS_CFG_SNIFFER 0x2FFF
-/* PPDU stats mask sent to FW to support BPR feature*/
-#define DP_PPDU_STATS_CFG_BPR 0x2000
-/* PPDU stats mask sent to FW to support BPR and enhanced stats feature */
-#define DP_PPDU_STATS_CFG_BPR_ENH (DP_PPDU_STATS_CFG_BPR | \
-				   DP_PPDU_STATS_CFG_ENH_STATS)
-/* PPDU stats mask sent to FW to support BPR and pcktlog stats feature */
-#define DP_PPDU_STATS_CFG_BPR_PKTLOG (DP_PPDU_STATS_CFG_BPR | \
-				      DP_PPDU_TXLITE_STATS_BITMASK_CFG)
-
 #define RNG_ERR		"SRNG setup failed for"
 
 /* Threshold for peer's cached buf queue beyond which frames are dropped */
@@ -290,27 +293,20 @@
 };
 
 /**
- * dp_cpu_ring_map_type - dp tx cpu ring map
- * @DP_NSS_DEFAULT_MAP: Default mode with no NSS offloaded
- * @DP_NSS_FIRST_RADIO_OFFLOADED_MAP: Only First Radio is offloaded
- * @DP_NSS_SECOND_RADIO_OFFLOADED_MAP: Only second radio is offloaded
- * @DP_NSS_DBDC_OFFLOADED_MAP: Both radios are offloaded
- * @DP_NSS_DBTC_OFFLOADED_MAP: All three radios are offloaded
- * @DP_NSS_CPU_RING_MAP_MAX: Max cpu ring map val
- */
-enum dp_cpu_ring_map_types {
-	DP_NSS_DEFAULT_MAP,
-	DP_NSS_FIRST_RADIO_OFFLOADED_MAP,
-	DP_NSS_SECOND_RADIO_OFFLOADED_MAP,
-	DP_NSS_DBDC_OFFLOADED_MAP,
-	DP_NSS_DBTC_OFFLOADED_MAP,
-	DP_NSS_CPU_RING_MAP_MAX
-};
-
-/**
  * @brief Cpu to tx ring map
  */
 #ifdef CONFIG_WIN
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+uint8_t
+dp_cpu_ring_map[DP_NSS_CPU_RING_MAP_MAX][WLAN_CFG_INT_NUM_CONTEXTS] = {
+	{0x0, 0x1, 0x2, 0x0, 0x0, 0x1, 0x2, 0x0, 0x0, 0x1, 0x2},
+	{0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1},
+	{0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0},
+	{0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2},
+	{0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3},
+	{0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1}
+};
+#else
 static uint8_t
 dp_cpu_ring_map[DP_NSS_CPU_RING_MAP_MAX][WLAN_CFG_INT_NUM_CONTEXTS] = {
 	{0x0, 0x1, 0x2, 0x0, 0x0, 0x1, 0x2, 0x0, 0x0, 0x1, 0x2},
@@ -319,6 +315,7 @@
 	{0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2},
 	{0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3}
 };
+#endif
 #else
 static uint8_t
 dp_cpu_ring_map[DP_NSS_CPU_RING_MAP_MAX][WLAN_CFG_INT_NUM_CONTEXTS] = {
@@ -3484,6 +3481,7 @@
 	qdf_event_create(&pdev->fw_peer_stats_event);
 
 	pdev->num_tx_allowed = wlan_cfg_get_num_tx_desc(soc->wlan_cfg_ctx);
+	dp_tx_ppdu_stats_attach(pdev);
 
 	return (struct cdp_pdev *)pdev;
 
@@ -3769,6 +3767,8 @@
 
 	dp_mon_link_free(pdev);
 
+	dp_tx_ppdu_stats_detach(pdev);
+
 	/* Cleanup per PDEV REO rings if configured */
 	if (wlan_cfg_per_pdev_rx_ring(soc->wlan_cfg_ctx)) {
 		dp_srng_cleanup(soc, &soc->reo_dest_ring[pdev->pdev_id],
@@ -5200,6 +5200,8 @@
 	qdf_atomic_set(&peer->is_default_route_set, 1);
 
 	dp_peer_rx_init(pdev, peer);
+	dp_peer_tx_init(pdev, peer);
+
 	return;
 }
 
@@ -6825,6 +6827,8 @@
 		DP_PRINT_STATS("	Tag[%d] = %llu", index,
 				pdev->stats.ppdu_stats_counter[index]);
 	}
+	DP_PRINT_STATS("tx_ppdu_proc: %llu\n",
+		       pdev->tx_ppdu_proc);
 
 	for (i = 0; i < CDP_WDI_NUM_EVENTS; i++) {
 		if (!pdev->stats.wdi_event[i])
@@ -8100,6 +8104,8 @@
 		break;
 	case CDP_CONFIG_ENH_RX_CAPTURE:
 		return dp_config_enh_rx_capture(pdev_handle, val);
+	case CDP_CONFIG_TX_CAPTURE:
+		return dp_config_enh_tx_capture(pdev_handle, val);
 	default:
 		return QDF_STATUS_E_INVAL;
 	}
@@ -10137,7 +10143,7 @@
  *
  * Return: Void
  */
-static void dp_soc_set_txrx_ring_map(struct dp_soc *soc)
+void dp_soc_set_txrx_ring_map(struct dp_soc *soc)
 {
 	uint32_t i;
 	for (i = 0; i < WLAN_CFG_INT_NUM_CONTEXTS; i++) {
diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c
index 2c636a8..64b85e0 100644
--- a/dp/wifi3.0/dp_peer.c
+++ b/dp/wifi3.0/dp_peer.c
@@ -34,6 +34,10 @@
 #include <cdp_txrx_handle.h>
 #include <wlan_cfg.h>
 
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+#include "dp_tx_capture.h"
+#endif
+
 #ifdef DP_LFR
 static inline void
 dp_set_ssn_valid_flag(struct hal_reo_cmd_params *params,
@@ -2061,6 +2065,62 @@
 #else
 static void dp_peer_setup_remaining_tids(struct dp_peer *peer) {};
 #endif
+
+#ifndef WLAN_TX_PKT_CAPTURE_ENH
+/*
+ * dp_peer_tid_queue_init() – Initialize ppdu stats queue per TID
+ * @peer: Datapath peer
+ *
+ */
+static inline void dp_peer_tid_queue_init(struct dp_peer *peer)
+{
+}
+
+/*
+ * dp_peer_tid_queue_cleanup() – remove ppdu stats queue per TID
+ * @peer: Datapath peer
+ *
+ */
+static inline void dp_peer_tid_queue_cleanup(struct dp_peer *peer)
+{
+}
+
+/*
+ * dp_peer_update_80211_hdr() – dp peer update 80211 hdr
+ * @vdev: Datapath vdev
+ * @peer: Datapath peer
+ *
+ */
+static inline void
+dp_peer_update_80211_hdr(struct dp_vdev *vdev, struct dp_peer *peer)
+{
+}
+#endif
+
+/*
+ * dp_peer_tx_init() – Initialize receive TID state
+ * @pdev: Datapath pdev
+ * @peer: Datapath peer
+ *
+ */
+void dp_peer_tx_init(struct dp_pdev *pdev, struct dp_peer *peer)
+{
+	dp_peer_tid_queue_init(peer);
+	dp_peer_update_80211_hdr(peer->vdev, peer);
+}
+
+/*
+ * dp_peer_tx_cleanup() – Deinitialize receive TID state
+ * @vdev: Datapath vdev
+ * @peer: Datapath peer
+ *
+ */
+static inline void
+dp_peer_tx_cleanup(struct dp_vdev *vdev, struct dp_peer *peer)
+{
+	dp_peer_tid_queue_cleanup(peer);
+}
+
 /*
  * dp_peer_rx_init() – Initialize receive TID state
  * @pdev: Datapath pdev
@@ -2162,6 +2222,8 @@
 	peer->last_disassoc_rcvd = 0;
 	peer->last_deauth_rcvd = 0;
 
+	dp_peer_tx_cleanup(vdev, peer);
+
 	/* cleanup the Rx reorder queues for this peer */
 	dp_peer_rx_cleanup(vdev, peer);
 }
diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c
index 56e534b..46cabe4 100644
--- a/dp/wifi3.0/dp_stats.c
+++ b/dp/wifi3.0/dp_stats.c
@@ -16,9 +16,12 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 #include "qdf_types.h"
-#include "htt_stats.h"
+#include "dp_peer.h"
 #include "dp_types.h"
 #include "dp_internal.h"
+#include "htt_stats.h"
+#include "htt_ppdu_stats.h"
+#include "dp_htt.h"
 
 #define DP_MAX_STRING_LEN 500
 
@@ -80,6 +83,10 @@
 };
 #endif
 
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+#include "dp_tx_capture.h"
+#endif
+
 /*
  * dp_print_stats_string_tlv: display htt_stats_string_tlv
  * @tag_buf: buffer containing the tlv htt_stats_string_tlv
diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c
index ed42092..d1adcbc 100644
--- a/dp/wifi3.0/dp_tx.c
+++ b/dp/wifi3.0/dp_tx.c
@@ -31,6 +31,7 @@
 #include "if_meta_hdr.h"
 #endif
 #include "enet.h"
+#include "dp_internal.h"
 
 #define DP_TX_QUEUE_MASK 0x3
 
@@ -59,6 +60,10 @@
 					HAL_TX_ENCRYPT_TYPE_AES_GCMP_256,
 					HAL_TX_ENCRYPT_TYPE_WAPI_GCM_SM4};
 
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+#include "dp_tx_capture.h"
+#endif
+
 /**
  * dp_tx_get_queue() - Returns Tx queue IDs to be used for this Tx frame
  * @vdev: DP Virtual device handle
@@ -3041,19 +3046,30 @@
 		time_latency = (qdf_ktime_to_ms(qdf_ktime_get()) -
 				desc->timestamp);
 	}
-	if (!(desc->msdu_ext_desc) &&
-	    (dp_get_completion_indication_for_stack(soc, desc->pdev,
-						    peer, ts, desc->nbuf,
-						    time_latency)
-			== QDF_STATUS_SUCCESS)) {
-		qdf_nbuf_unmap(soc->osdev, desc->nbuf,
-			       QDF_DMA_TO_DEVICE);
+	if (!(desc->msdu_ext_desc)) {
+		if (QDF_STATUS_SUCCESS ==
+		    dp_tx_add_to_comp_queue(soc, desc, ts, peer)) {
+			return;
+		}
 
-		dp_send_completion_to_stack(soc, desc->pdev, ts->peer_id,
-					    ts->ppdu_id, desc->nbuf);
-	} else {
-		dp_tx_comp_free_buf(soc, desc);
+		if (QDF_STATUS_SUCCESS ==
+		    dp_get_completion_indication_for_stack(soc,
+							   desc->pdev,
+							   peer, ts,
+							   desc->nbuf,
+							   time_latency)) {
+			qdf_nbuf_unmap(soc->osdev, desc->nbuf,
+				       QDF_DMA_TO_DEVICE);
+			dp_send_completion_to_stack(soc,
+						    desc->pdev,
+						    ts->peer_id,
+						    ts->ppdu_id,
+						    desc->nbuf);
+			return;
+		}
 	}
+
+	dp_tx_comp_free_buf(soc, desc);
 }
 
 /**
diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h
index 1afb049..da292be 100644
--- a/dp/wifi3.0/dp_types.h
+++ b/dp/wifi3.0/dp_types.h
@@ -57,6 +57,10 @@
 #include <pktlog.h>
 #endif
 
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+#include "dp_tx_capture.h"
+#endif
+
 #define REPT_MU_MIMO 1
 #define REPT_MU_OFDMA_MIMO 3
 #define DP_VO_TID 6
@@ -240,6 +244,32 @@
 	dp_nss_cfg_max
 };
 
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+#define DP_CPU_RING_MAP_1 1
+#endif
+
+/**
+ * dp_cpu_ring_map_type - dp tx cpu ring map
+ * @DP_NSS_DEFAULT_MAP: Default mode with no NSS offloaded
+ * @DP_NSS_FIRST_RADIO_OFFLOADED_MAP: Only First Radio is offloaded
+ * @DP_NSS_SECOND_RADIO_OFFLOADED_MAP: Only second radio is offloaded
+ * @DP_NSS_DBDC_OFFLOADED_MAP: Both radios are offloaded
+ * @DP_NSS_DBTC_OFFLOADED_MAP: All three radios are offloaded
+ * @DP_SINGLE_TX_RING_MAP: to avoid out of order all cpu mapped to single ring
+ * @DP_NSS_CPU_RING_MAP_MAX: Max cpu ring map val
+ */
+enum dp_cpu_ring_map_types {
+	DP_NSS_DEFAULT_MAP,
+	DP_NSS_FIRST_RADIO_OFFLOADED_MAP,
+	DP_NSS_SECOND_RADIO_OFFLOADED_MAP,
+	DP_NSS_DBDC_OFFLOADED_MAP,
+	DP_NSS_DBTC_OFFLOADED_MAP,
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+	DP_SINGLE_TX_RING_MAP,
+#endif
+	DP_NSS_CPU_RING_MAP_MAX
+};
+
 /**
  * struct rx_desc_pool
  * @pool_size: number of RX descriptor in the pool
@@ -1113,9 +1143,16 @@
 	TAILQ_ENTRY(dp_neighbour_peer) neighbour_peer_list_elem;
 };
 
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+#define WLAN_TX_PKT_CAPTURE_ENH 1
+#define DP_TX_PPDU_PROC_THRESHOLD 8
+#define DP_TX_PPDU_PROC_TIMEOUT 10
+#endif
+
 /**
  * struct ppdu_info - PPDU Status info descriptor
  * @ppdu_id         - Unique ppduid assigned by firmware for every tx packet
+ * @sched_cmdid     - schedule command id, which will be same in a burst
  * @max_ppdu_id     - wrap around for ppdu id
  * @last_tlv_cnt    - Keep track for missing ppdu tlvs
  * @last_user       - last ppdu processed for user
@@ -1123,9 +1160,11 @@
  * @nbuf            - ppdu descriptor payload
  * @ppdu_desc       - ppdu descriptor
  * @ppdu_info_list_elem - linked list of ppdu tlvs
+ * @ppdu_info_queue_elem - Singly linked list (queue) of ppdu tlvs
  */
 struct ppdu_info {
 	uint32_t ppdu_id;
+	uint32_t sched_cmdid;
 	uint32_t max_ppdu_id;
 	uint16_t tlv_bitmap;
 	uint16_t last_tlv_cnt;
@@ -1133,7 +1172,38 @@
 		 is_ampdu:1;
 	qdf_nbuf_t nbuf;
 	struct cdp_tx_completion_ppdu *ppdu_desc;
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+	union {
+		TAILQ_ENTRY(ppdu_info) ppdu_info_dlist_elem;
+		STAILQ_ENTRY(ppdu_info) ppdu_info_slist_elem;
+	} ulist;
+#define ppdu_info_list_elem ulist.ppdu_info_dlist_elem
+#define ppdu_info_queue_elem ulist.ppdu_info_slist_elem
+#else
 	TAILQ_ENTRY(ppdu_info) ppdu_info_list_elem;
+#endif
+};
+
+/**
+ * struct msdu_completion_info - wbm msdu completion info
+ * @ppdu_id            - Unique ppduid assigned by firmware for every tx packet
+ * @peer_id            - peer_id
+ * @tid                - tid which used during transmit
+ * @first_msdu         - first msdu indication
+ * @last_msdu          - last msdu indication
+ * @msdu_part_of_amsdu - msdu part of amsdu
+ * @transmit_cnt       - retried count
+ * @tsf                - timestamp which it transmitted
+ */
+struct msdu_completion_info {
+	uint32_t ppdu_id;
+	uint16_t peer_id;
+	uint8_t tid;
+	uint8_t first_msdu:1,
+		last_msdu:1,
+		msdu_part_of_amsdu:1;
+	uint8_t transmit_cnt;
+	uint32_t tsf;
 };
 
 #ifdef WLAN_SUPPORT_RX_PROTOCOL_TYPE_TAG
@@ -1150,6 +1220,14 @@
 
 #endif /* WLAN_SUPPORT_RX_PROTOCOL_TYPE_TAG */
 
+#ifndef WLAN_TX_PKT_CAPTURE_ENH
+struct dp_pdev_tx_capture {
+};
+
+struct dp_peer_tx_capture {
+};
+#endif
+
 /* PDEV level structure for data path */
 struct dp_pdev {
 	/**
@@ -1401,6 +1479,7 @@
 	uint32_t ppdu_id;
 	bool first_nbuf;
 	struct {
+		qdf_nbuf_t last_nbuf; /*Ptr to mgmt last buf */
 		uint8_t *mgmt_buf; /* Ptr to mgmt. payload in HTT ppdu stats */
 		uint32_t mgmt_buf_len; /* Len of mgmt. payload in ppdu stats */
 		uint32_t ppdu_id;
@@ -1471,6 +1550,12 @@
 		rx_err_proto_tag_stats[RX_PROTOCOL_TAG_MAX];
 #endif /* WLAN_SUPPORT_RX_TAG_STATISTICS */
 #endif /* WLAN_SUPPORT_RX_PROTOCOL_TYPE_TAG */
+
+	/* tx packet capture enhancement */
+	bool tx_capture_enabled;
+	struct dp_pdev_tx_capture tx_capture;
+	/* stats counter for tx ppdu processed */
+	uint64_t tx_ppdu_proc;
 };
 
 struct dp_peer;
@@ -1702,6 +1787,8 @@
 
 	/* TID structures */
 	struct dp_rx_tid rx_tid[DP_MAX_TIDS];
+	struct dp_peer_tx_capture tx_capture;
+
 
 	/* TBD: No transmit TID state required? */
 
diff --git a/qdf/inc/qdf_types.h b/qdf/inc/qdf_types.h
index fa6b665..151b74b 100644
--- a/qdf/inc/qdf_types.h
+++ b/qdf/inc/qdf_types.h
@@ -363,6 +363,7 @@
  * @QDF_MODULE_ID_SM_ENGINE: SM engine module ID
  * @QDF_MODULE_ID_CMN_MLME: CMN MLME module ID
  * @QDF_MODULE_ID_CFR: CFR module ID
+ * @QDF_MODULE_ID_TX_CAPTURE: Tx capture enhancement feature ID
  * @QDF_MODULE_ID_ANY: anything
  * @QDF_MODULE_ID_MAX: Max place holder module ID
  */
@@ -475,6 +476,7 @@
 	QDF_MODULE_ID_CMN_MLME,
 	QDF_MODULE_ID_BSSCOLOR,
 	QDF_MODULE_ID_CFR,
+	QDF_MODULE_ID_TX_CAPTURE,
 	QDF_MODULE_ID_ANY,
 	QDF_MODULE_ID_MAX,
 } QDF_MODULE_ID;
diff --git a/qdf/linux/src/qdf_trace.c b/qdf/linux/src/qdf_trace.c
index ba1497f..ff18667 100644
--- a/qdf/linux/src/qdf_trace.c
+++ b/qdf/linux/src/qdf_trace.c
@@ -2892,6 +2892,7 @@
 	[QDF_MODULE_ID_CMN_MLME] = {"CMN_MLME"},
 	[QDF_MODULE_ID_BSSCOLOR] = {"BSSCOLOR"},
 	[QDF_MODULE_ID_CFR] = {"CFR"},
+	[QDF_MODULE_ID_TX_CAPTURE] = {"TX_CAPTURE_ENHANCE"},
 	[QDF_MODULE_ID_ANY] = {"ANY"},
 };
 qdf_export_symbol(g_qdf_category_name);
@@ -3347,6 +3348,7 @@
 		[QDF_MODULE_ID_CMN_MLME] = QDF_TRACE_LEVEL_INFO,
 		[QDF_MODULE_ID_BSSCOLOR] = QDF_TRACE_LEVEL_ERROR,
 		[QDF_MODULE_ID_CFR] = QDF_TRACE_LEVEL_ERROR,
+		[QDF_MODULE_ID_TX_CAPTURE] = QDF_TRACE_LEVEL_NONE,
 		[QDF_MODULE_ID_ANY] = QDF_TRACE_LEVEL_INFO,
 	};