Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ecb72345 authored by Sarada Prasanna Garnayak's avatar Sarada Prasanna Garnayak Committed by Gerrit - the friendly Code Review server
Browse files

net: cnss_prealloc: add pre alloc support for socket buffer



The cnss wlan module which has interfaced with high latency
bus(e.g. SDIO) needs physical contiguous memory more than
one page for its socket buffer initialization. If the system
memory has high fragmented it’s not possible to get this much
huge physically contiguous memory through dynamic memory
allocation and will create the wlan driver load, socket descriptor
initiation, scanning and connection failure for the cnss wlan module.

This feature enable socket buffer to use pre allocated memory
for socket buffer initialization and release it to back to
pre-allocated pool.

CRs-Fixed: 1023094
Change-Id: I1cf730cc06096f4b2ab21b4e1dbf3e94d988630e
Signed-off-by: default avatarSarada Prasanna Garnayak <sgarna@codeaurora.org>
parent 20b1a290
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -303,6 +303,20 @@ config WCNSS_MEM_PRE_ALLOC
	  for it's internal usage and release it to back to pre allocated pool.
	  This memory is allocated at the cold boot time.

config WCNSS_SKB_PRE_ALLOC
	tristate "CNSS pre-alloc memory support for skb"
	depends on WCNSS_MEM_PRE_ALLOC
	---help---
	 The cnss wlan module which has interfaced with high latency
	 bus(e.g. SDIO) needs physical contiguous memory more than one
	 page for its socket buffer initialization. If the system memory
	 has high fragmented it’s not possible to get this much huge
	 physically contiguous memory through dynamic memory allocation.

	 This feature enable socket buffer to use pre allocated memory
	 for socket buffer initialization and release it to back to
	 pre-allocated pool.

config CNSS_CRYPTO
	tristate "Enable CNSS crypto support"
	---help---
+104 −3
Original line number Diff line number Diff line
/* Copyright (c) 2012,2014-2015 The Linux Foundation. All rights reserved.
/* Copyright (c) 2012,2014-2016 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
@@ -15,6 +15,10 @@
#include <linux/stacktrace.h>
#include <linux/wcnss_wlan.h>
#include <linux/spinlock.h>
#ifdef	CONFIG_WCNSS_SKB_PRE_ALLOC
#include <linux/skbuff.h>
#endif


static DEFINE_SPINLOCK(alloc_lock);

@@ -32,6 +36,16 @@ struct wcnss_prealloc {
#endif
};

#ifdef CONFIG_WCNSS_SKB_PRE_ALLOC
/* pre-alloced memory for skb */
static struct wcnss_prealloc wcnss_skb_allocs[] = {
	{0, 64 * 1024, NULL},
	{0, 64 * 1024, NULL},
	{0, 128 * 1024, NULL},
	{0, 128 * 1024, NULL},
};
#endif

/* pre-alloced mem for WLAN driver */
static struct wcnss_prealloc wcnss_allocs[] = {
	{0, 8  * 1024, NULL},
@@ -102,20 +116,57 @@ static struct wcnss_prealloc wcnss_allocs[] = {
	{0, 128 * 1024, NULL},
};

int wcnss_prealloc_init(void)
#ifdef CONFIG_WCNSS_SKB_PRE_ALLOC
int cnss_skb_prealloc_init(void)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(wcnss_skb_allocs); i++) {
		wcnss_skb_allocs[i].occupied = 0;
		wcnss_skb_allocs[i].ptr =
			dev_alloc_skb(wcnss_skb_allocs[i].size);
		if (wcnss_skb_allocs[i].ptr == NULL)
			return -ENOMEM;
	}

	return 0;
}
#else
int cnss_skb_prealloc_init(void)
{
	return 0;
}
#endif

int wcnss_prealloc_init(void)
{
	int i, ret;

	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;
	}
	ret = cnss_skb_prealloc_init();

	return 0;
	return ret;
}

#ifdef CONFIG_WCNSS_SKB_PRE_ALLOC
void cnss_skb_prealloc_deinit(void)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(wcnss_skb_allocs); i++) {
		dev_kfree_skb(wcnss_skb_allocs[i].ptr);
		wcnss_skb_allocs[i].ptr = NULL;
	}
}
#else
void cnss_skb_prealloc_deinit(void) {}
#endif

void wcnss_prealloc_deinit(void)
{
	int i = 0;
@@ -124,6 +175,8 @@ void wcnss_prealloc_deinit(void)
		kfree(wcnss_allocs[i].ptr);
		wcnss_allocs[i].ptr = NULL;
	}

	cnss_skb_prealloc_deinit();
}

#ifdef CONFIG_SLUB_DEBUG
@@ -195,6 +248,54 @@ int wcnss_prealloc_put(void *ptr)
}
EXPORT_SYMBOL(wcnss_prealloc_put);

#ifdef CONFIG_WCNSS_SKB_PRE_ALLOC
struct sk_buff *wcnss_skb_prealloc_get(unsigned int size)
{
	int i = 0;
	unsigned long flags;

	spin_lock_irqsave(&alloc_lock, flags);
	for (i = 0; i < ARRAY_SIZE(wcnss_skb_allocs); i++) {
		if (wcnss_skb_allocs[i].occupied)
			continue;

		if (wcnss_skb_allocs[i].size > size) {
			/* we found the slot */
			wcnss_skb_allocs[i].occupied = 1;
			spin_unlock_irqrestore(&alloc_lock, flags);
			wcnss_prealloc_save_stack_trace(&wcnss_allocs[i]);
			return wcnss_skb_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_skb_prealloc_get);

int wcnss_skb_prealloc_put(struct sk_buff *skb)
{
	int i = 0;
	unsigned long flags;

	spin_lock_irqsave(&alloc_lock, flags);
	for (i = 0; i < ARRAY_SIZE(wcnss_skb_allocs); i++) {
		if (wcnss_skb_allocs[i].ptr == skb) {
			wcnss_skb_allocs[i].occupied = 0;
			spin_unlock_irqrestore(&alloc_lock, flags);
			return 1;
		}
	}
	spin_unlock_irqrestore(&alloc_lock, flags);

	return 0;
}
EXPORT_SYMBOL(wcnss_skb_prealloc_put);
#endif

#ifdef CONFIG_SLUB_DEBUG
void wcnss_prealloc_check_memory_leak(void)
{
+9 −1
Original line number Diff line number Diff line
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016, 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
@@ -14,10 +14,18 @@
#define _NET_CNSS_PREALLOC_H_

#define WCNSS_PRE_ALLOC_GET_THRESHOLD (4*1024)
#ifdef CONFIG_WCNSS_SKB_PRE_ALLOC
#define WCNSS_PRE_SKB_ALLOC_GET_THRESHOLD (50*1024)
#endif

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);

#ifdef CONFIG_WCNSS_SKB_PRE_ALLOC
extern struct sk_buff *wcnss_skb_prealloc_get(unsigned int size);
extern int wcnss_skb_prealloc_put(struct sk_buff *skb);
#endif

#endif /* _NET_CNSS__PREALLOC_H_ */