Bladeren bron

qcacld-3.0: Add support to pre-allocate DP SRNG mem

Add logic to pre-allocate DP consistent memory and reuse later.
Only SRNG memory is preallocated. This is useful to prevent memory
allocation failures due to fragmentation over cycles of WLAN ON/OFF.

Change-Id: I1f814f9f18d482eb5f55e0b157606d1792e665f8
CRs-Fixed: 2740424
Jinwei Chen 4 jaren geleden
bovenliggende
commit
9406c02ec4
5 gewijzigde bestanden met toevoegingen van 250 en 0 verwijderingen
  1. 2 0
      core/cds/inc/cds_sched.h
  2. 4 0
      core/cds/src/cds_api.c
  3. 179 0
      core/dp/txrx3.0/dp_txrx.c
  4. 55 0
      core/dp/txrx3.0/dp_txrx.h
  5. 10 0
      core/hdd/src/wlan_hdd_driver_ops.c

+ 2 - 0
core/cds/inc/cds_sched.h

@@ -192,6 +192,8 @@ struct cds_context {
 
 
 	void *dp_soc;
 	void *dp_soc;
 
 
+	void *dp_mem_pre_alloc_ctx;
+
 	/* Configuration handle used to get system configuration */
 	/* Configuration handle used to get system configuration */
 	struct cdp_cfg *cfg_ctx;
 	struct cdp_cfg *cfg_ctx;
 
 

+ 4 - 0
core/cds/src/cds_api.c

@@ -122,6 +122,10 @@ static struct ol_if_ops  dp_ol_if_ops = {
 	.get_con_mode = cds_get_conparam,
 	.get_con_mode = cds_get_conparam,
 	.send_delba = cds_send_delba,
 	.send_delba = cds_send_delba,
 	.dp_rx_get_pending = dp_rx_tm_get_pending,
 	.dp_rx_get_pending = dp_rx_tm_get_pending,
+#ifdef DP_MEM_PRE_ALLOC
+	.dp_prealloc_get_consistent = dp_prealloc_get_coherent,
+	.dp_prealloc_put_consistent = dp_prealloc_put_coherent
+#endif
     /* TODO: Add any other control path calls required to OL_IF/WMA layer */
     /* TODO: Add any other control path calls required to OL_IF/WMA layer */
 };
 };
 #else
 #else

+ 179 - 0
core/dp/txrx3.0/dp_txrx.c

@@ -131,3 +131,182 @@ int dp_rx_tm_get_pending(ol_txrx_soc_handle soc)
 	return 0;
 	return 0;
 }
 }
 #endif
 #endif
+
+#ifdef DP_MEM_PRE_ALLOC
+/* Num elements in REO ring */
+#define REO_DST_RING_SIZE 1024
+
+/* Num elements in TCL Data ring */
+#define TCL_DATA_RING_SIZE 3072
+
+/* Num elements in WBM2SW ring */
+#define WBM2SW_RELEASE_RING_SIZE 4096
+
+/* Num elements in WBM Idle Link */
+#define WBM_IDLE_LINK_RING_SIZE (32 * 1024)
+
+/**
+ * struct dp_consistent_prealloc - element representing DP pre-alloc memory
+ * @ring_type: HAL ring type
+ * @size: size of pre-alloc memory
+ * @in_use: whether this element is in use (occupied)
+ * @va_unaligned: Unaligned virtual address
+ * @va_aligned: aligned virtual address.
+ * @pa_unaligned: Unaligned physical address.
+ * @pa_aligned: Aligned physical address.
+ */
+
+struct dp_consistent_prealloc {
+	enum hal_ring_type ring_type;
+	uint32_t size;
+	uint8_t in_use;
+	void *va_unaligned;
+	void *va_aligned;
+	qdf_dma_addr_t pa_unaligned;
+	qdf_dma_addr_t pa_aligned;
+};
+
+static struct  dp_consistent_prealloc g_dp_consistent_allocs[] = {
+	/* 5 REO DST rings */
+	{REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, NULL, NULL, 0, 0},
+	{REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, NULL, NULL, 0, 0},
+	{REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, NULL, NULL, 0, 0},
+	{REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, NULL, NULL, 0, 0},
+	{REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, NULL, NULL, 0, 0},
+	/* 3 TCL data rings */
+	{TCL_DATA, (sizeof(struct tlv_32_hdr) + sizeof(struct tcl_data_cmd)) * TCL_DATA_RING_SIZE, 0, NULL, NULL, 0, 0},
+	{TCL_DATA, (sizeof(struct tlv_32_hdr) + sizeof(struct tcl_data_cmd)) * TCL_DATA_RING_SIZE, 0, NULL, NULL, 0, 0},
+	{TCL_DATA, (sizeof(struct tlv_32_hdr) + sizeof(struct tcl_data_cmd)) * TCL_DATA_RING_SIZE, 0, NULL, NULL, 0, 0},
+	/* 4 WBM2SW rings */
+	{WBM2SW_RELEASE, (sizeof(struct wbm_release_ring)) * WBM2SW_RELEASE_RING_SIZE, 0, NULL, NULL, 0, 0},
+	{WBM2SW_RELEASE, (sizeof(struct wbm_release_ring)) * WBM2SW_RELEASE_RING_SIZE, 0, NULL, NULL, 0, 0},
+	{WBM2SW_RELEASE, (sizeof(struct wbm_release_ring)) * WBM2SW_RELEASE_RING_SIZE, 0, NULL, NULL, 0, 0},
+	{WBM2SW_RELEASE, (sizeof(struct wbm_release_ring)) * WBM2SW_RELEASE_RING_SIZE, 0, NULL, 0, 0},
+	/* 1 WBM idle link desc ring */
+	{WBM_IDLE_LINK, (sizeof(struct wbm_link_descriptor_ring)) * WBM_IDLE_LINK_RING_SIZE, 0, NULL, NULL, 0, 0},
+};
+
+void dp_prealloc_deinit(void)
+{
+	int i;
+	struct dp_consistent_prealloc *p;
+	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
+
+	if (!qdf_ctx) {
+		dp_warn("qdf_ctx is NULL");
+		return;
+	}
+
+	for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_allocs); i++) {
+		p = &g_dp_consistent_allocs[i];
+
+		if (p->in_use)
+			dp_warn("i %d: in use while free", i);
+
+		if (p->va_aligned) {
+			dp_debug("i %d: va aligned %pK pa aligned %llx size %d",
+				i, p->va_aligned, p->pa_aligned, p->size);
+			qdf_mem_free_consistent(qdf_ctx, qdf_ctx->dev,
+						p->size,
+						p->va_unaligned,
+						p->pa_unaligned, 0);
+			qdf_mem_zero(p, sizeof(*p));
+		}
+	}
+}
+
+QDF_STATUS dp_prealloc_init(void)
+{
+	int i;
+	struct dp_consistent_prealloc *p;
+	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
+
+	if (!qdf_ctx) {
+		dp_err("qdf_ctx is NULL");
+		QDF_BUG(0);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_allocs); i++) {
+		p = &g_dp_consistent_allocs[i];
+		p->in_use = 0;
+		p->va_aligned =
+			qdf_aligned_mem_alloc_consistent(qdf_ctx,
+							 &p->size,
+							 &p->va_unaligned,
+							 &p->pa_unaligned,
+							 &p->pa_aligned,
+							 DP_RING_BASE_ALIGN);
+		if (!p->va_unaligned) {
+			dp_warn("i %d: unable to preallocate %d bytes memory!",
+				i, p->size);
+			break;
+		}
+
+		dp_debug("i %d: va aligned %pK pa aligned %llx size %d", i,
+			p->va_aligned, p->pa_aligned, p->size);
+	}
+
+	if (i != QDF_ARRAY_SIZE(g_dp_consistent_allocs)) {
+		dp_err("unable to allocate memory!");
+		dp_prealloc_deinit();
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void *dp_prealloc_get_coherent(uint32_t *size, void **base_vaddr_unaligned,
+			       qdf_dma_addr_t *paddr_unaligned,
+			       qdf_dma_addr_t *paddr_aligned,
+			       uint32_t align,
+			       uint32_t ring_type)
+{
+	int i;
+	struct dp_consistent_prealloc *p;
+	void *va_aligned = NULL;
+
+	for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_allocs); i++) {
+		p = &g_dp_consistent_allocs[i];
+		if (p->ring_type == ring_type && !p->in_use &&
+		    p->va_unaligned && *size <= p->size) {
+			p->in_use = 1;
+			*base_vaddr_unaligned = p->va_unaligned;
+			*paddr_unaligned = p->pa_unaligned;
+			*paddr_aligned = p->pa_aligned;
+			va_aligned = p->va_aligned;
+			*size = p->size;
+			dp_debug("index %i -> ring type %s va-aligned %pK", i,
+				dp_srng_get_str_from_hal_ring_type(ring_type),
+				va_aligned);
+			break;
+		}
+	}
+
+	if (i == QDF_ARRAY_SIZE(g_dp_consistent_allocs))
+		dp_err("unable to allocate memory for ring type %s (%d) size %d",
+			dp_srng_get_str_from_hal_ring_type(ring_type),
+			ring_type, p->size);
+	return va_aligned;
+}
+
+void dp_prealloc_put_coherent(qdf_size_t size, void *vaddr_unligned,
+			      qdf_dma_addr_t paddr)
+{
+	int i;
+	struct dp_consistent_prealloc *p;
+
+	for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_allocs); i++) {
+		p = &g_dp_consistent_allocs[i];
+		if (p->va_unaligned == vaddr_unligned) {
+			dp_debug("index %d, returned", i);
+			p->in_use = 0;
+			qdf_mem_zero(p->va_unaligned, p->size);
+			break;
+		}
+	}
+
+	if (i == QDF_ARRAY_SIZE(g_dp_consistent_allocs))
+		dp_err("unable to find vaddr %pK", vaddr_unligned);
+}
+#endif

+ 55 - 0
core/dp/txrx3.0/dp_txrx.h

@@ -443,4 +443,59 @@ QDF_STATUS dp_txrx_set_cpu_mask(ol_txrx_soc_handle soc, qdf_cpu_mask *new_mask)
  * Return: number of frames
  * Return: number of frames
  */
  */
 int dp_rx_tm_get_pending(ol_txrx_soc_handle soc);
 int dp_rx_tm_get_pending(ol_txrx_soc_handle soc);
+
+#ifdef DP_MEM_PRE_ALLOC
+/**
+ * dp_prealloc_init() - Pre-allocate DP memory
+ *
+ * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure
+ */
+QDF_STATUS dp_prealloc_init(void);
+
+/**
+ * dp_prealloc_deinit() - Free pre-alloced DP memory
+ *
+ * Return: None
+ */
+void dp_prealloc_deinit(void);
+
+/**
+ * dp_prealloc_get_coherent() - gets pre-alloc DP memory
+ * @size: size of memory needed
+ * @base_vaddr_unaligned: Unaligned virtual address.
+ * @paddr_unaligned: Unaligned physical address.
+ * @paddr_aligned: Aligned physical address.
+ * @align: Base address alignment.
+ * @align: alignment needed
+ * @ring_type: HAL ring type
+ *
+ * The function does not handle concurrent access to pre-alloc memory.
+ * All ring memory allocation from pre-alloc memory should happen from single
+ * context to avoid race conditions.
+ *
+ * Return: unaligned virtual address if success or null if memory alloc fails.
+ */
+void *dp_prealloc_get_coherent(uint32_t *size, void **base_vaddr_unaligned,
+			       qdf_dma_addr_t *paddr_unaligned,
+			       qdf_dma_addr_t *paddr_aligned,
+			       uint32_t align,
+			       uint32_t ring_type);
+
+/**
+ * dp_prealloc_put_coherent() - puts back pre-alloc DP memory
+ * @size: size of memory to be returned
+ * @base_vaddr_unaligned: Unaligned virtual address.
+ * @paddr_unaligned: Unaligned physical address.
+ *
+ * Return: None
+ */
+void dp_prealloc_put_coherent(qdf_size_t size, void *vaddr_unligned,
+			      qdf_dma_addr_t paddr);
+#else
+static inline QDF_STATUS dp_prealloc_init(void) { return QDF_STATUS_SUCCESS; }
+
+static inline void dp_prealloc_deinit(void) { }
+
+#endif
+
 #endif /* _DP_TXRX_H */
 #endif /* _DP_TXRX_H */

+ 10 - 0
core/hdd/src/wlan_hdd_driver_ops.c

@@ -492,6 +492,13 @@ static int __hdd_soc_probe(struct device *dev,
 	if (errno)
 	if (errno)
 		goto unlock;
 		goto unlock;
 
 
+	status = dp_prealloc_init();
+
+	if (status != QDF_STATUS_SUCCESS) {
+		errno = qdf_status_to_os_return(status);
+		goto unlock;
+	}
+
 	hdd_ctx = hdd_context_create(dev);
 	hdd_ctx = hdd_context_create(dev);
 	if (IS_ERR(hdd_ctx)) {
 	if (IS_ERR(hdd_ctx)) {
 		errno = PTR_ERR(hdd_ctx);
 		errno = PTR_ERR(hdd_ctx);
@@ -525,6 +532,7 @@ hdd_context_destroy:
 	hdd_context_destroy(hdd_ctx);
 	hdd_context_destroy(hdd_ctx);
 
 
 assert_fail_count:
 assert_fail_count:
+	dp_prealloc_deinit();
 	probe_fail_cnt++;
 	probe_fail_cnt++;
 	hdd_err("consecutive probe failures:%u", probe_fail_cnt);
 	hdd_err("consecutive probe failures:%u", probe_fail_cnt);
 	QDF_BUG(probe_fail_cnt < SSR_MAX_FAIL_CNT);
 	QDF_BUG(probe_fail_cnt < SSR_MAX_FAIL_CNT);
@@ -712,6 +720,8 @@ static void __hdd_soc_remove(struct device *dev)
 	cds_set_driver_in_bad_state(false);
 	cds_set_driver_in_bad_state(false);
 	cds_set_unload_in_progress(false);
 	cds_set_unload_in_progress(false);
 
 
+	dp_prealloc_deinit();
+
 	pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME);
 	pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME);
 }
 }