[PATCH 09/15] lib: provide stub Linux "generic" allocator API

Sascha Hauer sha at pengutronix.de
Thu Jan 12 05:26:08 PST 2023


On Wed, Jan 11, 2023 at 06:40:17PM +0100, Ahmad Fatoum wrote:
> We may want to port the whole of the Linux generic allocator
> implementation in future as it would come in handy in drivers that need
> special memory for DMA. For now, support just the use case of the
> incoming Atmel NAND driver, which is mapping the whole of a mmio-sram.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  include/linux/genalloc.h |  36 ++++++++++++
>  lib/Kconfig              |   5 ++
>  lib/Makefile             |   1 +
>  lib/genalloc.c           | 118 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 160 insertions(+)
>  create mode 100644 include/linux/genalloc.h
>  create mode 100644 lib/genalloc.c
> 
> diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h
> new file mode 100644
> index 000000000000..566e62d1965c
> --- /dev/null
> +++ b/include/linux/genalloc.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Basic general purpose allocator for managing special purpose
> + * memory, for example, memory that is not managed by the regular
> + * kmalloc/kfree interface.  Uses for this includes on-device special
> + * memory, uncached memory etc.
> + */
> +
> +
> +#ifndef __GENALLOC_H__
> +#define __GENALLOC_H__
> +
> +#include <linux/types.h>
> +
> +struct device_node;
> +
> +struct gen_pool;
> +
> +extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long);
> +
> +extern void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size,
> +		dma_addr_t *dma);
> +
> +extern void *gen_pool_dma_zalloc(struct gen_pool *pool, size_t size, dma_addr_t *dma);
> +
> +#ifdef CONFIG_OFDEVICE
> +extern struct gen_pool *of_gen_pool_get(struct device_node *np,
> +	const char *propname, int index);
> +#else
> +static inline struct gen_pool *of_gen_pool_get(struct device_node *np,
> +	const char *propname, int index)
> +{
> +	return NULL;
> +}
> +#endif
> +#endif /* __GENALLOC_H__ */
> diff --git a/lib/Kconfig b/lib/Kconfig
> index 5af7ea33f27b..b8bc9d63d4f0 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -210,4 +210,9 @@ config ARCH_HAS_ZERO_PAGE
>  config HAVE_EFFICIENT_UNALIGNED_ACCESS
>  	bool
>  
> +config GENERIC_ALLOCATOR
> +	bool
> +	help
> +	  Support is curently limited to allocaing a complete mmio-sram at once.
> +
>  endmenu
> diff --git a/lib/Makefile b/lib/Makefile
> index 4717b8aec364..38478625423b 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -75,6 +75,7 @@ obj-$(CONFIG_CRC8)	+= crc8.o
>  obj-$(CONFIG_NLS)	+= nls_base.o
>  obj-$(CONFIG_FSL_QE_FIRMWARE) += fsl-qe-firmware.o
>  obj-$(CONFIG_UBSAN)	+= ubsan.o
> +obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
>  
>  # GCC library routines
>  obj-$(CONFIG_GENERIC_LIB_ASHLDI3) += ashldi3.o
> diff --git a/lib/genalloc.c b/lib/genalloc.c
> new file mode 100644
> index 000000000000..906e2dd5f14b
> --- /dev/null
> +++ b/lib/genalloc.c
> @@ -0,0 +1,118 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// SPDX-FileCopyrightText: 2005 Jes Sorensen <jes at trained-monkey.org>
> +/*
> + * Basic general purpose allocator for managing special purpose
> + * memory, for example, memory that is not managed by the regular
> + * kmalloc/kfree interface.  Uses for this includes on-device special
> + * memory, uncached memory etc.
> + */
> +
> +#include <io.h>
> +#include <linux/ioport.h>
> +#include <linux/genalloc.h>
> +#include <linux/export.h>
> +#include <of.h>
> +#include <driver.h>
> +#include <linux/string.h>
> +
> +struct gen_pool {
> +	struct resource res;
> +};
> +
> +#define res_to_gen_pool(res) \
> +	container_of(res, struct gen_pool, res)
> +
> +/**
> + * 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)
> +{
> +	return virt_to_phys((void *)addr);
> +}
> +EXPORT_SYMBOL(gen_pool_virt_to_phys);
> +
> +/**
> + * gen_pool_dma_alloc - allocate special memory from the pool for DMA usage
> + * @pool: pool to allocate from
> + * @size: number of bytes to allocate from the pool
> + * @dma: dma-view physical address return value.  Use %NULL if unneeded.
> + *
> + * Allocate the requested number of bytes from the specified pool.
> + * Uses the pool allocation function (with first-fit algorithm by default).
> + * Can not be used in NMI handler on architectures without
> + * NMI-safe cmpxchg implementation.
> + *
> + * Return: virtual address of the allocated memory, or %NULL on failure
> + */

Maybe add a comment here that we currently only support allocating the
whole area?

Can be done as followup later.

Sascha

> +void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size, dma_addr_t *dma)
> +{
> +	unsigned long vaddr;
> +
> +	if (!pool || resource_size(&pool->res) != size)
> +		return NULL;
> +
> +	vaddr = pool->res.start;
> +
> +	if (dma)
> +		*dma = gen_pool_virt_to_phys(pool, vaddr);
> +
> +	return (void *)vaddr;
> +}
> +EXPORT_SYMBOL(gen_pool_dma_alloc);
> +
> +/**
> + * gen_pool_dma_zalloc - allocate special zeroed memory from the pool for
> + * DMA usage
> + * @pool: pool to allocate from
> + * @size: number of bytes to allocate from the pool
> + * @dma: dma-view physical address return value.  Use %NULL if unneeded.
> + *
> + * Return: virtual address of the allocated zeroed memory, or %NULL on failure
> + */
> +void *gen_pool_dma_zalloc(struct gen_pool *pool, size_t size, dma_addr_t *dma)
> +{
> +	void *vaddr = gen_pool_dma_alloc(pool, size, dma);
> +
> +	if (vaddr)
> +		memset(vaddr, 0, size);
> +
> +	return vaddr;
> +}
> +EXPORT_SYMBOL(gen_pool_dma_zalloc);
> +
> +#ifdef CONFIG_OFDEVICE
> +/**
> + * of_gen_pool_get - find a pool by phandle property
> + * @np: device node
> + * @propname: property name containing phandle(s)
> + * @index: index into the phandle array
> + *
> + * Returns the pool that contains the chunk starting at the physical
> + * address of the device tree node pointed at by the phandle property,
> + * or NULL if not found.
> + */
> +struct gen_pool *of_gen_pool_get(struct device_node *np,
> +	const char *propname, int index)
> +{
> +	struct device *dev;
> +	struct device_node *np_pool;
> +
> +	np_pool = of_parse_phandle(np, propname, index);
> +	if (!np_pool)
> +		return NULL;
> +
> +	if (!of_device_is_compatible(np_pool, "mmio-sram"))
> +		return NULL;
> +
> +	dev = of_find_device_by_node(np_pool);
> +	if (!dev)
> +		return NULL;
> +
> +	return container_of(&dev->resource[0], struct gen_pool, res);
> +}
> +EXPORT_SYMBOL_GPL(of_gen_pool_get);
> +#endif /* CONFIG_OF */
> -- 
> 2.30.2
> 
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



More information about the barebox mailing list