diff options
| author | Himanshu Agarwal <himanaga@codeaurora.org> | 2017-11-22 16:53:26 +0530 |
|---|---|---|
| committer | Himanshu Agarwal <himanaga@codeaurora.org> | 2017-11-22 17:40:30 +0530 |
| commit | fafb2e2c467a42f36daa72a89ac9f5d6a5069219 (patch) | |
| tree | 0471ccb5cc706b43eb73b2deecce96ca20164793 | |
| parent | 6f1316f48bc142362bb688854f674213da6522ad (diff) | |
Revert "qcacmn: Add memory debug support for DMA allocations"
This reverts Change-id: I25c60a1c5d264e7ea08ed2286fd4b3c3134e9f81
When SMMU is enabled, crash is happening as soon as first client
is connected to softap interface with this change.
Change-Id: I4aa6ff39899117aeb050957eb888642822ae830d
CRs-Fixed: 2147823
| -rw-r--r-- | qdf/inc/qdf_mem.h | 42 | ||||
| -rw-r--r-- | qdf/linux/src/qdf_mem.c | 286 |
2 files changed, 121 insertions, 207 deletions
diff --git a/qdf/inc/qdf_mem.h b/qdf/inc/qdf_mem.h index 859a37fc36b3..e05af7634bce 100644 --- a/qdf/inc/qdf_mem.h +++ b/qdf/inc/qdf_mem.h @@ -211,44 +211,12 @@ void qdf_mem_move(void *dst_addr, const void *src_addr, uint32_t num_bytes); void qdf_mem_free_outline(void *buf); -/** - * __qdf_mem_alloc_consistent() - allocates consistent qdf memory - * @osdev: OS device handle - * @dev: Pointer to device handle - * @size: Size to be allocated - * @paddr: Physical address - * @file: file name of the call site - * @line: line numbe rof the call site - * - * Return: pointer of allocated memory or null if memory alloc fails - */ -void *__qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, - qdf_size_t size, qdf_dma_addr_t *paddr, - const char *file, uint32_t line); - -#define qdf_mem_alloc_consistent(osdev, dev, size, paddr) \ - __qdf_mem_alloc_consistent(osdev, dev, size, paddr, __FILE__, __LINE__) - -/** - * __qdf_mem_free_consistent() - free consistent qdf memory - * @osdev: OS device handle - * @size: Size to be allocated - * @vaddr: virtual address - * @paddr: Physical address - * @memctx: Pointer to DMA context - * @file: file name of the call site - * @line: line numbe rof the call site - * - * Return: none - */ -void __qdf_mem_free_consistent(qdf_device_t osdev, void *dev, - qdf_size_t size, void *vaddr, - qdf_dma_addr_t paddr, qdf_dma_context_t memctx, - const char *file, uint32_t line); +void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size, + qdf_dma_addr_t *paddr); -#define qdf_mem_free_consistent(osdev, dev, size, vaddr, paddr, memctx) \ - __qdf_mem_free_consistent(osdev, dev, size, vaddr, paddr, memctx, \ - __FILE__, __LINE__) +void qdf_mem_free_consistent(qdf_device_t osdev, void *dev, qdf_size_t size, + void *vaddr, qdf_dma_addr_t paddr, + qdf_dma_context_t memctx); void qdf_mem_zero_outline(void *buf, qdf_size_t size); diff --git a/qdf/linux/src/qdf_mem.c b/qdf/linux/src/qdf_mem.c index 1604d8af3cd7..f4d59a9c15de 100644 --- a/qdf/linux/src/qdf_mem.c +++ b/qdf/linux/src/qdf_mem.c @@ -98,9 +98,6 @@ const uint8_t *qdf_mem_domain_name(enum qdf_mem_domain domain) static qdf_list_t qdf_mem_domains[QDF_MEM_DOMAIN_MAX_COUNT]; static qdf_spinlock_t qdf_mem_list_lock; -static qdf_list_t qdf_mem_dma_domains[QDF_MEM_DOMAIN_MAX_COUNT]; -static qdf_spinlock_t qdf_mem_dma_list_lock; - static uint64_t WLAN_MEM_HEADER = 0x6162636465666768; static uint64_t WLAN_MEM_TRAILER = 0x8081828384858687; @@ -112,24 +109,11 @@ static inline qdf_list_t *qdf_mem_list(enum qdf_mem_domain domain) return &qdf_mem_domains[domain]; } -static inline qdf_list_t *qdf_mem_dma_list(enum qdf_mem_domain domain) -{ - if (domain < QDF_MEM_DOMAIN_INIT || domain >= QDF_MEM_DOMAIN_MAX_COUNT) - return NULL; - - return &qdf_mem_dma_domains[domain]; -} - static inline qdf_list_t *qdf_mem_active_list(void) { return &qdf_mem_domains[qdf_mem_get_domain()]; } -static inline qdf_list_t *qdf_mem_dma_active_list(void) -{ - return &qdf_mem_dma_domains[qdf_mem_get_domain()]; -} - /** * struct qdf_mem_header - memory object to dubug * @node: node to the list @@ -992,46 +976,78 @@ static void qdf_mem_debug_init(void) { int i; + /* Initalizing the list with maximum size of 60000 */ qdf_mem_current_domain = QDF_MEM_DOMAIN_INIT; - - /* mem */ for (i = 0; i < QDF_MEM_DOMAIN_MAX_COUNT; ++i) qdf_list_create(&qdf_mem_domains[i], 60000); qdf_spinlock_create(&qdf_mem_list_lock); - - /* dma */ - for (i = 0; i < QDF_MEM_DOMAIN_MAX_COUNT; ++i) - qdf_list_create(&qdf_mem_dma_domains[i], 0); - qdf_spinlock_create(&qdf_mem_dma_list_lock); - - /* skb */ qdf_net_buf_debug_init(); } -static uint32_t -qdf_mem_domain_check_for_leaks(enum qdf_mem_domain domain, qdf_list_t *mem_list) +#ifdef CONFIG_HALT_KMEMLEAK +/* + * There are two scenarios for handling memory leaks. We want to either: + * 1) Crash and not release memory for offline debugging (internal testing) + * 2) Clean up any leaks and continue (production devices) + */ + +static inline void qdf_mem_leak_panic(void) { - if (qdf_list_empty(mem_list)) - return 0; + QDF_BUG(0); +} - qdf_err("Memory leaks detected in %s domain!", - qdf_mem_domain_name(domain)); - qdf_mem_domain_print(mem_list, qdf_err_printer, NULL); +static inline void qdf_mem_free_leaked_memory(qdf_list_t *domain) { } +#else +static inline void qdf_mem_leak_panic(void) { } + +static void qdf_mem_free_leaked_memory(qdf_list_t *domain) +{ + QDF_STATUS status; + qdf_list_node_t *node; - return mem_list->count; + qdf_spin_lock(&qdf_mem_list_lock); + status = qdf_list_remove_front(domain, &node); + while (QDF_IS_STATUS_SUCCESS(status)) { + kfree(node); + status = qdf_list_remove_front(domain, &node); + } + qdf_spin_unlock(&qdf_mem_list_lock); } +#endif -static void qdf_mem_domain_set_check_for_leaks(qdf_list_t *domains) +/** + * qdf_mem_debug_clean() - display memory leak debug info and free leaked + * pointers + * + * Return: none + */ +static void qdf_mem_debug_clean(void) { - uint32_t leak_count = 0; + bool leaks_detected = false; int i; /* detect and print leaks */ - for (i = 0; i < QDF_MEM_DOMAIN_MAX_COUNT; ++i) - leak_count += qdf_mem_domain_check_for_leaks(i, domains + i); + for (i = 0; i < QDF_MEM_DOMAIN_MAX_COUNT; ++i) { + qdf_list_t *domain = &qdf_mem_domains[i]; + + if (qdf_list_empty(domain)) + continue; + + leaks_detected = true; + + qdf_err("\nMemory leaks detected in the %s (Id %d) domain!\n\n", + qdf_mem_domain_name(i), i); + qdf_mem_domain_print(domain, qdf_err_printer, NULL); + } - if (leak_count) - panic("%u fatal memory leaks detected!", leak_count); + if (leaks_detected) { + /* panic, if enabled */ + qdf_mem_leak_panic(); + + /* if we didn't crash, release the leaked memory */ + for (i = 0; i < QDF_MEM_DOMAIN_MAX_COUNT; ++i) + qdf_mem_free_leaked_memory(&qdf_mem_domains[i]); + } } /** @@ -1043,20 +1059,13 @@ static void qdf_mem_debug_exit(void) { int i; - /* skb */ qdf_net_buf_debug_exit(); + qdf_mem_debug_clean(); - /* mem */ - qdf_mem_domain_set_check_for_leaks(qdf_mem_domains); for (i = 0; i < QDF_MEM_DOMAIN_MAX_COUNT; ++i) qdf_list_destroy(&qdf_mem_domains[i]); - qdf_spinlock_destroy(&qdf_mem_list_lock); - /* dma */ - qdf_mem_domain_set_check_for_leaks(qdf_mem_dma_domains); - for (i = 0; i < QDF_MEM_DOMAIN_MAX_COUNT; ++i) - qdf_list_destroy(&qdf_mem_dma_domains[i]); - qdf_spinlock_destroy(&qdf_mem_dma_list_lock); + qdf_spinlock_destroy(&qdf_mem_list_lock); } void *qdf_mem_malloc_debug(size_t size, const char *file, uint32_t line) @@ -1084,10 +1093,8 @@ void *qdf_mem_malloc_debug(size_t size, const char *file, uint32_t line) qdf_warn("Malloc slept; %lums, %zuB @ %s:%d", duration, size, file, line); - if (!header) { - qdf_warn("Failed to malloc %zuB @ %s:%d", size, file, line); + if (!header) return NULL; - } qdf_mem_header_init(header, size, file, line); ptr = qdf_mem_get_ptr(header); @@ -1150,14 +1157,14 @@ void qdf_mem_check_for_leaks(void) { enum qdf_mem_domain domain = qdf_mem_current_domain; qdf_list_t *mem_list = &qdf_mem_domains[domain]; - qdf_list_t *dma_list = &qdf_mem_dma_domains[domain]; - uint32_t leaks_count = 0; - leaks_count += qdf_mem_domain_check_for_leaks(domain, mem_list); - leaks_count += qdf_mem_domain_check_for_leaks(domain, dma_list); + if (qdf_list_empty(mem_list)) + return; - if (leaks_count) - panic("%u fatal memory leaks detected!", leaks_count); + qdf_err("Memory leaks detected in %s domain!", + qdf_mem_domain_name(domain)); + qdf_mem_domain_print(mem_list, qdf_err_printer, NULL); + qdf_mem_leak_panic(); } #else static void qdf_mem_debug_init(void) {} @@ -1472,146 +1479,85 @@ void qdf_mem_move(void *dst_addr, const void *src_addr, uint32_t num_bytes) qdf_export_symbol(qdf_mem_move); #if defined(A_SIMOS_DEVHOST) || defined(HIF_SDIO) || defined(HIF_USB) -static inline void *qdf_mem_dma_alloc(qdf_device_t osdev, void *dev, - qdf_size_t size, qdf_dma_addr_t *paddr) +/** + * qdf_mem_alloc_consistent() - allocates consistent qdf memory + * @osdev: OS device handle + * @dev: Pointer to device handle + * @size: Size to be allocated + * @phy_addr: Physical address + * + * Return: pointer of allocated memory or null if memory alloc fails + */ +void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size, + qdf_dma_addr_t *phy_addr) { void *vaddr; - vaddr = kzmalloc(size, qdf_mem_malloc_flags()); - *paddr = (uintptr_t)vaddr; + vaddr = qdf_mem_malloc(size); + *phy_addr = ((uintptr_t) vaddr); /* using this type conversion to suppress "cast from pointer to integer * of different size" warning on some platforms */ - BUILD_BUG_ON(sizeof(*paddr) < sizeof(vaddr)); - + BUILD_BUG_ON(sizeof(*phy_addr) < sizeof(vaddr)); + if (vaddr) + qdf_mem_dma_inc(ksize(vaddr)); return vaddr; } -#else -static inline void *qdf_mem_dma_alloc(qdf_device_t osdev, void *dev, - qdf_size_t size, qdf_dma_addr_t *paddr) -{ - return dma_alloc_coherent(dev, size, paddr, qdf_mem_malloc_flags()); -} -#endif -#ifdef MEMORY_DEBUG -void *__qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, - qdf_size_t size, qdf_dma_addr_t *paddr, - const char *file, uint32_t line) +#else +void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size, + qdf_dma_addr_t *phy_addr) { - QDF_STATUS status; - qdf_list_t *mem_list = qdf_mem_dma_active_list(); - struct qdf_mem_header *header; - void *vaddr; - unsigned long start, duration; - - if (!size || size > QDF_MEM_MAX_MALLOC) { - qdf_err("Cannot malloc %zu bytes @ %s:%d", size, file, line); - return NULL; - } - - start = qdf_mc_timer_get_system_time(); - header = qdf_mem_dma_alloc(osdev, dev, size + QDF_MEM_DEBUG_SIZE, - paddr); - duration = qdf_mc_timer_get_system_time() - start; - - if (duration > QDF_MEM_WARN_THRESHOLD) - qdf_warn("Malloc slept; %lums, %zuB @ %s:%d", - duration, size, file, line); + void *ptr; - if (!header) { - qdf_warn("Failed to malloc %zuB @ %s:%d", size, file, line); + 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; } - qdf_mem_header_init(header, size, file, line); - vaddr = qdf_mem_get_ptr(header); - *paddr += sizeof(*header); - - qdf_spin_lock_irqsave(&qdf_mem_dma_list_lock); - status = qdf_list_insert_front(mem_list, &header->node); - qdf_spin_unlock_irqrestore(&qdf_mem_dma_list_lock); - if (QDF_IS_STATUS_ERROR(status)) - qdf_err("Failed to insert memory header; status %d", status); - qdf_mem_dma_inc(size); - return vaddr; + return ptr; } -#else -void *__qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, - qdf_size_t size, qdf_dma_addr_t *paddr, - const char *file, uint32_t line) -{ - void *vaddr = qdf_mem_dma_alloc(osdev, dev, size, paddr); - - if (vaddr) - qdf_mem_dma_inc(size); - return vaddr; -} -#endif /* MEMORY_DEBUG */ -qdf_export_symbol(__qdf_mem_alloc_consistent); +#endif +qdf_export_symbol(qdf_mem_alloc_consistent); #if defined(A_SIMOS_DEVHOST) || defined(HIF_SDIO) || defined(HIF_USB) -inline void -qdf_mem_dma_free(void *dev, qdf_size_t size, void *vaddr, qdf_dma_addr_t paddr) +/** + * qdf_mem_free_consistent() - free consistent qdf memory + * @osdev: OS device handle + * @size: Size to be allocated + * @vaddr: virtual address + * @phy_addr: Physical address + * @mctx: Pointer to DMA context + * + * Return: none + */ +inline void qdf_mem_free_consistent(qdf_device_t osdev, void *dev, + qdf_size_t size, void *vaddr, + qdf_dma_addr_t phy_addr, + qdf_dma_context_t memctx) { - kfree(vaddr); + qdf_mem_dma_dec(ksize(vaddr)); + qdf_mem_free(vaddr); + return; } #else -inline void -qdf_mem_dma_free(void *dev, qdf_size_t size, void *vaddr, qdf_dma_addr_t paddr) -{ - dma_free_coherent(dev, size, vaddr, paddr); -} -#endif - -#ifdef MEMORY_DEBUG -void __qdf_mem_free_consistent(qdf_device_t osdev, void *dev, - qdf_size_t size, void *vaddr, - qdf_dma_addr_t paddr, qdf_dma_context_t memctx, - const char *file, uint32_t line) -{ - enum qdf_mem_domain domain = qdf_mem_get_domain(); - struct qdf_mem_header *header; - enum qdf_mem_validation_bitmap error_bitmap; - - /* freeing a null pointer is valid */ - if (qdf_unlikely(!vaddr)) - return; - - if (qdf_unlikely((qdf_size_t)vaddr <= sizeof(*header))) - panic("Failed to free invalid memory location %pK", vaddr); - - qdf_spin_lock_irqsave(&qdf_mem_dma_list_lock); - header = qdf_mem_get_header(vaddr); - error_bitmap = qdf_mem_header_validate(header, domain); - if (!error_bitmap) { - header->freed = true; - list_del_init(&header->node); - qdf_mem_dma_list(header->domain)->count--; - } - qdf_spin_unlock_irqrestore(&qdf_mem_dma_list_lock); - - qdf_mem_header_assert_valid(header, domain, error_bitmap, file, line); - - qdf_mem_dma_dec(header->size); - qdf_mem_dma_free(dev, size + QDF_MEM_DEBUG_SIZE, header, - paddr - sizeof(*header)); -} -#else -void __qdf_mem_free_consistent(qdf_device_t osdev, void *dev, - qdf_size_t size, void *vaddr, - qdf_dma_addr_t paddr, qdf_dma_context_t memctx, - const char *file, uint32_t line) +inline void qdf_mem_free_consistent(qdf_device_t osdev, void *dev, + qdf_size_t size, void *vaddr, + qdf_dma_addr_t phy_addr, + qdf_dma_context_t memctx) { + dma_free_coherent(dev, size, vaddr, phy_addr); qdf_mem_dma_dec(size); - qdf_mem_dma_free(dev, size, vaddr, paddr); } -#endif /* MEMORY_DEBUG */ -qdf_export_symbol(__qdf_mem_free_consistent); + +#endif +qdf_export_symbol(qdf_mem_free_consistent); /** * qdf_mem_dma_sync_single_for_device() - assign memory to device |
