[PATCH V2] genalloc: add support to specify the physical address

Russell King - ARM Linux linux at arm.linux.org.uk
Thu Apr 28 04:15:35 EDT 2011


On Wed, Apr 20, 2011 at 08:54:15AM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> so we specify the virtual address as base of the pool chunk and then
> get the physical address for hardware IP
> 
> as example on at91 we will use on spi, uart or macb
> 
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
> Cc: Nicolas Ferre <nicolas.ferre at atmel.com>
> Cc: Patrice VILCHEZ <patrice.vilchez at atmel.com>
> Cc: Andrew Morton <akpm at linux-foundation.org>
> ---
> Hi Andrew,
> 	I integrate the documentation fix
> 	could replace the previous one with this one
> 
> V2:
> 	update documentation
> 	use phys_addr_t for physical addr
> Best Regards,

I notice no comments on this - maybe it needs to be Cc'd to linux-mm too?

Andrew - do you have any views on this?

> J.
>  include/linux/genalloc.h |   22 +++++++++++++++++++++-
>  lib/genalloc.c           |   45 +++++++++++++++++++++++++++++++++++++--------
>  2 files changed, 58 insertions(+), 9 deletions(-)
> 
> diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h
> index b1c70f1..5bbebda 100644
> --- a/include/linux/genalloc.h
> +++ b/include/linux/genalloc.h
> @@ -26,13 +26,33 @@ struct gen_pool {
>  struct gen_pool_chunk {
>  	spinlock_t lock;
>  	struct list_head next_chunk;	/* next chunk in pool */
> +	phys_addr_t phys_addr;		/* physical starting address of memory chunk */
>  	unsigned long start_addr;	/* starting address of memory chunk */
>  	unsigned long end_addr;		/* ending address of memory chunk */
>  	unsigned long bits[0];		/* bitmap for allocating memory chunk */
>  };
>  
>  extern struct gen_pool *gen_pool_create(int, int);
> -extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int);
> +extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long);
> +extern int gen_pool_add_virt(struct gen_pool *, unsigned long, phys_addr_t,
> +			     size_t, int);
> +/**
> + * gen_pool_add - add a new chunk of special memory to the pool
> + * @pool: pool to add new memory chunk to
> + * @addr: 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.
> + */
> +static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
> +			       size_t size, int nid)
> +{
> +	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 void gen_pool_free(struct gen_pool *, unsigned long, size_t);
> diff --git a/lib/genalloc.c b/lib/genalloc.c
> index 1923f14..577ddf8 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)
>  EXPORT_SYMBOL(gen_pool_create);
>  
>  /**
> - * gen_pool_add - add a new chunk of special memory to the pool
> + * gen_pool_add_virt - add a new chunk of special memory to the pool
>   * @pool: pool to add new memory chunk to
> - * @addr: starting address of memory chunk to add to pool
> + * @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 gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
> -		 int nid)
> +int 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;
> @@ -58,11 +61,12 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
>  
>  	chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid);
>  	if (unlikely(chunk == NULL))
> -		return -1;
> +		return -ENOMEM;
>  
>  	spin_lock_init(&chunk->lock);
> -	chunk->start_addr = addr;
> -	chunk->end_addr = addr + size;
> +	chunk->phys_addr = phys;
> +	chunk->start_addr = virt;
> +	chunk->end_addr = virt + size;
>  
>  	write_lock(&pool->lock);
>  	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,
>  
>  	return 0;
>  }
> -EXPORT_SYMBOL(gen_pool_add);
> +EXPORT_SYMBOL(gen_pool_add_virt);
> +
> +/**
> + * gen_pool_virt_to_phys - return the physical address of memory
> + * @pool: pool to allocate from
> + * @addr: starting address of memory
> + *
> + * Returns the physical address on success, or -1 on error.
> + */
> +phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr)
> +{
> +	struct list_head *_chunk;
> +	struct gen_pool_chunk *chunk;
> +
> +	read_lock(&pool->lock);
> +	list_for_each(_chunk, &pool->chunks) {
> +		chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
> +
> +		if (addr >= chunk->start_addr && addr < chunk->end_addr)
> +			return chunk->phys_addr + addr - chunk->start_addr;
> +	}
> +	read_unlock(&pool->lock);
> +
> +	return -1;
> +}
> +EXPORT_SYMBOL(gen_pool_virt_to_phys);
>  
>  /**
>   * gen_pool_destroy - destroy a special memory pool
> -- 
> 1.7.4.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



More information about the linux-arm-kernel mailing list