Loading drivers/net/wireless/cnss/cnss.c +3 −0 Original line number Diff line number Diff line Loading @@ -1691,6 +1691,9 @@ void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver) if (wdrv->remove) wdrv->remove(pdev); wcnss_prealloc_check_memory_leak(); wcnss_pre_alloc_reset(); if (penv->pcie_link_state && !penv->pcie_link_down_ind) { pci_save_state(pdev); penv->saved_state = pci_store_saved_state(pdev); Loading drivers/net/wireless/wcnss/wcnss_prealloc.c +70 −0 Original line number Diff line number Diff line Loading @@ -12,15 +12,24 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/stacktrace.h> #include <linux/wcnss_wlan.h> #include <linux/spinlock.h> static DEFINE_SPINLOCK(alloc_lock); #ifdef CONFIG_SLUB_DEBUG #define WCNSS_MAX_STACK_TRACE 64 #endif struct wcnss_prealloc { int occupied; unsigned int size; void *ptr; #ifdef CONFIG_SLUB_DEBUG unsigned long stack_trace[WCNSS_MAX_STACK_TRACE]; struct stack_trace trace; #endif }; /* pre-alloced mem for WLAN driver */ Loading Loading @@ -116,6 +125,28 @@ void wcnss_prealloc_deinit(void) } } #ifdef CONFIG_SLUB_DEBUG static void wcnss_prealloc_save_stack_trace(struct wcnss_prealloc *entry) { struct stack_trace *trace = &entry->trace; memset(&entry->stack_trace, 0, sizeof(entry->stack_trace)); trace->nr_entries = 0; trace->max_entries = WCNSS_MAX_STACK_TRACE; trace->entries = entry->stack_trace; trace->skip = 2; save_stack_trace(trace); return; } #else static inline void wcnss_prealloc_save_stack_trace(struct wcnss_prealloc *entry) { return; } #endif void *wcnss_prealloc_get(unsigned int size) { int i = 0; Loading @@ -130,10 +161,12 @@ void *wcnss_prealloc_get(unsigned int size) /* we found the slot */ wcnss_allocs[i].occupied = 1; spin_unlock_irqrestore(&alloc_lock, flags); wcnss_prealloc_save_stack_trace(&wcnss_allocs[i]); return wcnss_allocs[i].ptr; } } spin_unlock_irqrestore(&alloc_lock, flags); pr_err("wcnss: %s: prealloc not available for size: %d\n", __func__, size); Loading @@ -160,6 +193,43 @@ int wcnss_prealloc_put(void *ptr) } EXPORT_SYMBOL(wcnss_prealloc_put); #ifdef CONFIG_SLUB_DEBUG void wcnss_prealloc_check_memory_leak(void) { int i, j = 0; for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) { if (!wcnss_allocs[i].occupied) continue; if (j == 0) { pr_err("wcnss_prealloc: Memory leak detected\n"); j++; } pr_err("Size: %u, addr: %pK, backtrace:\n", wcnss_allocs[i].size, wcnss_allocs[i].ptr); print_stack_trace(&wcnss_allocs[i].trace, 1); } } #endif int wcnss_pre_alloc_reset(void) { int i, n = 0; for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) { if (!wcnss_allocs[i].occupied) continue; wcnss_allocs[i].occupied = 0; n++; } return n; } static int __init wcnss_pre_alloc_init(void) { return wcnss_prealloc_init(); Loading include/net/cnss.h +10 −0 Original line number Diff line number Diff line Loading @@ -152,7 +152,17 @@ extern void cnss_set_driver_status(enum cnss_driver_status driver_status); #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC extern void *wcnss_prealloc_get(unsigned int size); extern int wcnss_prealloc_put(void *ptr); extern int wcnss_pre_alloc_reset(void); #else static inline int wcnss_pre_alloc_reset(void) { return 0; } #endif #if defined(CONFIG_WCNSS_MEM_PRE_ALLOC) && defined(CONFIG_SLUB_DEBUG) void wcnss_prealloc_check_memory_leak(void); #else static inline void wcnss_prealloc_check_memory_leak(void) {} #endif extern int msm_pcie_enumerate(u32 rc_idx); #endif /* _NET_CNSS_H_ */ Loading
drivers/net/wireless/cnss/cnss.c +3 −0 Original line number Diff line number Diff line Loading @@ -1691,6 +1691,9 @@ void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver) if (wdrv->remove) wdrv->remove(pdev); wcnss_prealloc_check_memory_leak(); wcnss_pre_alloc_reset(); if (penv->pcie_link_state && !penv->pcie_link_down_ind) { pci_save_state(pdev); penv->saved_state = pci_store_saved_state(pdev); Loading
drivers/net/wireless/wcnss/wcnss_prealloc.c +70 −0 Original line number Diff line number Diff line Loading @@ -12,15 +12,24 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/stacktrace.h> #include <linux/wcnss_wlan.h> #include <linux/spinlock.h> static DEFINE_SPINLOCK(alloc_lock); #ifdef CONFIG_SLUB_DEBUG #define WCNSS_MAX_STACK_TRACE 64 #endif struct wcnss_prealloc { int occupied; unsigned int size; void *ptr; #ifdef CONFIG_SLUB_DEBUG unsigned long stack_trace[WCNSS_MAX_STACK_TRACE]; struct stack_trace trace; #endif }; /* pre-alloced mem for WLAN driver */ Loading Loading @@ -116,6 +125,28 @@ void wcnss_prealloc_deinit(void) } } #ifdef CONFIG_SLUB_DEBUG static void wcnss_prealloc_save_stack_trace(struct wcnss_prealloc *entry) { struct stack_trace *trace = &entry->trace; memset(&entry->stack_trace, 0, sizeof(entry->stack_trace)); trace->nr_entries = 0; trace->max_entries = WCNSS_MAX_STACK_TRACE; trace->entries = entry->stack_trace; trace->skip = 2; save_stack_trace(trace); return; } #else static inline void wcnss_prealloc_save_stack_trace(struct wcnss_prealloc *entry) { return; } #endif void *wcnss_prealloc_get(unsigned int size) { int i = 0; Loading @@ -130,10 +161,12 @@ void *wcnss_prealloc_get(unsigned int size) /* we found the slot */ wcnss_allocs[i].occupied = 1; spin_unlock_irqrestore(&alloc_lock, flags); wcnss_prealloc_save_stack_trace(&wcnss_allocs[i]); return wcnss_allocs[i].ptr; } } spin_unlock_irqrestore(&alloc_lock, flags); pr_err("wcnss: %s: prealloc not available for size: %d\n", __func__, size); Loading @@ -160,6 +193,43 @@ int wcnss_prealloc_put(void *ptr) } EXPORT_SYMBOL(wcnss_prealloc_put); #ifdef CONFIG_SLUB_DEBUG void wcnss_prealloc_check_memory_leak(void) { int i, j = 0; for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) { if (!wcnss_allocs[i].occupied) continue; if (j == 0) { pr_err("wcnss_prealloc: Memory leak detected\n"); j++; } pr_err("Size: %u, addr: %pK, backtrace:\n", wcnss_allocs[i].size, wcnss_allocs[i].ptr); print_stack_trace(&wcnss_allocs[i].trace, 1); } } #endif int wcnss_pre_alloc_reset(void) { int i, n = 0; for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) { if (!wcnss_allocs[i].occupied) continue; wcnss_allocs[i].occupied = 0; n++; } return n; } static int __init wcnss_pre_alloc_init(void) { return wcnss_prealloc_init(); Loading
include/net/cnss.h +10 −0 Original line number Diff line number Diff line Loading @@ -152,7 +152,17 @@ extern void cnss_set_driver_status(enum cnss_driver_status driver_status); #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC extern void *wcnss_prealloc_get(unsigned int size); extern int wcnss_prealloc_put(void *ptr); extern int wcnss_pre_alloc_reset(void); #else static inline int wcnss_pre_alloc_reset(void) { return 0; } #endif #if defined(CONFIG_WCNSS_MEM_PRE_ALLOC) && defined(CONFIG_SLUB_DEBUG) void wcnss_prealloc_check_memory_leak(void); #else static inline void wcnss_prealloc_check_memory_leak(void) {} #endif extern int msm_pcie_enumerate(u32 rc_idx); #endif /* _NET_CNSS_H_ */