Prechádzať zdrojové kódy

qcacmn: Extract memory debugging features from qdf_mem

When memory debugging is enabled, qdf_mem_malloc and qdf_mem_free do a
number of memory corruption checks. Extract these checks into their own
functions to allow other memory allocation/free logic to leverage the
same logic.

Change-Id: I07802093119c90b3d8c40a50d5b4bb152cb8243f
CRs-Fixed: 2136659
Dustin Brown 7 rokov pred
rodič
commit
7768da6890
2 zmenil súbory, kde vykonal 304 pridanie a 289 odobranie
  1. 36 9
      qdf/inc/qdf_mem.h
  2. 268 280
      qdf/linux/src/qdf_mem.c

+ 36 - 9
qdf/inc/qdf_mem.h

@@ -96,9 +96,36 @@ void qdf_mem_init(void);
 void qdf_mem_exit(void);
 
 #ifdef MEMORY_DEBUG
+/**
+ * qdf_mem_malloc_debug() - debug version of QDF memory allocation API
+ * @size: Number of bytes of memory to allocate.
+ * @file: File name of the call site
+ * @line: Line number of the call site
+ *
+ * This function will dynamicallly allocate the specified number of bytes of
+ * memory and add it to the qdf tracking list to check for memory leaks and
+ * corruptions
+ *
+ * Return: A valid memory location on success, or NULL on failure
+ */
+void *qdf_mem_malloc_debug(size_t size, const char *file, uint32_t line);
+
 #define qdf_mem_malloc(size) \
 	qdf_mem_malloc_debug(size, __FILE__, __LINE__)
-void *qdf_mem_malloc_debug(size_t size, char *file_name, uint32_t line_num);
+
+/**
+ * qdf_mem_free_debug() - debug version of qdf_mem_free
+ * @ptr: Pointer to the starting address of the memory to be freed.
+ *
+ * This function will free the memory pointed to by 'ptr'. It also checks for
+ * memory corruption, underrun, overrun, double free, domain mismatch, etc.
+ *
+ * Return: none
+ */
+void qdf_mem_free_debug(void *ptr, const char *file, uint32_t line);
+
+#define qdf_mem_free(ptr) \
+	qdf_mem_free_debug(ptr, __FILE__, __LINE__)
 
 /**
  * qdf_mem_check_for_leaks() - Assert that the current memory domain is empty
@@ -133,20 +160,20 @@ void *qdf_mem_malloc_debug(size_t size, char *file_name, uint32_t line_num);
 void qdf_mem_check_for_leaks(void);
 #else
 void *qdf_mem_malloc(qdf_size_t size);
-static inline void qdf_mem_check_for_leaks(void) { }
-#endif /* MEMORY_DEBUG */
-
-void *qdf_mem_alloc_outline(qdf_device_t osdev, qdf_size_t size);
 
 /**
  * qdf_mem_free() - free QDF memory
- * @ptr: Pointer to the starting address of the memory to be free'd.
- * This function will free the memory pointed to by 'ptr'.
- * Return:
- * None
+ * @ptr: Pointer to the starting address of the memory to be freed.
+ *
+ * Return: None
  */
 void qdf_mem_free(void *ptr);
 
+static inline void qdf_mem_check_for_leaks(void) { }
+#endif /* MEMORY_DEBUG */
+
+void *qdf_mem_alloc_outline(qdf_device_t osdev, qdf_size_t size);
+
 void qdf_mem_set(void *ptr, uint32_t num_bytes, uint32_t value);
 
 void qdf_mem_zero(void *ptr, uint32_t num_bytes);

+ 268 - 280
qdf/linux/src/qdf_mem.c

@@ -60,6 +60,10 @@
 #include "qdf_debug_domain.h"
 #include <qdf_list.h>
 
+/* Preprocessor Definitions and Constants */
+#define QDF_MEM_MAX_MALLOC (1024 * 1024) /* 1MiB */
+#define QDF_MEM_WARN_THRESHOLD 300 /* ms */
+
 static qdf_list_t qdf_mem_domains[QDF_DEBUG_DOMAIN_COUNT];
 static qdf_spinlock_t qdf_mem_list_lock;
 
@@ -69,29 +73,175 @@ static inline qdf_list_t *qdf_mem_list_get(enum qdf_debug_domain domain)
 }
 
 /**
- * struct s_qdf_mem_struct - memory object to dubug
- * @node:	node to the list
- * @filename:	name of file
- * @line_num:	line number
- * @size:	size of the file
- * @header:	array that contains header
- * @in_use:	memory usage count
+ * struct qdf_mem_header - memory object to dubug
+ * @node: node to the list
+ * @domain: the active memory domain at time of allocation
+ * @freed: flag set during free, used to detect double frees
+ *	Use uint8_t so we can detect corruption
+ * @file: name of the file the allocation was made from
+ * @line: line number of the file the allocation was made from
+ * @size: size of the allocation in bytes
+ * @header: a known value, used to detect out-of-bounds access
  */
-struct s_qdf_mem_struct {
+struct qdf_mem_header {
 	qdf_list_node_t node;
-	char *file_name;
-	uint32_t line_num;
+	enum qdf_debug_domain domain;
+	uint8_t freed;
+	const char *file;
+	uint32_t line;
 	uint32_t size;
 	uint64_t header;
-	enum qdf_debug_domain domain;
 };
 
 static uint64_t WLAN_MEM_HEADER = 0x6162636465666768;
-static uint64_t WLAN_MEM_TAIL = 0x8081828384858687;
-#endif /* MEMORY_DEBUG */
+static uint64_t WLAN_MEM_TRAILER = 0x8081828384858687;
 
-/* Preprocessor Definitions and Constants */
-#define QDF_GET_MEMORY_TIME_THRESHOLD 300
+static inline struct qdf_mem_header *qdf_mem_get_header(void *ptr)
+{
+	return (struct qdf_mem_header *)ptr - 1;
+}
+
+static inline uint64_t *qdf_mem_get_trailer(struct qdf_mem_header *header)
+{
+	return (uint64_t *)((void *)(header + 1) + header->size);
+}
+
+static inline void *qdf_mem_get_ptr(struct qdf_mem_header *header)
+{
+	return (void *)(header + 1);
+}
+
+/* number of bytes needed for the qdf memory debug information */
+#define QDF_MEM_DEBUG_SIZE \
+	(sizeof(struct qdf_mem_header) + sizeof(WLAN_MEM_TRAILER))
+
+static void qdf_mem_header_init(struct qdf_mem_header *header, qdf_size_t size,
+				const char *file, uint32_t line)
+{
+	QDF_BUG(header);
+	if (!header)
+		return;
+
+	header->domain = qdf_debug_domain_get();
+	header->freed = false;
+	header->file = file;
+	header->line = line;
+	header->size = size;
+	header->header = WLAN_MEM_HEADER;
+	*qdf_mem_get_trailer(header) = WLAN_MEM_TRAILER;
+}
+
+enum qdf_mem_validation_bitmap {
+	QDF_MEM_BAD_HEADER = 1 << 0,
+	QDF_MEM_BAD_TRAILER = 1 << 1,
+	QDF_MEM_BAD_SIZE = 1 << 2,
+	QDF_MEM_DOUBLE_FREE = 1 << 3,
+	QDF_MEM_BAD_FREED = 1 << 4,
+	QDF_MEM_BAD_NODE = 1 << 5,
+	QDF_MEM_BAD_DOMAIN = 1 << 6,
+	QDF_MEM_WRONG_DOMAIN = 1 << 7,
+};
+
+/**
+ * qdf_mem_validate_list_node() - validate that the node is in a list
+ * @qdf_node: node to check for being in a list
+ *
+ * Return: true if the node validly linked in an anchored doubly linked list
+ */
+static bool qdf_mem_validate_list_node(qdf_list_node_t *qdf_node)
+{
+	struct list_head *node = qdf_node;
+
+	/*
+	 * if the node is an empty list, it is not tied to an anchor node
+	 * and must have been removed with list_del_init
+	 */
+	if (list_empty(node))
+		return false;
+
+	if (!node->prev || !node->next)
+		return false;
+
+	if (node->prev->next != node || node->next->prev != node)
+		return false;
+
+	return true;
+}
+
+static enum qdf_mem_validation_bitmap
+qdf_mem_header_validate(struct qdf_mem_header *header,
+			enum qdf_debug_domain domain)
+{
+	enum qdf_mem_validation_bitmap error_bitmap = 0;
+
+	if (header->header != WLAN_MEM_HEADER)
+		error_bitmap |= QDF_MEM_BAD_HEADER;
+
+	if (header->size > QDF_MEM_MAX_MALLOC)
+		error_bitmap |= QDF_MEM_BAD_SIZE;
+	else if (*qdf_mem_get_trailer(header) != WLAN_MEM_TRAILER)
+		error_bitmap |= QDF_MEM_BAD_TRAILER;
+
+	if (header->freed == true)
+		error_bitmap |= QDF_MEM_DOUBLE_FREE;
+	else if (header->freed)
+		error_bitmap |= QDF_MEM_BAD_FREED;
+
+	if (!qdf_mem_validate_list_node(&header->node))
+		error_bitmap |= QDF_MEM_BAD_NODE;
+
+	if (header->domain < QDF_DEBUG_DOMAIN_INIT ||
+	    header->domain >= QDF_DEBUG_DOMAIN_COUNT)
+		error_bitmap |= QDF_MEM_BAD_DOMAIN;
+	else if (header->domain != domain)
+		error_bitmap |= QDF_MEM_WRONG_DOMAIN;
+
+	return error_bitmap;
+}
+
+static void
+qdf_mem_header_assert_valid(struct qdf_mem_header *header,
+			    enum qdf_debug_domain current_domain,
+			    enum qdf_mem_validation_bitmap error_bitmap,
+			    const char *file,
+			    uint32_t line)
+{
+	if (!error_bitmap)
+		return;
+
+	if (error_bitmap & QDF_MEM_BAD_HEADER)
+		qdf_err("Corrupted memory header 0x%llx (expected 0x%llx)",
+			header->header, WLAN_MEM_HEADER);
+
+	if (error_bitmap & QDF_MEM_BAD_SIZE)
+		qdf_err("Corrupted memory size %u (expected < %d)",
+			header->size, QDF_MEM_MAX_MALLOC);
+
+	if (error_bitmap & QDF_MEM_BAD_TRAILER)
+		qdf_err("Corrupted memory trailer 0x%llx (expected 0x%llx)",
+			*qdf_mem_get_trailer(header), WLAN_MEM_TRAILER);
+
+	if (error_bitmap & QDF_MEM_DOUBLE_FREE)
+		qdf_err("Memory has previously been freed");
+
+	if (error_bitmap & QDF_MEM_BAD_FREED)
+		qdf_err("Corrupted memory freed flag 0x%x", header->freed);
+
+	if (error_bitmap & QDF_MEM_BAD_NODE)
+		qdf_err("Corrupted memory header node or double free");
+
+	if (error_bitmap & QDF_MEM_BAD_DOMAIN)
+		qdf_err("Corrupted memory domain 0x%x", header->domain);
+
+	if (error_bitmap & QDF_MEM_WRONG_DOMAIN)
+		qdf_err("Memory domain mismatch; found %s(%d), expected %s(%d)",
+			qdf_debug_domain_name(header->domain), header->domain,
+			qdf_debug_domain_name(current_domain), current_domain);
+
+	panic("A fatal memory error was detected @ %s:%d",
+	      kbasename(file), line);
+}
+#endif /* MEMORY_DEBUG */
 
 u_int8_t prealloc_disabled = 1;
 qdf_declare_param(prealloc_disabled, byte);
@@ -171,15 +321,15 @@ static int seq_printf_printer(void *priv, const char *fmt, ...)
 
 /**
  * struct __qdf_mem_info - memory statistics
- * @file_name:	the file which allocated memory
- * @line_num:	the line at which allocation happened
- * @size:	the size of allocation
- * @count:	how many allocations of same type
+ * @file: the file which allocated memory
+ * @line: the line at which allocation happened
+ * @size: the size of allocation
+ * @count: how many allocations of same type
  *
  */
 struct __qdf_mem_info {
-	char *file_name;
-	uint32_t line_num;
+	const char *file;
+	uint32_t line;
 	uint32_t size;
 	uint32_t count;
 };
@@ -230,8 +380,8 @@ static void qdf_mem_meta_table_print(struct __qdf_mem_info *table,
 		      table[i].count,
 		      table[i].size,
 		      table[i].count * table[i].size,
-		      kbasename(table[i].file_name),
-		      table[i].line_num);
+		      kbasename(table[i].file),
+		      table[i].line);
 	}
 }
 
@@ -243,21 +393,21 @@ static void qdf_mem_meta_table_print(struct __qdf_mem_info *table,
  * Return: true if the table is full after inserting, false otherwise
  */
 static bool qdf_mem_meta_table_insert(struct __qdf_mem_info *table,
-				      struct s_qdf_mem_struct *meta)
+				      struct qdf_mem_header *meta)
 {
 	int i;
 
 	for (i = 0; i < QDF_MEM_STAT_TABLE_SIZE; i++) {
 		if (!table[i].count) {
-			table[i].file_name = meta->file_name;
-			table[i].line_num = meta->line_num;
+			table[i].file = meta->file;
+			table[i].line = meta->line;
 			table[i].size = meta->size;
 			table[i].count = 1;
 			break;
 		}
 
-		if (table[i].file_name == meta->file_name &&
-		    table[i].line_num == meta->line_num &&
+		if (table[i].file == meta->file &&
+		    table[i].line == meta->line &&
 		    table[i].size == meta->size) {
 			table[i].count++;
 			break;
@@ -291,7 +441,7 @@ static void qdf_mem_domain_print(qdf_list_t *domain,
 	qdf_spin_lock(&qdf_mem_list_lock);
 	status = qdf_list_peek_front(domain, &node);
 	while (QDF_IS_STATUS_SUCCESS(status)) {
-		struct s_qdf_mem_struct *meta = (struct s_qdf_mem_struct *)node;
+		struct qdf_mem_header *meta = (struct qdf_mem_header *)node;
 		bool is_full = qdf_mem_meta_table_insert(table, meta);
 
 		qdf_spin_unlock(&qdf_mem_list_lock);
@@ -735,16 +885,18 @@ EXPORT_SYMBOL(qdf_mem_zero_outline);
  */
 static void *qdf_mem_prealloc_get(size_t size)
 {
-	void *mem;
+	void *ptr;
 
 	if (size <= WCNSS_PRE_ALLOC_GET_THRESHOLD)
 		return NULL;
 
-	mem = wcnss_prealloc_get(size);
-	if (mem)
-		memset(mem, 0, size);
+	ptr = wcnss_prealloc_get(size);
+	if (!ptr)
+		return NULL;
 
-	return mem;
+	memset(ptr, 0, size);
+
+	return ptr;
 }
 
 static inline bool qdf_mem_prealloc_put(void *ptr)
@@ -763,6 +915,14 @@ static inline bool qdf_mem_prealloc_put(void *ptr)
 }
 #endif /* CONFIG_WCNSS_MEM_PRE_ALLOC */
 
+static int qdf_mem_malloc_flags(void)
+{
+	if (in_interrupt() || irqs_disabled() || in_atomic())
+		return GFP_ATOMIC;
+
+	return GFP_KERNEL;
+}
+
 /* External Function implementation */
 #ifdef MEMORY_DEBUG
 
@@ -867,245 +1027,83 @@ static void qdf_mem_debug_exit(void)
 	qdf_spinlock_destroy(&qdf_mem_list_lock);
 }
 
-/**
- * qdf_mem_malloc_debug() - debug version of QDF memory allocation API
- * @size: Number of bytes of memory to allocate.
- * @file_name: File name from which memory allocation is called
- * @line_num: Line number from which memory allocation is called
- *
- * This function will dynamicallly allocate the specified number of bytes of
- * memory and ad it in qdf tracking list to check against memory leaks and
- * corruptions
- *
- * Return:
- * Upon successful allocate, returns a non-NULL pointer to the allocated
- * memory.  If this function is unable to allocate the amount of memory
- * specified (for any reason) it returns %NULL.
- */
-void *qdf_mem_malloc_debug(size_t size, char *file_name, uint32_t line_num)
+void *qdf_mem_malloc_debug(size_t size, const char *file, uint32_t line)
 {
+	QDF_STATUS status;
 	enum qdf_debug_domain current_domain = qdf_debug_domain_get();
 	qdf_list_t *mem_list = qdf_mem_list_get(current_domain);
-	struct s_qdf_mem_struct *mem_struct;
-	void *mem_ptr = NULL;
-	uint32_t new_size;
-	int flags = GFP_KERNEL;
-	unsigned long time_before_kzalloc;
+	struct qdf_mem_header *header;
+	void *ptr;
+	unsigned long start, duration;
 
-	if (size > (1024 * 1024) || size == 0) {
-		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
-			  "%s: called with invalid arg; passed in %zu !!!",
-			  __func__, size);
+	if (!size || size > QDF_MEM_MAX_MALLOC) {
+		qdf_err("Cannot malloc %zu bytes @ %s:%d", size, file, line);
 		return NULL;
 	}
 
-	mem_ptr = qdf_mem_prealloc_get(size);
-	if (mem_ptr)
-		return mem_ptr;
+	ptr = qdf_mem_prealloc_get(size);
+	if (ptr)
+		return ptr;
 
-	if (in_interrupt() || irqs_disabled() || in_atomic())
-		flags = GFP_ATOMIC;
-
-	new_size = sizeof(*mem_struct) + size + sizeof(WLAN_MEM_TAIL);
-	time_before_kzalloc = qdf_mc_timer_get_system_time();
-	mem_struct = kzalloc(new_size, flags);
-	/**
-	 * If time taken by kmalloc is greater than
-	 * QDF_GET_MEMORY_TIME_THRESHOLD msec
-	 */
-	if (qdf_mc_timer_get_system_time() - time_before_kzalloc >=
-					  QDF_GET_MEMORY_TIME_THRESHOLD)
-			QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
-				  "%s: kzalloc took %lu msec for size %zu called from %p_s at line %d",
-			 __func__,
-			 qdf_mc_timer_get_system_time() - time_before_kzalloc,
-			 size, (void *)_RET_IP_, line_num);
-
-	if (mem_struct) {
-		QDF_STATUS status;
-		uint64_t *trailer;
-
-		mem_ptr = (void *)(mem_struct + 1);
-		trailer = (uint64_t *)(mem_ptr + size);
-
-		mem_struct->file_name = file_name;
-		mem_struct->line_num = line_num;
-		mem_struct->size = size;
-		mem_struct->domain = current_domain;
-		mem_struct->header = WLAN_MEM_HEADER;
-		*trailer = WLAN_MEM_TAIL;
-
-		qdf_mem_kmalloc_inc(ksize(mem_struct));
-
-		qdf_spin_lock_irqsave(&qdf_mem_list_lock);
-		status = qdf_list_insert_front(mem_list, &mem_struct->node);
-		qdf_spin_unlock_irqrestore(&qdf_mem_list_lock);
-		if (QDF_IS_STATUS_ERROR(status))
-			qdf_err("Unable to insert into list status %d", status);
-	}
+	start = qdf_mc_timer_get_system_time();
+	header = kzalloc(size + QDF_MEM_DEBUG_SIZE, qdf_mem_malloc_flags());
+	duration = qdf_mc_timer_get_system_time() - start;
 
-	return mem_ptr;
-}
-EXPORT_SYMBOL(qdf_mem_malloc_debug);
+	if (duration > QDF_MEM_WARN_THRESHOLD)
+		qdf_warn("Malloc slept; %lums, %zuB @ %s:%d",
+			 duration, size, file, line);
 
-/**
- * qdf_mem_validate_node_for_free() - validate that the node is in a list
- * @qdf_node: node to check for being in a list
- *
- * qdf_node should be a non null value.
- *
- * Return: true if the node validly linked in an anchored doubly linked list
- */
-static bool qdf_mem_validate_node_for_free(qdf_list_node_t *qdf_node)
-{
-	struct list_head *node = qdf_node;
-
-	/*
-	 * if the node is an empty list, it is not tied to an anchor node
-	 * and must have been removed with list_del_init
-	 */
-	if (list_empty(node))
-		return false;
-
-	if (node->prev == NULL)
-		return false;
+	if (!header)
+		return NULL;
 
-	if (node->next == NULL)
-		return false;
+	qdf_mem_header_init(header, size, file, line);
+	ptr = qdf_mem_get_ptr(header);
 
-	if (node->prev->next != node)
-		return false;
+	qdf_spin_lock_irqsave(&qdf_mem_list_lock);
+	status = qdf_list_insert_front(mem_list, &header->node);
+	qdf_spin_unlock_irqrestore(&qdf_mem_list_lock);
+	if (QDF_IS_STATUS_ERROR(status))
+		qdf_err("Failed to insert memory header; status %d", status);
 
-	if (node->next->prev != node)
-		return false;
+	qdf_mem_kmalloc_inc(size);
 
-	return true;
+	return ptr;
 }
+qdf_export_symbol(qdf_mem_malloc_debug);
 
-
-
-/**
- * qdf_mem_free() - QDF memory free API
- * @ptr: Pointer to the starting address of the memory to be free'd.
- *
- * This function will free the memory pointed to by 'ptr'. It also checks
- * is memory is corrupted or getting double freed and panic.
- *
- * Return: none
- */
-void qdf_mem_free(void *ptr)
+void qdf_mem_free_debug(void *ptr, const char *file, uint32_t line)
 {
 	enum qdf_debug_domain current_domain = qdf_debug_domain_get();
-	qdf_list_t *mem_list = qdf_mem_list_get(current_domain);
-	struct s_qdf_mem_struct *mem_struct;
-	uint64_t *trailer;
+	struct qdf_mem_header *header;
+	enum qdf_mem_validation_bitmap error_bitmap;
 
 	/* freeing a null pointer is valid */
-	if (qdf_unlikely(ptr == NULL))
+	if (qdf_unlikely(!ptr))
 		return;
 
 	if (qdf_mem_prealloc_put(ptr))
 		return;
 
-	mem_struct = ((struct s_qdf_mem_struct *)ptr) - 1;
-
-	if (qdf_unlikely(mem_struct == NULL)) {
-		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
-			  "%s: null mem_struct", __func__);
-		QDF_BUG(0);
-	}
-
-	trailer = (uint64_t *)(ptr + mem_struct->size);
+	if (qdf_unlikely((qdf_size_t)ptr <= sizeof(*header)))
+		panic("Failed to free invalid memory location %pK", ptr);
 
 	qdf_spin_lock_irqsave(&qdf_mem_list_lock);
-
-	/*
-	 * invalid memory access when checking the header/tailer
-	 * would be a use after free and would indicate a double free
-	 * or invalid pointer passed.
-	 */
-	if (mem_struct->header != WLAN_MEM_HEADER)
-		goto error;
-
-	/*
-	 * invalid memory access while checking validate node
-	 * would indicate corruption in the nodes pointed to
-	 */
-	if (!qdf_mem_validate_node_for_free(&mem_struct->node))
-		goto error;
-
-	/*
-	 * invalid memory access here is unlikely and would imply
-	 * that the size value was corrupted/incorrect.
-	 * It is unlikely that the above checks would pass in a
-	 * double free case.
-	 */
-	if (*trailer != WLAN_MEM_TAIL)
-		goto error;
-
-	/* make sure the memory belongs to the current domain */
-	if (mem_struct->domain != current_domain) {
-		qdf_spin_unlock_irqrestore(&qdf_mem_list_lock);
-		qdf_err("Memory domain mismatch; found %s, expected %s (%s:%u)",
-			qdf_debug_domain_name(mem_struct->domain),
-			qdf_debug_domain_name(current_domain),
-			kbasename(mem_struct->file_name),
-			mem_struct->line_num);
-		qdf_mem_leak_panic();
-
-		/* continue de-allocation if we didn't crash */
-		qdf_spin_lock_irqsave(&qdf_mem_list_lock);
+	header = qdf_mem_get_header(ptr);
+	error_bitmap = qdf_mem_header_validate(header, current_domain);
+	if (!error_bitmap) {
+		header->freed = true;
+		list_del_init(&header->node);
+		qdf_mem_list_get(header->domain)->count--;
 	}
-
-	/*
-	 * make the node an empty list before doing the spin unlock
-	 * The empty list check will guarantee that we avoid a race condition.
-	 */
-	list_del_init(&mem_struct->node);
-	mem_list->count--;
-	qdf_mem_kmalloc_dec(ksize(mem_struct));
-	kfree(mem_struct);
 	qdf_spin_unlock_irqrestore(&qdf_mem_list_lock);
 
-	return;
-
-error:
-	if (!qdf_list_has_node(mem_list, &mem_struct->node)) {
-		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
-			  "%s: Unallocated memory (double free?)",
-			  __func__);
-		qdf_spin_unlock_irqrestore(&qdf_mem_list_lock);
-		QDF_BUG(0);
-	}
-
-	if (mem_struct->header != WLAN_MEM_HEADER) {
-		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
-			  "Memory Header is corrupted.");
-		qdf_spin_unlock_irqrestore(&qdf_mem_list_lock);
-		QDF_BUG(0);
-	}
+	qdf_mem_header_assert_valid(header, current_domain, error_bitmap,
+				    file, line);
 
-	if (!qdf_mem_validate_node_for_free(&mem_struct->node)) {
-		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
-			  "Memory_struct is corrupted.");
-		qdf_spin_unlock_irqrestore(&qdf_mem_list_lock);
-		QDF_BUG(0);
-	}
-
-	if (*trailer != WLAN_MEM_TAIL) {
-		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
-			  "Memory Trailer is corrupted. mem_info: Filename %s, line_num %d",
-			  mem_struct->file_name, (int)mem_struct->line_num);
-		qdf_spin_unlock_irqrestore(&qdf_mem_list_lock);
-		QDF_BUG(0);
-	}
-
-	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
-		  "%s unexpected error", __func__);
-	qdf_spin_unlock_irqrestore(&qdf_mem_list_lock);
-	QDF_BUG(0);
+	qdf_mem_kmalloc_dec(header->size);
+	kfree(header);
 }
-EXPORT_SYMBOL(qdf_mem_free);
+qdf_export_symbol(qdf_mem_free_debug);
 
 void qdf_mem_check_for_leaks(void)
 {
@@ -1139,23 +1137,19 @@ static void qdf_mem_debug_exit(void) {}
  */
 void *qdf_mem_malloc(size_t size)
 {
-	int flags = GFP_KERNEL;
-	void *mem;
-
-	mem = qdf_mem_prealloc_get(size);
-	if (mem)
-		return mem;
-
-	if (in_interrupt() || irqs_disabled() || in_atomic())
-		flags = GFP_ATOMIC;
+	void *ptr;
 
-	mem = kzalloc(size, flags);
+	ptr = qdf_mem_prealloc_get(size);
+	if (ptr)
+		return ptr;
 
-	if (mem)
-		qdf_mem_kmalloc_inc(ksize(mem));
+	ptr = kzalloc(size, qdf_mem_malloc_flags());
+	if (!ptr)
+		return NULL;
 
-	return mem;
+	qdf_mem_kmalloc_inc(ksize(ptr));
 
+	return ptr;
 }
 EXPORT_SYMBOL(qdf_mem_malloc);
 
@@ -1530,50 +1524,44 @@ void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size,
 void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size,
 			       qdf_dma_addr_t *phy_addr)
 {
-	int flags = GFP_KERNEL;
-	void *alloc_mem = NULL;
-	int alloc_try_high_mem = 0;
-
-	if (in_interrupt() || irqs_disabled() || in_atomic())
-		flags = GFP_ATOMIC;
+	void *vaddr = NULL;
+	int i;
 
 	*phy_addr = 0;
 
-	while (alloc_try_high_mem++ < QDF_MEM_ALLOC_X86_MAX_RETRIES) {
-		alloc_mem = dma_alloc_coherent(dev, size, phy_addr, flags);
+	for (i = 0; i < QDF_MEM_ALLOC_X86_MAX_RETRIES; i++) {
+		vaddr = dma_alloc_coherent(dev, size, phy_addr,
+					   qdf_mem_malloc_flags());
 
-		if (alloc_mem == NULL) {
+		if (!vaddr) {
 			qdf_print("%s failed , size: %zu!\n", __func__, size);
 			return NULL;
 		}
 
-		if (*phy_addr < QCA8074_RAM_BASE) {
-			dma_free_coherent(dev, size, alloc_mem, *phy_addr);
-			alloc_mem = NULL;
-		} else
-			break;
+		if (*phy_addr >= QCA8074_RAM_BASE)
+			return vaddr;
+
+		dma_free_coherent(dev, size, vaddr, *phy_addr);
 	}
 
-	return alloc_mem;
+	return NULL;
 }
 #else
 void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size,
 			       qdf_dma_addr_t *phy_addr)
 {
-	int flags = GFP_KERNEL;
-	void *alloc_mem = NULL;
+	void *ptr;
 
-	if (in_interrupt() || irqs_disabled() || in_atomic())
-		flags = GFP_ATOMIC;
+	ptr = dma_alloc_coherent(dev, size, phy_addr, qdf_mem_malloc_flags());
+	if (!ptr) {
+		qdf_warn("Warning: unable to alloc consistent memory of size %zu!\n",
+			 size);
+		return NULL;
+	}
 
-	alloc_mem = dma_alloc_coherent(dev, size, phy_addr, flags);
-	if (alloc_mem == NULL)
-		qdf_print("%s Warning: unable to alloc consistent memory of size %zu!\n",
-			__func__, size);
-	else
-		qdf_mem_dma_inc(size);
+	qdf_mem_dma_inc(size);
 
-	return alloc_mem;
+	return ptr;
 }
 
 #endif