Эх сурвалжийг харах

qcacmn: Initialize DMA rings using hal_srng APIs

Initialize DMA rings for CIR/CFR capture and program them
to firmware.

Change-Id: I41c32cddc3fc0f7f0a972bf69ecbacfc9f0626f7
CRs-Fixed: 2053958
Naveen Rawat 8 жил өмнө
parent
commit
ba24c486a3

+ 3 - 0
hal/wifi3.0/hal_api.h

@@ -157,6 +157,9 @@ enum hal_ring_type {
 	RXDMA_MONITOR_STATUS,
 	RXDMA_MONITOR_DST,
 	RXDMA_MONITOR_DESC,
+#ifdef WLAN_FEATURE_CIF_CFR
+	WIFI_POS_SRC,
+#endif
 	MAX_RING_TYPES
 };
 

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

@@ -147,7 +147,10 @@ enum hal_srng_ring_id {
 	HAL_SRNG_WMAC1_RXDMA2SW0 = 133,
 	HAL_SRNG_WMAC1_RXDMA2SW1 = 134,
 	HAL_SRNG_WMAC1_SW2RXDMA1_DESC = 135,
-	/* 136-142 unused */
+#ifdef WLAN_FEATURE_CIF_CFR
+	HAL_SRNG_WIFI_POS_SRC_DMA_RING = 136,
+#endif
+	/* 137-142 unused */
 	HAL_SRNG_LMAC1_ID_END = 143
 };
 

+ 14 - 0
hal/wifi3.0/hal_srng.c

@@ -497,6 +497,20 @@ static struct hal_hw_srng_config hw_srng_table[] = {
 		.reg_start = {},
 		.reg_size = {},
 	},
+#ifdef WLAN_FEATURE_CIF_CFR
+	{ /* WIFI_POS_SRC */
+		.start_ring_id = HAL_SRNG_WIFI_POS_SRC_DMA_RING,
+		.max_rings = 1,
+		.entry_size = sizeof(wmi_oem_dma_buf_release_entry)  >> 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 = {},
+	},
+#endif
 };
 
 /**

+ 13 - 0
target_if/wifi_pos/inc/target_if_wifi_pos.h

@@ -124,6 +124,13 @@ static inline void target_if_wifi_pos_register_rx_ops(
 QDF_STATUS target_if_wifi_pos_init_cir_cfr_rings(struct wlan_objmgr_psoc *psoc,
 					     void *hal_soc, uint8_t num_mac,
 					     void *buf);
+/**
+ * target_if_wifi_pos_deinit_dma_rings: frees up DMA rings
+ * @psoc: pointer to psoc
+ *
+ * Return: status of operation
+ */
+QDF_STATUS target_if_wifi_pos_deinit_dma_rings(struct wlan_objmgr_psoc *psoc);
 #else
 static inline QDF_STATUS target_if_wifi_pos_init_cir_cfr_rings(
 				struct wlan_objmgr_psoc *psoc, void *hal_soc,
@@ -131,6 +138,12 @@ static inline QDF_STATUS target_if_wifi_pos_init_cir_cfr_rings(
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+static inline QDF_STATUS target_if_wifi_pos_deinit_dma_rings(
+				struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif
 
 #endif /* _WIFI_POS_TGT_IF_H_ */

+ 255 - 16
target_if/wifi_pos/src/target_if_wifi_pos.c

@@ -38,6 +38,65 @@
 #include "target_if.h"
 #ifdef WLAN_FEATURE_CIF_CFR
 #include "hal_api.h"
+
+#define RING_BASE_ALIGN 8
+
+static void *target_if_wifi_pos_vaddr_lookup(
+				struct wifi_pos_psoc_priv_obj *priv,
+				void *paddr, uint8_t ring_num, uint32_t cookie)
+{
+	if (priv->dma_buf_pool[ring_num][cookie].paddr == paddr) {
+		return priv->dma_buf_pool[ring_num][cookie].vaddr +
+				priv->dma_buf_pool[ring_num][cookie].offset;
+	} else {
+		target_if_err("incorrect paddr found on cookie slot");
+		return NULL;
+	}
+}
+
+static QDF_STATUS target_if_wifi_pos_replenish_ring(
+			struct wifi_pos_psoc_priv_obj *priv, uint8_t ring_idx,
+			void *alinged_vaddr, uint32_t cookie)
+{
+	uint64_t *ring_entry;
+	uint32_t dw_lo, dw_hi = 0, map_status;
+	void *hal_soc = priv->hal_soc;
+	void *srng = priv->dma_cfg[ring_idx].srng;
+	void *paddr;
+
+	if (!alinged_vaddr) {
+		target_if_debug("NULL alinged_vaddr provided");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	map_status = qdf_mem_map_nbytes_single(NULL, alinged_vaddr,
+			QDF_DMA_FROM_DEVICE,
+			priv->dma_cap[ring_idx].min_buf_size,
+			(qdf_dma_addr_t *)&paddr);
+	if (map_status) {
+		target_if_err("mem map failed status: %d", map_status);
+		return QDF_STATUS_E_FAILURE;
+	}
+	QDF_ASSERT(!((uint64_t)paddr % priv->dma_cap[ring_idx].min_buf_align));
+	priv->dma_buf_pool[ring_idx][cookie].paddr = paddr;
+
+	hal_srng_access_start(hal_soc, srng);
+	ring_entry = hal_srng_src_get_next(hal_soc, srng);
+	dw_lo = (uint64_t)paddr & 0xFFFFFFFF;
+	WMI_OEM_DMA_DATA_ADDR_HI_SET(dw_hi, (uint64_t)paddr >> 32);
+	WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA_SET(dw_hi, cookie);
+	*ring_entry = (uint64_t)dw_hi << 32 | dw_lo;
+	hal_srng_access_end(hal_soc, srng);
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS target_if_wifi_pos_replenish_ring(
+			struct wifi_pos_psoc_priv_obj *priv, uint8_t ring_idx,
+			void *vaddr, uint32_t cookie)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif
 
 /**
@@ -276,54 +335,234 @@ QDF_STATUS target_if_wifi_pos_deregister_events(struct wlan_objmgr_psoc *psoc)
 }
 
 #ifdef WLAN_FEATURE_CIF_CFR
-static QDF_STATUS target_if_wifi_pos_init_srngs(struct wlan_objmgr_psoc *psoc,
-			void *hal_soc, struct wifi_pos_psoc_priv_obj *priv_obj)
+static QDF_STATUS target_if_wifi_pos_fill_ring(uint8_t ring_idx,
+					struct hal_srng *srng,
+					struct wifi_pos_psoc_priv_obj *priv)
+{
+	uint32_t i;
+	void *buf, *buf_aligned;
+
+	for (i = 0; i < priv->dma_cfg[ring_idx].num_ptr; i++) {
+		buf = qdf_mem_malloc(priv->dma_cap[ring_idx].min_buf_size +
+				priv->dma_cap[ring_idx].min_buf_align - 1);
+		if (!buf) {
+			target_if_err("malloc failed");
+			return QDF_STATUS_E_NOMEM;
+		}
+		priv->dma_buf_pool[ring_idx][i].vaddr = buf;
+		buf_aligned = (void *)qdf_roundup((uint64_t)buf,
+				priv->dma_cap[ring_idx].min_buf_align);
+		priv->dma_buf_pool[ring_idx][i].offset = buf_aligned - buf;
+		priv->dma_buf_pool[ring_idx][i].cookie = i;
+		target_if_wifi_pos_replenish_ring(priv, ring_idx,
+						  buf_aligned, i);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS target_if_wifi_pos_empty_ring(uint8_t ring_idx,
+					struct wifi_pos_psoc_priv_obj *priv)
+{
+	uint32_t i;
+
+	for (i = 0; i < priv->dma_cfg[ring_idx].num_ptr; i++) {
+		qdf_mem_unmap_nbytes_single(NULL,
+			(qdf_dma_addr_t)priv->dma_buf_pool[ring_idx][i].vaddr,
+			QDF_DMA_FROM_DEVICE,
+			priv->dma_cap[ring_idx].min_buf_size);
+		qdf_mem_free(priv->dma_buf_pool[ring_idx][i].vaddr);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS target_if_wifi_pos_init_ring(uint8_t ring_idx,
+					struct wifi_pos_psoc_priv_obj *priv)
+{
+	void *srng;
+	uint32_t num_entries;
+	qdf_dma_addr_t paddr;
+	uint32_t ring_alloc_size;
+	void *hal_soc = priv->hal_soc;
+	struct hal_srng_params ring_params = {0};
+	uint32_t max_entries = hal_srng_max_entries(hal_soc, WIFI_POS_SRC);
+	uint32_t entry_size = hal_srng_get_entrysize(hal_soc, WIFI_POS_SRC);
+
+	num_entries = priv->dma_cap[ring_idx].min_num_ptr > max_entries ?
+			max_entries : priv->dma_cap[ring_idx].min_num_ptr;
+	priv->dma_cfg[ring_idx].num_ptr = num_entries;
+	priv->dma_buf_pool[ring_idx] = qdf_mem_malloc(num_entries *
+					sizeof(struct wifi_pos_dma_buf_info));
+	if (!priv->dma_buf_pool[ring_idx]) {
+		target_if_err("malloc failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	ring_alloc_size = (num_entries * entry_size) + RING_BASE_ALIGN - 1;
+	priv->dma_cfg[ring_idx].ring_alloc_size = ring_alloc_size;
+	priv->dma_cfg[ring_idx].base_vaddr_unaligned =
+		qdf_mem_alloc_consistent(NULL, NULL, ring_alloc_size, &paddr);
+	priv->dma_cfg[ring_idx].base_paddr_unaligned = (void *)paddr;
+	if (!priv->dma_cfg[ring_idx].base_vaddr_unaligned) {
+		target_if_err("malloc failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	priv->dma_cfg[ring_idx].base_vaddr_aligned = (void *)qdf_roundup(
+		(uint64_t)priv->dma_cfg[ring_idx].base_vaddr_unaligned,
+		RING_BASE_ALIGN);
+	ring_params.ring_base_vaddr =
+		priv->dma_cfg[ring_idx].base_vaddr_aligned;
+	priv->dma_cfg[ring_idx].base_paddr_aligned = (void *)qdf_roundup(
+		(uint64_t)priv->dma_cfg[ring_idx].base_paddr_unaligned,
+		RING_BASE_ALIGN);
+	ring_params.ring_base_paddr =
+		(qdf_dma_addr_t)priv->dma_cfg[ring_idx].base_paddr_aligned;
+	ring_params.num_entries = num_entries;
+	srng = hal_srng_setup(hal_soc, WIFI_POS_SRC, 0,
+				priv->dma_cap[ring_idx].pdev_id, &ring_params);
+	if (!srng) {
+		target_if_err("srng setup failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+	priv->dma_cfg[ring_idx].srng = srng;
+	priv->dma_cfg[ring_idx].tail_idx_addr =
+			(void *)hal_srng_get_tp_addr(hal_soc, srng);
+	priv->dma_cfg[ring_idx].head_idx_addr =
+			(void *)hal_srng_get_tp_addr(hal_soc, srng);
+
+	return target_if_wifi_pos_fill_ring(ring_idx, srng, priv);
+}
+
+static QDF_STATUS target_if_wifi_pos_deinit_ring(uint8_t ring_idx,
+					struct wifi_pos_psoc_priv_obj *priv)
+{
+	target_if_wifi_pos_empty_ring(ring_idx, priv);
+	priv->dma_buf_pool[ring_idx] = NULL;
+	hal_srng_cleanup(priv->hal_soc, priv->dma_cfg[ring_idx].srng);
+	qdf_mem_free_consistent(NULL, NULL,
+		priv->dma_cfg[ring_idx].ring_alloc_size,
+		priv->dma_cfg[ring_idx].base_vaddr_unaligned,
+		(qdf_dma_addr_t)priv->dma_cfg[ring_idx].base_paddr_unaligned,
+		0);
+	qdf_mem_free(priv->dma_buf_pool[ring_idx]);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS target_if_wifi_pos_init_srngs(
+					struct wifi_pos_psoc_priv_obj *priv)
+{
+	uint8_t i;
+	QDF_STATUS status;
+
+	/* allocate memory for num_rings pointers */
+	priv->dma_cfg = qdf_mem_malloc(priv->num_rings *
+				sizeof(struct wifi_pos_dma_rings_cap));
+	if (!priv->dma_cfg) {
+		target_if_err("malloc failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	priv->dma_buf_pool = qdf_mem_malloc(priv->num_rings *
+				sizeof(struct wifi_pos_dma_buf_info *));
+	if (!priv->dma_buf_pool) {
+		target_if_err("malloc failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	for (i = 0; i < priv->num_rings; i++) {
+		status = target_if_wifi_pos_init_ring(i, priv);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			target_if_err("init for ring[%d] failed", i);
+			return status;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS target_if_wifi_pos_deinit_srngs(
+					struct wifi_pos_psoc_priv_obj *priv)
 {
+	uint8_t i;
+
+	for (i = 0; i < priv->num_rings; i++)
+		target_if_wifi_pos_deinit_ring(i, priv);
+
+	qdf_mem_free(priv->dma_buf_pool);
+	priv->dma_buf_pool = NULL;
+
 	return QDF_STATUS_SUCCESS;
 }
 
 static QDF_STATUS target_if_wifi_pos_cfg_fw(struct wlan_objmgr_psoc *psoc,
-					struct wifi_pos_psoc_priv_obj *priv_obj)
+					struct wifi_pos_psoc_priv_obj *priv)
 {
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS target_if_wifi_pos_deinit_dma_rings(struct wlan_objmgr_psoc *psoc)
+{
+	struct wifi_pos_psoc_priv_obj *priv = wifi_pos_get_psoc_priv_obj(psoc);
+
+	target_if_wifi_pos_deinit_srngs(priv);
+	qdf_mem_free(priv->dma_cap);
+	priv->dma_cap = NULL;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS target_if_wifi_pos_init_cir_cfr_rings(struct wlan_objmgr_psoc *psoc,
 					     void *hal_soc, uint8_t num_mac,
 					     void *buf)
 {
 	uint8_t i;
-	struct wifi_pos_psoc_priv_obj *priv_obj =
-			wifi_pos_get_psoc_priv_obj(psoc);
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	WMI_OEM_DMA_RING_CAPABILITIES *dma_cap = buf;
+	struct wifi_pos_psoc_priv_obj *priv = wifi_pos_get_psoc_priv_obj(psoc);
 
-	if (!priv_obj) {
+	if (!priv) {
 		target_if_err("unable to get wifi_pos psoc obj");
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	priv_obj->hal_soc = hal_soc;
-	priv_obj->num_rings = num_mac;
-	priv_obj->dma_cap = qdf_mem_malloc(priv_obj->num_rings *
+	priv->hal_soc = hal_soc;
+	priv->num_rings = num_mac;
+	priv->dma_cap = qdf_mem_malloc(priv->num_rings *
 					sizeof(struct wifi_pos_dma_rings_cap));
-	if (!priv_obj->dma_cap) {
+	if (!priv->dma_cap) {
 		target_if_err("unable to get wifi_pos psoc obj");
 		return QDF_STATUS_E_NOMEM;
 	}
 
 	for (i = 0; i < num_mac; i++) {
-		priv_obj->dma_cap[i].pdev_id = dma_cap[i].pdev_id;
-		priv_obj->dma_cap[i].min_num_ptr = dma_cap[i].min_num_ptr;
-		priv_obj->dma_cap[i].min_buf_size = dma_cap[i].min_buf_size;
-		priv_obj->dma_cap[i].min_buf_align = dma_cap[i].min_buf_align;
+		priv->dma_cap[i].pdev_id = dma_cap[i].pdev_id;
+		priv->dma_cap[i].min_num_ptr = dma_cap[i].min_num_ptr;
+		priv->dma_cap[i].min_buf_size = dma_cap[i].min_buf_size;
+		priv->dma_cap[i].min_buf_align = dma_cap[i].min_buf_align;
 	}
 
 	/* initialize DMA rings now */
-	target_if_wifi_pos_init_srngs(psoc, hal_soc, priv_obj);
+	status = target_if_wifi_pos_init_srngs(priv);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		target_if_err("dma init failed: %d", status);
+		goto dma_init_failed;
+	}
 
 	/* send cfg req cmd to firmware */
-	target_if_wifi_pos_cfg_fw(psoc, priv_obj);
+	status = target_if_wifi_pos_cfg_fw(psoc, priv);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		target_if_err("configure to FW failed: %d", status);
+		goto dma_init_failed;
+	}
 
 	return QDF_STATUS_SUCCESS;
+
+dma_init_failed:
+	target_if_wifi_pos_deinit_dma_rings(psoc);
+	return status;
 }
+
 #endif

+ 2 - 0
umac/wifi_pos/src/wifi_pos_main.c

@@ -447,6 +447,8 @@ QDF_STATUS  wifi_pos_psoc_obj_destroyed_notification(
 		return QDF_STATUS_E_FAULT;
 	}
 
+	target_if_wifi_pos_deinit_dma_rings(psoc);
+
 	status = wlan_objmgr_psoc_component_obj_detach(psoc,
 						WLAN_UMAC_COMP_WIFI_POS,
 						wifi_pos_obj);

+ 35 - 13
umac/wifi_pos/src/wifi_pos_utils_i.h

@@ -196,26 +196,44 @@ struct wifi_pos_dma_rings_cap {
 	uint32_t min_buf_align;
 };
 
+/**
+ * struct wifi_pos_dma_buf_info - buffer info struct containing phy to virtual
+ * mapping.
+ * @cookie: this identifies location of DMA buffer in pool array
+ * @paddr: aligned physical address as exchanged with firmware
+ * @vaddr: virtual address - unaligned. this helps in freeing later
+ * @offset: offset of aligned address from unaligned
+ */
+struct wifi_pos_dma_buf_info {
+	uint32_t cookie;
+	void *paddr;
+	void *vaddr;
+	uint8_t offset;
+};
+
 /**
  * struct wifi_pos_dma_rings_cfg - DMA ring parameters to be programmed to FW.
  * @pdev_id: pdev_id of ring
- * @base_addr_lo: Base address of ring, bits 31:0
- * @base_addr_hi: Base address of ring, bits 63:32
- * @head_idx_addr_lo: Address of head index register, bits 31:0
- * @head_idx_addr_hi: Address of head index register, bits 63:32
- * @tail_idx_addr_lo: Address of tail index register, bits 31:0
- * @tail_idx_addr_hi: Address of tail index register, bits 63:32
- * @num_ptr: Number of pointers in the ring
+ * @num_ptr: depth of ring
+ * @base_paddr_unaligned: base physical addr unaligned
+ * @base_vaddr_unaligned: base virtual addr unaligned
+ * @base_paddr_aligned: base physical addr aligned
+ * @base_vaddr_aligned: base virtual addr unaligned
+ * @head_idx_addr: head index addr
+ * @tail_idx_addr: tail index addr
+ * @srng: hal srng
  */
 struct wifi_pos_dma_rings_cfg {
 	uint32_t pdev_id;
-	uint32_t base_addr_lo;
-	uint32_t base_addr_hi;
-	uint32_t head_idx_addr_lo;
-	uint32_t head_idx_addr_hi;
-	uint32_t tail_idx_addr_lo;
-	uint32_t tail_idx_addr_hi;
 	uint32_t num_ptr;
+	uint32_t ring_alloc_size;
+	void *base_paddr_unaligned;
+	void *base_vaddr_unaligned;
+	void *base_paddr_aligned;
+	void *base_vaddr_aligned;
+	void *head_idx_addr;
+	void *tail_idx_addr;
+	void *srng;
 };
 
 /**
@@ -234,9 +252,11 @@ struct wifi_pos_dma_rings_cfg {
  * @allowed_dwell_time_max: allowed dwell time max, populated from HDD
  * @current_dwell_time_min: current dwell time min, populated from HDD
  * @current_dwell_time_max: current dwell time max, populated from HDD
+ * @hal_soc: hal_soc
  * @num_rings: DMA ring cap requested by firmware
  * @dma_cap: dma cap as read from service ready ext event
  * @dma_cfg: DMA ring cfg to be programmed to firmware
+ * @dma_buf_pool: DMA buffer pools maintained at host: this will be 2-D array
  * where with num_rows = number of rings num_elements in each row = ring depth
  * @wifi_pos_lock: lock to access wifi pos priv object
  * @wifi_pos_req_handler: function pointer to handle TLV or non-TLV
@@ -269,9 +289,11 @@ struct wifi_pos_psoc_priv_obj {
 	uint16_t current_dwell_time_min;
 	uint16_t current_dwell_time_max;
 
+	void *hal_soc;
 	uint8_t num_rings;
 	struct wifi_pos_dma_rings_cap *dma_cap;
 	struct wifi_pos_dma_rings_cfg *dma_cfg;
+	struct wifi_pos_dma_buf_info **dma_buf_pool;
 
 	qdf_spinlock_t wifi_pos_lock;
 	QDF_STATUS (*wifi_pos_req_handler)(struct wlan_objmgr_psoc *psoc,