Merge "qcacmn: Revert "qcacmn: Add filters to the MKKN filter table""
diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h
index 83132d6..9f32f8c 100644
--- a/dp/inc/cdp_txrx_stats_struct.h
+++ b/dp/inc/cdp_txrx_stats_struct.h
@@ -1996,6 +1996,10 @@
 	OL_ATH_PARAM_GET_PDEV_NUM_PEERS = 435,
 	/* Number of monitor vdevs configured per PDEV */
 	OL_ATH_PARAM_GET_PDEV_NUM_MONITOR_VDEVS = 436,
+#ifdef CE_TASKLET_DEBUG_ENABLE
+	/* Enable/disable CE stats print */
+	OL_ATH_PARAM_ENABLE_CE_LATENCY_STATS = 437,
+#endif
 };
 #endif
 /* Bitmasks for stats that can block */
diff --git a/dp/wifi3.0/dp_ipa.c b/dp/wifi3.0/dp_ipa.c
index 92dcb35..35b80b9 100644
--- a/dp/wifi3.0/dp_ipa.c
+++ b/dp/wifi3.0/dp_ipa.c
@@ -1831,16 +1831,16 @@
 	bool is_nbuf_head = true;
 	uint32_t copy_len = 0;
 
-	dst_nbuf = qdf_nbuf_alloc(soc->osdev, RX_BUFFER_SIZE,
-				  RX_BUFFER_RESERVATION, RX_BUFFER_ALIGNMENT,
-				  FALSE);
+	dst_nbuf = qdf_nbuf_alloc(soc->osdev, RX_DATA_BUFFER_SIZE,
+				  RX_BUFFER_RESERVATION,
+				  RX_DATA_BUFFER_ALIGNMENT, FALSE);
 
 	if (!dst_nbuf) {
 		dp_err_rl("nbuf allocate fail");
 		return NULL;
 	}
 
-	if ((nbuf_len + L3_HEADER_PADDING) > RX_BUFFER_SIZE) {
+	if ((nbuf_len + L3_HEADER_PADDING) > RX_DATA_BUFFER_SIZE) {
 		qdf_nbuf_free(dst_nbuf);
 		dp_err_rl("nbuf is jumbo data");
 		return NULL;
diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c
index 3937a90..6851c97 100644
--- a/dp/wifi3.0/dp_main.c
+++ b/dp/wifi3.0/dp_main.c
@@ -4804,7 +4804,7 @@
 			htt_h2t_rx_ring_cfg(soc->htt_handle, mac_for_pdev,
 					    soc->rx_refill_buf_ring[lmac_id].
 					    hal_srng,
-					    RXDMA_BUF, RX_BUFFER_SIZE,
+					    RXDMA_BUF, RX_DATA_BUFFER_SIZE,
 					    &htt_tlv_filter);
 		}
 	}
@@ -6240,7 +6240,7 @@
 	struct cdp_peer_cookie peer_cookie;
 	enum wlan_op_mode vdev_opmode;
 	uint8_t vdev_mac_addr[QDF_MAC_ADDR_SIZE];
-
+	struct dp_ast_entry *peer_ast_entry = NULL;
 
 	/*
 	 * Hold the lock all the way from checking if the peer ref count
@@ -6272,7 +6272,9 @@
 
 		qdf_spin_lock_bh(&soc->ast_lock);
 		if (peer->self_ast_entry) {
-			dp_peer_del_ast(soc, peer->self_ast_entry);
+			peer_ast_entry = peer->self_ast_entry;
+			dp_peer_unlink_ast_entry(soc, peer_ast_entry);
+			dp_peer_free_ast_entry(soc, peer_ast_entry);
 			peer->self_ast_entry = NULL;
 		}
 		qdf_spin_unlock_bh(&soc->ast_lock);
@@ -6558,13 +6560,14 @@
 		status = htt_h2t_rx_ring_cfg(soc->htt_handle, mac_for_pdev,
 					     soc->rxdma_mon_buf_ring[ring_num]
 					     .hal_srng,
-					     RXDMA_MONITOR_BUF, RX_BUFFER_SIZE,
+					     RXDMA_MONITOR_BUF,
+					     RX_MONITOR_BUFFER_SIZE,
 					     &htt_tlv_filter);
 	else
 		status = htt_h2t_rx_ring_cfg(soc->htt_handle, mac_for_pdev,
 					     pdev->rx_mac_buf_ring[ring_num]
 					     .hal_srng,
-					     RXDMA_BUF, RX_BUFFER_SIZE,
+					     RXDMA_BUF, RX_DATA_BUFFER_SIZE,
 					     &htt_tlv_filter);
 
 	return status;
@@ -6621,7 +6624,7 @@
 		htt_h2t_rx_ring_cfg(soc->htt_handle, mac_for_pdev,
 				    soc->rxdma_mon_status_ring[lmac_id]
 				    .hal_srng,
-				    RXDMA_MONITOR_STATUS, RX_BUFFER_SIZE,
+				    RXDMA_MONITOR_STATUS, RX_DATA_BUFFER_SIZE,
 				    &htt_tlv_filter);
 	}
 
@@ -6835,7 +6838,7 @@
 				    soc->rxdma_mon_status_ring[lmac_id]
 				    .hal_srng,
 				    RXDMA_MONITOR_STATUS,
-				    RX_BUFFER_SIZE, &htt_tlv_filter);
+				    RX_DATA_BUFFER_SIZE, &htt_tlv_filter);
 	}
 
 	return status;
@@ -6969,7 +6972,8 @@
 
 		htt_h2t_rx_ring_cfg(soc->htt_handle, mac_for_pdev,
 			soc->rxdma_mon_status_ring[lmac_id].hal_srng,
-			RXDMA_MONITOR_STATUS, RX_BUFFER_SIZE, &htt_tlv_filter);
+			RXDMA_MONITOR_STATUS, RX_DATA_BUFFER_SIZE,
+			&htt_tlv_filter);
 	}
 
 	htt_tlv_filter.mpdu_start = 1;
@@ -7060,7 +7064,8 @@
 
 		htt_h2t_rx_ring_cfg(soc->htt_handle, mac_for_pdev,
 			soc->rxdma_mon_status_ring[lmac_id].hal_srng,
-			RXDMA_MONITOR_STATUS, RX_BUFFER_SIZE, &htt_tlv_filter);
+			RXDMA_MONITOR_STATUS, RX_DATA_BUFFER_SIZE,
+			&htt_tlv_filter);
 	}
 
 	return QDF_STATUS_SUCCESS;
@@ -7686,7 +7691,8 @@
 
 		htt_h2t_rx_ring_cfg(pdev->soc->htt_handle, mac_for_pdev,
 			pdev->soc->rxdma_mon_status_ring[lmac_id].hal_srng,
-			RXDMA_MONITOR_STATUS, RX_BUFFER_SIZE, &htt_tlv_filter);
+			RXDMA_MONITOR_STATUS, RX_DATA_BUFFER_SIZE,
+			&htt_tlv_filter);
 	}
 }
 
@@ -7749,7 +7755,8 @@
 
 		htt_h2t_rx_ring_cfg(pdev->soc->htt_handle, mac_for_pdev,
 			pdev->soc->rxdma_mon_status_ring[lmac_id].hal_srng,
-			RXDMA_MONITOR_STATUS, RX_BUFFER_SIZE, &htt_tlv_filter);
+			RXDMA_MONITOR_STATUS, RX_DATA_BUFFER_SIZE,
+			&htt_tlv_filter);
 	}
 }
 
@@ -11175,7 +11182,7 @@
 				    soc->rxdma_mon_status_ring[mac_id]
 				    .hal_srng,
 				    RXDMA_MONITOR_STATUS,
-				    RX_BUFFER_SIZE,
+				    RX_DATA_BUFFER_SIZE,
 				    &htt_tlv_filter);
 	}
 }
@@ -11313,7 +11320,7 @@
 					soc->rxdma_mon_status_ring[lmac_id]
 					.hal_srng,
 					RXDMA_MONITOR_STATUS,
-					RX_BUFFER_SIZE,
+					RX_DATA_BUFFER_SIZE,
 					&htt_tlv_filter);
 
 				}
@@ -11436,7 +11443,7 @@
 					soc->rxdma_mon_status_ring[lmac_id]
 					.hal_srng,
 					RXDMA_MONITOR_STATUS,
-					RX_BUFFER_SIZE,
+					RX_DATA_BUFFER_SIZE,
 					&htt_tlv_filter);
 				}
 
diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c
index aab8ef1..727b0b3 100644
--- a/dp/wifi3.0/dp_peer.c
+++ b/dp/wifi3.0/dp_peer.c
@@ -677,8 +677,7 @@
 			 * can take care of adding HMWDS ast enty on delete
 			 * confirmation from target
 			 */
-			if ((type == CDP_TXRX_AST_TYPE_WDS_HM) &&
-			    soc->is_peer_map_unmap_v2) {
+			if (type == CDP_TXRX_AST_TYPE_WDS_HM) {
 				struct dp_ast_free_cb_params *param = NULL;
 
 				if (ast_entry->type ==
@@ -836,6 +835,67 @@
 }
 
 /*
+ * dp_peer_free_ast_entry() - Free up the ast entry memory
+ * @soc: SoC handle
+ * @ast_entry: Address search entry
+ *
+ * This API is used to free up the memory associated with
+ * AST entry.
+ *
+ * Return: None
+ */
+void dp_peer_free_ast_entry(struct dp_soc *soc,
+			    struct dp_ast_entry *ast_entry)
+{
+	/*
+	 * NOTE: Ensure that call to this API is done
+	 * after soc->ast_lock is taken
+	 */
+	ast_entry->callback = NULL;
+	ast_entry->cookie = NULL;
+
+	DP_STATS_INC(soc, ast.deleted, 1);
+	dp_peer_ast_hash_remove(soc, ast_entry);
+	dp_peer_ast_cleanup(soc, ast_entry);
+	qdf_mem_free(ast_entry);
+	soc->num_ast_entries--;
+}
+
+/*
+ * dp_peer_unlink_ast_entry() - Free up the ast entry memory
+ * @soc: SoC handle
+ * @ast_entry: Address search entry
+ *
+ * This API is used to remove/unlink AST entry from the peer list
+ * and hash list.
+ *
+ * Return: None
+ */
+void dp_peer_unlink_ast_entry(struct dp_soc *soc,
+			      struct dp_ast_entry *ast_entry)
+{
+	/*
+	 * NOTE: Ensure that call to this API is done
+	 * after soc->ast_lock is taken
+	 */
+	struct dp_peer *peer = ast_entry->peer;
+
+	TAILQ_REMOVE(&peer->ast_entry_list, ast_entry, ase_list_elem);
+
+	if (ast_entry == peer->self_ast_entry)
+		peer->self_ast_entry = NULL;
+
+	/*
+	 * release the reference only if it is mapped
+	 * to ast_table
+	 */
+	if (ast_entry->is_mapped)
+		soc->ast_table[ast_entry->ast_idx] = NULL;
+
+	ast_entry->peer = NULL;
+}
+
+/*
  * dp_peer_del_ast() - Delete and free AST entry
  * @soc: SoC handle
  * @ast_entry: AST entry of the node
@@ -853,45 +913,45 @@
 	if (!ast_entry)
 		return;
 
-	peer =  ast_entry->peer;
+	if (ast_entry->delete_in_progress)
+		return;
 
+	ast_entry->delete_in_progress = true;
+
+	peer = ast_entry->peer;
 	dp_peer_ast_send_wds_del(soc, ast_entry);
 
-	/*
-	 * release the reference only if it is mapped
-	 * to ast_table
-	 */
+	/* Remove SELF and STATIC entries in teardown itself */
+	if (!ast_entry->next_hop)
+		dp_peer_unlink_ast_entry(soc, ast_entry);
+
 	if (ast_entry->is_mapped)
 		soc->ast_table[ast_entry->ast_idx] = NULL;
 
-	/*
-	 * if peer map v2 is enabled we are not freeing ast entry
+	/* if peer map v2 is enabled we are not freeing ast entry
 	 * here and it is supposed to be freed in unmap event (after
 	 * we receive delete confirmation from target)
 	 *
 	 * if peer_id is invalid we did not get the peer map event
 	 * for the peer free ast entry from here only in this case
 	 */
-	if (soc->is_peer_map_unmap_v2) {
 
-		/*
-		 * For HM_SEC and SELF type we do not receive unmap event
-		 * free ast_entry from here it self
-		 */
-		if ((ast_entry->type != CDP_TXRX_AST_TYPE_WDS_HM_SEC) &&
-		    (ast_entry->type != CDP_TXRX_AST_TYPE_SELF))
-			return;
-	}
+	/* For HM_SEC and SELF type we do not receive unmap event
+	 * free ast_entry from here it self
+	 */
+	if ((ast_entry->type != CDP_TXRX_AST_TYPE_WDS_HM_SEC) &&
+	    (ast_entry->type != CDP_TXRX_AST_TYPE_SELF))
+		return;
 
-	/* SELF and STATIC entries are removed in teardown itself */
-	if (ast_entry->next_hop)
-		TAILQ_REMOVE(&peer->ast_entry_list, ast_entry, ase_list_elem);
+	/* for WDS secondary entry ast_entry->next_hop would be set so
+	 * unlinking has to be done explicitly here.
+	 * As this entry is not a mapped entry unmap notification from
+	 * FW wil not come. Hence unlinkling is done right here.
+	 */
+	if (ast_entry->type == CDP_TXRX_AST_TYPE_WDS_HM_SEC)
+		dp_peer_unlink_ast_entry(soc, ast_entry);
 
-	DP_STATS_INC(soc, ast.deleted, 1);
-	dp_peer_ast_hash_remove(soc, ast_entry);
-	dp_peer_ast_cleanup(soc, ast_entry);
-	qdf_mem_free(ast_entry);
-	soc->num_ast_entries--;
+	dp_peer_free_ast_entry(soc, ast_entry);
 }
 
 /*
@@ -1088,9 +1148,6 @@
 	struct dp_peer *peer = ast_entry->peer;
 	struct cdp_soc_t *cdp_soc = &soc->cdp_soc;
 
-	if (ast_entry->delete_in_progress)
-		return;
-
 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_TRACE,
 		  "%s: ast_entry->type: %d pdevid: %u vdev: %u mac_addr: %pM next_hop: %u peer_mac: %pM\n",
 		  __func__, ast_entry->type, peer->vdev->pdev->pdev_id,
@@ -1104,14 +1161,6 @@
 						    ast_entry->type);
 	}
 
-	/* Remove SELF and STATIC entries in teardown itself */
-	if (!ast_entry->next_hop) {
-		TAILQ_REMOVE(&peer->ast_entry_list, ast_entry, ase_list_elem);
-		peer->self_ast_entry = NULL;
-		ast_entry->peer = NULL;
-	}
-
-	ast_entry->delete_in_progress = true;
 }
 
 /**
@@ -1148,19 +1197,13 @@
 		soc->ast_table[ast_entry->ast_idx] = NULL;
 	}
 
-	TAILQ_REMOVE(&peer->ast_entry_list, ast_entry, ase_list_elem);
-	DP_STATS_INC(soc, ast.deleted, 1);
-	dp_peer_ast_hash_remove(soc, ast_entry);
-
 	cb = ast_entry->callback;
 	cookie = ast_entry->cookie;
-	ast_entry->callback = NULL;
-	ast_entry->cookie = NULL;
 
-	if (ast_entry == peer->self_ast_entry)
-		peer->self_ast_entry = NULL;
 
-	soc->num_ast_entries--;
+	dp_peer_unlink_ast_entry(soc, ast_entry);
+	dp_peer_free_ast_entry(soc, ast_entry);
+
 	qdf_spin_unlock_bh(&soc->ast_lock);
 
 	if (cb) {
@@ -1169,7 +1212,6 @@
 		   cookie,
 		   CDP_TXRX_AST_DELETED);
 	}
-	qdf_mem_free(ast_entry);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -1602,7 +1644,7 @@
 
 	/* If V2 Peer map messages are enabled AST entry has to be freed here
 	 */
-	if (soc->is_peer_map_unmap_v2 && is_wds) {
+	if (is_wds) {
 		if (!dp_peer_ast_free_entry_by_mac(soc, peer, mac_addr))
 			return;
 
diff --git a/dp/wifi3.0/dp_peer.h b/dp/wifi3.0/dp_peer.h
index dff74d5..2544110 100644
--- a/dp/wifi3.0/dp_peer.h
+++ b/dp/wifi3.0/dp_peer.h
@@ -148,6 +148,12 @@
 void dp_peer_ast_hash_remove(struct dp_soc *soc,
 			     struct dp_ast_entry *ase);
 
+void dp_peer_free_ast_entry(struct dp_soc *soc,
+			    struct dp_ast_entry *ast_entry);
+
+void dp_peer_unlink_ast_entry(struct dp_soc *soc,
+			      struct dp_ast_entry *ast_entry);
+
 /*
  * dp_peer_find_by_id_exist - check if peer exists for given id
  * @soc: core DP soc context
diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c
index 514bbf0..a1a65d1 100644
--- a/dp/wifi3.0/dp_rx.c
+++ b/dp/wifi3.0/dp_rx.c
@@ -123,6 +123,8 @@
 	void *rxdma_ring_entry;
 	union dp_rx_desc_list_elem_t *next;
 	QDF_STATUS ret;
+	uint16_t buf_size = rx_desc_pool->buf_size;
+	uint8_t buf_alignment = rx_desc_pool->buf_alignment;
 
 	void *rxdma_srng;
 
@@ -190,9 +192,9 @@
 
 	while (count < num_req_buffers) {
 		rx_netbuf = qdf_nbuf_alloc(dp_soc->osdev,
-					RX_BUFFER_SIZE,
+					buf_size,
 					RX_BUFFER_RESERVATION,
-					RX_BUFFER_ALIGNMENT,
+					buf_alignment,
 					FALSE);
 
 		if (qdf_unlikely(!rx_netbuf)) {
@@ -217,7 +219,7 @@
 		 * allocating new nbuf. We can try for 100 times.
 		 * this is a temp WAR till we fix it properly.
 		 */
-		ret = check_x86_paddr(dp_soc, &rx_netbuf, &paddr, dp_pdev);
+		ret = check_x86_paddr(dp_soc, &rx_netbuf, &paddr, rx_desc_pool);
 		if (ret == QDF_STATUS_E_FAILURE) {
 			DP_STATS_INC(dp_pdev, replenish.x86_fail, 1);
 			break;
@@ -256,8 +258,10 @@
 	dp_verbose_debug("replenished buffers %d, rx desc added back to free list %u",
 			 count, num_desc_to_free);
 
-	DP_STATS_INC_PKT(dp_pdev, replenish.pkts, count,
-			 (RX_BUFFER_SIZE * count));
+	/* No need to count the number of bytes received during replenish.
+	 * Therefore set replenish.pkts.bytes as 0.
+	 */
+	DP_STATS_INC_PKT(dp_pdev, replenish.pkts, count, 0);
 
 free_descs:
 	DP_STATS_INC(dp_pdev, buf_freelist, num_desc_to_free);
@@ -1014,15 +1018,15 @@
 {
 	bool last_nbuf;
 
-	if (*mpdu_len > (RX_BUFFER_SIZE - RX_PKT_TLVS_LEN)) {
-		qdf_nbuf_set_pktlen(nbuf, RX_BUFFER_SIZE);
+	if (*mpdu_len > (RX_DATA_BUFFER_SIZE - RX_PKT_TLVS_LEN)) {
+		qdf_nbuf_set_pktlen(nbuf, RX_DATA_BUFFER_SIZE);
 		last_nbuf = false;
 	} else {
 		qdf_nbuf_set_pktlen(nbuf, (*mpdu_len + RX_PKT_TLVS_LEN));
 		last_nbuf = true;
 	}
 
-	*mpdu_len -= (RX_BUFFER_SIZE - RX_PKT_TLVS_LEN);
+	*mpdu_len -= (RX_DATA_BUFFER_SIZE - RX_PKT_TLVS_LEN);
 
 	return last_nbuf;
 }
@@ -1248,9 +1252,8 @@
 	struct dp_peer_cached_bufq *bufqi = &peer->bufq_info;
 	int num_buff_elem;
 
-	QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_TXRX, "bufq->curr %d bufq->drops %d",
-			   bufqi->entries, bufqi->dropped);
-
+	dp_debug_rl("bufq->curr %d bufq->drops %d", bufqi->entries,
+		    bufqi->dropped);
 	if (!peer->valid) {
 		bufqi->dropped = dp_rx_drop_nbuf_list(peer->vdev->pdev,
 						      rx_buf_list);
@@ -1307,11 +1310,11 @@
 }
 #endif
 
-static inline void dp_rx_deliver_to_stack(struct dp_soc *soc,
-					  struct dp_vdev *vdev,
-					  struct dp_peer *peer,
-					  qdf_nbuf_t nbuf_head,
-					  qdf_nbuf_t nbuf_tail)
+void dp_rx_deliver_to_stack(struct dp_soc *soc,
+			    struct dp_vdev *vdev,
+			    struct dp_peer *peer,
+			    qdf_nbuf_t nbuf_head,
+			    qdf_nbuf_t nbuf_tail)
 {
 	int num_nbuf = 0;
 
@@ -1331,11 +1334,13 @@
 	 * callback function. if so let us free the nbuf_list.
 	 */
 	if (qdf_unlikely(!vdev->osif_rx)) {
-		if (dp_rx_is_peer_cache_bufq_supported())
+		if (peer && dp_rx_is_peer_cache_bufq_supported()) {
 			dp_rx_enqueue_rx(peer, nbuf_head);
-		else
-			dp_rx_drop_nbuf_list(vdev->pdev, nbuf_head);
-
+		} else {
+			num_nbuf = dp_rx_drop_nbuf_list(vdev->pdev,
+							nbuf_head);
+			DP_STATS_DEC(peer, rx.to_stack.num, num_nbuf);
+		}
 		return;
 	}
 
@@ -1344,7 +1349,6 @@
 		vdev->osif_rsim_rx_decap(vdev->osif_vdev, &nbuf_head,
 				&nbuf_tail, peer->mac_addr.raw);
 	}
-
 	vdev->osif_rx(vdev->osif_vdev, nbuf_head);
 }
 
@@ -1901,8 +1905,8 @@
 				 * reap this MPDU
 				 */
 				if (((msdu_desc_info.msdu_len /
-				     (RX_BUFFER_SIZE - RX_PKT_TLVS_LEN) + 1)) >
-				     num_entries_avail) {
+				     (RX_DATA_BUFFER_SIZE - RX_PKT_TLVS_LEN) +
+				     1)) > num_entries_avail) {
 					DP_STATS_INC(
 						soc,
 						rx.msdu_scatter_wait_break,
@@ -2382,14 +2386,15 @@
 
 static QDF_STATUS
 dp_pdev_nbuf_alloc_and_map(struct dp_soc *dp_soc, qdf_nbuf_t *nbuf,
-			   struct dp_pdev *dp_pdev)
+			   struct dp_pdev *dp_pdev,
+			   struct rx_desc_pool *rx_desc_pool)
 {
 	qdf_dma_addr_t paddr;
 	QDF_STATUS ret = QDF_STATUS_E_FAILURE;
 
-	*nbuf = qdf_nbuf_alloc(dp_soc->osdev, RX_BUFFER_SIZE,
-			      RX_BUFFER_RESERVATION, RX_BUFFER_ALIGNMENT,
-			      FALSE);
+	*nbuf = qdf_nbuf_alloc(dp_soc->osdev, rx_desc_pool->buf_size,
+			       RX_BUFFER_RESERVATION,
+			       rx_desc_pool->buf_alignment, FALSE);
 	if (!(*nbuf)) {
 		dp_err("nbuf alloc failed");
 		DP_STATS_INC(dp_pdev, replenish.nbuf_alloc_fail, 1);
@@ -2407,7 +2412,7 @@
 
 	paddr = qdf_nbuf_get_frag_paddr(*nbuf, 0);
 
-	ret = check_x86_paddr(dp_soc, nbuf, &paddr, dp_pdev);
+	ret = check_x86_paddr(dp_soc, nbuf, &paddr, rx_desc_pool);
 	if (ret == QDF_STATUS_E_FAILURE) {
 		qdf_nbuf_unmap_single(dp_soc->osdev, *nbuf,
 				      QDF_DMA_FROM_DEVICE);
@@ -2495,7 +2500,7 @@
 				break;
 			ret = dp_pdev_nbuf_alloc_and_map(dp_soc,
 							 &rx_nbuf_arr[nr_nbuf],
-							 dp_pdev);
+							 dp_pdev, rx_desc_pool);
 			if (QDF_IS_STATUS_ERROR(ret))
 				break;
 
@@ -2537,8 +2542,11 @@
 		QDF_BUG(0);
 		return QDF_STATUS_E_RESOURCES;
 	}
-	DP_STATS_INC_PKT(dp_pdev, replenish.pkts, nr_nbuf,
-			 RX_BUFFER_SIZE * nr_nbuf_total);
+
+	/* No need to count the number of bytes received during replenish.
+	 * Therefore set replenish.pkts.bytes as 0.
+	 */
+	DP_STATS_INC_PKT(dp_pdev, replenish.pkts, nr_nbuf, 0);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -2588,6 +2596,9 @@
 			      rx_desc_pool);
 
 	rx_desc_pool->owner = DP_WBM2SW_RBM;
+	rx_desc_pool->buf_size = RX_DATA_BUFFER_SIZE;
+	rx_desc_pool->buf_alignment = RX_DATA_BUFFER_ALIGNMENT;
+
 	/* For Rx buffers, WBM release ring is SW RING 3,for all pdev's */
 
 	ret_val = dp_rx_fst_attach(soc, pdev);
@@ -2626,9 +2637,9 @@
 			nbuf_retry_count++) {
 		/* Allocate a new skb */
 		nbuf = qdf_nbuf_alloc(soc->osdev,
-					RX_BUFFER_SIZE,
+					RX_DATA_BUFFER_SIZE,
 					RX_BUFFER_RESERVATION,
-					RX_BUFFER_ALIGNMENT,
+					RX_DATA_BUFFER_ALIGNMENT,
 					FALSE);
 
 		if (!nbuf) {
@@ -2639,7 +2650,7 @@
 
 		buf = qdf_nbuf_data(nbuf);
 
-		memset(buf, 0, RX_BUFFER_SIZE);
+		memset(buf, 0, RX_DATA_BUFFER_SIZE);
 
 		ret = qdf_nbuf_map_single(soc->osdev, nbuf,
 				    QDF_DMA_FROM_DEVICE);
diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h
index 26e8f9f..f101308 100644
--- a/dp/wifi3.0/dp_rx.h
+++ b/dp/wifi3.0/dp_rx.h
@@ -25,13 +25,15 @@
 #include "dp_internal.h"
 
 #ifdef RXDMA_OPTIMIZATION
-#ifdef NO_RX_PKT_HDR_TLV
-#define RX_BUFFER_ALIGNMENT     0
-#else
-#define RX_BUFFER_ALIGNMENT     128
-#endif /* NO_RX_PKT_HDR_TLV */
+#ifndef RX_DATA_BUFFER_ALIGNMENT
+#define RX_DATA_BUFFER_ALIGNMENT        128
+#endif
+#ifndef RX_MONITOR_BUFFER_ALIGNMENT
+#define RX_MONITOR_BUFFER_ALIGNMENT     128
+#endif
 #else /* RXDMA_OPTIMIZATION */
-#define RX_BUFFER_ALIGNMENT     4
+#define RX_DATA_BUFFER_ALIGNMENT        4
+#define RX_MONITOR_BUFFER_ALIGNMENT     4
 #endif /* RXDMA_OPTIMIZATION */
 
 #ifdef QCA_HOST2FW_RXBUF_RING
@@ -613,14 +615,14 @@
 /*for qcn9000 emulation the pcie is complete phy and no address restrictions*/
 #if !defined(BUILD_X86) || defined(QCA_WIFI_QCN9000)
 static inline int check_x86_paddr(struct dp_soc *dp_soc, qdf_nbuf_t *rx_netbuf,
-		qdf_dma_addr_t *paddr, struct dp_pdev *pdev)
+		qdf_dma_addr_t *paddr, struct rx_desc_pool *rx_desc_pool)
 {
 	return QDF_STATUS_SUCCESS;
 }
 #else
 #define MAX_RETRY 100
 static inline int check_x86_paddr(struct dp_soc *dp_soc, qdf_nbuf_t *rx_netbuf,
-		qdf_dma_addr_t *paddr, struct dp_pdev *pdev)
+		qdf_dma_addr_t *paddr, struct rx_desc_pool *rx_desc_pool)
 {
 	uint32_t nbuf_retry = 0;
 	int32_t ret;
@@ -651,10 +653,10 @@
 			}
 
 			*rx_netbuf = qdf_nbuf_alloc(dp_soc->osdev,
-							RX_BUFFER_SIZE,
-							RX_BUFFER_RESERVATION,
-							RX_BUFFER_ALIGNMENT,
-							FALSE);
+						    rx_desc_pool->buf_size,
+						    RX_BUFFER_RESERVATION,
+						    rx_desc_pool->buf_alignment,
+						    FALSE);
 
 			if (qdf_unlikely(!(*rx_netbuf)))
 				return QDF_STATUS_E_FAILURE;
@@ -1104,4 +1106,22 @@
 {
 }
 #endif
+
+/**
+ * dp_rx_deliver_to_stack() - deliver pkts to network stack
+ * Caller to hold peer refcount and check for valid peer
+ * @soc: soc
+ * @vdev: vdev
+ * @peer: peer
+ * @nbuf_head: skb list head
+ * @nbuf_tail: skb list tail
+ *
+ * Return: None
+ */
+void dp_rx_deliver_to_stack(struct dp_soc *soc,
+			    struct dp_vdev *vdev,
+			    struct dp_peer *peer,
+			    qdf_nbuf_t nbuf_head,
+			    qdf_nbuf_t nbuf_tail);
+
 #endif /* _DP_RX_H */
diff --git a/dp/wifi3.0/dp_rx_defrag.c b/dp/wifi3.0/dp_rx_defrag.c
index 310f4df..3b69102 100644
--- a/dp/wifi3.0/dp_rx_defrag.c
+++ b/dp/wifi3.0/dp_rx_defrag.c
@@ -424,7 +424,7 @@
 static QDF_STATUS dp_rx_defrag_tkip_decap(qdf_nbuf_t msdu, uint16_t hdrlen)
 {
 	uint8_t *ivp, *orig_hdr;
-	int rx_desc_len = sizeof(struct rx_pkt_tlvs);
+	int rx_desc_len = SIZE_OF_DATA_RX_TLV;
 
 	/* start of 802.11 header info */
 	orig_hdr = (uint8_t *)(qdf_nbuf_data(msdu) + rx_desc_len);
@@ -454,7 +454,7 @@
 static QDF_STATUS dp_rx_defrag_ccmp_demic(qdf_nbuf_t nbuf, uint16_t hdrlen)
 {
 	uint8_t *ivp, *orig_hdr;
-	int rx_desc_len = sizeof(struct rx_pkt_tlvs);
+	int rx_desc_len = SIZE_OF_DATA_RX_TLV;
 
 	/* start of the 802.11 header */
 	orig_hdr = (uint8_t *)(qdf_nbuf_data(nbuf) + rx_desc_len);
@@ -481,7 +481,7 @@
 static QDF_STATUS dp_rx_defrag_ccmp_decap(qdf_nbuf_t nbuf, uint16_t hdrlen)
 {
 	uint8_t *ivp, *origHdr;
-	int rx_desc_len = sizeof(struct rx_pkt_tlvs);
+	int rx_desc_len = SIZE_OF_DATA_RX_TLV;
 
 	origHdr = (uint8_t *) (qdf_nbuf_data(nbuf) + rx_desc_len);
 	ivp = origHdr + hdrlen;
@@ -506,7 +506,7 @@
 static QDF_STATUS dp_rx_defrag_wep_decap(qdf_nbuf_t msdu, uint16_t hdrlen)
 {
 	uint8_t *origHdr;
-	int rx_desc_len = sizeof(struct rx_pkt_tlvs);
+	int rx_desc_len = SIZE_OF_DATA_RX_TLV;
 
 	origHdr = (uint8_t *) (qdf_nbuf_data(msdu) + rx_desc_len);
 	qdf_mem_move(origHdr + dp_f_wep.ic_header, origHdr, hdrlen);
@@ -639,7 +639,7 @@
 	uint32_t l, r;
 	const uint8_t *data;
 	uint32_t space;
-	int rx_desc_len = sizeof(struct rx_pkt_tlvs);
+	int rx_desc_len = SIZE_OF_DATA_RX_TLV;
 
 	dp_rx_defrag_michdr((struct ieee80211_frame *)(qdf_nbuf_data(wbuf)
 		+ rx_desc_len), hdr);
@@ -871,7 +871,7 @@
 {
 	struct ol_if_ops *tops = NULL;
 	struct dp_pdev *pdev = vdev->pdev;
-	int rx_desc_len = sizeof(struct rx_pkt_tlvs);
+	int rx_desc_len = SIZE_OF_DATA_RX_TLV;
 	uint8_t *orig_hdr;
 	struct ieee80211_frame *wh;
 	struct cdp_rx_mic_err_info mic_failure_info;
@@ -1031,6 +1031,7 @@
 	struct dp_rx_reorder_array_elem *rx_reorder_array_elem =
 						peer->rx_tid[tid].array;
 	qdf_nbuf_t nbuf_head;
+	struct rx_desc_pool *rx_desc_pool = NULL;
 
 	nbuf_head = dp_ipa_handle_rx_reo_reinject(soc, head);
 	if (qdf_unlikely(!nbuf_head)) {
@@ -1112,8 +1113,9 @@
 	dp_ipa_handle_rx_buf_smmu_mapping(soc, head, true);
 
 	paddr = qdf_nbuf_get_frag_paddr(head, 0);
+	rx_desc_pool = &soc->rx_desc_buf[pdev->lmac_id];
 
-	ret = check_x86_paddr(soc, &head, &paddr, pdev);
+	ret = check_x86_paddr(soc, &head, &paddr, rx_desc_pool);
 
 	if (ret == QDF_STATUS_E_FAILURE) {
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
diff --git a/dp/wifi3.0/dp_rx_defrag.h b/dp/wifi3.0/dp_rx_defrag.h
index 30d3583..02d2b1d 100644
--- a/dp/wifi3.0/dp_rx_defrag.h
+++ b/dp/wifi3.0/dp_rx_defrag.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -69,7 +69,7 @@
 static inline
 struct ieee80211_frame *dp_rx_frag_get_mac_hdr(uint8_t *rx_desc_info)
 {
-	int rx_desc_len = hal_rx_get_desc_len();
+	int rx_desc_len = SIZE_OF_DATA_RX_TLV;
 	return (struct ieee80211_frame *)(rx_desc_info + rx_desc_len);
 }
 
diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c
index caed5d6..2f2b373 100644
--- a/dp/wifi3.0/dp_rx_err.c
+++ b/dp/wifi3.0/dp_rx_err.c
@@ -513,8 +513,7 @@
 	 */
 
 	rx_tlv_hdr = qdf_nbuf_data(nbuf);
-	bar = (struct ieee80211_frame_bar *)(rx_tlv_hdr +
-					     sizeof(struct rx_pkt_tlvs));
+	bar = (struct ieee80211_frame_bar *)(rx_tlv_hdr + SIZE_OF_DATA_RX_TLV);
 
 	type = bar->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
 	subtype = bar->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
@@ -667,7 +666,7 @@
 }
 
 /**
- * dp_rx_null_q_check_pkt_len_exception() - Check for pktlen validity
+ * dp_rx_check_pkt_len() - Check for pktlen validity
  * @soc: DP SOC context
  * @pkt_len: computed length of the pkt from caller in bytes
  *
@@ -675,9 +674,9 @@
  *
  */
 static inline
-bool dp_rx_null_q_check_pkt_len_exception(struct dp_soc *soc, uint32_t pkt_len)
+bool dp_rx_check_pkt_len(struct dp_soc *soc, uint32_t pkt_len)
 {
-	if (qdf_unlikely(pkt_len > RX_BUFFER_SIZE)) {
+	if (qdf_unlikely(pkt_len > RX_DATA_BUFFER_SIZE)) {
 		DP_STATS_INC_PKT(soc, rx.err.rx_invalid_pkt_len,
 				 1, pkt_len);
 		return true;
@@ -697,7 +696,7 @@
 }
 
 static inline
-bool dp_rx_null_q_check_pkt_len_exception(struct dp_soc *soc, uint32_t pkt_len)
+bool dp_rx_check_pkt_len(struct dp_soc *soc, uint32_t pkt_len)
 {
 	return false;
 }
@@ -758,12 +757,12 @@
 	pkt_len = msdu_len + l2_hdr_offset + RX_PKT_TLVS_LEN;
 
 	if (qdf_likely(!qdf_nbuf_is_frag(nbuf))) {
-		if (dp_rx_null_q_check_pkt_len_exception(soc, pkt_len))
+		if (dp_rx_check_pkt_len(soc, pkt_len))
 			goto drop_nbuf;
 
 		/* Set length in nbuf */
-		qdf_nbuf_set_pktlen(nbuf,
-				    qdf_min(pkt_len, (uint32_t)RX_BUFFER_SIZE));
+		qdf_nbuf_set_pktlen(
+			nbuf, qdf_min(pkt_len, (uint32_t)RX_DATA_BUFFER_SIZE));
 		qdf_assert_always(nbuf->data == rx_tlv_hdr);
 	}
 
@@ -956,6 +955,11 @@
 	msdu_len = hal_rx_msdu_start_msdu_len_get(rx_tlv_hdr);
 	pkt_len = msdu_len + l2_hdr_offset + RX_PKT_TLVS_LEN;
 
+	if (dp_rx_check_pkt_len(soc, pkt_len)) {
+		/* Drop & free packet */
+		qdf_nbuf_free(nbuf);
+		return;
+	}
 	/* Set length in nbuf */
 	qdf_nbuf_set_pktlen(nbuf, pkt_len);
 
@@ -1068,7 +1072,7 @@
 		/* Update the flow tag in SKB based on FSE metadata */
 		dp_rx_update_flow_tag(soc, vdev, nbuf, rx_tlv_hdr, true);
 		DP_STATS_INC(peer, rx.to_stack.num, 1);
-		vdev->osif_rx(vdev->osif_vdev, nbuf);
+		dp_rx_deliver_to_stack(soc, vdev, peer, nbuf, NULL);
 	}
 
 	return;
diff --git a/dp/wifi3.0/dp_rx_mon_dest.c b/dp/wifi3.0/dp_rx_mon_dest.c
index 9a0df29..0b46146 100644
--- a/dp/wifi3.0/dp_rx_mon_dest.c
+++ b/dp/wifi3.0/dp_rx_mon_dest.c
@@ -113,8 +113,8 @@
 static inline void dp_mon_adjust_frag_len(uint32_t *total_len,
 uint32_t *frag_len)
 {
-	if (*total_len >= (RX_BUFFER_SIZE - RX_PKT_TLVS_LEN)) {
-		*frag_len = RX_BUFFER_SIZE - RX_PKT_TLVS_LEN;
+	if (*total_len >= (RX_MONITOR_BUFFER_SIZE - RX_PKT_TLVS_LEN)) {
+		*frag_len = RX_MONITOR_BUFFER_SIZE - RX_PKT_TLVS_LEN;
 		*total_len -= *frag_len;
 	} else {
 		*frag_len = *total_len;
@@ -446,7 +446,7 @@
 				  __func__, total_frag_len, frag_len,
 				  msdu_list.msdu_info[i].msdu_flags);
 
-			rx_pkt_offset = HAL_RX_MON_HW_RX_DESC_SIZE();
+			rx_pkt_offset = SIZE_OF_MONITOR_TLV;
 			/*
 			 * HW structures call this L3 header padding
 			 * -- even though this is actually the offset
@@ -537,7 +537,7 @@
 	uint32_t rx_pkt_offset, l2_hdr_offset;
 
 	data = qdf_nbuf_data(msdu);
-	rx_pkt_offset = HAL_RX_MON_HW_RX_DESC_SIZE();
+	rx_pkt_offset = SIZE_OF_MONITOR_TLV;
 	l2_hdr_offset = hal_rx_msdu_end_l3_hdr_padding_get(soc->hal_soc, data);
 	qdf_nbuf_pull_head(msdu, rx_pkt_offset + l2_hdr_offset);
 }
@@ -1223,6 +1223,8 @@
 		return status;
 
 	rx_desc_pool->owner = HAL_RX_BUF_RBM_SW3_BM;
+	rx_desc_pool->buf_size = RX_MONITOR_BUFFER_SIZE;
+	rx_desc_pool->buf_alignment = RX_MONITOR_BUFFER_ALIGNMENT;
 
 	replenish_size = ((num_entries - 1) < MON_BUF_MIN_ALLOC_ENTRIES) ?
 			  (num_entries - 1) : MON_BUF_MIN_ALLOC_ENTRIES;
diff --git a/dp/wifi3.0/dp_rx_mon_status.c b/dp/wifi3.0/dp_rx_mon_status.c
index 37db9ba..c64794b 100644
--- a/dp/wifi3.0/dp_rx_mon_status.c
+++ b/dp/wifi3.0/dp_rx_mon_status.c
@@ -1420,7 +1420,8 @@
 
 				rx_tlv = hal_rx_status_get_next_tlv(rx_tlv);
 
-				if ((rx_tlv - rx_tlv_start) >= RX_BUFFER_SIZE)
+				if ((rx_tlv - rx_tlv_start) >=
+					RX_DATA_BUFFER_SIZE)
 					break;
 
 			} while ((tlv_status == HAL_TLV_STATUS_PPDU_NOT_DONE) ||
@@ -1599,7 +1600,7 @@
 				hal_srng_src_get_next(hal_soc, mon_status_srng);
 				continue;
 			}
-			qdf_nbuf_set_pktlen(status_nbuf, RX_BUFFER_SIZE);
+			qdf_nbuf_set_pktlen(status_nbuf, RX_DATA_BUFFER_SIZE);
 
 			qdf_nbuf_unmap_single(soc->osdev, status_nbuf,
 				QDF_DMA_FROM_DEVICE);
@@ -1934,6 +1935,9 @@
 	if (!QDF_IS_STATUS_SUCCESS(status))
 		return status;
 
+	rx_desc_pool->buf_size = RX_DATA_BUFFER_SIZE;
+	rx_desc_pool->buf_alignment = RX_DATA_BUFFER_ALIGNMENT;
+
 	dp_debug("Mon RX Status Buffers Replenish ring_id=%d", ring_id);
 
 	status = dp_rx_mon_status_buffers_replenish(soc, ring_id,
diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c
index d369080..c9f62df 100644
--- a/dp/wifi3.0/dp_stats.c
+++ b/dp/wifi3.0/dp_stats.c
@@ -5682,8 +5682,6 @@
 	DP_PRINT_STATS("Replenished:");
 	DP_PRINT_STATS("	Packets = %d",
 		       pdev->stats.replenish.pkts.num);
-	DP_PRINT_STATS("	Bytes = %llu",
-		       pdev->stats.replenish.pkts.bytes);
 	DP_PRINT_STATS("	Buffers Added To Freelist = %d",
 		       pdev->stats.buf_freelist);
 	DP_PRINT_STATS("	Low threshold intr = %d",
diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h
index 950f48f..51ee721 100644
--- a/dp/wifi3.0/dp_types.h
+++ b/dp/wifi3.0/dp_types.h
@@ -292,6 +292,8 @@
  * @freelist: pointer to free RX descriptor link list
  * @lock: Protection for the RX descriptor pool
  * @owner: owner for nbuf
+ * @buf_size: Buffer size
+ * @buf_alignment: Buffer alignment
  */
 struct rx_desc_pool {
 	uint32_t pool_size;
@@ -304,6 +306,8 @@
 	union dp_rx_desc_list_elem_t *freelist;
 	qdf_spinlock_t lock;
 	uint8_t owner;
+	uint16_t buf_size;
+	uint8_t buf_alignment;
 };
 
 /**
diff --git a/hal/wifi3.0/hal_api_mon.h b/hal/wifi3.0/hal_api_mon.h
index cc874f0..5913d9a 100644
--- a/hal/wifi3.0/hal_api_mon.h
+++ b/hal/wifi3.0/hal_api_mon.h
@@ -175,13 +175,6 @@
 };
 
 static inline
-uint32_t HAL_RX_MON_HW_RX_DESC_SIZE(void)
-{
-	/* return the HW_RX_DESC size */
-	return sizeof(struct rx_pkt_tlvs);
-}
-
-static inline
 uint8_t *HAL_RX_MON_DEST_GET_DESC(uint8_t *data)
 {
 	return data;
@@ -191,7 +184,8 @@
 uint32_t HAL_RX_DESC_GET_MPDU_LENGTH_ERR(void *hw_desc_addr)
 {
 	struct rx_attention *rx_attn;
-	struct rx_pkt_tlvs *rx_desc = (struct rx_pkt_tlvs *)hw_desc_addr;
+	struct rx_mon_pkt_tlvs *rx_desc =
+		(struct rx_mon_pkt_tlvs *)hw_desc_addr;
 
 	rx_attn = &rx_desc->attn_tlv.rx_attn;
 
@@ -202,7 +196,8 @@
 uint32_t HAL_RX_DESC_GET_MPDU_FCS_ERR(void *hw_desc_addr)
 {
 	struct rx_attention *rx_attn;
-	struct rx_pkt_tlvs *rx_desc = (struct rx_pkt_tlvs *)hw_desc_addr;
+	struct rx_mon_pkt_tlvs *rx_desc =
+		(struct rx_mon_pkt_tlvs *)hw_desc_addr;
 
 	rx_attn = &rx_desc->attn_tlv.rx_attn;
 
@@ -219,7 +214,8 @@
 static inline
 bool HAL_RX_HW_DESC_MPDU_VALID(void *hw_desc_addr)
 {
-	struct rx_pkt_tlvs *rx_desc = (struct rx_pkt_tlvs *)hw_desc_addr;
+	struct rx_mon_pkt_tlvs *rx_desc =
+		(struct rx_mon_pkt_tlvs *)hw_desc_addr;
 	uint32_t tlv_tag;
 
 	tlv_tag = HAL_RX_GET_USER_TLV32_TYPE(
@@ -543,10 +539,25 @@
 struct hal_rx_ppdu_cfr_info {};
 #endif
 
+struct mon_rx_info {
+	uint8_t  qos_control_info_valid;
+	uint16_t qos_control;
+	uint8_t mac_addr1_valid;
+	uint8_t mac_addr1[QDF_MAC_ADDR_SIZE];
+};
+
+struct mon_rx_user_info {
+	uint16_t qos_control;
+	uint8_t qos_control_info_valid;
+	uint32_t bar_frame:1;
+};
+
 struct hal_rx_ppdu_info {
 	struct hal_rx_ppdu_common_info com_info;
 	struct mon_rx_status rx_status;
 	struct mon_rx_user_status rx_user_status[HAL_MAX_UL_MU_USERS];
+	struct mon_rx_info rx_info;
+	struct mon_rx_user_info rx_user_info[HAL_MAX_UL_MU_USERS];
 	struct hal_rx_msdu_payload_info msdu_info;
 	struct hal_rx_msdu_payload_info fcs_ok_msdu_info;
 	struct hal_rx_nac_info nac_info;
diff --git a/hal/wifi3.0/hal_generic_api.h b/hal/wifi3.0/hal_generic_api.h
index b42be51..c8c9bc2 100644
--- a/hal/wifi3.0/hal_generic_api.h
+++ b/hal/wifi3.0/hal_generic_api.h
@@ -310,6 +310,30 @@
 	hal_rx_populate_byte_count(rx_tlv, ppdu_info, mon_rx_user_status);
 }
 
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+static inline void
+hal_rx_populate_tx_capture_user_info(void *ppduinfo,
+				     uint32_t user_id)
+{
+	struct hal_rx_ppdu_info *ppdu_info;
+	struct mon_rx_info *mon_rx_info;
+	struct mon_rx_user_info *mon_rx_user_info;
+
+	ppdu_info = (struct hal_rx_ppdu_info *)ppduinfo;
+	mon_rx_info = &ppdu_info->rx_info;
+	mon_rx_user_info = &ppdu_info->rx_user_info[user_id];
+	mon_rx_user_info->qos_control_info_valid =
+		mon_rx_info->qos_control_info_valid;
+	mon_rx_user_info->qos_control =  mon_rx_info->qos_control;
+}
+#else
+static inline void
+hal_rx_populate_tx_capture_user_info(void *ppduinfo,
+				     uint32_t user_id)
+{
+}
+#endif
+
 #define HAL_RX_UPDATE_RSSI_PER_CHAIN_BW(chain, word_1, word_2, \
 					ppdu_info, rssi_info_tlv) \
 	{						\
@@ -357,6 +381,50 @@
 	return 0;
 }
 
+#ifdef WLAN_TX_PKT_CAPTURE_ENH
+static inline void
+hal_get_qos_control(void *rx_tlv,
+		    struct hal_rx_ppdu_info *ppdu_info)
+{
+	ppdu_info->rx_info.qos_control_info_valid =
+		HAL_RX_GET(rx_tlv, RX_PPDU_END_USER_STATS_3,
+			   QOS_CONTROL_INFO_VALID);
+
+	if (ppdu_info->rx_info.qos_control_info_valid)
+		ppdu_info->rx_info.qos_control =
+			HAL_RX_GET(rx_tlv,
+				   RX_PPDU_END_USER_STATS_5,
+				   QOS_CONTROL_FIELD);
+}
+
+static inline void
+hal_get_mac_addr1(uint8_t *rx_mpdu_start,
+		  struct hal_rx_ppdu_info *ppdu_info)
+{
+	if (ppdu_info->sw_frame_group_id
+	    == HAL_MPDU_SW_FRAME_GROUP_MGMT_PROBE_REQ) {
+		ppdu_info->rx_info.mac_addr1_valid =
+				HAL_RX_GET_MAC_ADDR1_VALID(rx_mpdu_start);
+
+		*(uint32_t *)&ppdu_info->rx_info.mac_addr1[0] =
+			HAL_RX_GET(rx_mpdu_start,
+				   RX_MPDU_INFO_15,
+				   MAC_ADDR_AD1_31_0);
+	}
+}
+#else
+static inline void
+hal_get_qos_control(void *rx_tlv,
+		    struct hal_rx_ppdu_info *ppdu_info)
+{
+}
+
+static inline void
+hal_get_mac_addr1(uint8_t *rx_mpdu_start,
+		  struct hal_rx_ppdu_info *ppdu_info)
+{
+}
+#endif
 /**
  * hal_rx_status_get_tlv_info() - process receive info TLV
  * @rx_tlv_hdr: pointer to TLV header
@@ -504,6 +572,8 @@
 					HAL_RX_GET(rx_tlv,
 						   RX_PPDU_END_USER_STATS_4,
 						   FRAME_CONTROL_FIELD);
+
+			hal_get_qos_control(rx_tlv, ppdu_info);
 		}
 
 		ppdu_info->rx_status.data_sequence_control_info_valid =
@@ -564,6 +634,10 @@
 
 			hal_rx_populate_mu_user_info(rx_tlv, ppdu_info,
 						     mon_rx_user_status);
+
+			hal_rx_populate_tx_capture_user_info(ppdu_info,
+							     user_id);
+
 		}
 		break;
 	}
@@ -1392,6 +1466,9 @@
 				ppdu_info->nac_info.frame_control;
 		}
 
+		hal_get_mac_addr1(rx_mpdu_start,
+				  ppdu_info);
+
 		ppdu_info->nac_info.mac_addr2_valid =
 				HAL_RX_GET_MAC_ADDR2_VALID(rx_mpdu_start);
 
diff --git a/hal/wifi3.0/hal_rx.h b/hal/wifi3.0/hal_rx.h
index 2f8277b..eab4d0e 100644
--- a/hal/wifi3.0/hal_rx.h
+++ b/hal/wifi3.0/hal_rx.h
@@ -30,14 +30,13 @@
 	HAL_RX_MASk(block, field)) >> \
 	HAL_RX_LSB(block, field))
 
-#ifdef NO_RX_PKT_HDR_TLV
-/* RX_BUFFER_SIZE = 1536 data bytes + 256 RX TLV bytes. We are avoiding
- * 128 bytes of RX_PKT_HEADER_TLV.
- */
-#define RX_BUFFER_SIZE			1792
-#else
-/* RX_BUFFER_SIZE = 1536 data bytes + 384 RX TLV bytes + some spare bytes */
-#define RX_BUFFER_SIZE			2048
+/* BUFFER_SIZE = 1536 data bytes + 384 RX TLV bytes + some spare bytes */
+#ifndef RX_DATA_BUFFER_SIZE
+#define RX_DATA_BUFFER_SIZE     2048
+#endif
+
+#ifndef RX_MONITOR_BUFFER_SIZE
+#define RX_MONITOR_BUFFER_SIZE  2048
 #endif
 
 /* HAL_RX_NON_QOS_TID = NON_QOS_TID which is 16 */
@@ -577,6 +576,9 @@
 
 #define RXDMA_OPTIMIZATION
 
+/* rx_pkt_tlvs structure should be used to process Data buffers, monitor status
+ * buffers, monitor destination buffers and monitor descriptor buffers.
+ */
 #ifdef RXDMA_OPTIMIZATION
 /*
  * The RX_PADDING_BYTES is required so that the TLV's don't
@@ -611,7 +613,33 @@
 };
 #endif /* RXDMA_OPTIMIZATION */
 
-#define RX_PKT_TLVS_LEN		(sizeof(struct rx_pkt_tlvs))
+/* rx_mon_pkt_tlvs structure should be used to process monitor data buffers */
+#ifdef RXDMA_OPTIMIZATION
+struct rx_mon_pkt_tlvs {
+	struct rx_msdu_end_tlv   msdu_end_tlv;	/*  72 bytes */
+	struct rx_attention_tlv  attn_tlv;	/*  16 bytes */
+	struct rx_msdu_start_tlv msdu_start_tlv;/*  40 bytes */
+	uint8_t rx_padding0[RX_PADDING0_BYTES];	/*   4 bytes */
+	struct rx_mpdu_start_tlv mpdu_start_tlv;/*  96 bytes */
+	struct rx_mpdu_end_tlv   mpdu_end_tlv;	/*  12 bytes */
+	uint8_t rx_padding1[RX_PADDING1_BYTES];	/*  16 bytes */
+	struct rx_pkt_hdr_tlv	 pkt_hdr_tlv;	/* 128 bytes */
+};
+#else /* RXDMA_OPTIMIZATION */
+struct rx_mon_pkt_tlvs {
+	struct rx_attention_tlv  attn_tlv;
+	struct rx_mpdu_start_tlv mpdu_start_tlv;
+	struct rx_msdu_start_tlv msdu_start_tlv;
+	struct rx_msdu_end_tlv   msdu_end_tlv;
+	struct rx_mpdu_end_tlv   mpdu_end_tlv;
+	struct rx_pkt_hdr_tlv	 pkt_hdr_tlv;
+};
+#endif
+
+#define SIZE_OF_MONITOR_TLV sizeof(struct rx_mon_pkt_tlvs)
+#define SIZE_OF_DATA_RX_TLV sizeof(struct rx_pkt_tlvs)
+
+#define RX_PKT_TLVS_LEN		SIZE_OF_DATA_RX_TLV
 
 #ifdef NO_RX_PKT_HDR_TLV
 static inline uint8_t
@@ -1137,7 +1165,9 @@
  * @ HAL_MPDU_SW_FRAME_GROUP_UNICAST_DATA: unicast data frame
  * @ HAL_MPDU_SW_FRAME_GROUP_NULL_DATA: NULL data frame
  * @ HAL_MPDU_SW_FRAME_GROUP_MGMT: management frame
+ * @ HAL_MPDU_SW_FRAME_GROUP_MGMT_PROBE_REQ: probe req frame
  * @ HAL_MPDU_SW_FRAME_GROUP_CTRL: control frame
+ * @ HAL_MPDU_SW_FRAME_GROUP_CTRL_BAR: BAR frame
  * @ HAL_MPDU_SW_FRAME_GROUP_UNSUPPORTED: unsupported
  * @ HAL_MPDU_SW_FRAME_GROUP_MAX: max limit
  */
@@ -1147,8 +1177,10 @@
 	HAL_MPDU_SW_FRAME_GROUP_UNICAST_DATA,
 	HAL_MPDU_SW_FRAME_GROUP_NULL_DATA,
 	HAL_MPDU_SW_FRAME_GROUP_MGMT,
+	HAL_MPDU_SW_FRAME_GROUP_MGMT_PROBE_REQ = 8,
 	HAL_MPDU_SW_FRAME_GROUP_MGMT_BEACON = 12,
 	HAL_MPDU_SW_FRAME_GROUP_CTRL = 20,
+	HAL_MPDU_SW_FRAME_GROUP_CTRL_BAR = 28,
 	HAL_MPDU_SW_FRAME_GROUP_UNSUPPORTED = 36,
 	HAL_MPDU_SW_FRAME_GROUP_MAX = 37,
 };
@@ -2822,7 +2854,7 @@
 static inline
 uint16_t hal_rx_get_desc_len(void)
 {
-	return sizeof(struct rx_pkt_tlvs);
+	return SIZE_OF_DATA_RX_TLV;
 }
 
 /*
@@ -3082,10 +3114,13 @@
 static inline
 uint8_t *
 HAL_RX_DESC_GET_80211_HDR(void *hw_desc_addr) {
-	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
-		  "[%s][%d] decap format not raw", __func__, __LINE__);
-	QDF_ASSERT(0);
-	return 0;
+	uint8_t *rx_pkt_hdr;
+	struct rx_mon_pkt_tlvs *rx_desc =
+		(struct rx_mon_pkt_tlvs *)hw_desc_addr;
+
+	rx_pkt_hdr = &rx_desc->pkt_hdr_tlv.rx_pkt_hdr[0];
+
+	return rx_pkt_hdr;
 }
 #else
 static inline
diff --git a/hal/wifi3.0/qca6290/hal_6290_rx.h b/hal/wifi3.0/qca6290/hal_6290_rx.h
index 5ad1241..9417cf7 100644
--- a/hal/wifi3.0/qca6290/hal_6290_rx.h
+++ b/hal/wifi3.0/qca6290/hal_6290_rx.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -255,6 +255,9 @@
 #define HAL_RX_GET_TO_DS_FLAG(rx_mpdu_start)	\
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, TO_DS)
 
+#define HAL_RX_GET_MAC_ADDR1_VALID(rx_mpdu_start) \
+	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, MAC_ADDR_AD1_VALID)
+
 #define HAL_RX_GET_MAC_ADDR2_VALID(rx_mpdu_start) \
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, MAC_ADDR_AD2_VALID)
 
diff --git a/hal/wifi3.0/qca6390/hal_6390_rx.h b/hal/wifi3.0/qca6390/hal_6390_rx.h
index b8f1bd5..5786948 100644
--- a/hal/wifi3.0/qca6390/hal_6390_rx.h
+++ b/hal/wifi3.0/qca6390/hal_6390_rx.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -261,6 +261,9 @@
 #define HAL_RX_GET_TO_DS_FLAG(rx_mpdu_start)	\
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, TO_DS)
 
+#define HAL_RX_GET_MAC_ADDR1_VALID(rx_mpdu_start) \
+	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, MAC_ADDR_AD1_VALID)
+
 #define HAL_RX_GET_MAC_ADDR2_VALID(rx_mpdu_start) \
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, MAC_ADDR_AD2_VALID)
 
diff --git a/hal/wifi3.0/qca6490/hal_6490_rx.h b/hal/wifi3.0/qca6490/hal_6490_rx.h
index 5e565f3..e7ae7e7 100644
--- a/hal/wifi3.0/qca6490/hal_6490_rx.h
+++ b/hal/wifi3.0/qca6490/hal_6490_rx.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -264,6 +264,9 @@
 #define HAL_RX_GET_TO_DS_FLAG(rx_mpdu_start)	\
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_11, TO_DS)
 
+#define HAL_RX_GET_MAC_ADDR1_VALID(rx_mpdu_start) \
+	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_11, MAC_ADDR_AD1_VALID)
+
 #define HAL_RX_GET_MAC_ADDR2_VALID(rx_mpdu_start) \
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_11, MAC_ADDR_AD2_VALID)
 
diff --git a/hal/wifi3.0/qca6750/hal_6750_rx.h b/hal/wifi3.0/qca6750/hal_6750_rx.h
index 4e1be34..cad9366 100644
--- a/hal/wifi3.0/qca6750/hal_6750_rx.h
+++ b/hal/wifi3.0/qca6750/hal_6750_rx.h
@@ -264,6 +264,9 @@
 #define HAL_RX_GET_TO_DS_FLAG(rx_mpdu_start)	\
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_11, TO_DS)
 
+#define HAL_RX_GET_MAC_ADDR1_VALID(rx_mpdu_start) \
+	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_11, MAC_ADDR_AD1_VALID)
+
 #define HAL_RX_GET_MAC_ADDR2_VALID(rx_mpdu_start) \
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_11, MAC_ADDR_AD2_VALID)
 
diff --git a/hal/wifi3.0/qca8074v1/hal_8074v1_rx.h b/hal/wifi3.0/qca8074v1/hal_8074v1_rx.h
index 00941fd..6df3e2d 100644
--- a/hal/wifi3.0/qca8074v1/hal_8074v1_rx.h
+++ b/hal/wifi3.0/qca8074v1/hal_8074v1_rx.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -244,6 +244,9 @@
 #define HAL_RX_GET_TO_DS_FLAG(rx_mpdu_start)	\
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, TO_DS)
 
+#define HAL_RX_GET_MAC_ADDR1_VALID(rx_mpdu_start) \
+	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, MAC_ADDR_AD1_VALID)
+
 #define HAL_RX_GET_MAC_ADDR2_VALID(rx_mpdu_start) \
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, MAC_ADDR_AD2_VALID)
 
diff --git a/hal/wifi3.0/qca8074v2/hal_8074v2_rx.h b/hal/wifi3.0/qca8074v2/hal_8074v2_rx.h
index 502808e..8ceae38 100644
--- a/hal/wifi3.0/qca8074v2/hal_8074v2_rx.h
+++ b/hal/wifi3.0/qca8074v2/hal_8074v2_rx.h
@@ -253,6 +253,9 @@
 #define HAL_RX_GET_TO_DS_FLAG(rx_mpdu_start)	\
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, TO_DS)
 
+#define HAL_RX_GET_MAC_ADDR1_VALID(rx_mpdu_start) \
+	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, MAC_ADDR_AD1_VALID)
+
 #define HAL_RX_GET_MAC_ADDR2_VALID(rx_mpdu_start) \
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_2, MAC_ADDR_AD2_VALID)
 
diff --git a/hal/wifi3.0/qcn9000/hal_9000_rx.h b/hal/wifi3.0/qcn9000/hal_9000_rx.h
index 4d36fe6..4552856 100644
--- a/hal/wifi3.0/qcn9000/hal_9000_rx.h
+++ b/hal/wifi3.0/qcn9000/hal_9000_rx.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -38,6 +38,9 @@
 #define HAL_RX_GET_TO_DS_FLAG(rx_mpdu_start)	\
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_11, TO_DS)
 
+#define HAL_RX_GET_MAC_ADDR1_VALID(rx_mpdu_start) \
+	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_11, MAC_ADDR_AD1_VALID)
+
 #define HAL_RX_GET_MAC_ADDR2_VALID(rx_mpdu_start) \
 	HAL_RX_GET(rx_mpdu_start, RX_MPDU_INFO_11, MAC_ADDR_AD2_VALID)
 
diff --git a/hif/inc/hif.h b/hif/inc/hif.h
index 2e28873..85e0591 100644
--- a/hif/inc/hif.h
+++ b/hif/inc/hif.h
@@ -860,6 +860,10 @@
 		      enum qdf_bus_type bus_type,
 		      enum hif_enable_type type);
 void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type);
+#ifdef CE_TASKLET_DEBUG_ENABLE
+void hif_enable_ce_latency_stats(struct hif_opaque_softc *hif_ctx,
+				 uint8_t value);
+#endif
 void hif_display_stats(struct hif_opaque_softc *hif_ctx);
 void hif_clear_stats(struct hif_opaque_softc *hif_ctx);
 #ifdef FEATURE_RUNTIME_PM
@@ -871,6 +875,7 @@
 int hif_pm_runtime_get(struct hif_opaque_softc *hif_ctx);
 void hif_pm_runtime_get_noresume(struct hif_opaque_softc *hif_ctx);
 int hif_pm_runtime_put(struct hif_opaque_softc *hif_ctx);
+int hif_pm_runtime_put_noidle(struct hif_opaque_softc *hif_ctx);
 void hif_pm_runtime_mark_last_busy(struct hif_opaque_softc *hif_ctx);
 int hif_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name);
 void hif_runtime_lock_deinit(struct hif_opaque_softc *hif_ctx,
@@ -908,6 +913,8 @@
 { return 0; }
 static inline int hif_pm_runtime_put(struct hif_opaque_softc *hif_ctx)
 { return 0; }
+static inline int hif_pm_runtime_put_noidle(struct hif_opaque_softc *hif_ctx)
+{ return 0; }
 static inline void
 hif_pm_runtime_mark_last_busy(struct hif_opaque_softc *hif_ctx) {};
 static inline int hif_runtime_lock_init(qdf_runtime_lock_t *lock,
diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c
index ed3030c..ced2765 100644
--- a/hif/src/ce/ce_tasklet.c
+++ b/hif/src/ce/ce_tasklet.c
@@ -189,33 +189,34 @@
 	struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(hif_ctx);
 	struct ce_stats *stats = &hif_ce_state->stats;
 
+	hif_err("\tCE TASKLET ARRIVAL AND EXECUTION STATS");
 	for (i = 0; i < CE_COUNT_MAX; i++) {
-		qdf_nofl_info("\n\t\tCE Ring %d Tasklet Execution Bucket", i);
+		hif_nofl_err("\n\t\tCE Ring %d Tasklet Execution Bucket", i);
 		for (j = 0; j < CE_BUCKET_MAX; j++) {
-			qdf_nofl_info("\t Bucket %sms :%llu\t last update:%llu",
-				      buck_str[j],
-				      stats->ce_tasklet_exec_bucket[i][j],
-				      stats->ce_tasklet_exec_last_update[i][j]);
+			hif_nofl_err("\t Bucket %sms :%llu\t last update:%llu",
+				     buck_str[j],
+				     stats->ce_tasklet_exec_bucket[i][j],
+				     stats->ce_tasklet_exec_last_update[i][j]);
 		}
 
-		qdf_nofl_info("\n\t\tCE Ring %d Tasklet Scheduled Bucket", i);
+		hif_nofl_err("\n\t\tCE Ring %d Tasklet Scheduled Bucket", i);
 		for (j = 0; j < CE_BUCKET_MAX; j++) {
-			qdf_nofl_info("\t Bucket %sms :%llu\t last update :%lld",
-				      buck_str[j],
-				      stats->ce_tasklet_sched_bucket[i][j],
-				      stats->
+			hif_nofl_err("\t Bucket %sms :%llu\t last update :%lld",
+				     buck_str[j],
+				     stats->ce_tasklet_sched_bucket[i][j],
+				     stats->
 					   ce_tasklet_sched_last_update[i][j]);
 		}
 
-		qdf_nofl_info("\n\t\t CE RING %d Last %d time records",
-			      i, HIF_REQUESTED_EVENTS);
+		hif_nofl_err("\n\t\t CE RING %d Last %d time records",
+			     i, HIF_REQUESTED_EVENTS);
 		index = stats->record_index[i];
 		start_index = stats->record_index[i];
 
 		for (j = 0; j < HIF_REQUESTED_EVENTS; j++) {
-			qdf_nofl_info("\t Execuiton time:  %luus Total Scheduled time: %luus",
-				      stats->tasklet_exec_time_record[i][index],
-				      stats->
+			hif_nofl_err("\t Execuiton time:  %luus Total Scheduled time: %luus",
+				     stats->tasklet_exec_time_record[i][index],
+				     stats->
 					   tasklet_sched_time_record[i][index]);
 			index = (index - 1) % HIF_REQUESTED_EVENTS;
 			if (index == start_index)
@@ -345,7 +346,9 @@
 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ce_state);
 	struct CE_state *CE_state = scn->ce_id_to_state[tasklet_entry->ce_id];
 
-	hif_record_tasklet_exec_entry_ts(scn, tasklet_entry->ce_id);
+	if (scn->ce_latency_stats)
+		hif_record_tasklet_exec_entry_ts(scn, tasklet_entry->ce_id);
+
 	hif_record_ce_desc_event(scn, tasklet_entry->ce_id,
 				 HIF_CE_TASKLET_ENTRY, NULL, NULL, -1, 0);
 
@@ -375,7 +378,10 @@
 
 	hif_record_ce_desc_event(scn, tasklet_entry->ce_id, HIF_CE_TASKLET_EXIT,
 				NULL, NULL, -1, 0);
-	ce_tasklet_update_bucket(hif_ce_state, tasklet_entry->ce_id);
+
+	if (scn->ce_latency_stats)
+		ce_tasklet_update_bucket(hif_ce_state, tasklet_entry->ce_id);
+
 	qdf_atomic_dec(&scn->active_tasklet_cnt);
 }
 
@@ -555,7 +561,8 @@
 		qdf_debug("CE id[%2d] - %s", i, str_buffer);
 	}
 
-	hif_ce_latency_stats(hif_ctx);
+	if (hif_ctx->ce_latency_stats)
+		hif_ce_latency_stats(hif_ctx);
 #undef STR_SIZE
 }
 
@@ -589,7 +596,9 @@
 	}
 
 	tasklet_schedule(&tasklet_entry->intr_tq);
-	hif_record_tasklet_sched_entry_ts(scn, tasklet_entry->ce_id);
+	if (scn->ce_latency_stats)
+		hif_record_tasklet_sched_entry_ts(scn, tasklet_entry->ce_id);
+
 	return true;
 }
 
diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c
index 8ee43de..05f18f4 100644
--- a/hif/src/hif_main.c
+++ b/hif/src/hif_main.c
@@ -653,6 +653,18 @@
 	HIF_DBG("%s: X", __func__);
 }
 
+#ifdef CE_TASKLET_DEBUG_ENABLE
+void hif_enable_ce_latency_stats(struct hif_opaque_softc *hif_ctx, uint8_t val)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
+
+	if (!scn)
+		return;
+
+	scn->ce_latency_stats = val;
+}
+#endif
+
 void hif_display_stats(struct hif_opaque_softc *hif_ctx)
 {
 	hif_display_bus_stats(hif_ctx);
diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h
index 2d4a644..adf7c29 100644
--- a/hif/src/hif_main.h
+++ b/hif/src/hif_main.h
@@ -176,6 +176,7 @@
 	bool hif_init_done;
 	bool request_irq_done;
 	bool ext_grp_irq_configured;
+	uint8_t ce_latency_stats;
 	/* Packet statistics */
 	struct hif_ce_stats pkt_stats;
 	enum hif_target_status target_status;
@@ -233,7 +234,6 @@
 #if defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF)
 	struct ce_desc_hist hif_ce_desc_hist;
 #endif /*defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF)*/
-
 #ifdef IPA_OFFLOAD
 	qdf_shared_mem_t *ipa_ce_ring;
 #endif
diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c
index 79aa0ed..42b4ca9 100644
--- a/hif/src/pcie/if_pci.c
+++ b/hif/src/pcie/if_pci.c
@@ -4119,9 +4119,9 @@
 }
 
 /**
- * hif_pm_runtime_put() - do a put opperation on the device
+ * hif_pm_runtime_put() - do a put operation on the device
  *
- * A put opperation will allow a runtime suspend after a corresponding
+ * A put operation will allow a runtime suspend after a corresponding
  * get was done.  This api should be used when sending data.
  *
  * This api will return a failure if runtime pm is stopped
@@ -4170,6 +4170,46 @@
 	return 0;
 }
 
+/**
+ * hif_pm_runtime_put_noidle() - do a put operation with no idle
+ *
+ * This API will do a runtime put no idle operation
+ *
+ * @hif_ctx: pointer of HIF context
+ *
+ * Return: 0 for success otherwise an error code
+ */
+int hif_pm_runtime_put_noidle(struct hif_opaque_softc *hif_ctx)
+{
+	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx);
+	int usage_count, pm_state;
+	char *err = NULL;
+
+	if (!sc)
+		return -EINVAL;
+
+	if (!pm_runtime_enabled(sc->dev))
+		return 0;
+
+	usage_count = atomic_read(&sc->dev->power.usage_count);
+	if (usage_count == 1) {
+		pm_state = qdf_atomic_read(&sc->pm_state);
+		if (pm_state == HIF_PM_RUNTIME_STATE_NONE)
+			err = "Ignore unexpected Put as runtime PM is disabled";
+	} else if (usage_count == 0) {
+		err = "Put without a Get Operation";
+	}
+
+	if (err) {
+		hif_pci_runtime_pm_warn(sc, err);
+		return -EINVAL;
+	}
+
+	sc->pm_stats.runtime_put++;
+	pm_runtime_put_noidle(sc->dev);
+
+	return 0;
+}
 
 /**
  * __hif_pm_runtime_prevent_suspend() - prevent runtime suspend for a protocol
diff --git a/os_if/linux/scan/src/wlan_cfg80211_scan.c b/os_if/linux/scan/src/wlan_cfg80211_scan.c
index a7f6616..14c24b1 100644
--- a/os_if/linux/scan/src/wlan_cfg80211_scan.c
+++ b/os_if/linux/scan/src/wlan_cfg80211_scan.c
@@ -1295,6 +1295,7 @@
 	enum wlan_band band;
 	struct net_device *netdev = NULL;
 	QDF_STATUS qdf_status;
+	enum QDF_OPMODE opmode;
 	uint32_t extra_ie_len = 0;
 
 	psoc = wlan_pdev_get_psoc(pdev);
@@ -1388,8 +1389,9 @@
 				  pssid->ssid);
 		}
 	}
+	opmode = wlan_vdev_mlme_get_opmode(vdev);
 	if (request->ssids ||
-	   (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE))
+	   (opmode == QDF_P2P_GO_MODE) || (opmode == QDF_P2P_DEVICE_MODE))
 		req->scan_req.scan_f_passive = false;
 
 	if (params->half_rate)
diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h
index 24de579..c105bb3 100644
--- a/wmi/inc/wmi_unified_param.h
+++ b/wmi/inc/wmi_unified_param.h
@@ -2865,6 +2865,7 @@
  * @enable: Enable/Disable Thermal mitigation
  * @dc: DC
  * @dc_per_event: DC per event
+ * @num_thermal_conf: Number of thermal configurations to be sent
  * @tt_level_config: TT level config params
  */
 struct thermal_mitigation_params {
@@ -2872,6 +2873,7 @@
 	uint32_t enable;
 	uint32_t dc;
 	uint32_t dc_per_event;
+	uint8_t num_thermal_conf;
 	tt_level_config levelconf[THERMAL_LEVELS];
 };
 
diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c
index 0babe37..ba6316f 100644
--- a/wmi/src/wmi_unified_tlv.c
+++ b/wmi/src/wmi_unified_tlv.c
@@ -6562,7 +6562,8 @@
 	int i;
 
 	len = sizeof(*tt_conf) + WMI_TLV_HDR_SIZE +
-			THERMAL_LEVELS * sizeof(wmi_therm_throt_level_config_info);
+			param->num_thermal_conf *
+			sizeof(wmi_therm_throt_level_config_info);
 
 	buf = wmi_buf_alloc(wmi_handle, len);
 	if (!buf)
@@ -6581,15 +6582,16 @@
 	tt_conf->enable = param->enable;
 	tt_conf->dc = param->dc;
 	tt_conf->dc_per_event = param->dc_per_event;
-	tt_conf->therm_throt_levels = THERMAL_LEVELS;
+	tt_conf->therm_throt_levels = param->num_thermal_conf;
 
 	buf_ptr = (uint8_t *) ++tt_conf;
 	/* init TLV params */
 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
-			(THERMAL_LEVELS * sizeof(wmi_therm_throt_level_config_info)));
+			(param->num_thermal_conf *
+			sizeof(wmi_therm_throt_level_config_info)));
 
 	lvl_conf = (wmi_therm_throt_level_config_info *) (buf_ptr +  WMI_TLV_HDR_SIZE);
-	for (i = 0; i < THERMAL_LEVELS; i++) {
+	for (i = 0; i < param->num_thermal_conf; i++) {
 		WMITLV_SET_HDR(&lvl_conf->tlv_header,
 			WMITLV_TAG_STRUC_wmi_therm_throt_level_config_info,
 			WMITLV_GET_STRUCT_TLVLEN(wmi_therm_throt_level_config_info));