wcnss: Pre-alloc memory for WLAN driver
WLAN driver will use this pre-allocated memory (when available) for
large memory allocations; this will prevent WLAN driver load
failures because of the un-availability of the large size slabs
during module load.
Change-Id: I8a8139bdf343ddc871036f6d5c6ab90993816de0
Signed-off-by: Sameer Thalappil <sameert@codeaurora.org>
diff --git a/drivers/net/wireless/wcnss/wcnss_prealloc.c b/drivers/net/wireless/wcnss/wcnss_prealloc.c
new file mode 100644
index 0000000..7d10657
--- /dev/null
+++ b/drivers/net/wireless/wcnss/wcnss_prealloc.c
@@ -0,0 +1,103 @@
+/* Copyright (c) 2012, 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/wcnss_wlan.h>
+
+static DEFINE_MUTEX(alloc_lock);
+
+struct wcnss_prealloc {
+ int occupied;
+ unsigned int size;
+ void *ptr;
+};
+
+/* 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, 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},
+};
+
+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);
+}
+
+void *wcnss_prealloc_get(unsigned int size)
+{
+ int i = 0;
+
+ mutex_lock(&alloc_lock);
+ 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;
+ mutex_unlock(&alloc_lock);
+ return wcnss_allocs[i].ptr;
+ }
+ }
+ pr_err("wcnss: %s: prealloc not available\n", __func__);
+ mutex_unlock(&alloc_lock);
+
+ return NULL;
+}
+EXPORT_SYMBOL(wcnss_prealloc_get);
+
+int wcnss_prealloc_put(void *ptr)
+{
+ int i = 0;
+
+ mutex_lock(&alloc_lock);
+ for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
+ if (wcnss_allocs[i].ptr == ptr) {
+ wcnss_allocs[i].occupied = 0;
+ mutex_unlock(&alloc_lock);
+ return 1;
+ }
+ }
+ mutex_unlock(&alloc_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(wcnss_prealloc_put);