From 3cedbff33e9884fdf3f7aaaa83ab9774d8145d1f Mon Sep 17 00:00:00 2001 From: Andrew Dodd Date: Sat, 16 Feb 2013 18:50:12 -0500 Subject: wireless backport from 3.4 Courtesy of Brian Beloshapka (bbelos) Change-Id: I4b0a8d591bfe57c9f69943ecaf2fa80e772fde8e --- lib/genalloc.c | 54 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 22 deletions(-) (limited to 'lib') 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 #include #include - +#include /* 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); } -- cgit v1.1