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@xxxxxxxxxxxxxx> > --- > 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@xxxxxxxxxxxxxxxxxx> > +/* > + * 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 |