diff --git a/qdf/inc/qdf_mem.h b/qdf/inc/qdf_mem.h index 7c9b7e2317..04b9bd3440 100644 --- a/qdf/inc/qdf_mem.h +++ b/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); + +/** + * qdf_mem_free() - free QDF memory + * @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); -/** - * 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 - */ -void qdf_mem_free(void *ptr); - void qdf_mem_set(void *ptr, uint32_t num_bytes, uint32_t value); void qdf_mem_zero(void *ptr, uint32_t num_bytes); diff --git a/qdf/linux/src/qdf_mem.c b/qdf/linux/src/qdf_mem.c index f5b4d794ec..a5185fedc5 100644 --- a/qdf/linux/src/qdf_mem.c +++ b/qdf/linux/src/qdf_mem.c @@ -60,6 +60,10 @@ #include "qdf_debug_domain.h" #include +/* 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; + 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; - 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 (duration > QDF_MEM_WARN_THRESHOLD) + qdf_warn("Malloc slept; %lums, %zuB @ %s:%d", + duration, size, file, line); - if (mem_struct) { - QDF_STATUS status; - uint64_t *trailer; + if (!header) + return NULL; - mem_ptr = (void *)(mem_struct + 1); - trailer = (uint64_t *)(mem_ptr + size); + qdf_mem_header_init(header, size, file, line); + ptr = qdf_mem_get_ptr(header); - 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_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); - qdf_mem_kmalloc_inc(ksize(mem_struct)); + qdf_mem_kmalloc_inc(size); - 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); - } - - return mem_ptr; + return ptr; } -EXPORT_SYMBOL(qdf_mem_malloc_debug); +qdf_export_symbol(qdf_mem_malloc_debug); -/** - * 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 (node->next == NULL) - return false; - - if (node->prev->next != node) - return false; - - if (node->next->prev != node) - return false; - - return true; -} - - - -/** - * 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; + qdf_mem_header_assert_valid(header, current_domain, error_bitmap, + file, line); -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); - } - - 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; + void *ptr; - mem = qdf_mem_prealloc_get(size); - if (mem) - return mem; + ptr = qdf_mem_prealloc_get(size); + if (ptr) + return ptr; - if (in_interrupt() || irqs_disabled() || in_atomic()) - flags = GFP_ATOMIC; + ptr = kzalloc(size, qdf_mem_malloc_flags()); + if (!ptr) + return NULL; - mem = kzalloc(size, flags); - - if (mem) - qdf_mem_kmalloc_inc(ksize(mem)); - - 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