aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>2011-05-24 20:13:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-25 11:39:54 -0400
commit3c8f370ded3483b27f1218ff0051fcf0c7a2facd (patch)
treeda0bcb089d586737ddf14e6d610ded5d3134e8d9
parent6aae6e0304d33e537298867dafb2703ec58c2e4f (diff)
lib/genalloc.c: add support for specifying the physical address
So we can specify the virtual address as the base of the pool chunk and then get physical addresses for hardware IP. For example on at91 we will use this on spi, uart or macb Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Nicolas Ferre <nicolas.ferre@atmel.com> Cc: Patrice VILCHEZ <patrice.vilchez@atmel.com> Cc: Jes Sorensen <jes@wildopensource.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/genalloc.h22
-rw-r--r--lib/genalloc.c45
2 files changed, 58 insertions, 9 deletions
diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h
index b1c70f10c42b..5bbebda78b02 100644
--- a/include/linux/genalloc.h
+++ b/include/linux/genalloc.h
@@ -26,13 +26,33 @@ struct gen_pool {
26struct gen_pool_chunk { 26struct gen_pool_chunk {
27 spinlock_t lock; 27 spinlock_t lock;
28 struct list_head next_chunk; /* next chunk in pool */ 28 struct list_head next_chunk; /* next chunk in pool */
29 phys_addr_t phys_addr; /* physical starting address of memory chunk */
29 unsigned long start_addr; /* starting address of memory chunk */ 30 unsigned long start_addr; /* starting address of memory chunk */
30 unsigned long end_addr; /* ending address of memory chunk */ 31 unsigned long end_addr; /* ending address of memory chunk */
31 unsigned long bits[0]; /* bitmap for allocating memory chunk */ 32 unsigned long bits[0]; /* bitmap for allocating memory chunk */
32}; 33};
33 34
34extern struct gen_pool *gen_pool_create(int, int); 35extern struct gen_pool *gen_pool_create(int, int);
35extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int); 36extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long);
37extern int gen_pool_add_virt(struct gen_pool *, unsigned long, phys_addr_t,
38 size_t, int);
39/**
40 * gen_pool_add - add a new chunk of special memory to the pool
41 * @pool: pool to add new memory chunk to
42 * @addr: starting address of memory chunk to add to pool
43 * @size: size in bytes of the memory chunk to add to pool
44 * @nid: node id of the node the chunk structure and bitmap should be
45 * allocated on, or -1
46 *
47 * Add a new chunk of special memory to the specified pool.
48 *
49 * Returns 0 on success or a -ve errno on failure.
50 */
51static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
52 size_t size, int nid)
53{
54 return gen_pool_add_virt(pool, addr, -1, size, nid);
55}
36extern void gen_pool_destroy(struct gen_pool *); 56extern void gen_pool_destroy(struct gen_pool *);
37extern unsigned long gen_pool_alloc(struct gen_pool *, size_t); 57extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
38extern void gen_pool_free(struct gen_pool *, unsigned long, size_t); 58extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 1923f1490e72..577ddf805975 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -39,17 +39,20 @@ struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
39EXPORT_SYMBOL(gen_pool_create); 39EXPORT_SYMBOL(gen_pool_create);
40 40
41/** 41/**
42 * gen_pool_add - add a new chunk of special memory to the pool 42 * gen_pool_add_virt - add a new chunk of special memory to the pool
43 * @pool: pool to add new memory chunk to 43 * @pool: pool to add new memory chunk to
44 * @addr: starting address of memory chunk to add to pool 44 * @virt: virtual starting address of memory chunk to add to pool
45 * @phys: physical starting address of memory chunk to add to pool
45 * @size: size in bytes of the memory chunk to add to pool 46 * @size: size in bytes of the memory chunk to add to pool
46 * @nid: node id of the node the chunk structure and bitmap should be 47 * @nid: node id of the node the chunk structure and bitmap should be
47 * allocated on, or -1 48 * allocated on, or -1
48 * 49 *
49 * Add a new chunk of special memory to the specified pool. 50 * Add a new chunk of special memory to the specified pool.
51 *
52 * Returns 0 on success or a -ve errno on failure.
50 */ 53 */
51int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size, 54int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phys,
52 int nid) 55 size_t size, int nid)
53{ 56{
54 struct gen_pool_chunk *chunk; 57 struct gen_pool_chunk *chunk;
55 int nbits = size >> pool->min_alloc_order; 58 int nbits = size >> pool->min_alloc_order;
@@ -58,11 +61,12 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
58 61
59 chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid); 62 chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid);
60 if (unlikely(chunk == NULL)) 63 if (unlikely(chunk == NULL))
61 return -1; 64 return -ENOMEM;
62 65
63 spin_lock_init(&chunk->lock); 66 spin_lock_init(&chunk->lock);
64 chunk->start_addr = addr; 67 chunk->phys_addr = phys;
65 chunk->end_addr = addr + size; 68 chunk->start_addr = virt;
69 chunk->end_addr = virt + size;
66 70
67 write_lock(&pool->lock); 71 write_lock(&pool->lock);
68 list_add(&chunk->next_chunk, &pool->chunks); 72 list_add(&chunk->next_chunk, &pool->chunks);
@@ -70,7 +74,32 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
70 74
71 return 0; 75 return 0;
72} 76}
73EXPORT_SYMBOL(gen_pool_add); 77EXPORT_SYMBOL(gen_pool_add_virt);
78
79/**
80 * gen_pool_virt_to_phys - return the physical address of memory
81 * @pool: pool to allocate from
82 * @addr: starting address of memory
83 *
84 * Returns the physical address on success, or -1 on error.
85 */
86phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr)
87{
88 struct list_head *_chunk;
89 struct gen_pool_chunk *chunk;
90
91 read_lock(&pool->lock);
92 list_for_each(_chunk, &pool->chunks) {
93 chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
94
95 if (addr >= chunk->start_addr && addr < chunk->end_addr)
96 return chunk->phys_addr + addr - chunk->start_addr;
97 }
98 read_unlock(&pool->lock);
99
100 return -1;
101}
102EXPORT_SYMBOL(gen_pool_virt_to_phys);
74 103
75/** 104/**
76 * gen_pool_destroy - destroy a special memory pool 105 * gen_pool_destroy - destroy a special memory pool