summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYue Ma <yuem@codeaurora.org>2016-01-26 17:46:14 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:16:40 -0700
commit0c00aa87c1b8f3e28e9839b4970d078d47f1a469 (patch)
tree25854ce848632bbf990df684ddecceb7c333db7b
parentffe5134f23b5ba5d7ee8d24fa4b6c95104677b5f (diff)
net: cnss_prealloc: Add snapshot of cnss prealloc driver
This is a snapshot of the cnss prealloc driver and associated files as of msm-3.18 commit: e70ad0cd5efdd9dc91a77dcdac31d6132e1315c1 (Promotion of kernel.lnx. 3.18-151201.) Signed-off-by: Yue Ma <yuem@codeaurora.org>
-rw-r--r--drivers/net/wireless/Kconfig8
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/cnss_prealloc/Makefile2
-rw-r--r--drivers/net/wireless/cnss_prealloc/cnss_prealloc.c247
-rw-r--r--include/net/cnss_prealloc.h23
5 files changed, 282 insertions, 0 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 80177e0cf08e..057b5fb07d8d 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -295,6 +295,14 @@ config WCNSS_REGISTER_DUMP_ON_BITE
register access failures. So this feature is to enable/disable the
register dump on WCNSS WDOG bite.
+config WCNSS_MEM_PRE_ALLOC
+ tristate "WCNSS pre-alloc memory support"
+ ---help---
+ Pre-allocate memory for the WLAN driver module.
+ This feature enable cld wlan driver to use pre allocated memory
+ for it's internal usage and release it to back to pre allocated pool.
+ This memory is allocated at the cold boot time.
+
source "drivers/net/wireless/ath/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
source "drivers/net/wireless/b43legacy/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 2a97a0e9ee43..25d33bd9cde8 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -62,3 +62,5 @@ obj-$(CONFIG_CW1200) += cw1200/
obj-$(CONFIG_RSI_91X) += rsi/
obj-$(CONFIG_WCNSS_CORE) += wcnss/
+
+obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
diff --git a/drivers/net/wireless/cnss_prealloc/Makefile b/drivers/net/wireless/cnss_prealloc/Makefile
new file mode 100644
index 000000000000..a93da4900470
--- /dev/null
+++ b/drivers/net/wireless/cnss_prealloc/Makefile
@@ -0,0 +1,2 @@
+cnssprealloccore-objs += cnss_prealloc.o ../wcnss/qcomwlan_secif.o
+obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnssprealloccore.o
diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
new file mode 100644
index 000000000000..8cf48edbe592
--- /dev/null
+++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
@@ -0,0 +1,247 @@
+/* Copyright (c) 2012,2014-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#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 */
+static struct wcnss_prealloc wcnss_allocs[] = {
+ {0, 8 * 1024, NULL},
+ {0, 8 * 1024, NULL},
+ {0, 8 * 1024, NULL},
+ {0, 8 * 1024, NULL},
+ {0, 8 * 1024, NULL},
+ {0, 8 * 1024, NULL},
+ {0, 8 * 1024, NULL},
+ {0, 8 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 12 * 1024, NULL},
+ {0, 16 * 1024, NULL},
+ {0, 16 * 1024, NULL},
+ {0, 16 * 1024, NULL},
+ {0, 16 * 1024, NULL},
+ {0, 16 * 1024, NULL},
+ {0, 16 * 1024, NULL},
+ {0, 24 * 1024, NULL},
+ {0, 24 * 1024, NULL},
+ {0, 32 * 1024, NULL},
+ {0, 32 * 1024, NULL},
+ {0, 32 * 1024, NULL},
+ {0, 32 * 1024, NULL},
+ {0, 32 * 1024, NULL},
+ {0, 32 * 1024, NULL},
+ {0, 32 * 1024, NULL},
+ {0, 32 * 1024, NULL},
+ {0, 64 * 1024, NULL},
+ {0, 64 * 1024, NULL},
+ {0, 64 * 1024, NULL},
+ {0, 64 * 1024, NULL},
+ {0, 76 * 1024, NULL},
+};
+
+int wcnss_prealloc_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
+ wcnss_allocs[i].occupied = 0;
+ wcnss_allocs[i].ptr = kmalloc(wcnss_allocs[i].size, GFP_KERNEL);
+ if (wcnss_allocs[i].ptr == NULL)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void wcnss_prealloc_deinit(void)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
+ kfree(wcnss_allocs[i].ptr);
+ wcnss_allocs[i].ptr = NULL;
+ }
+}
+
+#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;
+ unsigned long flags;
+
+ spin_lock_irqsave(&alloc_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
+ if (wcnss_allocs[i].occupied)
+ continue;
+
+ if (wcnss_allocs[i].size > 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);
+
+ return NULL;
+}
+EXPORT_SYMBOL(wcnss_prealloc_get);
+
+int wcnss_prealloc_put(void *ptr)
+{
+ int i = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&alloc_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
+ if (wcnss_allocs[i].ptr == ptr) {
+ wcnss_allocs[i].occupied = 0;
+ spin_unlock_irqrestore(&alloc_lock, flags);
+ return 1;
+ }
+ }
+ spin_unlock_irqrestore(&alloc_lock, flags);
+
+ return 0;
+}
+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();
+}
+
+static void __exit wcnss_pre_alloc_exit(void)
+{
+ wcnss_prealloc_deinit();
+}
+
+module_init(wcnss_pre_alloc_init);
+module_exit(wcnss_pre_alloc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DEVICE "WCNSS Prealloc Driver");
diff --git a/include/net/cnss_prealloc.h b/include/net/cnss_prealloc.h
new file mode 100644
index 000000000000..734b4b69ecbb
--- /dev/null
+++ b/include/net/cnss_prealloc.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _NET_CNSS_PREALLOC_H_
+#define _NET_CNSS_PREALLOC_H_
+
+#define WCNSS_PRE_ALLOC_GET_THRESHOLD (4*1024)
+
+extern void *wcnss_prealloc_get(unsigned int size);
+extern int wcnss_prealloc_put(void *ptr);
+extern int wcnss_pre_alloc_reset(void);
+void wcnss_prealloc_check_memory_leak(void);
+
+#endif /* _NET_CNSS__PREALLOC_H_ */