From 9406c02ec47d198f1bf01c51245bbd2086b783fb Mon Sep 17 00:00:00 2001 From: Jinwei Chen Date: Sat, 25 Jul 2020 07:03:32 -0700 Subject: [PATCH] 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 --- core/cds/inc/cds_sched.h | 2 + core/cds/src/cds_api.c | 4 + core/dp/txrx3.0/dp_txrx.c | 179 +++++++++++++++++++++++++++++ core/dp/txrx3.0/dp_txrx.h | 55 +++++++++ core/hdd/src/wlan_hdd_driver_ops.c | 10 ++ 5 files changed, 250 insertions(+) diff --git a/core/cds/inc/cds_sched.h b/core/cds/inc/cds_sched.h index 390c6585e3d8..1b086ff23333 100644 --- a/core/cds/inc/cds_sched.h +++ b/core/cds/inc/cds_sched.h @@ -192,6 +192,8 @@ struct cds_context { void *dp_soc; + void *dp_mem_pre_alloc_ctx; + /* Configuration handle used to get system configuration */ struct cdp_cfg *cfg_ctx; diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c index 7b3707edd81d..04ad4c265f87 100644 --- a/core/cds/src/cds_api.c +++ b/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, .send_delba = cds_send_delba, .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 */ }; #else diff --git a/core/dp/txrx3.0/dp_txrx.c b/core/dp/txrx3.0/dp_txrx.c index 41c52a1eec38..1af956da2927 100644 --- a/core/dp/txrx3.0/dp_txrx.c +++ b/core/dp/txrx3.0/dp_txrx.c @@ -131,3 +131,182 @@ int dp_rx_tm_get_pending(ol_txrx_soc_handle soc) return 0; } #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 diff --git a/core/dp/txrx3.0/dp_txrx.h b/core/dp/txrx3.0/dp_txrx.h index ba81ed44f2f1..ded670852f7c 100644 --- a/core/dp/txrx3.0/dp_txrx.h +++ b/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 */ 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 */ diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index 6f079c0b23d8..e5e06e29f293 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -492,6 +492,13 @@ static int __hdd_soc_probe(struct device *dev, if (errno) 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); if (IS_ERR(hdd_ctx)) { errno = PTR_ERR(hdd_ctx); @@ -525,6 +532,7 @@ hdd_context_destroy: hdd_context_destroy(hdd_ctx); assert_fail_count: + dp_prealloc_deinit(); probe_fail_cnt++; hdd_err("consecutive probe failures:%u", probe_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_unload_in_progress(false); + dp_prealloc_deinit(); + pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME); }