瀏覽代碼

qcacmn: Add TX descriptor changes for WCN6450

WCN6450 is a chip based on Rhine architecture. Unlike LI/BE targets,
chipsets based on Rhine (RH) do not have host facing UMAC HW blocks.
Their corresponding SRNG interfaces are also removed. The functionality
of these UMAC HW blocks is replaced with a software implementation in
the firmware. Communication between the driver and firmware will happen
over copy engine (CE).

Although there are no host facing UMAC HW blocks, the CE hardware used
in WCN6450 expects the host driver to use the TX descriptor (HW) format
of LI targets during TX packet enqueue. Therefore it is required to
create a new pool of TX descriptors (HW) pool for WCN6450 that is used
during TX.

The logic to create/free/init/deinit these descriptors is specific
to WCN6450/Rhine, therefore it is implemented in architecture specific
Rhine code.

Introduce new APIs in struct dp_arch_ops {} to allocate and free
arch specific TX descriptors. These ops will be no-op for LI/BE
architectures.

Also for Rhine targets, allocate/free other TX descriptors like TX EXT &
TSO descriptors as part of the arch APIs.

Change-Id: I452ac69143395881ab8580355a0f75571dc3e929
CRs-Fixed: 3381711
Manikanta Pubbisetty 2 年之前
父節點
當前提交
6758a546bc

+ 2 - 0
dp/wifi3.0/be/dp_be.c

@@ -2693,6 +2693,8 @@ void dp_initialize_arch_ops_be(struct dp_arch_ops *arch_ops)
 		dp_tx_comp_get_params_from_hal_desc_be;
 	arch_ops->dp_tx_process_htt_completion =
 				dp_tx_process_htt_completion_be;
+	arch_ops->dp_tx_desc_pool_alloc = dp_tx_desc_pool_alloc_be;
+	arch_ops->dp_tx_desc_pool_free = dp_tx_desc_pool_free_be;
 	arch_ops->dp_tx_desc_pool_init = dp_tx_desc_pool_init_be;
 	arch_ops->dp_tx_desc_pool_deinit = dp_tx_desc_pool_deinit_be;
 	arch_ops->dp_rx_desc_pool_init = dp_rx_desc_pool_init_be;

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

@@ -1844,3 +1844,13 @@ release_desc:
 	return nbuf;
 }
 #endif
+
+QDF_STATUS dp_tx_desc_pool_alloc_be(struct dp_soc *soc, uint32_t num_elem,
+				    uint8_t pool_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+void dp_tx_desc_pool_free_be(struct dp_soc *soc, uint8_t pool_id)
+{
+}

+ 20 - 0
dp/wifi3.0/be/dp_be_tx.h

@@ -336,4 +336,24 @@ QDF_STATUS dp_tx_compute_tx_delay_be(struct dp_soc *soc,
 				     struct dp_vdev *vdev,
 				     struct hal_tx_completion_status *ts,
 				     uint32_t *delay_us);
+
+/**
+ * dp_tx_desc_pool_alloc_be() - Allocate TX descriptor pool
+ * @soc: Handle to DP Soc structure
+ * @num_elem: Number of elements to allocate
+ * @pool_id: TCL descriptor pool ID
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS dp_tx_desc_pool_alloc_be(struct dp_soc *soc, uint32_t num_elem,
+				    uint8_t pool_id);
+
+/**
+ * dp_tx_desc_pool_free_be() - Free TX descriptor pool
+ * @soc: Handle to DP Soc structure
+ * @pool_id: TCL descriptor pool ID
+ *
+ * Return: none
+ */
+void dp_tx_desc_pool_free_be(struct dp_soc *soc, uint8_t pool_id);
 #endif

+ 12 - 0
dp/wifi3.0/dp_tx_desc.c

@@ -120,6 +120,7 @@ QDF_STATUS dp_tx_desc_pool_alloc(struct dp_soc *soc, uint8_t pool_id,
 {
 	uint32_t desc_size;
 	struct dp_tx_desc_pool_s *tx_desc_pool;
+	QDF_STATUS status;
 
 	desc_size = DP_TX_DESC_SIZE(sizeof(struct dp_tx_desc_s));
 	tx_desc_pool = &((soc)->tx_desc[(pool_id)]);
@@ -133,6 +134,14 @@ QDF_STATUS dp_tx_desc_pool_alloc(struct dp_soc *soc, uint8_t pool_id,
 		dp_err("Multi page alloc fail, tx desc");
 		return QDF_STATUS_E_NOMEM;
 	}
+
+	/* Arch specific TX descriptor allocation */
+	status = soc->arch_ops.dp_tx_desc_pool_alloc(soc, num_elem, pool_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("failed to allocate arch specific descriptors");
+		return QDF_STATUS_E_NOMEM;
+	}
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -146,6 +155,9 @@ void dp_tx_desc_pool_free(struct dp_soc *soc, uint8_t pool_id)
 		dp_desc_multi_pages_mem_free(soc, DP_TX_DESC_TYPE,
 					     &tx_desc_pool->desc_pages, 0,
 					     true);
+
+	/* Free arch specific TX descriptor */
+	soc->arch_ops.dp_tx_desc_pool_free(soc, pool_id);
 }
 
 QDF_STATUS dp_tx_desc_pool_init(struct dp_soc *soc, uint8_t pool_id,

+ 11 - 0
dp/wifi3.0/dp_tx_desc.h

@@ -31,12 +31,23 @@
  * 5 bits offset id 0 ~ 31 (Desc size = 128, Num descs per page = 4096/128 = 32)
  */
 /* ???Ring ID needed??? */
+
+/* TODO: Need to revisit this change for Rhine */
+#ifdef WLAN_SOFTUMAC_SUPPORT
+#define DP_TX_DESC_ID_POOL_MASK    0x018000
+#define DP_TX_DESC_ID_POOL_OS      15
+#define DP_TX_DESC_ID_PAGE_MASK    0x007FF0
+#define DP_TX_DESC_ID_PAGE_OS      4
+#define DP_TX_DESC_ID_OFFSET_MASK  0x00000F
+#define DP_TX_DESC_ID_OFFSET_OS    0
+#else
 #define DP_TX_DESC_ID_POOL_MASK    0x018000
 #define DP_TX_DESC_ID_POOL_OS      15
 #define DP_TX_DESC_ID_PAGE_MASK    0x007FE0
 #define DP_TX_DESC_ID_PAGE_OS      5
 #define DP_TX_DESC_ID_OFFSET_MASK  0x00001F
 #define DP_TX_DESC_ID_OFFSET_OS    0
+#endif /* WLAN_SOFTUMAC_SUPPORT */
 
 /*
  * Compilation assert on tx desc size

+ 15 - 0
dp/wifi3.0/dp_types.h

@@ -518,6 +518,7 @@ enum dp_ctxt_type {
  * @DP_RX_DESC_STATUS_TYPE: DP RX SW descriptor for monitor status
  * @DP_HW_LINK_DESC_TYPE: DP HW link descriptor
  * @DP_HW_CC_SPT_PAGE_TYPE: DP pages for HW CC secondary page table
+ * @DP_TX_TCL_DESC_TYPE: DP TCL descriptor
  */
 enum dp_desc_type {
 	DP_TX_DESC_TYPE,
@@ -530,6 +531,7 @@ enum dp_desc_type {
 	DP_RX_DESC_STATUS_TYPE,
 	DP_HW_LINK_DESC_TYPE,
 	DP_HW_CC_SPT_PAGE_TYPE,
+	DP_TX_TCL_DESC_TYPE,
 };
 
 /**
@@ -638,6 +640,8 @@ struct dp_tx_ext_desc_pool_s {
  * @msdu_ext_desc: MSDU extension descriptor
  * @timestamp:
  * @comp:
+ * @tcl_cmd_vaddr: VADDR of the TCL descriptor, valid for soft-umac arch
+ * @tcl_cmd_paddr: PADDR of the TCL descriptor, valid for soft-umac arch
  */
 struct dp_tx_desc_s {
 	struct dp_tx_desc_s *next;
@@ -664,6 +668,10 @@ struct dp_tx_desc_s {
 	struct dp_tx_ext_desc_elem_s *msdu_ext_desc;
 	qdf_ktime_t timestamp;
 	struct hal_tx_desc_comp_s comp;
+#ifdef WLAN_SOFTUMAC_SUPPORT
+	void *tcl_cmd_vaddr;
+	qdf_dma_addr_t tcl_cmd_paddr;
+#endif
 };
 
 #ifdef QCA_AC_BASED_FLOW_CONTROL
@@ -2205,6 +2213,8 @@ enum dp_context_type {
  * @dp_free_ppeds_interrupts:
  * @dp_rx_wbm_err_reap_desc: Reap WBM Error Ring Descriptor
  * @dp_rx_null_q_desc_handle: Handle Null Queue Exception Error
+ * @dp_tx_desc_pool_alloc: Allocate arch specific TX descriptor pool
+ * @dp_tx_desc_pool_free: Free arch specific TX descriptor pool
  */
 struct dp_arch_ops {
 	/* INIT/DEINIT Arch Ops */
@@ -2433,6 +2443,11 @@ struct dp_arch_ops {
 					       struct dp_txrx_peer *txrx_peer,
 					       bool is_reo_exception,
 					       uint8_t link_id);
+
+	QDF_STATUS (*dp_tx_desc_pool_alloc)(struct dp_soc *soc,
+					    uint32_t num_elem,
+					    uint8_t pool_id);
+	void (*dp_tx_desc_pool_free)(struct dp_soc *soc, uint8_t pool_id);
 };
 
 /**

+ 2 - 0
dp/wifi3.0/li/dp_li.c

@@ -613,6 +613,8 @@ void dp_initialize_arch_ops_li(struct dp_arch_ops *arch_ops)
 			dp_tx_process_htt_completion_li;
 	arch_ops->dp_wbm_get_rx_desc_from_hal_desc =
 			dp_wbm_get_rx_desc_from_hal_desc_li;
+	arch_ops->dp_tx_desc_pool_alloc = dp_tx_desc_pool_alloc_li;
+	arch_ops->dp_tx_desc_pool_free = dp_tx_desc_pool_free_li;
 	arch_ops->dp_tx_desc_pool_init = dp_tx_desc_pool_init_li;
 	arch_ops->dp_tx_desc_pool_deinit = dp_tx_desc_pool_deinit_li;
 	arch_ops->dp_rx_desc_pool_init = dp_rx_desc_pool_init_li;

+ 10 - 0
dp/wifi3.0/li/dp_li_tx.c

@@ -603,3 +603,13 @@ QDF_STATUS dp_tx_compute_tx_delay_li(struct dp_soc *soc,
 {
 	return dp_tx_compute_hw_delay_li(soc, vdev, ts, delay_us);
 }
+
+QDF_STATUS dp_tx_desc_pool_alloc_li(struct dp_soc *soc, uint32_t num_elem,
+				    uint8_t pool_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+void dp_tx_desc_pool_free_li(struct dp_soc *soc, uint8_t pool_id)
+{
+}

+ 20 - 0
dp/wifi3.0/li/dp_li_tx.h

@@ -106,4 +106,24 @@ QDF_STATUS dp_tx_compute_tx_delay_li(struct dp_soc *soc,
 				     struct dp_vdev *vdev,
 				     struct hal_tx_completion_status *ts,
 				     uint32_t *delay_us);
+
+/**
+ * dp_tx_desc_pool_alloc_li() - Allocate TX descriptor pool
+ * @soc: Handle to DP Soc structure
+ * @num_elem: Number of elements to allocate
+ * @pool_id: TCL descriptor pool ID
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS dp_tx_desc_pool_alloc_li(struct dp_soc *soc, uint32_t num_elem,
+				    uint8_t pool_id);
+
+/**
+ * dp_tx_desc_pool_free_li() - Free TX descriptor pool
+ * @soc: Handle to DP Soc structure
+ * @pool_id: TCL descriptor pool ID
+ *
+ * Return: none
+ */
+void dp_tx_desc_pool_free_li(struct dp_soc *soc, uint8_t pool_id);
 #endif

+ 2 - 0
dp/wifi3.0/rh/dp_rh.c

@@ -415,6 +415,8 @@ void dp_initialize_arch_ops_rh(struct dp_arch_ops *arch_ops)
 			dp_tx_process_htt_completion_rh;
 	arch_ops->dp_wbm_get_rx_desc_from_hal_desc =
 			dp_wbm_get_rx_desc_from_hal_desc_rh;
+	arch_ops->dp_tx_desc_pool_alloc = dp_tx_desc_pool_alloc_rh;
+	arch_ops->dp_tx_desc_pool_free = dp_tx_desc_pool_free_rh;
 	arch_ops->dp_tx_desc_pool_init = dp_tx_desc_pool_init_rh;
 	arch_ops->dp_tx_desc_pool_deinit = dp_tx_desc_pool_deinit_rh;
 	arch_ops->dp_rx_desc_pool_init = dp_rx_desc_pool_init_rh;

+ 13 - 0
dp/wifi3.0/rh/dp_rh.h

@@ -23,13 +23,16 @@
 #include <hal_rh_tx.h>
 #include <hal_rh_rx.h>
 #include <qdf_pkt_add_timestamp.h>
+#include "dp_rh_tx.h"
 
 /**
  * struct dp_soc_rh - Extended DP soc for RH targets
  * @soc: dp soc structure
+ * @tcl_desc_pool: A pool of TCL descriptors that are allocated for RH targets
  */
 struct dp_soc_rh {
 	struct dp_soc soc;
+	struct dp_tx_tcl_desc_pool_s tcl_desc_pool[MAX_TXDESC_POOLS];
 };
 
 /**
@@ -105,4 +108,14 @@ qdf_size_t dp_get_context_size_rh(enum dp_context_type context_type);
 
 qdf_size_t dp_mon_get_context_size_rh(enum dp_context_type context_type);
 
+/**
+ * dp_get_rh_soc_from_dp_soc() - get dp_soc_rh from dp_soc
+ * @soc: dp_soc pointer
+ *
+ * Return: dp_soc_rh pointer
+ */
+static inline struct dp_soc_rh *dp_get_rh_soc_from_dp_soc(struct dp_soc *soc)
+{
+	return (struct dp_soc_rh *)soc;
+}
 #endif

+ 244 - 0
dp/wifi3.0/rh/dp_rh_tx.c

@@ -54,16 +54,193 @@ dp_tx_hw_enqueue_rh(struct dp_soc *soc, struct dp_vdev *vdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * dp_tx_tcl_desc_pool_alloc_rh() - Allocate the tcl descriptor pool
+ *				    based on pool_id
+ * @soc: Handle to DP SoC structure
+ * @num_elem: Number of descriptor elements per pool
+ * @pool_id: Pool to allocate
+ *
+ * Return: QDF_STATUS_SUCCESS
+ *	   QDF_STATUS_E_NOMEM
+ */
+static QDF_STATUS
+dp_tx_tcl_desc_pool_alloc_rh(struct dp_soc *soc, uint32_t num_elem,
+			     uint8_t pool_id)
+{
+	struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc);
+	struct dp_tx_tcl_desc_pool_s *tcl_desc_pool;
+	uint16_t elem_size = DP_RH_TX_TCL_DESC_SIZE;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	qdf_dma_context_t memctx = 0;
+
+	if (pool_id > MAX_TXDESC_POOLS - 1)
+		return QDF_STATUS_E_INVAL;
+
+	/* Allocate tcl descriptors in coherent memory */
+	tcl_desc_pool = &rh_soc->tcl_desc_pool[pool_id];
+	memctx = qdf_get_dma_mem_context(tcl_desc_pool, memctx);
+	dp_desc_multi_pages_mem_alloc(soc, DP_TX_TCL_DESC_TYPE,
+				      &tcl_desc_pool->desc_pages,
+				      elem_size, num_elem, memctx, false);
+
+	if (!tcl_desc_pool->desc_pages.num_pages) {
+		dp_err("failed to allocate tcl desc Pages");
+		status = QDF_STATUS_E_NOMEM;
+		goto err_alloc_fail;
+	}
+
+	return status;
+
+err_alloc_fail:
+	dp_desc_multi_pages_mem_free(soc, DP_TX_TCL_DESC_TYPE,
+				     &tcl_desc_pool->desc_pages,
+				     memctx, false);
+	return status;
+}
+
+/**
+ * dp_tx_tcl_desc_pool_free_rh() -  Free the tcl descriptor pool
+ * @soc: Handle to DP SoC structure
+ * @pool_id: pool to free
+ *
+ */
+static void dp_tx_tcl_desc_pool_free_rh(struct dp_soc *soc, uint8_t pool_id)
+{
+	struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc);
+	struct dp_tx_tcl_desc_pool_s *tcl_desc_pool;
+	qdf_dma_context_t memctx = 0;
+
+	if (pool_id > MAX_TXDESC_POOLS - 1)
+		return;
+
+	tcl_desc_pool = &rh_soc->tcl_desc_pool[pool_id];
+	memctx = qdf_get_dma_mem_context(tcl_desc_pool, memctx);
+
+	dp_desc_multi_pages_mem_free(soc, DP_TX_TCL_DESC_TYPE,
+				     &tcl_desc_pool->desc_pages,
+				     memctx, false);
+}
+
+/**
+ * dp_tx_tcl_desc_pool_init_rh() - Initialize tcl descriptor pool
+ *				   based on pool_id
+ * @soc: Handle to DP SoC structure
+ * @num_elem: Number of descriptor elements per pool
+ * @pool_id: pool to initialize
+ *
+ * Return: QDF_STATUS_SUCCESS
+ *	   QDF_STATUS_E_FAULT
+ */
+static QDF_STATUS
+dp_tx_tcl_desc_pool_init_rh(struct dp_soc *soc, uint32_t num_elem,
+			    uint8_t pool_id)
+{
+	struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc);
+	struct dp_tx_tcl_desc_pool_s *tcl_desc_pool;
+	struct qdf_mem_dma_page_t *page_info;
+	QDF_STATUS status;
+
+	tcl_desc_pool = &rh_soc->tcl_desc_pool[pool_id];
+	tcl_desc_pool->elem_size = DP_RH_TX_TCL_DESC_SIZE;
+	tcl_desc_pool->elem_count = num_elem;
+
+	/* Link tcl descriptors into a freelist */
+	if (qdf_mem_multi_page_link(soc->osdev, &tcl_desc_pool->desc_pages,
+				    tcl_desc_pool->elem_size,
+				    tcl_desc_pool->elem_count,
+				    false)) {
+		dp_err("failed to link tcl desc Pages");
+		status = QDF_STATUS_E_FAULT;
+		goto err_link_fail;
+	}
+
+	page_info = tcl_desc_pool->desc_pages.dma_pages;
+	tcl_desc_pool->freelist = (uint32_t *)page_info->page_v_addr_start;
+
+	return QDF_STATUS_SUCCESS;
+
+err_link_fail:
+	return status;
+}
+
+/**
+ * dp_tx_tcl_desc_pool_deinit_rh() - De-initialize tcl descriptor pool
+ *				     based on pool_id
+ * @soc: Handle to DP SoC structure
+ * @pool_id: pool to de-initialize
+ *
+ */
+static void dp_tx_tcl_desc_pool_deinit_rh(struct dp_soc *soc, uint8_t pool_id)
+{
+}
+
+/**
+ * dp_tx_alloc_tcl_desc_rh() - Allocate a tcl descriptor from the pool
+ * @tcl_desc_pool: Tcl descriptor pool
+ * @tx_desc: SW TX descriptor
+ * @index: Index into the tcl descriptor pool
+ */
+static void dp_tx_alloc_tcl_desc_rh(struct dp_tx_tcl_desc_pool_s *tcl_desc_pool,
+				    struct dp_tx_desc_s *tx_desc,
+				    uint32_t index)
+{
+	struct qdf_mem_dma_page_t *dma_page;
+	uint32_t page_id;
+	uint32_t offset;
+
+	tx_desc->tcl_cmd_vaddr = (void *)tcl_desc_pool->freelist;
+
+	if (tcl_desc_pool->freelist)
+		tcl_desc_pool->freelist =
+			*((uint32_t **)tcl_desc_pool->freelist);
+
+	page_id = index / tcl_desc_pool->desc_pages.num_element_per_page;
+	offset = index % tcl_desc_pool->desc_pages.num_element_per_page;
+	dma_page = &tcl_desc_pool->desc_pages.dma_pages[page_id];
+
+	tx_desc->tcl_cmd_paddr =
+		dma_page->page_p_addr + offset * tcl_desc_pool->elem_size;
+}
+
 QDF_STATUS dp_tx_desc_pool_init_rh(struct dp_soc *soc,
 				   uint32_t num_elem,
 				   uint8_t pool_id)
 {
+	struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc);
 	uint32_t id, count, page_id, offset, pool_id_32;
 	struct dp_tx_desc_s *tx_desc;
+	struct dp_tx_tcl_desc_pool_s *tcl_desc_pool;
 	struct dp_tx_desc_pool_s *tx_desc_pool;
 	uint16_t num_desc_per_page;
+	QDF_STATUS status;
+
+	status = dp_tx_tcl_desc_pool_init_rh(soc, num_elem, pool_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("failed to initialise tcl desc pool %d", pool_id);
+		goto err_out;
+	}
+
+	status = dp_tx_ext_desc_pool_init_by_id(soc, num_elem, pool_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("failed to initialise tx ext desc pool %d", pool_id);
+		goto err_deinit_tcl_pool;
+	}
+
+	status = dp_tx_tso_desc_pool_init_by_id(soc, num_elem, pool_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("failed to initialise tso desc pool %d", pool_id);
+		goto err_deinit_tx_ext_pool;
+	}
+
+	status = dp_tx_tso_num_seg_pool_init_by_id(soc, num_elem, pool_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("failed to initialise tso num seg pool %d", pool_id);
+		goto err_deinit_tso_pool;
+	}
 
 	tx_desc_pool = &soc->tx_desc[pool_id];
+	tcl_desc_pool = &rh_soc->tcl_desc_pool[pool_id];
 	tx_desc = tx_desc_pool->freelist;
 	count = 0;
 	pool_id_32 = (uint32_t)pool_id;
@@ -77,17 +254,33 @@ QDF_STATUS dp_tx_desc_pool_init_rh(struct dp_soc *soc,
 		tx_desc->id = id;
 		tx_desc->pool_id = pool_id;
 		dp_tx_desc_set_magic(tx_desc, DP_TX_MAGIC_PATTERN_FREE);
+		dp_tx_alloc_tcl_desc_rh(tcl_desc_pool, tx_desc, count);
 		tx_desc = tx_desc->next;
 		count++;
 	}
 
 	return QDF_STATUS_SUCCESS;
+
+err_deinit_tso_pool:
+	dp_tx_tso_desc_pool_deinit_by_id(soc, pool_id);
+err_deinit_tx_ext_pool:
+	dp_tx_ext_desc_pool_deinit_by_id(soc, pool_id);
+err_deinit_tcl_pool:
+	dp_tx_tcl_desc_pool_deinit_rh(soc, pool_id);
+err_out:
+	/* TODO: is assert needed ? */
+	qdf_assert_always(0);
+	return status;
 }
 
 void dp_tx_desc_pool_deinit_rh(struct dp_soc *soc,
 			       struct dp_tx_desc_pool_s *tx_desc_pool,
 			       uint8_t pool_id)
 {
+	dp_tx_tso_num_seg_pool_free_by_id(soc, pool_id);
+	dp_tx_tso_desc_pool_deinit_by_id(soc, pool_id);
+	dp_tx_ext_desc_pool_deinit_by_id(soc, pool_id);
+	dp_tx_tcl_desc_pool_deinit_rh(soc, pool_id);
 }
 
 QDF_STATUS dp_tx_compute_tx_delay_rh(struct dp_soc *soc,
@@ -97,3 +290,54 @@ QDF_STATUS dp_tx_compute_tx_delay_rh(struct dp_soc *soc,
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+QDF_STATUS dp_tx_desc_pool_alloc_rh(struct dp_soc *soc, uint32_t num_elem,
+				    uint8_t pool_id)
+{
+	QDF_STATUS status;
+
+	status = dp_tx_tcl_desc_pool_alloc_rh(soc, num_elem, pool_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("failed to allocate tcl desc pool %d\n", pool_id);
+		goto err_tcl_desc_pool;
+	}
+
+	status = dp_tx_ext_desc_pool_alloc_by_id(soc, num_elem, pool_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("failed to allocate tx ext desc pool %d\n", pool_id);
+		goto err_free_tcl_pool;
+	}
+
+	status = dp_tx_tso_desc_pool_alloc_by_id(soc, num_elem, pool_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("failed to allocate tso desc pool %d\n", pool_id);
+		goto err_free_tx_ext_pool;
+	}
+
+	status = dp_tx_tso_num_seg_pool_alloc_by_id(soc, num_elem, pool_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("failed to allocate tso num seg pool %d\n", pool_id);
+		goto err_free_tso_pool;
+	}
+
+	return status;
+
+err_free_tso_pool:
+	dp_tx_tso_desc_pool_free_by_id(soc, pool_id);
+err_free_tx_ext_pool:
+	dp_tx_ext_desc_pool_free_by_id(soc, pool_id);
+err_free_tcl_pool:
+	dp_tx_tcl_desc_pool_free_rh(soc, pool_id);
+err_tcl_desc_pool:
+	/* TODO: is assert needed ? */
+	qdf_assert_always(0);
+	return status;
+}
+
+void dp_tx_desc_pool_free_rh(struct dp_soc *soc, uint8_t pool_id)
+{
+	dp_tx_tso_num_seg_pool_free_by_id(soc, pool_id);
+	dp_tx_tso_desc_pool_free_by_id(soc, pool_id);
+	dp_tx_ext_desc_pool_free_by_id(soc, pool_id);
+	dp_tx_tcl_desc_pool_free_rh(soc, pool_id);
+}

+ 41 - 0
dp/wifi3.0/rh/dp_rh_tx.h

@@ -20,6 +20,27 @@
 
 #include <dp_types.h>
 
+#define DP_RH_TX_TLV_HDR_SIZE	sizeof(struct tlv_32_hdr)
+#define DP_RH_TX_TCL_DESC_SIZE	(HAL_TX_DESC_LEN_BYTES + DP_RH_TX_TLV_HDR_SIZE)
+
+/*
+ * NB: intentionally not using kernel-doc comment because the kernel-doc
+ *     script does not handle the qdf_dma_mem_context macro
+ * struct dp_tx_tcl_desc_pool_s - Tx Extension Descriptor Pool
+ * @elem_count: Number of descriptors in the pool
+ * @elem_size: Size of each descriptor
+ * @desc_pages: multiple page allocation information for actual descriptors
+ * @freelist: freelist of TCL descriptors
+ * @memctx:
+ */
+struct dp_tx_tcl_desc_pool_s {
+	uint16_t elem_count;
+	int elem_size;
+	struct qdf_mem_multi_page_t desc_pages;
+	uint32_t *freelist;
+	qdf_dma_mem_context(memctx);
+};
+
 /**
  * dp_tx_hw_enqueue_rh() - Enqueue to TCL HW for transmit
  * @soc: DP Soc Handle
@@ -105,4 +126,24 @@ QDF_STATUS dp_tx_compute_tx_delay_rh(struct dp_soc *soc,
 				     struct dp_vdev *vdev,
 				     struct hal_tx_completion_status *ts,
 				     uint32_t *delay_us);
+
+/**
+ * dp_tx_desc_pool_alloc_rh() - Allocate coherent memory for TCL descriptors
+ * @soc: Handle to DP Soc structure
+ * @num_elem: Number of elements to allocate
+ * @pool_id: TCL descriptor pool ID
+ *
+ * Return: QDF_STATUS_SUCCESS - success, others - failure
+ */
+QDF_STATUS dp_tx_desc_pool_alloc_rh(struct dp_soc *soc, uint32_t num_elem,
+				    uint8_t pool_id);
+
+/**
+ * dp_tx_desc_pool_free_rh() - Free TCL descriptor memory
+ * @soc: Handle to DP Soc structure
+ * @pool_id: TCL descriptor pool ID
+ *
+ * Return: none
+ */
+void dp_tx_desc_pool_free_rh(struct dp_soc *soc, uint8_t pool_id);
 #endif