ソースを参照

qcacmn: qcacmn: Add Monitor 1.0 support for WCN6450

Currently in monitor mode, links are released to WBM through the
SW2WBM_RELEASE ring and WBM will feed the links back to RXDMA
through the WBM2RXDMA_LINK_RING.

WCN6450 uses SOFTUMAC architecture where WBM is not present.
Hence the WBM2RXDMA_LINK_RING is repurposed to SW2RXDMA_LINK_RING
where host will directly release the links to RXDMA using this ring.

Change-Id: I110f607e38c4c2ab10eb1bd7b1f5a7bce2f03692
CRs-Fixed: 3493368
Venkateswara Naralasetty 2 年 前
コミット
39ed82e609

+ 4 - 0
dp/wifi3.0/dp_htt.c

@@ -715,6 +715,10 @@ int htt_srng_setup(struct htt_soc *soc, int mac_id,
 		htt_ring_id = HTT_TX_MON_MON2HOST_DEST_RING;
 		htt_ring_type = HTT_HW_TO_SW_RING;
 		break;
+	case SW2RXDMA_LINK_RELEASE:
+		htt_ring_id = HTT_RXDMA_MONITOR_DESC_RING;
+		htt_ring_type = HTT_SW_TO_HW_RING;
+		break;
 
 	default:
 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,

+ 12 - 0
dp/wifi3.0/dp_internal.h

@@ -679,6 +679,18 @@ dp_monitor_get_link_desc_pages(struct dp_soc *soc, uint32_t mac_id)
 	return NULL;
 }
 
+static inline struct dp_srng*
+dp_monitor_get_link_desc_ring(struct dp_soc *soc, uint32_t mac_id)
+{
+	return NULL;
+}
+
+static inline uint32_t
+dp_monitor_get_num_link_desc_ring_entries(struct dp_soc *soc)
+{
+	return 0;
+}
+
 static inline uint32_t *
 dp_monitor_get_total_link_descs(struct dp_soc *soc, uint32_t mac_id)
 {

+ 132 - 0
dp/wifi3.0/dp_main.c

@@ -1696,6 +1696,138 @@ static QDF_STATUS dp_soc_interrupt_attach_wrapper(struct cdp_soc_t *txrx_soc)
 #endif
 #endif
 
+void dp_link_desc_ring_replenish(struct dp_soc *soc, uint32_t mac_id)
+{
+	uint32_t cookie = 0;
+	uint32_t page_idx = 0;
+	struct qdf_mem_multi_page_t *pages;
+	struct qdf_mem_dma_page_t *dma_pages;
+	uint32_t offset = 0;
+	uint32_t count = 0;
+	uint32_t desc_id = 0;
+	void *desc_srng;
+	int link_desc_size = hal_get_link_desc_size(soc->hal_soc);
+	uint32_t *total_link_descs_addr;
+	uint32_t total_link_descs;
+	uint32_t scatter_buf_num;
+	uint32_t num_entries_per_buf = 0;
+	uint32_t rem_entries;
+	uint32_t num_descs_per_page;
+	uint32_t num_scatter_bufs = 0;
+	uint8_t *scatter_buf_ptr;
+	void *desc;
+
+	num_scatter_bufs = soc->num_scatter_bufs;
+
+	if (mac_id == WLAN_INVALID_PDEV_ID) {
+		pages = &soc->link_desc_pages;
+		total_link_descs = soc->total_link_descs;
+		desc_srng = soc->wbm_idle_link_ring.hal_srng;
+	} else {
+		pages = dp_monitor_get_link_desc_pages(soc, mac_id);
+		/* dp_monitor_get_link_desc_pages returns NULL only
+		 * if monitor SOC is  NULL
+		 */
+		if (!pages) {
+			dp_err("can not get link desc pages");
+			QDF_ASSERT(0);
+			return;
+		}
+		total_link_descs_addr =
+				dp_monitor_get_total_link_descs(soc, mac_id);
+		total_link_descs = *total_link_descs_addr;
+		desc_srng = dp_monitor_get_link_desc_ring(soc, mac_id);
+	}
+
+	dma_pages = pages->dma_pages;
+	do {
+		qdf_mem_zero(dma_pages[page_idx].page_v_addr_start,
+			     pages->page_size);
+		page_idx++;
+	} while (page_idx < pages->num_pages);
+
+	if (desc_srng) {
+		hal_srng_access_start_unlocked(soc->hal_soc, desc_srng);
+		page_idx = 0;
+		count = 0;
+		offset = 0;
+		while ((desc = hal_srng_src_get_next(soc->hal_soc,
+						     desc_srng)) &&
+			(count < total_link_descs)) {
+			page_idx = count / pages->num_element_per_page;
+			if (desc_id == pages->num_element_per_page)
+				desc_id = 0;
+
+			offset = count % pages->num_element_per_page;
+			cookie = LINK_DESC_COOKIE(desc_id, page_idx,
+						  soc->link_desc_id_start);
+
+			hal_set_link_desc_addr(soc->hal_soc, desc, cookie,
+					       dma_pages[page_idx].page_p_addr
+					       + (offset * link_desc_size),
+					       soc->idle_link_bm_id);
+			count++;
+			desc_id++;
+		}
+		hal_srng_access_end_unlocked(soc->hal_soc, desc_srng);
+	} else {
+		/* Populate idle list scatter buffers with link descriptor
+		 * pointers
+		 */
+		scatter_buf_num = 0;
+		num_entries_per_buf = hal_idle_scatter_buf_num_entries(
+					soc->hal_soc,
+					soc->wbm_idle_scatter_buf_size);
+
+		scatter_buf_ptr = (uint8_t *)(
+			soc->wbm_idle_scatter_buf_base_vaddr[scatter_buf_num]);
+		rem_entries = num_entries_per_buf;
+		page_idx = 0; count = 0;
+		offset = 0;
+		num_descs_per_page = pages->num_element_per_page;
+
+		while (count < total_link_descs) {
+			page_idx = count / num_descs_per_page;
+			offset = count % num_descs_per_page;
+			if (desc_id == pages->num_element_per_page)
+				desc_id = 0;
+
+			cookie = LINK_DESC_COOKIE(desc_id, page_idx,
+						  soc->link_desc_id_start);
+			hal_set_link_desc_addr(soc->hal_soc,
+					       (void *)scatter_buf_ptr,
+					       cookie,
+					       dma_pages[page_idx].page_p_addr +
+					       (offset * link_desc_size),
+					       soc->idle_link_bm_id);
+			rem_entries--;
+			if (rem_entries) {
+				scatter_buf_ptr += link_desc_size;
+			} else {
+				rem_entries = num_entries_per_buf;
+				scatter_buf_num++;
+				if (scatter_buf_num >= num_scatter_bufs)
+					break;
+				scatter_buf_ptr = (uint8_t *)
+					(soc->wbm_idle_scatter_buf_base_vaddr[
+					 scatter_buf_num]);
+			}
+			count++;
+			desc_id++;
+		}
+		/* Setup link descriptor idle list in HW */
+		hal_setup_link_idle_list(soc->hal_soc,
+			soc->wbm_idle_scatter_buf_base_paddr,
+			soc->wbm_idle_scatter_buf_base_vaddr,
+			num_scatter_bufs, soc->wbm_idle_scatter_buf_size,
+			(uint32_t)(scatter_buf_ptr -
+			(uint8_t *)(soc->wbm_idle_scatter_buf_base_vaddr[
+			scatter_buf_num-1])), total_link_descs);
+	}
+}
+
+qdf_export_symbol(dp_link_desc_ring_replenish);
+
 /**
  * dp_soc_ppeds_stop() - Stop PPE DS processing
  * @soc_handle: DP SOC handle

+ 30 - 0
dp/wifi3.0/dp_rings.h

@@ -26,6 +26,23 @@
 #include <dp_mon.h>
 #endif
 
+#ifdef WLAN_FEATURE_DP_EVENT_HISTORY
+static inline bool dp_is_mon_mask_valid(struct dp_soc *soc,
+					struct dp_intr *intr_ctx)
+{
+	if (intr_ctx->rx_mon_ring_mask)
+		return true;
+
+	return false;
+}
+#else
+static inline bool dp_is_mon_mask_valid(struct dp_soc *soc,
+					struct dp_intr *intr_ctx)
+{
+	return false;
+}
+#endif
+
 #ifndef QCA_HOST_MODE_WIFI_DISABLED
 
 /**
@@ -651,11 +668,24 @@ static inline QDF_STATUS dp_soc_srng_alloc(struct dp_soc *soc)
 static inline QDF_STATUS dp_soc_attach_poll(struct cdp_soc_t *txrx_soc)
 {
 	struct dp_soc *soc = (struct dp_soc *)txrx_soc;
+	uint32_t lmac_id = 0;
+	int i;
 
 	qdf_mem_set(&soc->mon_intr_id_lmac_map,
 		    sizeof(soc->mon_intr_id_lmac_map), DP_MON_INVALID_LMAC_ID);
 	soc->intr_mode = DP_INTR_POLL;
 
+	for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) {
+		soc->intr_ctx[i].rx_mon_ring_mask =
+				wlan_cfg_get_rx_mon_ring_mask(soc->wlan_cfg_ctx, i);
+
+		if (dp_is_mon_mask_valid(soc, &soc->intr_ctx[i])) {
+			hif_event_history_init(soc->hif_handle, i);
+			soc->mon_intr_id_lmac_map[lmac_id] = i;
+			lmac_id++;
+		}
+	}
+
 	qdf_timer_init(soc->osdev, &soc->int_timer,
 		       dp_interrupt_timer, (void *)soc,
 		       QDF_TIMER_TYPE_WAKE_APPS);

+ 0 - 149
dp/wifi3.0/dp_rings_main.c

@@ -1447,23 +1447,6 @@ budget_done:
 
 #endif /* QCA_HOST_MODE_WIFI_DISABLED */
 
-#ifdef WLAN_FEATURE_DP_EVENT_HISTORY
-static inline bool dp_is_mon_mask_valid(struct dp_soc *soc,
-					struct dp_intr *intr_ctx)
-{
-	if (intr_ctx->rx_mon_ring_mask)
-		return true;
-
-	return false;
-}
-#else
-static inline bool dp_is_mon_mask_valid(struct dp_soc *soc,
-					struct dp_intr *intr_ctx)
-{
-	return false;
-}
-#endif
-
 QDF_STATUS dp_soc_attach_poll(struct cdp_soc_t *txrx_soc)
 {
 	struct dp_soc *soc = (struct dp_soc *)txrx_soc;
@@ -2257,138 +2240,6 @@ void dp_hw_link_desc_ring_deinit(struct dp_soc *soc)
 	dp_srng_deinit(soc, &soc->wbm_idle_link_ring, WBM_IDLE_LINK, 0);
 }
 
-void dp_link_desc_ring_replenish(struct dp_soc *soc, uint32_t mac_id)
-{
-	uint32_t cookie = 0;
-	uint32_t page_idx = 0;
-	struct qdf_mem_multi_page_t *pages;
-	struct qdf_mem_dma_page_t *dma_pages;
-	uint32_t offset = 0;
-	uint32_t count = 0;
-	uint32_t desc_id = 0;
-	void *desc_srng;
-	int link_desc_size = hal_get_link_desc_size(soc->hal_soc);
-	uint32_t *total_link_descs_addr;
-	uint32_t total_link_descs;
-	uint32_t scatter_buf_num;
-	uint32_t num_entries_per_buf = 0;
-	uint32_t rem_entries;
-	uint32_t num_descs_per_page;
-	uint32_t num_scatter_bufs = 0;
-	uint8_t *scatter_buf_ptr;
-	void *desc;
-
-	num_scatter_bufs = soc->num_scatter_bufs;
-
-	if (mac_id == WLAN_INVALID_PDEV_ID) {
-		pages = &soc->link_desc_pages;
-		total_link_descs = soc->total_link_descs;
-		desc_srng = soc->wbm_idle_link_ring.hal_srng;
-	} else {
-		pages = dp_monitor_get_link_desc_pages(soc, mac_id);
-		/* dp_monitor_get_link_desc_pages returns NULL only
-		 * if monitor SOC is  NULL
-		 */
-		if (!pages) {
-			dp_err("can not get link desc pages");
-			QDF_ASSERT(0);
-			return;
-		}
-		total_link_descs_addr =
-				dp_monitor_get_total_link_descs(soc, mac_id);
-		total_link_descs = *total_link_descs_addr;
-		desc_srng = soc->rxdma_mon_desc_ring[mac_id].hal_srng;
-	}
-
-	dma_pages = pages->dma_pages;
-	do {
-		qdf_mem_zero(dma_pages[page_idx].page_v_addr_start,
-			     pages->page_size);
-		page_idx++;
-	} while (page_idx < pages->num_pages);
-
-	if (desc_srng) {
-		hal_srng_access_start_unlocked(soc->hal_soc, desc_srng);
-		page_idx = 0;
-		count = 0;
-		offset = 0;
-		while ((desc = hal_srng_src_get_next(soc->hal_soc,
-						     desc_srng)) &&
-			(count < total_link_descs)) {
-			page_idx = count / pages->num_element_per_page;
-			if (desc_id == pages->num_element_per_page)
-				desc_id = 0;
-
-			offset = count % pages->num_element_per_page;
-			cookie = LINK_DESC_COOKIE(desc_id, page_idx,
-						  soc->link_desc_id_start);
-
-			hal_set_link_desc_addr(soc->hal_soc, desc, cookie,
-					       dma_pages[page_idx].page_p_addr
-					       + (offset * link_desc_size),
-					       soc->idle_link_bm_id);
-			count++;
-			desc_id++;
-		}
-		hal_srng_access_end_unlocked(soc->hal_soc, desc_srng);
-	} else {
-		/* Populate idle list scatter buffers with link descriptor
-		 * pointers
-		 */
-		scatter_buf_num = 0;
-		num_entries_per_buf = hal_idle_scatter_buf_num_entries(
-					soc->hal_soc,
-					soc->wbm_idle_scatter_buf_size);
-
-		scatter_buf_ptr = (uint8_t *)(
-			soc->wbm_idle_scatter_buf_base_vaddr[scatter_buf_num]);
-		rem_entries = num_entries_per_buf;
-		page_idx = 0; count = 0;
-		offset = 0;
-		num_descs_per_page = pages->num_element_per_page;
-
-		while (count < total_link_descs) {
-			page_idx = count / num_descs_per_page;
-			offset = count % num_descs_per_page;
-			if (desc_id == pages->num_element_per_page)
-				desc_id = 0;
-
-			cookie = LINK_DESC_COOKIE(desc_id, page_idx,
-						  soc->link_desc_id_start);
-			hal_set_link_desc_addr(soc->hal_soc,
-					       (void *)scatter_buf_ptr,
-					       cookie,
-					       dma_pages[page_idx].page_p_addr +
-					       (offset * link_desc_size),
-					       soc->idle_link_bm_id);
-			rem_entries--;
-			if (rem_entries) {
-				scatter_buf_ptr += link_desc_size;
-			} else {
-				rem_entries = num_entries_per_buf;
-				scatter_buf_num++;
-				if (scatter_buf_num >= num_scatter_bufs)
-					break;
-				scatter_buf_ptr = (uint8_t *)
-					(soc->wbm_idle_scatter_buf_base_vaddr[
-					 scatter_buf_num]);
-			}
-			count++;
-			desc_id++;
-		}
-		/* Setup link descriptor idle list in HW */
-		hal_setup_link_idle_list(soc->hal_soc,
-			soc->wbm_idle_scatter_buf_base_paddr,
-			soc->wbm_idle_scatter_buf_base_vaddr,
-			num_scatter_bufs, soc->wbm_idle_scatter_buf_size,
-			(uint32_t)(scatter_buf_ptr -
-			(uint8_t *)(soc->wbm_idle_scatter_buf_base_vaddr[
-			scatter_buf_num-1])), total_link_descs);
-	}
-}
-
-qdf_export_symbol(dp_link_desc_ring_replenish);
-
 #ifdef IPA_OFFLOAD
 #define USE_1_IPA_RX_REO_RING 1
 #define USE_2_IPA_RX_REO_RINGS 2

+ 12 - 14
dp/wifi3.0/dp_types.h

@@ -2627,6 +2627,9 @@ struct dp_soc {
 	/* RXDMA monitor status ring. TBD: Check format of this ring */
 	struct dp_srng rxdma_mon_status_ring[MAX_NUM_LMAC_HW];
 
+	/* Ring to handover links to hw in monitor mode for SOFTUMAC arch */
+	struct dp_srng sw2rxdma_link_ring[MAX_NUM_LMAC_HW];
+
 	/* Number of PDEVs */
 	uint8_t pdev_count;
 
@@ -5174,15 +5177,6 @@ void dp_hw_link_desc_pool_banks_free(struct dp_soc *soc, uint32_t mac_id);
  */
 QDF_STATUS dp_hw_link_desc_pool_banks_alloc(struct dp_soc *soc,
 					    uint32_t mac_id);
-
-/**
- * dp_link_desc_ring_replenish() - Replenish hw link desc rings
- * @soc: DP SOC handle
- * @mac_id: mac id
- *
- * Return: None
- */
-void dp_link_desc_ring_replenish(struct dp_soc *soc, uint32_t mac_id);
 #else
 static inline void dp_hw_link_desc_pool_banks_free(struct dp_soc *soc,
 						   uint32_t mac_id)
@@ -5194,13 +5188,17 @@ static inline QDF_STATUS dp_hw_link_desc_pool_banks_alloc(struct dp_soc *soc,
 {
 	return QDF_STATUS_SUCCESS;
 }
-
-static inline void dp_link_desc_ring_replenish(struct dp_soc *soc,
-					       uint32_t mac_id)
-{
-}
 #endif
 
+/**
+ * dp_link_desc_ring_replenish() - Replenish hw link desc rings
+ * @soc: DP SOC handle
+ * @mac_id: mac id
+ *
+ * Return: None
+ */
+void dp_link_desc_ring_replenish(struct dp_soc *soc, uint32_t mac_id);
+
 #ifdef WLAN_FEATURE_RX_PREALLOC_BUFFER_POOL
 void dp_rx_refill_buff_pool_enqueue(struct dp_soc *soc);
 #else

+ 59 - 0
dp/wifi3.0/monitor/1.0/dp_mon_1.0.c

@@ -228,6 +228,8 @@ void dp_mon_rings_deinit_1_0(struct dp_pdev *pdev)
 
 		dp_srng_deinit(soc, &soc->rxdma_mon_status_ring[lmac_id],
 			       RXDMA_MONITOR_STATUS, 0);
+		dp_srng_deinit(soc, &soc->sw2rxdma_link_ring[lmac_id],
+			       SW2RXDMA_LINK_RELEASE, 0);
 
 		dp_mon_dest_rings_deinit(pdev, lmac_id);
 	}
@@ -246,11 +248,46 @@ void dp_mon_rings_free_1_0(struct dp_pdev *pdev)
 							 pdev->pdev_id);
 
 		dp_srng_free(soc, &soc->rxdma_mon_status_ring[lmac_id]);
+		dp_srng_free(soc, &soc->sw2rxdma_link_ring[lmac_id]);
 
 		dp_mon_dest_rings_free(pdev, lmac_id);
 	}
 }
 
+#ifdef WLAN_SOFTUMAC_SUPPORT
+static QDF_STATUS
+dp_mon_sw2rxdma_link_ring_alloc(struct dp_pdev *pdev, int lmac_id)
+{
+	struct dp_soc *soc = pdev->soc;
+	struct wlan_cfg_dp_pdev_ctxt *pdev_cfg_ctx = pdev->wlan_cfg_ctx;
+	int entries;
+
+	entries = wlan_cfg_get_dma_sw2rxdma_link_ring_size(pdev_cfg_ctx);
+
+	return dp_srng_alloc(soc, &soc->sw2rxdma_link_ring[lmac_id],
+			     SW2RXDMA_LINK_RELEASE, entries, 0);
+}
+
+static QDF_STATUS
+dp_mon_sw2rxdma_link_ring_init(struct dp_soc *soc, int lmac_id)
+{
+	return dp_srng_init(soc, &soc->sw2rxdma_link_ring[lmac_id],
+			    SW2RXDMA_LINK_RELEASE, 0, lmac_id);
+}
+#else
+static QDF_STATUS
+dp_mon_sw2rxdma_link_ring_alloc(struct dp_pdev *pdev, int lmac_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+dp_mon_sw2rxdma_link_ring_init(struct dp_soc *soc, int lmac_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 QDF_STATUS dp_mon_rings_init_1_0(struct dp_pdev *pdev)
 {
 	struct dp_soc *soc = pdev->soc;
@@ -269,6 +306,11 @@ QDF_STATUS dp_mon_rings_init_1_0(struct dp_pdev *pdev)
 			goto fail1;
 		}
 
+		if (dp_mon_sw2rxdma_link_ring_init(soc, lmac_id)) {
+			dp_mon_err("%pK: " RNG_ERR "sw2rxdma_link_ring", soc);
+			goto fail1;
+		}
+
 		if (dp_mon_dest_rings_init(pdev, lmac_id))
 			goto fail1;
 	}
@@ -301,6 +343,11 @@ QDF_STATUS dp_mon_rings_alloc_1_0(struct dp_pdev *pdev)
 			goto fail1;
 		}
 
+		if (dp_mon_sw2rxdma_link_ring_alloc(pdev, lmac_id)) {
+			dp_mon_err("%pK: " RNG_ERR "sw2rxdma_link_ring", soc);
+			goto fail1;
+		}
+
 		if (dp_mon_dest_rings_alloc(pdev, lmac_id))
 			goto fail1;
 	}
@@ -733,6 +780,18 @@ QDF_STATUS dp_mon_htt_srng_setup_1_0(struct dp_soc *soc,
 		return status;
 	}
 
+	if (!soc->sw2rxdma_link_ring[mac_id].hal_srng)
+		return QDF_STATUS_SUCCESS;
+
+	status = htt_srng_setup(soc->htt_handle, mac_for_pdev,
+				soc->sw2rxdma_link_ring[mac_id].hal_srng,
+				SW2RXDMA_LINK_RELEASE);
+
+	if (status != QDF_STATUS_SUCCESS) {
+		dp_mon_err("Failed to send htt srng setup message for sw2rxdma link ring");
+		return status;
+	}
+
 	return status;
 }
 #else

+ 12 - 0
dp/wifi3.0/monitor/1.0/dp_rx_mon_1.0.h

@@ -911,6 +911,7 @@ void *dp_rx_cookie_2_mon_link_desc(struct dp_pdev *pdev,
 	return dp_rx_cookie_2_link_desc_va(pdev->soc, buf_info);
 }
 
+#ifndef WLAN_SOFTUMAC_SUPPORT
 /**
  * dp_rx_monitor_link_desc_return() - Return Link descriptor based on target
  * @pdev: core physical device context
@@ -933,6 +934,17 @@ QDF_STATUS dp_rx_monitor_link_desc_return(struct dp_pdev *pdev,
 	return dp_rx_link_desc_return_by_addr(pdev->soc, p_last_buf_addr_info,
 				      bm_action);
 }
+#else
+static inline
+QDF_STATUS dp_rx_monitor_link_desc_return(struct dp_pdev *pdev,
+					  hal_buff_addrinfo_t
+					  p_last_buf_addr_info,
+					  uint8_t mac_id, uint8_t bm_action)
+{
+	return dp_rx_mon_link_desc_return(pdev, p_last_buf_addr_info,
+					  mac_id);
+}
+#endif
 
 static inline bool dp_is_rxdma_dst_ring_common(struct dp_pdev *pdev)
 {

+ 117 - 4
dp/wifi3.0/monitor/1.0/dp_rx_mon_dest_1.0.c

@@ -105,7 +105,6 @@ QDF_STATUS
 dp_rx_mon_link_desc_return(struct dp_pdev *dp_pdev,
 	hal_buff_addrinfo_t buf_addr_info, int mac_id)
 {
-	struct dp_srng *dp_srng;
 	hal_ring_handle_t hal_ring_hdl;
 	hal_soc_handle_t hal_soc;
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
@@ -113,8 +112,7 @@ dp_rx_mon_link_desc_return(struct dp_pdev *dp_pdev,
 
 	hal_soc = dp_pdev->soc->hal_soc;
 
-	dp_srng = &dp_pdev->soc->rxdma_mon_desc_ring[mac_id];
-	hal_ring_hdl = dp_srng->hal_srng;
+	hal_ring_hdl = dp_monitor_get_link_desc_ring(dp_pdev->soc, mac_id);
 
 	qdf_assert(hal_ring_hdl);
 
@@ -1186,6 +1184,108 @@ dp_rx_mon_check_n_drop_mpdu(struct dp_pdev *pdev, uint32_t mac_id,
 #endif
 #endif
 
+#ifdef WLAN_SOFTUMAC_SUPPORT
+static void dp_mon_hw_link_desc_bank_free(struct dp_soc *soc, uint32_t mac_id)
+{
+	struct qdf_mem_multi_page_t *pages;
+
+	pages = dp_monitor_get_link_desc_pages(soc, mac_id);
+	if (!pages) {
+		dp_err("can not get mon link desc pages");
+		QDF_ASSERT(0);
+		return;
+	}
+
+	if (pages->dma_pages) {
+		wlan_minidump_remove((void *)
+				     pages->dma_pages->page_v_addr_start,
+				     pages->num_pages * pages->page_size,
+				     soc->ctrl_psoc,
+				     WLAN_MD_DP_SRNG_SW2RXDMA_LINK_RING,
+				     "mon hw_link_desc_bank");
+		dp_desc_multi_pages_mem_free(soc, QDF_DP_HW_LINK_DESC_TYPE,
+					     pages, 0, false);
+	}
+}
+
+static QDF_STATUS
+dp_mon_hw_link_desc_bank_alloc(struct dp_soc *soc, uint32_t mac_id)
+{
+	struct qdf_mem_multi_page_t *pages;
+	uint32_t *total_link_descs, total_mem_size;
+	uint32_t num_entries;
+	uint32_t max_alloc_size = wlan_cfg_max_alloc_size(soc->wlan_cfg_ctx);
+	int link_desc_size = hal_get_link_desc_size(soc->hal_soc);
+	int link_desc_align = hal_get_link_desc_align(soc->hal_soc);
+	uint8_t minidump_str[MINIDUMP_STR_SIZE];
+
+	pages = dp_monitor_get_link_desc_pages(soc, mac_id);
+	if (!pages) {
+		dp_err("can not get mon link desc pages");
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_FAULT;
+	}
+
+	/* If link descriptor banks are allocated, return from here */
+	if (pages->num_pages)
+		return QDF_STATUS_SUCCESS;
+
+	num_entries = dp_monitor_get_num_link_desc_ring_entries(soc, mac_id);
+	total_link_descs = dp_monitor_get_total_link_descs(soc, mac_id);
+	qdf_str_lcopy(minidump_str, "mon_link_desc_bank",
+		      MINIDUMP_STR_SIZE);
+
+	/* Round up to power of 2 */
+	*total_link_descs = 1;
+	while (*total_link_descs < num_entries)
+		*total_link_descs <<= 1;
+
+	dp_init_info("%pK: total_link_descs: %u, link_desc_size: %d",
+		     soc, *total_link_descs, link_desc_size);
+
+	total_mem_size =  *total_link_descs * link_desc_size;
+	total_mem_size += link_desc_align;
+
+	dp_init_info("%pK: total_mem_size: %d", soc, total_mem_size);
+
+	dp_set_max_page_size(pages, max_alloc_size);
+	dp_desc_multi_pages_mem_alloc(soc, QDF_DP_HW_LINK_DESC_TYPE,
+				      pages, link_desc_size,
+				      *total_link_descs, 0, false);
+
+	if (!pages->num_pages) {
+		dp_err("Multi page alloc fail for mon hw link desc pool");
+		return QDF_STATUS_E_FAULT;
+	}
+
+	wlan_minidump_log(pages->dma_pages->page_v_addr_start,
+			  pages->num_pages * pages->page_size,
+			  soc->ctrl_psoc,
+			  WLAN_MD_DP_SRNG_SW2RXDMA_LINK_RING,
+			  "mon hw_link_desc_bank");
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void
+dp_mon_link_desc_ring_replenish(struct dp_soc *soc, int mac_id)
+{
+	dp_link_desc_ring_replenish(soc, mac_id);
+}
+#else
+static QDF_STATUS
+dp_mon_hw_link_desc_bank_alloc(struct dp_soc *soc, uint32_t mac_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static void
+dp_mon_hw_link_desc_bank_free(struct dp_soc *soc, uint32_t mac_id) {}
+
+static void
+dp_mon_link_desc_ring_replenish(struct dp_soc *soc, int mac_id) {}
+#endif
+
 static void
 dp_rx_pdev_mon_cmn_desc_pool_free(struct dp_pdev *pdev, int mac_id)
 {
@@ -1194,6 +1294,7 @@ dp_rx_pdev_mon_cmn_desc_pool_free(struct dp_pdev *pdev, int mac_id)
 	int mac_for_pdev = dp_get_lmac_id_for_pdev_id(soc, mac_id, pdev_id);
 
 	dp_rx_pdev_mon_status_desc_pool_free(pdev, mac_for_pdev);
+	dp_mon_hw_link_desc_bank_free(soc, mac_for_pdev);
 	dp_rx_pdev_mon_dest_desc_pool_free(pdev, mac_for_pdev);
 }
 
@@ -1235,6 +1336,7 @@ dp_rx_pdev_mon_cmn_desc_pool_init(struct dp_pdev *pdev, int mac_id)
 
 	mac_for_pdev = dp_get_lmac_id_for_pdev_id(soc, mac_id, pdev->pdev_id);
 	dp_rx_pdev_mon_status_desc_pool_init(pdev, mac_for_pdev);
+	dp_mon_link_desc_ring_replenish(soc, mac_for_pdev);
 
 	dp_rx_pdev_mon_dest_desc_pool_init(pdev, mac_for_pdev);
 }
@@ -1326,12 +1428,23 @@ dp_rx_pdev_mon_cmn_desc_pool_alloc(struct dp_pdev *pdev, int mac_id)
 		goto fail;
 	}
 
+	/* Allocate hw link desc bank for monitor mode for
+	 * SOFTUMAC architecture.
+	 */
+	status = dp_mon_hw_link_desc_bank_alloc(soc, mac_for_pdev);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		dp_err("dp_mon_hw_link_desc_bank_alloc() failed");
+		goto mon_status_dealloc;
+	}
+
 	status = dp_rx_pdev_mon_dest_desc_pool_alloc(pdev, mac_for_pdev);
 	if (!QDF_IS_STATUS_SUCCESS(status))
-		goto mon_status_dealloc;
+		goto link_desc_bank_free;
 
 	return status;
 
+link_desc_bank_free:
+	dp_mon_hw_link_desc_bank_free(soc, mac_for_pdev);
 mon_status_dealloc:
 	dp_rx_pdev_mon_status_desc_pool_free(pdev, mac_for_pdev);
 fail:

+ 43 - 0
dp/wifi3.0/monitor/dp_mon.h

@@ -1826,6 +1826,49 @@ dp_monitor_get_link_desc_pages(struct dp_soc *soc, uint32_t mac_id)
 	return &soc->monitor_soc->mon_link_desc_pages[mac_id];
 }
 
+#ifndef WLAN_SOFTUMAC_SUPPORT
+/*
+ * dp_monitor_get_link_desc_ring() - Get link desc ring
+ * @soc: point to soc
+ * @mac_id: mac id
+ *
+ * Return: return point to link desc ring
+ */
+static inline hal_ring_handle_t
+dp_monitor_get_link_desc_ring(struct dp_soc *soc, uint32_t mac_id)
+{
+	return soc->rxdma_mon_desc_ring[mac_id].hal_srng;
+}
+
+static inline uint32_t
+dp_monitor_get_num_link_desc_ring_entries(struct dp_soc *soc, uint32_t mac_id)
+{
+	struct dp_srng *ring;
+
+	ring = &soc->rxdma_mon_desc_ring[mac_id];
+
+	return ring->alloc_size / hal_srng_get_entrysize(soc->hal_soc,
+							 RXDMA_MONITOR_DESC);
+}
+#else
+static inline hal_ring_handle_t
+dp_monitor_get_link_desc_ring(struct dp_soc *soc, uint32_t mac_id)
+{
+	return soc->sw2rxdma_link_ring[mac_id].hal_srng;
+}
+
+static inline uint32_t
+dp_monitor_get_num_link_desc_ring_entries(struct dp_soc *soc, uint32_t mac_id)
+{
+	struct dp_srng *ring;
+
+	ring = &soc->sw2rxdma_link_ring[mac_id];
+
+	return ring->alloc_size / hal_srng_get_entrysize(soc->hal_soc,
+							 SW2RXDMA_LINK_RELEASE);
+}
+#endif
+
 /**
  * dp_monitor_get_total_link_descs() - Get total link descs
  * @soc: point to soc

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

@@ -349,7 +349,8 @@ enum hal_srng_ring_id {
 #endif
 	HAL_SRNG_WMAC1_TXMON2SW0,
 	HAL_SRNG_SW2TXMON_BUF0,
-	HAL_SRNG_LMAC1_ID_END = (HAL_SRNG_SW2TXMON_BUF0 + 2),
+	HAL_SRNG_WMAC1_SW2RXDMA_LINK_RING = HAL_SRNG_SW2TXMON_BUF0 + 2,
+	HAL_SRNG_LMAC1_ID_END = HAL_SRNG_WMAC1_SW2RXDMA_LINK_RING,
 };
 
 #define HAL_SRNG_DMAC_CMN_ID_END 0
@@ -395,6 +396,7 @@ enum hal_ring_type {
 	TX_MONITOR_BUF,
 	TX_MONITOR_DST,
 	SW2RXDMA_NEW,
+	SW2RXDMA_LINK_RELEASE,
 	MAX_RING_TYPES
 };
 

+ 1 - 0
hal/wifi3.0/kiwi/hal_kiwi.c

@@ -2821,6 +2821,7 @@ struct hal_hw_srng_config hw_srng_table_kiwi[] = {
 	{0},
 #endif
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

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

@@ -2300,6 +2300,7 @@ struct hal_hw_srng_config hw_srng_table_5018[] = {
 	{ /* TX_MONITOR_BUF */ 0},
 	{ /* TX_MONITOR_DST */ 0},
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

+ 1 - 0
hal/wifi3.0/qca5332/hal_5332.c

@@ -2095,6 +2095,7 @@ struct hal_hw_srng_config hw_srng_table_5332[] = {
 		.max_size = HAL_RXDMA_MAX_RING_SIZE_BE,
 		.dmac_cmn_ring = TRUE,
 	},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

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

@@ -1648,6 +1648,7 @@ struct hal_hw_srng_config hw_srng_table_6290[] = {
 	{ /* TX_MONITOR_BUF */ 0},
 	{ /* TX_MONITOR_DST */ 0},
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

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

@@ -1734,6 +1734,7 @@ struct hal_hw_srng_config hw_srng_table_6390[] = {
 	{ /* TX_MONITOR_BUF */ 0},
 	{ /* TX_MONITOR_DST */ 0},
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

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

@@ -2371,6 +2371,7 @@ struct hal_hw_srng_config hw_srng_table_6490[] = {
 	{ /* TX_MONITOR_BUF */ 0},
 	{ /* TX_MONITOR_DST */ 0},
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

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

@@ -2512,6 +2512,7 @@ struct hal_hw_srng_config hw_srng_table_6750[] = {
 	{ /* TX_MONITOR_BUF */ 0},
 	{ /* TX_MONITOR_DST */ 0},
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

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

@@ -1844,6 +1844,7 @@ struct hal_hw_srng_config hw_srng_table_8074[] = {
 	{ /* TX_MONITOR_BUF */ 0},
 	{ /* TX_MONITOR_DST */ 0},
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

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

@@ -1845,6 +1845,7 @@ struct hal_hw_srng_config hw_srng_table_8074v2[] = {
 	{ /* TX_MONITOR_BUF */ 0},
 	{ /* TX_MONITOR_DST */ 0},
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 

+ 1 - 0
hal/wifi3.0/qcn6122/hal_qcn6122.c

@@ -2399,6 +2399,7 @@ struct hal_hw_srng_config hw_srng_table_6122[] = {
 	{ /* TX_MONITOR_BUF */ 0},
 	{ /* TX_MONITOR_DST */ 0},
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

+ 1 - 0
hal/wifi3.0/qcn6432/hal_6432.c

@@ -2278,6 +2278,7 @@ struct hal_hw_srng_config hw_srng_table_6432[] = {
 		.max_size = HAL_RXDMA_MAX_RING_SIZE_BE,
 		.dmac_cmn_ring = TRUE,
 	},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

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

@@ -2400,6 +2400,7 @@ struct hal_hw_srng_config hw_srng_table_9000[] = {
 	{ /* TX_MONITOR_BUF */ 0},
 	{ /* TX_MONITOR_DST */ 0},
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

+ 1 - 0
hal/wifi3.0/qcn9224/v2/hal_9224v2.c

@@ -547,6 +547,7 @@ struct hal_hw_srng_config hw_srng_table_9224v2[] = {
 		.max_size = HAL_RXDMA_MAX_RING_SIZE_BE,
 		.dmac_cmn_ring = TRUE,
 	},
+	{ /* SW2RXDMA_LINK_RELEASE */ 0},
 };
 
 /**

+ 16 - 1
hal/wifi3.0/wcn6450/hal_wcn6450.c

@@ -213,6 +213,20 @@ struct hal_hw_srng_config hw_srng_table_wcn6450[] = {
 	{ /* TX_MONITOR_BUF */ 0},
 	{ /* TX_MONITOR_DST */ 0},
 	{ /* SW2RXDMA_NEW */ 0},
+	{ /* SW2RXDMA_LINK_RELEASE */
+		.start_ring_id = HAL_SRNG_WMAC1_SW2RXDMA_LINK_RING,
+		.max_rings = 1,
+		.entry_size = sizeof(struct wbm_buffer_ring) >> 2,
+		.lmac_ring = TRUE,
+		.ring_dir = HAL_SRNG_SRC_RING,
+		/* reg_start is not set because LMAC rings are not accessed
+		 * from host
+		 */
+		.reg_start = {},
+		.reg_size = {},
+		.max_size = HAL_RXDMA_MAX_RING_SIZE,
+	},
+
 };
 
 static void hal_get_hw_hptp_6450(struct hal_soc *hal_soc,
@@ -260,9 +274,10 @@ static void hal_tx_init_cmd_credit_ring_6450(hal_soc_handle_t hal_soc_hdl,
 {
 }
 
+#define LINK_DESC_SIZE (NUM_OF_DWORDS_RX_MSDU_LINK << 2)
 static uint32_t hal_get_link_desc_size_6450(void)
 {
-	return 0;
+	return LINK_DESC_SIZE;
 }
 
 static void hal_reo_status_get_header_6450(hal_ring_desc_t ring_desc,