qcacmn: Add reduction limit to qdf_flex_mem

Add the ability to prevent qdf_flex_mem_pool from freeing memory
segments unless there are more than some minimum number in the pool
already.

Change-Id: I20bde2ed629b97924ea71b4f7f46a2c1fc1bab28
CRs-Fixed: 2229511
This commit is contained in:
Dustin Brown
2018-04-17 15:37:03 -07:00
committed by nshrivas
parent 4f263a9a19
commit 03a7ac6e19
5 changed files with 68 additions and 6 deletions

View File

@@ -45,6 +45,7 @@ linux/src/qdf_perf.o \
linux/src/qdf_threads.o \
linux/src/qdf_trace.o \
linux/src/qdf_file.o \
src/qdf_flex_mem.o \
src/qdf_parse.o \
src/qdf_str.o \
src/qdf_types.o

View File

@@ -44,11 +44,13 @@
* qdf_flex_mem_pool - a pool of memory segments
* @seg_list: the list containing the memory segments
* @lock: spinlock for protecting internal data structures
* @reduction_limit: the minimum number of segments to keep during reduction
* @item_size: the size of the items the pool will allocate
*/
struct qdf_flex_mem_pool {
qdf_list_t seg_list;
struct qdf_spinlock lock;
uint16_t reduction_limit;
uint16_t item_size;
};
@@ -70,8 +72,9 @@ struct qdf_flex_mem_segment {
* DEFINE_QDF_FLEX_MEM_POOL() - define a new flex mem pool with one segment
* @name: the name of the pool variable
* @size_of_item: size of the items the pool will allocate
* @rm_limit: min number of segments to keep during reduction
*/
#define DEFINE_QDF_FLEX_MEM_POOL(name, size_of_item) \
#define DEFINE_QDF_FLEX_MEM_POOL(name, size_of_item, rm_limit) \
struct qdf_flex_mem_pool name; \
uint8_t __ ## name ## _head_bytes[QDF_FM_BITMAP_BITS * (size_of_item)];\
struct qdf_flex_mem_segment __ ## name ## _head = { \
@@ -81,6 +84,7 @@ struct qdf_flex_mem_segment {
}; \
struct qdf_flex_mem_pool name = { \
.seg_list = QDF_LIST_INIT_SINGLE(__ ## name ## _head.node), \
.reduction_limit = (rm_limit), \
.item_size = (size_of_item), \
}
@@ -126,4 +130,14 @@ void *qdf_flex_mem_alloc(struct qdf_flex_mem_pool *pool);
*/
void qdf_flex_mem_free(struct qdf_flex_mem_pool *pool, void *ptr);
/**
* qdf_flex_mem_release() - release unused segments
* @pool: the pool to operate against
*
* This function physically releases as much unused pool memory as possible.
*
* Return: None
*/
void qdf_flex_mem_release(struct qdf_flex_mem_pool *pool);
#endif /* __QDF_FLEX_MEM_H */

View File

@@ -109,6 +109,9 @@ static inline void qdf_list_create(__qdf_list_t *list, uint32_t max_size)
#define qdf_list_for_each(list_ptr, cursor, node_field) \
__qdf_list_for_each(list_ptr, cursor, node_field)
#define qdf_list_for_each_del(list_ptr, cursor, next, node_field) \
__qdf_list_for_each_del(list_ptr, cursor, next, node_field)
/**
* qdf_init_list_head() - initialize list head
* @list_head: pointer to list head

View File

@@ -79,6 +79,9 @@ static inline void __qdf_list_create(__qdf_list_t *list, uint32_t max_size)
#define __qdf_list_for_each(list_ptr, cursor, node_field) \
list_for_each_entry(cursor, &(list_ptr)->anchor, node_field)
#define __qdf_list_for_each_del(list_ptr, cursor, next, node_field) \
list_for_each_entry_safe(cursor, next, &(list_ptr)->anchor, node_field)
/**
* __qdf_init_list_head() - initialize list head
* @list_head: pointer to list head

View File

@@ -20,6 +20,7 @@
#include "qdf_list.h"
#include "qdf_lock.h"
#include "qdf_mem.h"
#include "qdf_module.h"
#include "qdf_trace.h"
#include "qdf_util.h"
@@ -27,17 +28,20 @@ void qdf_flex_mem_init(struct qdf_flex_mem_pool *pool)
{
qdf_spinlock_create(&pool->lock);
}
qdf_export_symbol(qdf_flex_mem_init);
void qdf_flex_mem_deinit(struct qdf_flex_mem_pool *pool)
{
qdf_spinlock_destroy(&pool->lock);
}
qdf_export_symbol(qdf_flex_mem_deinit);
static struct qdf_flex_mem_segment *qdf_flex_mem_seg_alloc(uint16_t item_size)
static struct qdf_flex_mem_segment *
qdf_flex_mem_seg_alloc(struct qdf_flex_mem_pool *pool)
{
size_t bytes_size = item_size * QDF_FM_BITMAP_BITS;
size_t total_size = sizeof(struct qdf_flex_mem_segment) + bytes_size;
struct qdf_flex_mem_segment *seg;
size_t total_size = sizeof(struct qdf_flex_mem_segment) +
pool->item_size * QDF_FM_BITMAP_BITS;
seg = qdf_mem_malloc(total_size);
if (!seg)
@@ -70,7 +74,7 @@ static void *__qdf_flex_mem_alloc(struct qdf_flex_mem_pool *pool)
return ptr;
}
seg = qdf_flex_mem_seg_alloc(pool->item_size);
seg = qdf_flex_mem_seg_alloc(pool);
if (!seg)
return NULL;
@@ -94,10 +98,18 @@ void *qdf_flex_mem_alloc(struct qdf_flex_mem_pool *pool)
return ptr;
}
qdf_export_symbol(qdf_flex_mem_alloc);
static void qdf_flex_mem_seg_free(struct qdf_flex_mem_pool *pool,
struct qdf_flex_mem_segment *seg)
{
if (!seg->dynamic)
return;
if (qdf_list_size(&pool->seg_list) <= pool->reduction_limit)
return;
qdf_list_remove_node(&pool->seg_list, &seg->node);
qdf_mem_free(seg);
}
@@ -120,7 +132,7 @@ static void __qdf_flex_mem_free(struct qdf_flex_mem_pool *pool, void *ptr)
QDF_BUG(index < QDF_FM_BITMAP_BITS);
seg->used_bitmap ^= (QDF_FM_BITMAP)1 << index;
if (!seg->used_bitmap && seg->dynamic)
if (!seg->used_bitmap)
qdf_flex_mem_seg_free(pool, seg);
return;
@@ -144,4 +156,33 @@ void qdf_flex_mem_free(struct qdf_flex_mem_pool *pool, void *ptr)
__qdf_flex_mem_free(pool, ptr);
qdf_spin_unlock_bh(&pool->lock);
}
qdf_export_symbol(qdf_flex_mem_free);
static void __qdf_flex_mem_release(struct qdf_flex_mem_pool *pool)
{
struct qdf_flex_mem_segment *seg;
struct qdf_flex_mem_segment *next;
qdf_list_for_each_del(&pool->seg_list, seg, next, node) {
if (!seg->dynamic)
continue;
if (seg->used_bitmap != 0)
continue;
qdf_list_remove_node(&pool->seg_list, &seg->node);
qdf_mem_free(seg);
}
}
void qdf_flex_mem_release(struct qdf_flex_mem_pool *pool)
{
QDF_BUG(pool);
if (!pool)
return;
qdf_spin_lock_bh(&pool->lock);
__qdf_flex_mem_release(pool);
qdf_spin_unlock_bh(&pool->lock);
}
qdf_export_symbol(qdf_flex_mem_release);