瀏覽代碼

qcacmn: Handle special descriptor cases for global tx pool

Handle special descriptor cases for global tx desc pool

Change-Id: I33253b726b1b8a2e7438b3bc1dddcac43ad8fb25
CRs-Fixed: 3592887
Neha Bisht 1 年之前
父節點
當前提交
5e70737f80

+ 6 - 0
dp/inc/cdp_txrx_cmn.h

@@ -177,11 +177,16 @@ struct dp_global_context {
 	struct dp_rx_fst *fst_ctx;
 	struct dp_tx_desc_pool_s *tx_desc[4];
 	struct dp_hw_cookie_conversion_t *tx_cc_ctx[4];
+	struct dp_tx_desc_pool_s *spcl_tx_desc[4];
+	struct dp_hw_cookie_conversion_t *spcl_tx_cc_ctx[4];
 	qdf_atomic_t rx_fst_ref_cnt;
 	qdf_atomic_t global_descriptor_in_use;
 	int tx_cookie_ctx_alloc_cnt;
 	int tx_desc_pool_alloc_cnt;
 	int tx_desc_pool_init_cnt;
+	int spcl_tx_cookie_ctx_alloc_cnt;
+	int spcl_tx_desc_pool_alloc_cnt;
+	int spcl_tx_desc_pool_init_cnt;
 };
 
 /**
@@ -205,6 +210,7 @@ static inline QDF_STATUS cdp_global_ctx_init(void)
 	if (!dp_global)
 		return QDF_STATUS_E_FAILURE;
 
+	qdf_mem_zero(dp_global, sizeof(*dp_global));
 	wlan_objmgr_set_global_ctx(dp_global);
 	qdf_atomic_set(&dp_global->global_descriptor_in_use, 0);
 	dp_global->fst_ctx = NULL;

+ 46 - 3
dp/wifi3.0/be/dp_be.c

@@ -868,6 +868,16 @@ static void dp_soc_tx_cookie_detach_be(struct dp_soc *soc)
 			qdf_mem_free(dp_global->tx_cc_ctx[i]);
 		}
 	}
+
+	dp_global->spcl_tx_cookie_ctx_alloc_cnt--;
+	if (dp_global->spcl_tx_cookie_ctx_alloc_cnt == 0) {
+		for (i = 0; i < MAX_TXDESC_POOLS; i++) {
+			dp_hw_cookie_conversion_detach(
+					be_soc,
+					dp_global->spcl_tx_cc_ctx[i]);
+			qdf_mem_free(dp_global->spcl_tx_cc_ctx[i]);
+		}
+	}
 }
 
 static QDF_STATUS dp_soc_tx_cookie_attach_be(struct dp_soc *soc)
@@ -875,6 +885,7 @@ static QDF_STATUS dp_soc_tx_cookie_attach_be(struct dp_soc *soc)
 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
 	struct dp_hw_cookie_conversion_t *cc_ctx;
 	struct dp_global_context *dp_global;
+	struct dp_hw_cookie_conversion_t *spcl_cc_ctx;
 	uint32_t num_entries;
 	int i = 0;
 	QDF_STATUS qdf_status;
@@ -886,8 +897,8 @@ static QDF_STATUS dp_soc_tx_cookie_attach_be(struct dp_soc *soc)
 				qdf_mem_malloc(
 				sizeof(struct dp_hw_cookie_conversion_t));
 			cc_ctx = dp_global->tx_cc_ctx[i];
-			num_entries = wlan_cfg_get_num_tx_desc(
-					soc->wlan_cfg_ctx);
+			num_entries =
+				wlan_cfg_get_num_tx_desc(soc->wlan_cfg_ctx);
 			qdf_status =
 				dp_hw_cookie_conversion_attach(
 						be_soc,
@@ -899,6 +910,26 @@ static QDF_STATUS dp_soc_tx_cookie_attach_be(struct dp_soc *soc)
 		}
 	}
 	dp_global->tx_cookie_ctx_alloc_cnt++;
+
+	if (dp_global->spcl_tx_cookie_ctx_alloc_cnt == 0) {
+		for (i = 0; i < MAX_TXDESC_POOLS; i++) {
+			dp_global->spcl_tx_cc_ctx[i] =
+				qdf_mem_malloc(
+				sizeof(struct dp_hw_cookie_conversion_t));
+			spcl_cc_ctx = dp_global->spcl_tx_cc_ctx[i];
+			num_entries =
+				wlan_cfg_get_num_tx_spl_desc(soc->wlan_cfg_ctx);
+			qdf_status =
+				dp_hw_cookie_conversion_attach(
+						be_soc,
+						spcl_cc_ctx,
+						num_entries,
+						QDF_DP_TX_SPCL_DESC_TYPE, i);
+			if (!QDF_IS_STATUS_SUCCESS(qdf_status))
+				return QDF_STATUS_E_FAILURE;
+		}
+	}
+	dp_global->spcl_tx_cookie_ctx_alloc_cnt++;
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -914,6 +945,9 @@ static void dp_soc_tx_cookie_deinit_be(struct dp_soc *soc)
 		dp_hw_cookie_conversion_deinit(
 				be_soc,
 				dp_global->tx_cc_ctx[i]);
+	for (i = 0; i < MAX_TXDESC_POOLS; i++)
+		dp_hw_cookie_conversion_deinit(be_soc,
+					       dp_global->spcl_tx_cc_ctx[i]);
 }
 
 static QDF_STATUS dp_soc_tx_cookie_init_be(struct dp_soc *soc)
@@ -921,6 +955,7 @@ static QDF_STATUS dp_soc_tx_cookie_init_be(struct dp_soc *soc)
 	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
 	struct dp_global_context *dp_global;
 	struct dp_hw_cookie_conversion_t *cc_ctx;
+	struct dp_hw_cookie_conversion_t *spcl_cc_ctx;
 	QDF_STATUS qdf_status;
 	int i = 0;
 
@@ -929,7 +964,15 @@ static QDF_STATUS dp_soc_tx_cookie_init_be(struct dp_soc *soc)
 		cc_ctx = dp_global->tx_cc_ctx[i];
 		qdf_status =
 			dp_hw_cookie_conversion_init(be_soc,
-					cc_ctx);
+						     cc_ctx);
+		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
+			return QDF_STATUS_E_FAILURE;
+	}
+	for (i = 0; i < MAX_TXDESC_POOLS; i++) {
+		spcl_cc_ctx = dp_global->spcl_tx_cc_ctx[i];
+		qdf_status =
+			dp_hw_cookie_conversion_init(be_soc,
+						     spcl_cc_ctx);
 		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
 			return QDF_STATUS_E_FAILURE;
 	}

+ 53 - 0
dp/wifi3.0/be/dp_be.h

@@ -134,10 +134,27 @@ enum CMEM_MEM_CLIENTS {
 	((WLAN_CFG_NUM_TX_DESC_MAX / DP_CC_SPT_PAGE_MAX_ENTRIES) * \
 	 DP_CC_PPT_ENTRY_SIZE_4K_ALIGNED)
 
+#ifndef QCA_SUPPORT_DP_GLOBAL_CTX
 /* Offset of rx descripotor pool */
 #define DP_RX_DESC_CMEM_OFFSET \
 	DP_TX_DESC_CMEM_OFFSET + (MAX_TXDESC_POOLS * DP_TX_DESC_POOL_CMEM_SIZE)
 
+#else
+/* tx special descriptor are programmed after tx desc CMEM region*/
+#define DP_TX_SPCL_DESC_CMEM_OFFSET \
+	DP_TX_DESC_CMEM_OFFSET + (MAX_TXDESC_POOLS * DP_TX_DESC_POOL_CMEM_SIZE)
+
+/* size of CMEM needed for a tx special desc pool*/
+#define DP_TX_SPCL_DESC_POOL_CMEM_SIZE \
+	((WLAN_CFG_NUM_TX_SPL_DESC_MAX / DP_CC_SPT_PAGE_MAX_ENTRIES) * \
+	 DP_CC_PPT_ENTRY_SIZE_4K_ALIGNED)
+
+/* Offset of rx descripotor pool */
+#define DP_RX_DESC_CMEM_OFFSET \
+	DP_TX_SPCL_DESC_CMEM_OFFSET + (MAX_TXDESC_POOLS * \
+	DP_TX_SPCL_DESC_POOL_CMEM_SIZE)
+#endif
+
 /* size of CMEM needed for a rx desc pool */
 #define DP_RX_DESC_POOL_CMEM_SIZE \
 	((WLAN_CFG_RX_SW_DESC_NUM_SIZE_MAX / DP_CC_SPT_PAGE_MAX_ENTRIES) * \
@@ -654,6 +671,16 @@ struct dp_hw_cookie_conversion_t *dp_get_tx_cookie_t(struct dp_soc *soc,
 	dp_global = wlan_objmgr_get_global_ctx();
 	return dp_global->tx_cc_ctx[pool_id];
 }
+
+static inline
+struct dp_hw_cookie_conversion_t *dp_get_spcl_tx_cookie_t(struct dp_soc *soc,
+							  uint8_t pool_id)
+{
+	struct dp_global_context *dp_global = NULL;
+
+	dp_global = wlan_objmgr_get_global_ctx();
+	return dp_global->spcl_tx_cc_ctx[pool_id];
+}
 #else
 static inline
 struct dp_hw_cookie_conversion_t *dp_get_tx_cookie_t(struct dp_soc *soc,
@@ -663,6 +690,15 @@ struct dp_hw_cookie_conversion_t *dp_get_tx_cookie_t(struct dp_soc *soc,
 
 	return &be_soc->tx_cc_ctx[pool_id];
 }
+
+static inline
+struct dp_hw_cookie_conversion_t *dp_get_spcl_tx_cookie_t(struct dp_soc *soc,
+							  uint8_t pool_id)
+{
+	struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
+
+	return &be_soc->tx_cc_ctx[pool_id];
+}
 #endif
 
 /**
@@ -957,6 +993,21 @@ _dp_srng_test_and_update_nf_params(struct dp_soc *soc,
 }
 #endif
 
+#ifdef QCA_SUPPORT_DP_GLOBAL_CTX
+static inline
+uint32_t dp_desc_pool_get_spcl_cmem_base(uint8_t desc_pool_id)
+{
+	return (DP_TX_SPCL_DESC_CMEM_OFFSET +
+		(desc_pool_id * DP_TX_SPCL_DESC_POOL_CMEM_SIZE));
+}
+#else
+static inline
+uint32_t dp_desc_pool_get_spcl_cmem_base(uint8_t desc_pool_id)
+{
+	QDF_BUG(0);
+	return 0;
+}
+#endif
 static inline
 uint32_t dp_desc_pool_get_cmem_base(uint8_t chip_id, uint8_t desc_pool_id,
 				    enum qdf_dp_desc_type desc_type)
@@ -965,6 +1016,8 @@ uint32_t dp_desc_pool_get_cmem_base(uint8_t chip_id, uint8_t desc_pool_id,
 	case QDF_DP_TX_DESC_TYPE:
 		return (DP_TX_DESC_CMEM_OFFSET +
 			(desc_pool_id * DP_TX_DESC_POOL_CMEM_SIZE));
+	case QDF_DP_TX_SPCL_DESC_TYPE:
+		return dp_desc_pool_get_spcl_cmem_base(desc_pool_id);
 	case QDF_DP_RX_DESC_BUF_TYPE:
 		return (DP_RX_DESC_CMEM_OFFSET +
 			((chip_id * MAX_RXDESC_POOLS) + desc_pool_id) *

+ 14 - 10
dp/wifi3.0/be/dp_be_tx.c

@@ -1610,11 +1610,11 @@ void dp_tx_update_bank_profile(struct dp_soc_be *be_soc,
 
 QDF_STATUS dp_tx_desc_pool_init_be(struct dp_soc *soc,
 				   uint32_t num_elem,
-				   uint8_t pool_id)
+				   uint8_t pool_id,
+				   bool spcl_tx_desc)
 {
 	struct dp_tx_desc_pool_s *tx_desc_pool;
 	struct dp_hw_cookie_conversion_t *cc_ctx;
-	struct dp_soc_be *be_soc;
 	struct dp_spt_page_desc *page_desc;
 	struct dp_tx_desc_s *tx_desc;
 	uint32_t ppt_idx = 0;
@@ -1625,10 +1625,13 @@ QDF_STATUS dp_tx_desc_pool_init_be(struct dp_soc *soc,
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	be_soc = dp_get_be_soc_from_dp_soc(soc);
-	tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
-	cc_ctx  = dp_get_tx_cookie_t(soc, pool_id);
-
+	if (spcl_tx_desc) {
+		tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, pool_id);
+		cc_ctx  = dp_get_spcl_tx_cookie_t(soc, pool_id);
+	} else {
+		tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);;
+		cc_ctx  = dp_get_tx_cookie_t(soc, pool_id);
+	}
 	tx_desc = tx_desc_pool->freelist;
 	page_desc = &cc_ctx->page_desc_base[0];
 	while (tx_desc) {
@@ -1661,15 +1664,16 @@ QDF_STATUS dp_tx_desc_pool_init_be(struct dp_soc *soc,
 
 void dp_tx_desc_pool_deinit_be(struct dp_soc *soc,
 			       struct dp_tx_desc_pool_s *tx_desc_pool,
-			       uint8_t pool_id)
+			       uint8_t pool_id, bool spcl_tx_desc)
 {
 	struct dp_spt_page_desc *page_desc;
-	struct dp_soc_be *be_soc;
 	int i = 0;
 	struct dp_hw_cookie_conversion_t *cc_ctx;
 
-	be_soc = dp_get_be_soc_from_dp_soc(soc);
-	cc_ctx  = dp_get_tx_cookie_t(soc, pool_id);
+	if (spcl_tx_desc)
+		cc_ctx  = dp_get_spcl_tx_cookie_t(soc, pool_id);
+	else
+		cc_ctx  = dp_get_tx_cookie_t(soc, pool_id);
 
 	for (i = 0; i < cc_ctx->total_page_num; i++) {
 		page_desc = &cc_ctx->page_desc_base[i];

+ 5 - 2
dp/wifi3.0/be/dp_be_tx.h

@@ -213,23 +213,26 @@ void dp_tx_update_bank_profile(struct dp_soc_be *be_soc,
  * @soc: Handle to DP Soc structure
  * @num_elem: number of descriptor in pool
  * @pool_id: pool ID to allocate
+ * @spcl_tx_desc: if special desc
  *
  * Return: QDF_STATUS_SUCCESS - success, others - failure
  */
 QDF_STATUS dp_tx_desc_pool_init_be(struct dp_soc *soc,
 				   uint32_t num_elem,
-				   uint8_t pool_id);
+				   uint8_t pool_id,
+				   bool spcl_tx_desc);
 /**
  * dp_tx_desc_pool_deinit_be() - De-initialize Tx Descriptor pool(s)
  * @soc: Handle to DP Soc structure
  * @tx_desc_pool: Tx descriptor pool handler
  * @pool_id: pool ID to deinit
+ * @spcl_tx_desc: if special desc
  *
  * Return: None
  */
 void dp_tx_desc_pool_deinit_be(struct dp_soc *soc,
 			       struct dp_tx_desc_pool_s *tx_desc_pool,
-			       uint8_t pool_id);
+			       uint8_t pool_id, bool spcl_tx_desc);
 
 #ifdef WLAN_SUPPORT_PPEDS
 /**

+ 172 - 22
dp/wifi3.0/dp_tx.c

@@ -422,7 +422,10 @@ dp_tx_desc_release(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 		    tx_desc->id, comp_status,
 		    qdf_atomic_read(&pdev->num_tx_outstanding));
 
-	dp_tx_desc_free(soc, tx_desc, desc_pool_id);
+	if (tx_desc->nbuf->protocol == QDF_NBUF_TRAC_EAPOL_ETH_TYPE)
+		dp_tx_spcl_desc_free(soc, tx_desc, desc_pool_id);
+	else
+		dp_tx_desc_free(soc, tx_desc, desc_pool_id);
 	return;
 }
 
@@ -1176,7 +1179,10 @@ struct dp_tx_desc_s *dp_tx_prepare_desc_single(struct dp_vdev *vdev,
 		return NULL;
 
 	/* Allocate software Tx descriptor */
-	tx_desc = dp_tx_desc_alloc(soc, desc_pool_id);
+	if (nbuf->protocol == QDF_NBUF_TRAC_EAPOL_ETH_TYPE)
+		tx_desc = dp_tx_spcl_desc_alloc(soc, desc_pool_id);
+	else
+		tx_desc = dp_tx_desc_alloc(soc, desc_pool_id);
 
 	if (qdf_unlikely(!tx_desc)) {
 		DP_STATS_INC(vdev, tx_i.dropped.desc_na.num, 1);
@@ -1322,7 +1328,11 @@ static struct dp_tx_desc_s *dp_tx_prepare_desc(struct dp_vdev *vdev,
 		return NULL;
 
 	/* Allocate software Tx descriptor */
-	tx_desc = dp_tx_desc_alloc(soc, desc_pool_id);
+	if (nbuf->protocol == QDF_NBUF_TRAC_EAPOL_ETH_TYPE)
+		tx_desc = dp_tx_spcl_desc_alloc(soc, desc_pool_id);
+	else
+		tx_desc = dp_tx_desc_alloc(soc, desc_pool_id);
+
 	if (!tx_desc) {
 		DP_STATS_INC(vdev, tx_i.dropped.desc_na.num, 1);
 		return NULL;
@@ -5706,7 +5716,13 @@ dp_tx_comp_process_desc_list(struct dp_soc *soc,
 			if (desc->pool_id != DP_TX_PPEDS_POOL_ID) {
 				nbuf = desc->nbuf;
 				dp_tx_nbuf_dev_queue_free_no_flag(&h, nbuf);
-				dp_tx_desc_free(soc, desc, desc->pool_id);
+				if (nbuf->protocol ==
+						QDF_NBUF_TRAC_EAPOL_ETH_TYPE)
+					dp_tx_spcl_desc_free(soc, desc,
+							     desc->pool_id);
+				else
+					dp_tx_desc_free(soc, desc,
+							desc->pool_id);
 
 				__dp_tx_outstanding_dec(soc);
 			} else {
@@ -6414,16 +6430,32 @@ static QDF_STATUS dp_tx_alloc_static_pools(struct dp_soc *soc, int num_pool,
 	return QDF_STATUS_SUCCESS;
 }
 
+static QDF_STATUS dp_tx_spcl_alloc_static_pools(struct dp_soc *soc,
+						int num_pool,
+						int num_spcl_desc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
 static QDF_STATUS dp_tx_init_static_pools(struct dp_soc *soc, int num_pool,
 					  uint32_t num_desc)
 {
 	return QDF_STATUS_SUCCESS;
 }
 
+static QDF_STATUS dp_tx_spcl_init_static_pools(struct dp_soc *soc, int num_pool,
+					       uint32_t num_spcl_desc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
 static void dp_tx_deinit_static_pools(struct dp_soc *soc, int num_pool)
 {
 }
 
+static void dp_tx_spcl_deinit_static_pools(struct dp_soc *soc, int num_pool)
+{
+}
 static void dp_tx_delete_static_pools(struct dp_soc *soc, int num_pool)
 {
 	uint8_t i;
@@ -6431,6 +6463,10 @@ static void dp_tx_delete_static_pools(struct dp_soc *soc, int num_pool)
 	for (i = 0; i < num_pool; i++)
 		qdf_spinlock_destroy(&soc->tx_desc[i].flow_pool_lock);
 }
+
+static void dp_tx_spcl_delete_static_pools(struct dp_soc *soc, int num_pool)
+{
+}
 #else /* QCA_LL_TX_FLOW_CONTROL_V2! */
 static QDF_STATUS dp_tx_alloc_static_pools(struct dp_soc *soc, int num_pool,
 					   uint32_t num_desc)
@@ -6444,11 +6480,11 @@ static QDF_STATUS dp_tx_alloc_static_pools(struct dp_soc *soc, int num_pool,
 
 	if (dp_global->tx_desc_pool_alloc_cnt == 0) {
 		for (i = 0; i < num_pool; i++) {
-			if (dp_tx_desc_pool_alloc(soc, i, num_desc)) {
+			if (dp_tx_desc_pool_alloc(soc, i, num_desc, false)) {
 			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
 				  FL("Tx Desc Pool alloc %d failed %pK"),
-				  i, soc);
-				goto fail;
+				      i, soc);
+			goto fail;
 			}
 		}
 	}
@@ -6457,8 +6493,37 @@ static QDF_STATUS dp_tx_alloc_static_pools(struct dp_soc *soc, int num_pool,
 
 fail:
 	for (count = 0; count < i; count++)
-		dp_tx_desc_pool_free(soc, count);
+		dp_tx_desc_pool_free(soc, count, false);
+	return QDF_STATUS_E_NOMEM;
+}
+
+static QDF_STATUS dp_tx_spcl_alloc_static_pools(struct dp_soc *soc,
+						int num_pool,
+						uint32_t num_spcl_desc)
+{
+	uint8_t j, count;
+	struct dp_global_context *dp_global;
+
+	dp_global = wlan_objmgr_get_global_ctx();
 
+	/* Allocate software Tx descriptor pools */
+	if (dp_global->spcl_tx_desc_pool_alloc_cnt == 0) {
+		for (j = 0; j < num_pool; j++) {
+			if (dp_tx_desc_pool_alloc(soc, j, num_spcl_desc, true)) {
+				QDF_TRACE(QDF_MODULE_ID_DP,
+					  QDF_TRACE_LEVEL_ERROR,
+					  FL("Tx special Desc Pool alloc %d failed %pK"),
+					      j, soc);
+				goto fail;
+			}
+		}
+	}
+	dp_global->spcl_tx_desc_pool_alloc_cnt++;
+	return QDF_STATUS_SUCCESS;
+
+fail:
+	for (count = 0; count < j; count++)
+		dp_tx_desc_pool_free(soc, count, true);
 	return QDF_STATUS_E_NOMEM;
 }
 
@@ -6472,7 +6537,7 @@ static QDF_STATUS dp_tx_init_static_pools(struct dp_soc *soc, int num_pool,
 
 	if (dp_global->tx_desc_pool_init_cnt == 0) {
 		for (i = 0; i < num_pool; i++) {
-			if (dp_tx_desc_pool_init(soc, i, num_desc)) {
+			if (dp_tx_desc_pool_init(soc, i, num_desc, false)) {
 				QDF_TRACE(QDF_MODULE_ID_DP,
 					  QDF_TRACE_LEVEL_ERROR,
 					  FL("Tx Desc Pool init %d failed %pK"),
@@ -6485,6 +6550,29 @@ static QDF_STATUS dp_tx_init_static_pools(struct dp_soc *soc, int num_pool,
 	return QDF_STATUS_SUCCESS;
 }
 
+static QDF_STATUS dp_tx_spcl_init_static_pools(struct dp_soc *soc, int num_pool,
+					       uint32_t num_spcl_desc)
+{
+	uint8_t i;
+	struct dp_global_context *dp_global;
+
+	dp_global = wlan_objmgr_get_global_ctx();
+
+	if (dp_global->spcl_tx_desc_pool_init_cnt == 0) {
+		for (i = 0; i < num_pool; i++) {
+			if (dp_tx_desc_pool_init(soc, i, num_spcl_desc, true)) {
+				QDF_TRACE(QDF_MODULE_ID_DP,
+					  QDF_TRACE_LEVEL_ERROR,
+					  FL("Tx special Desc Pool init %d failed %pK"),
+					  i, soc);
+				return QDF_STATUS_E_NOMEM;
+			}
+		}
+	}
+	dp_global->spcl_tx_desc_pool_init_cnt++;
+	return QDF_STATUS_SUCCESS;
+}
+
 static void dp_tx_deinit_static_pools(struct dp_soc *soc, int num_pool)
 {
 	uint8_t i;
@@ -6495,7 +6583,21 @@ static void dp_tx_deinit_static_pools(struct dp_soc *soc, int num_pool)
 	dp_global->tx_desc_pool_init_cnt--;
 	if (dp_global->tx_desc_pool_init_cnt == 0) {
 		for (i = 0; i < num_pool; i++)
-			dp_tx_desc_pool_deinit(soc, i);
+			dp_tx_desc_pool_deinit(soc, i, false);
+	}
+}
+
+static void dp_tx_spcl_deinit_static_pools(struct dp_soc *soc, int num_pool)
+{
+	uint8_t i;
+	struct dp_global_context *dp_global;
+
+	dp_global = wlan_objmgr_get_global_ctx();
+
+	dp_global->spcl_tx_desc_pool_init_cnt--;
+	if (dp_global->spcl_tx_desc_pool_init_cnt == 0) {
+		for (i = 0; i < num_pool; i++)
+			dp_tx_desc_pool_deinit(soc, i, true);
 	}
 }
 
@@ -6509,7 +6611,21 @@ static void dp_tx_delete_static_pools(struct dp_soc *soc, int num_pool)
 	dp_global->tx_desc_pool_alloc_cnt--;
 	if (dp_global->tx_desc_pool_alloc_cnt == 0) {
 		for (i = 0; i < num_pool; i++)
-			dp_tx_desc_pool_free(soc, i);
+			dp_tx_desc_pool_free(soc, i, false);
+	}
+}
+
+static void dp_tx_spcl_delete_static_pools(struct dp_soc *soc, int num_pool)
+{
+	uint8_t i;
+	struct dp_global_context *dp_global;
+
+	dp_global = wlan_objmgr_get_global_ctx();
+
+	dp_global->spcl_tx_desc_pool_alloc_cnt--;
+	if (dp_global->spcl_tx_desc_pool_alloc_cnt == 0) {
+		for (i = 0; i < num_pool; i++)
+			dp_tx_desc_pool_free(soc, i, true);
 	}
 }
 #endif /* !QCA_LL_TX_FLOW_CONTROL_V2 */
@@ -6646,36 +6762,44 @@ QDF_STATUS dp_soc_tx_desc_sw_pools_alloc(struct dp_soc *soc)
 {
 	uint8_t num_pool, num_ext_pool;
 	uint32_t num_desc;
+	uint32_t num_spcl_desc;
 	uint32_t num_ext_desc;
 
 	num_pool = wlan_cfg_get_num_tx_desc_pool(soc->wlan_cfg_ctx);
 	num_ext_pool = dp_get_ext_tx_desc_pool_num(soc);
 	num_desc = wlan_cfg_get_num_tx_desc(soc->wlan_cfg_ctx);
+	num_spcl_desc = wlan_cfg_get_num_tx_spl_desc(soc->wlan_cfg_ctx);
 	num_ext_desc = wlan_cfg_get_num_tx_ext_desc(soc->wlan_cfg_ctx);
 
 	dp_info("Tx Desc Alloc num_pool: %d descs: %d", num_pool, num_desc);
 
 	if ((num_pool > MAX_TXDESC_POOLS) ||
 	    (num_ext_pool > MAX_TXDESC_POOLS) ||
-	    (num_desc > WLAN_CFG_NUM_TX_DESC_MAX))
+	    (num_desc > WLAN_CFG_NUM_TX_DESC_MAX) ||
+	    (num_spcl_desc > WLAN_CFG_NUM_TX_SPL_DESC_MAX))
 		goto fail1;
 
 	if (dp_tx_alloc_static_pools(soc, num_pool, num_desc))
 		goto fail1;
 
-	if (dp_tx_ext_desc_pool_alloc(soc, num_ext_pool, num_ext_desc))
+	if (dp_tx_spcl_alloc_static_pools(soc, num_pool, num_spcl_desc))
 		goto fail2;
 
+	if (dp_tx_ext_desc_pool_alloc(soc, num_ext_pool, num_ext_desc))
+		goto fail3;
+
 	if (wlan_cfg_is_tso_desc_attach_defer(soc->wlan_cfg_ctx))
 		return QDF_STATUS_SUCCESS;
 
 	if (dp_tx_tso_cmn_desc_pool_alloc(soc, num_ext_pool, num_ext_desc))
-		goto fail3;
+		goto fail4;
 
 	return QDF_STATUS_SUCCESS;
 
-fail3:
+fail4:
 	dp_tx_ext_desc_pool_free(soc, num_ext_pool);
+fail3:
+	dp_tx_spcl_delete_static_pools(soc, num_pool);
 fail2:
 	dp_tx_delete_static_pools(soc, num_pool);
 fail1:
@@ -6686,31 +6810,38 @@ QDF_STATUS dp_soc_tx_desc_sw_pools_init(struct dp_soc *soc)
 {
 	uint8_t num_pool, num_ext_pool;
 	uint32_t num_desc;
+	uint32_t num_spcl_desc;
 	uint32_t num_ext_desc;
 
 	num_pool = wlan_cfg_get_num_tx_desc_pool(soc->wlan_cfg_ctx);
 	num_ext_pool = dp_get_ext_tx_desc_pool_num(soc);
 	num_desc = wlan_cfg_get_num_tx_desc(soc->wlan_cfg_ctx);
+	num_spcl_desc = wlan_cfg_get_num_tx_spl_desc(soc->wlan_cfg_ctx);
 	num_ext_desc = wlan_cfg_get_num_tx_ext_desc(soc->wlan_cfg_ctx);
 
 	if (dp_tx_init_static_pools(soc, num_pool, num_desc))
 		goto fail1;
 
-	if (dp_tx_ext_desc_pool_init(soc, num_ext_pool, num_ext_desc))
+	if (dp_tx_spcl_init_static_pools(soc, num_pool, num_spcl_desc))
 		goto fail2;
 
+	if (dp_tx_ext_desc_pool_init(soc, num_ext_pool, num_ext_desc))
+		goto fail3;
+
 	if (wlan_cfg_is_tso_desc_attach_defer(soc->wlan_cfg_ctx))
 		return QDF_STATUS_SUCCESS;
 
 	if (dp_tx_tso_cmn_desc_pool_init(soc, num_ext_pool, num_ext_desc))
-		goto fail3;
+		goto fail4;
 
 	dp_tx_flow_control_init(soc);
 	soc->process_tx_status = CONFIG_PROCESS_TX_STATUS;
 	return QDF_STATUS_SUCCESS;
 
-fail3:
+fail4:
 	dp_tx_ext_desc_pool_deinit(soc, num_ext_pool);
+fail3:
+	dp_tx_spcl_deinit_static_pools(soc, num_pool);
 fail2:
 	dp_tx_deinit_static_pools(soc, num_pool);
 fail1:
@@ -6722,38 +6853,57 @@ QDF_STATUS dp_soc_tx_desc_sw_pools_alloc(struct dp_soc *soc)
 {
 	uint8_t num_pool;
 	uint32_t num_desc;
+	uint32_t num_spcl_desc;
 
 	num_pool = wlan_cfg_get_num_tx_desc_pool(soc->wlan_cfg_ctx);
 	num_desc = wlan_cfg_get_num_tx_desc(soc->wlan_cfg_ctx);
+	num_spcl_desc = wlan_cfg_get_num_tx_spl_desc(soc->wlan_cfg_ctx);
 
 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
 		  "%s Tx Desc Alloc num_pool = %d, descs = %d",
 		  __func__, num_pool, num_desc);
 
 	if ((num_pool > MAX_TXDESC_POOLS) ||
-	    (num_desc > WLAN_CFG_NUM_TX_DESC_MAX))
-		return QDF_STATUS_E_RESOURCES;
+	    (num_desc > WLAN_CFG_NUM_TX_DESC_MAX) ||
+	    (num_spcl_desc > WLAN_CFG_NUM_TX_SPL_DESC_MAX))
+		goto fail1;
 
 	if (dp_tx_alloc_static_pools(soc, num_pool, num_desc))
-		return QDF_STATUS_E_RESOURCES;
+		goto fail1;
 
+	if (dp_tx_spcl_alloc_static_pools(soc, num_pool, num_spcl_desc))
+		goto fail2;
 	return QDF_STATUS_SUCCESS;
+
+fail2:
+	dp_tx_delete_static_pools(soc, num_pool);
+fail1:
+	return QDF_STATUS_E_RESOURCES;
 }
 
 QDF_STATUS dp_soc_tx_desc_sw_pools_init(struct dp_soc *soc)
 {
 	uint8_t num_pool;
 	uint32_t num_desc;
+	uint32_t num_spcl_desc;
 
 	num_pool = wlan_cfg_get_num_tx_desc_pool(soc->wlan_cfg_ctx);
 	num_desc = wlan_cfg_get_num_tx_desc(soc->wlan_cfg_ctx);
+	num_spcl_desc = wlan_cfg_get_num_tx_spl_desc(soc->wlan_cfg_ctx);
 
 	if (dp_tx_init_static_pools(soc, num_pool, num_desc))
-		return QDF_STATUS_E_RESOURCES;
+		goto fail;
+
+	if (dp_tx_spcl_init_static_pools(soc, num_pool, num_spcl_desc))
+		goto fail1;
 
 	dp_tx_flow_control_init(soc);
 	soc->process_tx_status = CONFIG_PROCESS_TX_STATUS;
 	return QDF_STATUS_SUCCESS;
+fail1:
+	dp_tx_delete_static_pools(soc, num_pool);
+fail:
+	return QDF_STATUS_E_RESOURCES;
 }
 #endif
 

+ 17 - 0
dp/wifi3.0/dp_tx.h

@@ -1598,6 +1598,16 @@ struct dp_tx_desc_pool_s *dp_get_tx_desc_pool(struct dp_soc *soc,
 	dp_global = wlan_objmgr_get_global_ctx();
 	return dp_global->tx_desc[pool_id];
 }
+
+static inline
+struct dp_tx_desc_pool_s *dp_get_spcl_tx_desc_pool(struct dp_soc *soc,
+						   uint8_t pool_id)
+{
+	struct dp_global_context *dp_global = NULL;
+
+	dp_global = wlan_objmgr_get_global_ctx();
+	return dp_global->spcl_tx_desc[pool_id];
+}
 #else
 static inline
 struct dp_tx_desc_pool_s *dp_get_tx_desc_pool(struct dp_soc *soc,
@@ -1605,6 +1615,13 @@ struct dp_tx_desc_pool_s *dp_get_tx_desc_pool(struct dp_soc *soc,
 {
 	return &soc->tx_desc[pool_id];
 }
+
+static inline
+struct dp_tx_desc_pool_s *dp_get_spcl_tx_desc_pool(struct dp_soc *soc,
+						   uint8_t pool_id)
+{
+	return &soc->tx_desc[pool_id];
+}
 #endif
 
 #ifdef DP_TX_TRACKING

+ 80 - 15
dp/wifi3.0/dp_tx_desc.c

@@ -99,7 +99,7 @@ void dp_tx_desc_pool_cleanup(struct dp_soc *soc, qdf_nbuf_t *nbuf_list)
 {
 	int i;
 	struct dp_tx_desc_pool_s *tx_desc_pool = NULL;
-	uint32_t num_pool = wlan_cfg_get_num_tx_desc_pool(soc->wlan_cfg_ctx);
+	uint8_t num_pool = wlan_cfg_get_num_tx_desc_pool(soc->wlan_cfg_ctx);
 
 	for (i = 0; i < num_pool; i++) {
 		tx_desc_pool = dp_get_tx_desc_pool(soc, i);
@@ -115,20 +115,65 @@ void dp_tx_desc_pool_cleanup(struct dp_soc *soc, qdf_nbuf_t *nbuf_list)
 }
 #endif
 
+#ifdef QCA_SUPPORT_DP_GLOBAL_CTX
+static void dp_tx_desc_pool_alloc_mem(int8_t pool_id, bool spcl_tx_desc)
+{
+	struct dp_global_context *dp_global = NULL;
+
+	dp_global = wlan_objmgr_get_global_ctx();
+
+	if (spcl_tx_desc) {
+		dp_global->spcl_tx_desc[pool_id] =
+			qdf_mem_malloc(sizeof(struct dp_tx_desc_pool_s));
+	} else {
+		dp_global->tx_desc[pool_id] =
+			qdf_mem_malloc(sizeof(struct dp_tx_desc_pool_s));
+	}
+}
+
+static void dp_tx_desc_pool_free_mem(int8_t pool_id, bool spcl_tx_desc)
+{
+	struct dp_global_context *dp_global = NULL;
+
+	dp_global = wlan_objmgr_get_global_ctx();
+	if (spcl_tx_desc)
+		qdf_mem_free(dp_global->spcl_tx_desc[pool_id]);
+	else
+		qdf_mem_free(dp_global->tx_desc[pool_id]);
+}
+#else
+static void dp_tx_desc_pool_alloc_mem(int8_t pool_id, bool spcl_tx_desc)
+{
+}
+
+static void dp_tx_desc_pool_free_mem(int8_t pool_id, bool spcl_tx_desc)
+{
+}
+#endif
+
 QDF_STATUS dp_tx_desc_pool_alloc(struct dp_soc *soc, uint8_t pool_id,
-				 uint32_t num_elem)
+				 uint32_t num_elem, bool spcl_tx_desc)
 {
 	uint32_t desc_size, num_elem_t;
 	struct dp_tx_desc_pool_s *tx_desc_pool;
 	QDF_STATUS status;
+	enum qdf_dp_desc_type desc_type = QDF_DP_TX_DESC_TYPE;
 
-	num_elem_t = dp_get_updated_tx_desc(soc->ctrl_psoc, pool_id, num_elem);
 	desc_size = DP_TX_DESC_SIZE(sizeof(struct dp_tx_desc_s));
 
-	tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
+	dp_tx_desc_pool_alloc_mem(pool_id, spcl_tx_desc);
+	if (spcl_tx_desc) {
+		tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, pool_id);
+		desc_type = QDF_DP_TX_SPCL_DESC_TYPE;
+		num_elem_t = num_elem;
+	} else {
+		tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
+		desc_type = QDF_DP_TX_DESC_TYPE;
+		num_elem_t = dp_get_updated_tx_desc(soc->ctrl_psoc, pool_id, num_elem);
+	}
 
 	tx_desc_pool->desc_pages.page_size = DP_BLOCKMEM_SIZE;
-	dp_desc_multi_pages_mem_alloc(soc, QDF_DP_TX_DESC_TYPE,
+	dp_desc_multi_pages_mem_alloc(soc, desc_type,
 				      &tx_desc_pool->desc_pages,
 				      desc_size, num_elem_t,
 				      0, true);
@@ -148,11 +193,19 @@ QDF_STATUS dp_tx_desc_pool_alloc(struct dp_soc *soc, uint8_t pool_id,
 	return QDF_STATUS_SUCCESS;
 }
 
-void dp_tx_desc_pool_free(struct dp_soc *soc, uint8_t pool_id)
+void dp_tx_desc_pool_free(struct dp_soc *soc, uint8_t pool_id,
+			  bool spcl_tx_desc)
 {
 	struct dp_tx_desc_pool_s *tx_desc_pool;
-
-	tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
+	enum qdf_dp_desc_type desc_type = QDF_DP_TX_DESC_TYPE;
+
+	if (spcl_tx_desc) {
+		tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, pool_id);
+		desc_type = QDF_DP_TX_SPCL_DESC_TYPE;
+	} else {
+		tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
+		desc_type = QDF_DP_TX_DESC_TYPE;
+	}
 
 	if (tx_desc_pool->desc_pages.num_pages)
 		dp_desc_multi_pages_mem_free(soc, QDF_DP_TX_DESC_TYPE,
@@ -161,18 +214,24 @@ void dp_tx_desc_pool_free(struct dp_soc *soc, uint8_t pool_id)
 
 	/* Free arch specific TX descriptor */
 	soc->arch_ops.dp_tx_desc_pool_free(soc, pool_id);
+	dp_tx_desc_pool_free_mem(pool_id, spcl_tx_desc);
 }
 
 QDF_STATUS dp_tx_desc_pool_init(struct dp_soc *soc, uint8_t pool_id,
-				uint32_t num_elem)
+				uint32_t num_elem, bool spcl_tx_desc)
 {
 	struct dp_tx_desc_pool_s *tx_desc_pool = NULL;
 	uint32_t desc_size, num_elem_t;
 
 	desc_size = DP_TX_DESC_SIZE(sizeof(struct dp_tx_desc_s));
 
-	num_elem_t = dp_get_updated_tx_desc(soc->ctrl_psoc, pool_id, num_elem);
-	tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
+	if (spcl_tx_desc) {
+		tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, pool_id);
+		num_elem_t = num_elem;
+	} else {
+		tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
+		num_elem_t = dp_get_updated_tx_desc(soc->ctrl_psoc, pool_id, num_elem);
+	}
 	if (qdf_mem_multi_page_link(soc->osdev,
 				    &tx_desc_pool->desc_pages,
 				    desc_size, num_elem_t, true)) {
@@ -184,7 +243,8 @@ QDF_STATUS dp_tx_desc_pool_init(struct dp_soc *soc, uint8_t pool_id,
 		*tx_desc_pool->desc_pages.cacheable_pages;
 	/* Set unique IDs for each Tx descriptor */
 	if (QDF_STATUS_SUCCESS != soc->arch_ops.dp_tx_desc_pool_init(
-						soc, num_elem_t, pool_id)) {
+						soc, num_elem_t,
+						pool_id, spcl_tx_desc)) {
 		dp_err("initialization per target failed");
 		return QDF_STATUS_E_FAULT;
 	}
@@ -197,12 +257,17 @@ QDF_STATUS dp_tx_desc_pool_init(struct dp_soc *soc, uint8_t pool_id,
 	return QDF_STATUS_SUCCESS;
 }
 
-void dp_tx_desc_pool_deinit(struct dp_soc *soc, uint8_t pool_id)
+void dp_tx_desc_pool_deinit(struct dp_soc *soc, uint8_t pool_id,
+			    bool spcl_tx_desc)
 {
 	struct dp_tx_desc_pool_s *tx_desc_pool;
 
-	tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
-	soc->arch_ops.dp_tx_desc_pool_deinit(soc, tx_desc_pool, pool_id);
+	if (spcl_tx_desc)
+		tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, pool_id);
+	else
+		tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
+	soc->arch_ops.dp_tx_desc_pool_deinit(soc, tx_desc_pool,
+					     pool_id, spcl_tx_desc);
 	TX_DESC_POOL_MEMBER_CLEAN(tx_desc_pool);
 	TX_DESC_LOCK_DESTROY(&tx_desc_pool->lock);
 }

+ 83 - 8
dp/wifi3.0/dp_tx_desc.h

@@ -123,6 +123,7 @@ static inline void dp_tx_desc_set_magic(struct dp_tx_desc_s *tx_desc,
  * @soc: Handle to DP SoC structure
  * @pool_id: pool to allocate
  * @num_elem: Number of descriptor elements per pool
+ * @spcl_tx_desc: if special desc
  *
  * This function allocates memory for SW tx descriptors
  * (used within host for tx data path).
@@ -147,35 +148,40 @@ static inline void dp_tx_desc_set_magic(struct dp_tx_desc_s *tx_desc,
  * Return: Status code. 0 for success.
  */
 QDF_STATUS dp_tx_desc_pool_alloc(struct dp_soc *soc, uint8_t pool_id,
-				 uint32_t num_elem);
+				 uint32_t num_elem, bool spcl_tx_desc);
 
 /**
  * dp_tx_desc_pool_init() - Initialize Tx Descriptor pool(s)
  * @soc: Handle to DP SoC structure
  * @pool_id: pool to allocate
  * @num_elem: Number of descriptor elements per pool
+ * @spcl_tx_desc: if special desc
  *
  * Return: QDF_STATUS_SUCCESS
  *	   QDF_STATUS_E_FAULT
  */
 QDF_STATUS dp_tx_desc_pool_init(struct dp_soc *soc, uint8_t pool_id,
-				uint32_t num_elem);
+				uint32_t num_elem, bool spcl_tx_desc);
 
 /**
  * dp_tx_desc_pool_free() -  Free the tx dexcriptor pools
  * @soc: Handle to DP SoC structure
  * @pool_id: pool to free
+ * @spcl_tx_desc: if special desc
  *
  */
-void dp_tx_desc_pool_free(struct dp_soc *soc, uint8_t pool_id);
+void dp_tx_desc_pool_free(struct dp_soc *soc, uint8_t pool_id,
+			  bool spcl_tx_desc);
 
 /**
  * dp_tx_desc_pool_deinit() - de-initialize Tx Descriptor pool(s)
  * @soc: Handle to DP SoC structure
  * @pool_id: pool to de-initialize
+ * @spcl_tx_desc: if special desc
  *
  */
-void dp_tx_desc_pool_deinit(struct dp_soc *soc, uint8_t pool_id);
+void dp_tx_desc_pool_deinit(struct dp_soc *soc, uint8_t pool_id,
+			    bool spcl_tx_desc);
 
 /**
  * dp_tx_ext_desc_pool_alloc_by_id() - allocate TX extension Descriptor pool
@@ -794,8 +800,8 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 		break;
 	case FLOW_POOL_INVALID:
 		if (pool->avail_desc == pool->pool_size) {
-			dp_tx_desc_pool_deinit(soc, desc_pool_id);
-			dp_tx_desc_pool_free(soc, desc_pool_id);
+			dp_tx_desc_pool_deinit(soc, desc_pool_id, false);
+			dp_tx_desc_pool_free(soc, desc_pool_id, false);
 			qdf_spin_unlock_bh(&pool->flow_pool_lock);
 			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
 				  "%s %d pool is freed!!",
@@ -818,6 +824,18 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 			      act, reason);
 	qdf_spin_unlock_bh(&pool->flow_pool_lock);
 }
+
+static inline void
+dp_tx_spcl_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
+		     uint8_t desc_pool_id)
+{
+}
+
+static inline struct dp_tx_desc_s *dp_tx_spcl_desc_alloc(struct dp_soc *soc,
+							 uint8_t desc_pool_id)
+{
+	return NULL;
+}
 #else /* QCA_AC_BASED_FLOW_CONTROL */
 
 static inline bool
@@ -872,6 +890,10 @@ dp_tx_desc_alloc(struct dp_soc *soc, uint8_t desc_pool_id)
 	return tx_desc;
 }
 
+static inline struct dp_tx_desc_s *dp_tx_spcl_desc_alloc(struct dp_soc *soc,
+							 uint8_t desc_pool_id)
+{
+}
 /**
  * dp_tx_desc_free() - Free a tx descriptor and attach it to free list
  * @soc: Handle to DP SoC structure
@@ -903,8 +925,8 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 		break;
 	case FLOW_POOL_INVALID:
 		if (pool->avail_desc == pool->pool_size) {
-			dp_tx_desc_pool_deinit(soc, desc_pool_id);
-			dp_tx_desc_pool_free(soc, desc_pool_id);
+			dp_tx_desc_pool_deinit(soc, desc_pool_id, false);
+			dp_tx_desc_pool_free(soc, desc_pool_id, false);
 			qdf_spin_unlock_bh(&pool->flow_pool_lock);
 			qdf_print("%s %d pool is freed!!",
 				  __func__, __LINE__);
@@ -923,6 +945,11 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 	qdf_spin_unlock_bh(&pool->flow_pool_lock);
 }
 
+static inline void
+dp_tx_spcl_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
+		     uint8_t desc_pool_id)
+{
+}
 #endif /* QCA_AC_BASED_FLOW_CONTROL */
 
 static inline bool
@@ -1016,6 +1043,36 @@ static inline struct dp_tx_desc_s *dp_tx_desc_alloc(struct dp_soc *soc,
 	return tx_desc;
 }
 
+static inline struct dp_tx_desc_s *dp_tx_spcl_desc_alloc(struct dp_soc *soc,
+							 uint8_t desc_pool_id)
+{
+	struct dp_tx_desc_s *tx_desc = NULL;
+	struct dp_tx_desc_pool_s *pool = NULL;
+
+	pool = dp_get_spcl_tx_desc_pool(soc, desc_pool_id);
+
+	TX_DESC_LOCK_LOCK(&pool->lock);
+
+	tx_desc = pool->freelist;
+
+	/* Pool is exhausted */
+	if (!tx_desc) {
+		TX_DESC_LOCK_UNLOCK(&pool->lock);
+		return NULL;
+	}
+
+	pool->freelist = pool->freelist->next;
+	pool->num_allocated++;
+	pool->num_free--;
+	dp_tx_prefetch_desc(pool->freelist);
+
+	tx_desc->flags = DP_TX_DESC_FLAG_ALLOCATED;
+
+	TX_DESC_LOCK_UNLOCK(&pool->lock);
+
+	return tx_desc;
+}
+
 /**
  * dp_tx_desc_alloc_multiple() - Allocate batch of software Tx Descriptors
  *                            from given pool
@@ -1079,6 +1136,7 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 {
 	struct dp_tx_desc_pool_s *pool = NULL;
 
+	dp_tx_desc_clear(tx_desc);
 	pool = dp_get_tx_desc_pool(soc, desc_pool_id);
 	TX_DESC_LOCK_LOCK(&pool->lock);
 	tx_desc->next = pool->freelist;
@@ -1088,6 +1146,23 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 	TX_DESC_LOCK_UNLOCK(&pool->lock);
 }
 
+static inline void
+dp_tx_spcl_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
+		     uint8_t desc_pool_id)
+{
+	struct dp_tx_desc_pool_s *pool = NULL;
+
+	dp_tx_desc_clear(tx_desc);
+
+	pool = dp_get_spcl_tx_desc_pool(soc, desc_pool_id);
+	TX_DESC_LOCK_LOCK(&pool->lock);
+	tx_desc->next = pool->freelist;
+	pool->freelist = tx_desc;
+	pool->num_allocated--;
+	pool->num_free++;
+	TX_DESC_LOCK_UNLOCK(&pool->lock);
+}
+
 static inline void
 dp_tx_desc_free_list(struct dp_tx_desc_pool_s *pool,
 		     struct dp_tx_desc_s *head_desc,

+ 7 - 7
dp/wifi3.0/dp_tx_flow_control.c

@@ -341,15 +341,15 @@ struct dp_tx_desc_pool_s *dp_tx_create_flow_pool(struct dp_soc *soc,
 		return pool;
 	}
 
-	if (dp_tx_desc_pool_alloc(soc, flow_pool_id, flow_pool_size)) {
+	if (dp_tx_desc_pool_alloc(soc, flow_pool_id, flow_pool_size, false)) {
 		qdf_spin_unlock_bh(&pool->flow_pool_lock);
 		dp_err("dp_tx_desc_pool_alloc failed flow_pool_id: %d",
 			flow_pool_id);
 		return NULL;
 	}
 
-	if (dp_tx_desc_pool_init(soc, flow_pool_id, flow_pool_size)) {
-		dp_tx_desc_pool_free(soc, flow_pool_id);
+	if (dp_tx_desc_pool_init(soc, flow_pool_id, flow_pool_size, false)) {
+		dp_tx_desc_pool_free(soc, flow_pool_id, false);
 		qdf_spin_unlock_bh(&pool->flow_pool_lock);
 		dp_err("dp_tx_desc_pool_init failed flow_pool_id: %d",
 			flow_pool_id);
@@ -490,8 +490,8 @@ int dp_tx_delete_flow_pool(struct dp_soc *soc, struct dp_tx_desc_pool_s *pool,
 	}
 
 	/* We have all the descriptors for the pool, we can delete the pool */
-	dp_tx_desc_pool_deinit(soc, pool->flow_pool_id);
-	dp_tx_desc_pool_free(soc, pool->flow_pool_id);
+	dp_tx_desc_pool_deinit(soc, pool->flow_pool_id, false);
+	dp_tx_desc_pool_free(soc, pool->flow_pool_id, false);
 	qdf_spin_unlock_bh(&pool->flow_pool_lock);
 	return 0;
 }
@@ -683,8 +683,8 @@ static inline void dp_tx_desc_pool_dealloc(struct dp_soc *soc)
 		if (!tx_desc_pool->desc_pages.num_pages)
 			continue;
 
-		dp_tx_desc_pool_deinit(soc, i);
-		dp_tx_desc_pool_free(soc, i);
+		dp_tx_desc_pool_deinit(soc, i, false);
+		dp_tx_desc_pool_free(soc, i, false);
 	}
 }
 

+ 4 - 2
dp/wifi3.0/dp_types.h

@@ -2334,11 +2334,13 @@ struct dp_arch_ops {
 
 	QDF_STATUS (*dp_tx_desc_pool_init)(struct dp_soc *soc,
 					   uint32_t num_elem,
-					   uint8_t pool_id);
+					   uint8_t pool_id,
+					   bool spcl_tx_desc);
 	void (*dp_tx_desc_pool_deinit)(
 				struct dp_soc *soc,
 				struct dp_tx_desc_pool_s *tx_desc_pool,
-				uint8_t pool_id);
+				uint8_t pool_id,
+				bool spcl_tx_desc);
 
 	QDF_STATUS (*dp_rx_desc_pool_init)(struct dp_soc *soc,
 					   struct rx_desc_pool *rx_desc_pool,

+ 7 - 3
dp/wifi3.0/li/dp_li_tx.c

@@ -570,14 +570,18 @@ ring_access_fail:
 
 QDF_STATUS dp_tx_desc_pool_init_li(struct dp_soc *soc,
 				   uint32_t num_elem,
-				   uint8_t pool_id)
+				   uint8_t pool_id,
+				   bool spcl_tx_desc)
 {
 	uint32_t id, count, page_id, offset, pool_id_32;
 	struct dp_tx_desc_s *tx_desc;
 	struct dp_tx_desc_pool_s *tx_desc_pool;
 	uint16_t num_desc_per_page;
 
-	tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
+	if (spcl_tx_desc)
+		tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, pool_id);
+	else
+		tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
 	tx_desc = tx_desc_pool->freelist;
 	count = 0;
 	pool_id_32 = (uint32_t)pool_id;
@@ -601,7 +605,7 @@ QDF_STATUS dp_tx_desc_pool_init_li(struct dp_soc *soc,
 
 void dp_tx_desc_pool_deinit_li(struct dp_soc *soc,
 			       struct dp_tx_desc_pool_s *tx_desc_pool,
-			       uint8_t pool_id)
+			       uint8_t pool_id, bool spcl_tx_desc)
 {
 }
 

+ 5 - 2
dp/wifi3.0/li/dp_li_tx.h

@@ -74,24 +74,27 @@ void dp_tx_process_htt_completion_li(struct dp_soc *soc,
  * @soc: Handle to DP Soc structure
  * @num_elem: pool descriptor number
  * @pool_id: pool to allocate
+ * @spcl_tx_desc: if special desc
  *
  * Return: QDF_STATUS_SUCCESS - success, others - failure
  */
 QDF_STATUS dp_tx_desc_pool_init_li(struct dp_soc *soc,
 				   uint32_t num_elem,
-				   uint8_t pool_id);
+				   uint8_t pool_id,
+				   bool spcl_tx_desc);
 
 /**
  * dp_tx_desc_pool_deinit_li() - De-initialize Tx Descriptor pool(s)
  * @soc: Handle to DP Soc structure
  * @tx_desc_pool: Tx descriptor pool handler
  * @pool_id: pool to deinit
+ * @spcl_tx_desc: if special desc
  *
  * Return: None.
  */
 void dp_tx_desc_pool_deinit_li(struct dp_soc *soc,
 			       struct dp_tx_desc_pool_s *tx_desc_pool,
-			       uint8_t pool_id);
+			       uint8_t pool_id, bool spcl_tx_desc);
 
 /**
  * dp_tx_compute_tx_delay_li() - Compute HW Tx completion delay

+ 3 - 2
dp/wifi3.0/rh/dp_rh_tx.c

@@ -553,7 +553,8 @@ static void dp_tx_alloc_tcl_desc_rh(struct dp_tx_tcl_desc_pool_s *tcl_desc_pool,
 
 QDF_STATUS dp_tx_desc_pool_init_rh(struct dp_soc *soc,
 				   uint32_t num_elem,
-				   uint8_t pool_id)
+				   uint8_t pool_id,
+				   bool spcl_tx_desc)
 {
 	struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc);
 	uint32_t id, count, page_id, offset, pool_id_32;
@@ -623,7 +624,7 @@ err_out:
 
 void dp_tx_desc_pool_deinit_rh(struct dp_soc *soc,
 			       struct dp_tx_desc_pool_s *tx_desc_pool,
-			       uint8_t pool_id)
+			       uint8_t pool_id, bool spcl_tx_desc)
 {
 	dp_tx_tso_num_seg_pool_free_by_id(soc, pool_id);
 	dp_tx_tso_desc_pool_deinit_by_id(soc, pool_id);

+ 5 - 2
dp/wifi3.0/rh/dp_rh_tx.h

@@ -103,24 +103,27 @@ void dp_tx_process_htt_completion_rh(struct dp_soc *soc,
  * @soc: Handle to DP Soc structure
  * @num_elem: pool descriptor number
  * @pool_id: pool to allocate
+ * @spcl_tx_desc: if special desc
  *
  * Return: QDF_STATUS_SUCCESS - success, others - failure
  */
 QDF_STATUS dp_tx_desc_pool_init_rh(struct dp_soc *soc,
 				   uint32_t num_elem,
-				   uint8_t pool_id);
+				   uint8_t pool_id,
+				   bool spcl_tx_desc);
 
 /**
  * dp_tx_desc_pool_deinit_rh() - De-initialize Tx Descriptor pool(s)
  * @soc: Handle to DP Soc structure
  * @tx_desc_pool: Tx descriptor pool handler
  * @pool_id: pool to deinit
+ * @spcl_tx_desc: if special desc
  *
  * Return: None.
  */
 void dp_tx_desc_pool_deinit_rh(struct dp_soc *soc,
 			       struct dp_tx_desc_pool_s *tx_desc_pool,
-			       uint8_t pool_id);
+			       uint8_t pool_id, bool spcl_tx_desc);
 
 /**
  * dp_tx_compute_tx_delay_rh() - Compute HW Tx completion delay

+ 2 - 0
qdf/inc/qdf_types.h

@@ -1806,6 +1806,7 @@ enum qdf_iommu_attr {
 /**
  * enum qdf_dp_desc_type - source type for multiple pages allocation
  * @QDF_DP_TX_DESC_TYPE: DP SW TX descriptor
+ * @QDF_DP_TX_SPCL_DESC_TYPE: DP SW TX special descriptor
  * @QDF_DP_TX_PPEDS_DESC_TYPE: DP PPE-DS Tx descriptor
  * @QDF_DP_TX_EXT_DESC_TYPE: DP TX msdu extension descriptor
  * @QDF_DP_TX_EXT_DESC_LINK_TYPE: DP link descriptor for msdu ext_desc
@@ -1824,6 +1825,7 @@ enum qdf_iommu_attr {
  */
 enum qdf_dp_desc_type {
 	QDF_DP_TX_DESC_TYPE,
+	QDF_DP_TX_SPCL_DESC_TYPE,
 	QDF_DP_TX_PPEDS_DESC_TYPE,
 	QDF_DP_TX_EXT_DESC_TYPE,
 	QDF_DP_TX_EXT_DESC_LINK_TYPE,