Selaa lähdekoodia

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
Dustin Brown 7 vuotta sitten
vanhempi
sitoutus
03a7ac6e19
5 muutettua tiedostoa jossa 68 lisäystä ja 6 poistoa
  1. 1 0
      qdf/Kbuild
  2. 15 1
      qdf/inc/qdf_flex_mem.h
  3. 3 0
      qdf/inc/qdf_list.h
  4. 3 0
      qdf/linux/src/i_qdf_list.h
  5. 46 5
      qdf/src/qdf_flex_mem.c

+ 1 - 0
qdf/Kbuild

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

+ 15 - 1
qdf/inc/qdf_flex_mem.h

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

+ 3 - 0
qdf/inc/qdf_list.h

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

+ 3 - 0
qdf/linux/src/i_qdf_list.h

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

+ 46 - 5
qdf/src/qdf_flex_mem.c

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