lib: genalloc: Add API to allocate at specified addr.
Krishna Reddy [Wed, 11 Jan 2012 00:33:33 +0000 (16:33 -0800)]
Add API to allocate at specified alloc address.

Change-Id: I188e5430220c050026c6a3e17a586012d9a9fa04
Signed-off-by: Krishna Reddy <vdumpa@nvidia.com>
Reviewed-on: http://git-master/r/74468
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Stephen Warren <swarren@nvidia.com>

include/linux/genalloc.h
lib/genalloc.c

index 5e98eeb..32034bc 100644 (file)
@@ -72,7 +72,17 @@ static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
        return gen_pool_add_virt(pool, addr, -1, size, nid);
 }
 extern void gen_pool_destroy(struct gen_pool *);
-extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
+extern unsigned long gen_pool_alloc_addr(struct gen_pool *,
+       size_t, unsigned long);
+/**
+ * gen_pool_alloc - allocate special memory from the pool
+ * @pool: pool to allocate from
+ * @size: number of bytes to allocate from the pool
+ */
+static inline unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
+{
+       return gen_pool_alloc_addr(pool, size);
+}
 extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
 extern void gen_pool_for_each_chunk(struct gen_pool *,
        void (*)(struct gen_pool *, struct gen_pool_chunk *, void *), void *);
index f352cc4..667bd5f 100644 (file)
@@ -250,20 +250,23 @@ void gen_pool_destroy(struct gen_pool *pool)
 EXPORT_SYMBOL(gen_pool_destroy);
 
 /**
- * gen_pool_alloc - allocate special memory from the pool
+ * gen_pool_alloc_addr - allocate special memory from the pool
  * @pool: pool to allocate from
  * @size: number of bytes to allocate from the pool
+ * @alloc_addr: if non-zero, allocate starting at alloc_addr.
  *
  * Allocate the requested number of bytes from the specified pool.
  * Uses a first-fit algorithm. Can not be used in NMI handler on
  * architectures without NMI-safe cmpxchg implementation.
  */
-unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
+unsigned long gen_pool_alloc_addr(struct gen_pool *pool, size_t size,
+                                   unsigned long alloc_addr)
 {
        struct gen_pool_chunk *chunk;
        unsigned long addr = 0;
        int order = pool->min_alloc_order;
        int nbits, start_bit = 0, end_bit, remain;
+       int alloc_bit_needed = 0;
 
 #ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
        BUG_ON(in_nmi());
@@ -272,6 +275,9 @@ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
        if (size == 0)
                return 0;
 
+       if (alloc_addr & (1 << order) - 1)
+               return 0;
+
        nbits = (size + (1UL << order) - 1) >> order;
        rcu_read_lock();
        list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
@@ -279,9 +285,20 @@ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
                        continue;
 
                end_bit = (chunk->end_addr - chunk->start_addr) >> order;
+               if (alloc_addr) {
+                       if (alloc_addr < chunk->start_addr ||
+                               alloc_addr >= chunk->end_addr)
+                               continue;
+                       if (alloc_addr + size > chunk->end_addr)
+                               return 0;
+                       alloc_bit_needed = start_bit =
+                               (alloc_addr - chunk->start_addr) >> order;
+               }
 retry:
                start_bit = bitmap_find_next_zero_area(chunk->bits, end_bit,
                                                       start_bit, nbits, 0);
+               if (alloc_addr && alloc_bit_needed != start_bit)
+                       return 0;
                if (start_bit >= end_bit)
                        continue;
                remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
@@ -300,7 +317,7 @@ retry:
        rcu_read_unlock();
        return addr;
 }
-EXPORT_SYMBOL(gen_pool_alloc);
+EXPORT_SYMBOL(gen_pool_alloc_addr);
 
 /**
  * gen_pool_free - free allocated special memory back to the pool