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
This commit is contained in:
Jinwei Chen 2020-07-25 07:03:32 -07:00 • committed by snandini
commit 9406c02ec4
5 changed files with 250 additions and 0 deletions

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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);
}