diff options
author | Andrew Dodd <atd7@cornell.edu> | 2013-02-16 18:50:12 -0500 |
---|---|---|
committer | Andrew Dodd <atd7@cornell.edu> | 2013-02-27 09:19:15 -0500 |
commit | 3cedbff33e9884fdf3f7aaaa83ab9774d8145d1f (patch) | |
tree | c150f93f01c3e33e310abdb7495c8f3c26ae73e3 /lib/genalloc.c | |
parent | 78eca744f2700e1bb0d4ac93c944329d82006e16 (diff) | |
download | kernel_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.c | 54 |
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); } |