aboutsummaryrefslogtreecommitdiffstats
path: root/lib/genalloc.c
diff options
context:
space:
mode:
authorAndrew Dodd <atd7@cornell.edu>2013-02-16 18:50:12 -0500
committerAndrew Dodd <atd7@cornell.edu>2013-02-27 09:19:15 -0500
commit3cedbff33e9884fdf3f7aaaa83ab9774d8145d1f (patch)
treec150f93f01c3e33e310abdb7495c8f3c26ae73e3 /lib/genalloc.c
parent78eca744f2700e1bb0d4ac93c944329d82006e16 (diff)
downloadkernel_samsung_smdk4412-3cedbff33e9884fdf3f7aaaa83ab9774d8145d1f.zip
kernel_samsung_smdk4412-3cedbff33e9884fdf3f7aaaa83ab9774d8145d1f.tar.gz
kernel_samsung_smdk4412-3cedbff33e9884fdf3f7aaaa83ab9774d8145d1f.tar.bz2
wireless backport from 3.4
Courtesy of Brian Beloshapka (bbelos) Change-Id: I4b0a8d591bfe57c9f69943ecaf2fa80e772fde8e
Diffstat (limited to 'lib/genalloc.c')
-rw-r--r--lib/genalloc.c54
1 files changed, 32 insertions, 22 deletions
diff --git a/lib/genalloc.c b/lib/genalloc.c
index bb1d323..ceaa003 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -14,7 +14,7 @@
#include <linux/module.h>
#include <linux/bitmap.h>
#include <linux/genalloc.h>
-
+#include <linux/vmalloc.h>
/* General purpose special memory pool descriptor. */
struct gen_pool {
@@ -33,7 +33,6 @@ struct gen_pool_chunk {
unsigned long bits[0]; /* bitmap for allocating memory chunk */
};
-
/**
* gen_pool_create() - create a new special memory pool
* @order: Log base 2 of number of bytes each bitmap bit
@@ -63,28 +62,25 @@ EXPORT_SYMBOL(gen_pool_create);
/**
* gen_pool_add_virt - add a new chunk of special memory to the pool
- * @pool: Pool to add new memory chunk to
- * @virt: Virtual starting address of memory chunk to add to pool
- * @phys: Physical starting address of memory chunk to add to pool
- * @size: Size in bytes of the memory chunk to add to pool
- * @nid: Node id of the node the chunk structure and bitmap should be
- * allocated on, or -1
+ * @pool: pool to add new memory chunk to
+ * @virt: virtual starting address of memory chunk to add to pool
+ * @phys: physical starting address of memory chunk to add to pool
+ * @size: size in bytes of the memory chunk to add to pool
+ * @nid: node id of the node the chunk structure and bitmap should be
+ * allocated on, or -1
*
* Add a new chunk of special memory to the specified pool.
*
* Returns 0 on success or a -ve errno on failure.
*/
-int __must_check
-gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phys,
- size_t size, int nid)
+int __must_check gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phys,
+ size_t size, int nid)
{
struct gen_pool_chunk *chunk;
- int nbits = size >> pool->min_alloc_order;
- int nbytes = sizeof(struct gen_pool_chunk) +
- BITS_TO_LONGS(nbits) * sizeof(long);
+ size_t nbytes;
if (WARN_ON(!virt || virt + size < virt ||
- (virt & ((1 << pool->order) - 1))))
+ (virt & ((1 << pool->order) - 1))))
return -EINVAL;
size = size >> pool->order;
@@ -92,14 +88,22 @@ gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phys,
return -EINVAL;
nbytes = sizeof *chunk + BITS_TO_LONGS(size) * sizeof *chunk->bits;
- chunk = kzalloc_node(nbytes, GFP_KERNEL, nid);
+
+ if (nbytes <= PAGE_SIZE)
+ chunk = kzalloc_node(nbytes, GFP_KERNEL, nid);
+ else
+ chunk = vmalloc(nbytes);
+
if (!chunk)
return -ENOMEM;
+ if (nbytes > PAGE_SIZE)
+ memset(chunk, 0, nbytes);
+
spin_lock_init(&chunk->lock);
+ chunk->phys_addr = phys;
chunk->start = virt >> pool->order;
chunk->size = size;
- chunk->phys_addr = phys;
write_lock(&pool->lock);
list_add(&chunk->next_chunk, &pool->chunks);
@@ -123,12 +127,11 @@ phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr)
read_lock(&pool->lock);
list_for_each(_chunk, &pool->chunks) {
- unsigned long start_addr;
chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
- start_addr = chunk->start << pool->order;
- if (addr >= start_addr && addr < start_addr + chunk->size)
- return chunk->phys_addr + addr - start_addr;
+ if (addr >= chunk->start &&
+ addr < (chunk->start + chunk->size))
+ return chunk->phys_addr + addr - chunk->start;
}
read_unlock(&pool->lock);
@@ -147,6 +150,7 @@ void gen_pool_destroy(struct gen_pool *pool)
{
struct gen_pool_chunk *chunk;
int bit;
+ size_t nbytes;
while (!list_empty(&pool->chunks)) {
chunk = list_entry(pool->chunks.next, struct gen_pool_chunk,
@@ -156,7 +160,13 @@ void gen_pool_destroy(struct gen_pool *pool)
bit = find_next_bit(chunk->bits, chunk->size, 0);
BUG_ON(bit < chunk->size);
- kfree(chunk);
+ nbytes = sizeof *chunk + BITS_TO_LONGS(chunk->size) *
+ sizeof *chunk->bits;
+
+ if (nbytes <= PAGE_SIZE)
+ kfree(chunk);
+ else
+ vfree(chunk);
}
kfree(pool);
}