mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 21:59:12 -04:00
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:
parent
db7393e971
commit
9406c02ec4
5 changed files with 250 additions and 0 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue