162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Basic general purpose allocator for managing special purpose 462306a36Sopenharmony_ci * memory, for example, memory that is not managed by the regular 562306a36Sopenharmony_ci * kmalloc/kfree interface. Uses for this includes on-device special 662306a36Sopenharmony_ci * memory, uncached memory etc. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * It is safe to use the allocator in NMI handlers and other special 962306a36Sopenharmony_ci * unblockable contexts that could otherwise deadlock on locks. This 1062306a36Sopenharmony_ci * is implemented by using atomic operations and retries on any 1162306a36Sopenharmony_ci * conflicts. The disadvantage is that there may be livelocks in 1262306a36Sopenharmony_ci * extreme cases. For better scalability, one allocator can be used 1362306a36Sopenharmony_ci * for each CPU. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * The lockless operation only works if there is enough memory 1662306a36Sopenharmony_ci * available. If new memory is added to the pool a lock has to be 1762306a36Sopenharmony_ci * still taken. So any user relying on locklessness has to ensure 1862306a36Sopenharmony_ci * that sufficient memory is preallocated. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * The basic atomic operation of this allocator is cmpxchg on long. 2162306a36Sopenharmony_ci * On architectures that don't have NMI-safe cmpxchg implementation, 2262306a36Sopenharmony_ci * the allocator can NOT be used in NMI handler. So code uses the 2362306a36Sopenharmony_ci * allocator in NMI handler should depend on 2462306a36Sopenharmony_ci * CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Copyright 2005 (C) Jes Sorensen <jes@trained-monkey.org> 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/export.h> 3162306a36Sopenharmony_ci#include <linux/bitmap.h> 3262306a36Sopenharmony_ci#include <linux/rculist.h> 3362306a36Sopenharmony_ci#include <linux/interrupt.h> 3462306a36Sopenharmony_ci#include <linux/genalloc.h> 3562306a36Sopenharmony_ci#include <linux/of.h> 3662306a36Sopenharmony_ci#include <linux/of_platform.h> 3762306a36Sopenharmony_ci#include <linux/platform_device.h> 3862306a36Sopenharmony_ci#include <linux/vmalloc.h> 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic inline size_t chunk_size(const struct gen_pool_chunk *chunk) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci return chunk->end_addr - chunk->start_addr + 1; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic inline int 4662306a36Sopenharmony_ciset_bits_ll(unsigned long *addr, unsigned long mask_to_set) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci unsigned long val = READ_ONCE(*addr); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci do { 5162306a36Sopenharmony_ci if (val & mask_to_set) 5262306a36Sopenharmony_ci return -EBUSY; 5362306a36Sopenharmony_ci cpu_relax(); 5462306a36Sopenharmony_ci } while (!try_cmpxchg(addr, &val, val | mask_to_set)); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic inline int 6062306a36Sopenharmony_ciclear_bits_ll(unsigned long *addr, unsigned long mask_to_clear) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci unsigned long val = READ_ONCE(*addr); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci do { 6562306a36Sopenharmony_ci if ((val & mask_to_clear) != mask_to_clear) 6662306a36Sopenharmony_ci return -EBUSY; 6762306a36Sopenharmony_ci cpu_relax(); 6862306a36Sopenharmony_ci } while (!try_cmpxchg(addr, &val, val & ~mask_to_clear)); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* 7462306a36Sopenharmony_ci * bitmap_set_ll - set the specified number of bits at the specified position 7562306a36Sopenharmony_ci * @map: pointer to a bitmap 7662306a36Sopenharmony_ci * @start: a bit position in @map 7762306a36Sopenharmony_ci * @nr: number of bits to set 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * Set @nr bits start from @start in @map lock-lessly. Several users 8062306a36Sopenharmony_ci * can set/clear the same bitmap simultaneously without lock. If two 8162306a36Sopenharmony_ci * users set the same bit, one user will return remain bits, otherwise 8262306a36Sopenharmony_ci * return 0. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_cistatic unsigned long 8562306a36Sopenharmony_cibitmap_set_ll(unsigned long *map, unsigned long start, unsigned long nr) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci unsigned long *p = map + BIT_WORD(start); 8862306a36Sopenharmony_ci const unsigned long size = start + nr; 8962306a36Sopenharmony_ci int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG); 9062306a36Sopenharmony_ci unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci while (nr >= bits_to_set) { 9362306a36Sopenharmony_ci if (set_bits_ll(p, mask_to_set)) 9462306a36Sopenharmony_ci return nr; 9562306a36Sopenharmony_ci nr -= bits_to_set; 9662306a36Sopenharmony_ci bits_to_set = BITS_PER_LONG; 9762306a36Sopenharmony_ci mask_to_set = ~0UL; 9862306a36Sopenharmony_ci p++; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci if (nr) { 10162306a36Sopenharmony_ci mask_to_set &= BITMAP_LAST_WORD_MASK(size); 10262306a36Sopenharmony_ci if (set_bits_ll(p, mask_to_set)) 10362306a36Sopenharmony_ci return nr; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * bitmap_clear_ll - clear the specified number of bits at the specified position 11162306a36Sopenharmony_ci * @map: pointer to a bitmap 11262306a36Sopenharmony_ci * @start: a bit position in @map 11362306a36Sopenharmony_ci * @nr: number of bits to set 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * Clear @nr bits start from @start in @map lock-lessly. Several users 11662306a36Sopenharmony_ci * can set/clear the same bitmap simultaneously without lock. If two 11762306a36Sopenharmony_ci * users clear the same bit, one user will return remain bits, 11862306a36Sopenharmony_ci * otherwise return 0. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_cistatic unsigned long 12162306a36Sopenharmony_cibitmap_clear_ll(unsigned long *map, unsigned long start, unsigned long nr) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci unsigned long *p = map + BIT_WORD(start); 12462306a36Sopenharmony_ci const unsigned long size = start + nr; 12562306a36Sopenharmony_ci int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG); 12662306a36Sopenharmony_ci unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci while (nr >= bits_to_clear) { 12962306a36Sopenharmony_ci if (clear_bits_ll(p, mask_to_clear)) 13062306a36Sopenharmony_ci return nr; 13162306a36Sopenharmony_ci nr -= bits_to_clear; 13262306a36Sopenharmony_ci bits_to_clear = BITS_PER_LONG; 13362306a36Sopenharmony_ci mask_to_clear = ~0UL; 13462306a36Sopenharmony_ci p++; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci if (nr) { 13762306a36Sopenharmony_ci mask_to_clear &= BITMAP_LAST_WORD_MASK(size); 13862306a36Sopenharmony_ci if (clear_bits_ll(p, mask_to_clear)) 13962306a36Sopenharmony_ci return nr; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/** 14662306a36Sopenharmony_ci * gen_pool_create - create a new special memory pool 14762306a36Sopenharmony_ci * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents 14862306a36Sopenharmony_ci * @nid: node id of the node the pool structure should be allocated on, or -1 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * Create a new special memory pool that can be used to manage special purpose 15162306a36Sopenharmony_ci * memory not managed by the regular kmalloc/kfree interface. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_cistruct gen_pool *gen_pool_create(int min_alloc_order, int nid) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct gen_pool *pool; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci pool = kmalloc_node(sizeof(struct gen_pool), GFP_KERNEL, nid); 15862306a36Sopenharmony_ci if (pool != NULL) { 15962306a36Sopenharmony_ci spin_lock_init(&pool->lock); 16062306a36Sopenharmony_ci INIT_LIST_HEAD(&pool->chunks); 16162306a36Sopenharmony_ci pool->min_alloc_order = min_alloc_order; 16262306a36Sopenharmony_ci pool->algo = gen_pool_first_fit; 16362306a36Sopenharmony_ci pool->data = NULL; 16462306a36Sopenharmony_ci pool->name = NULL; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci return pool; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_create); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/** 17162306a36Sopenharmony_ci * gen_pool_add_owner- add a new chunk of special memory to the pool 17262306a36Sopenharmony_ci * @pool: pool to add new memory chunk to 17362306a36Sopenharmony_ci * @virt: virtual starting address of memory chunk to add to pool 17462306a36Sopenharmony_ci * @phys: physical starting address of memory chunk to add to pool 17562306a36Sopenharmony_ci * @size: size in bytes of the memory chunk to add to pool 17662306a36Sopenharmony_ci * @nid: node id of the node the chunk structure and bitmap should be 17762306a36Sopenharmony_ci * allocated on, or -1 17862306a36Sopenharmony_ci * @owner: private data the publisher would like to recall at alloc time 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * Add a new chunk of special memory to the specified pool. 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * Returns 0 on success or a -ve errno on failure. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_ciint gen_pool_add_owner(struct gen_pool *pool, unsigned long virt, phys_addr_t phys, 18562306a36Sopenharmony_ci size_t size, int nid, void *owner) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct gen_pool_chunk *chunk; 18862306a36Sopenharmony_ci unsigned long nbits = size >> pool->min_alloc_order; 18962306a36Sopenharmony_ci unsigned long nbytes = sizeof(struct gen_pool_chunk) + 19062306a36Sopenharmony_ci BITS_TO_LONGS(nbits) * sizeof(long); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci chunk = vzalloc_node(nbytes, nid); 19362306a36Sopenharmony_ci if (unlikely(chunk == NULL)) 19462306a36Sopenharmony_ci return -ENOMEM; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci chunk->phys_addr = phys; 19762306a36Sopenharmony_ci chunk->start_addr = virt; 19862306a36Sopenharmony_ci chunk->end_addr = virt + size - 1; 19962306a36Sopenharmony_ci chunk->owner = owner; 20062306a36Sopenharmony_ci atomic_long_set(&chunk->avail, size); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci spin_lock(&pool->lock); 20362306a36Sopenharmony_ci list_add_rcu(&chunk->next_chunk, &pool->chunks); 20462306a36Sopenharmony_ci spin_unlock(&pool->lock); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_add_owner); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/** 21162306a36Sopenharmony_ci * gen_pool_virt_to_phys - return the physical address of memory 21262306a36Sopenharmony_ci * @pool: pool to allocate from 21362306a36Sopenharmony_ci * @addr: starting address of memory 21462306a36Sopenharmony_ci * 21562306a36Sopenharmony_ci * Returns the physical address on success, or -1 on error. 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ciphys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct gen_pool_chunk *chunk; 22062306a36Sopenharmony_ci phys_addr_t paddr = -1; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci rcu_read_lock(); 22362306a36Sopenharmony_ci list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) { 22462306a36Sopenharmony_ci if (addr >= chunk->start_addr && addr <= chunk->end_addr) { 22562306a36Sopenharmony_ci paddr = chunk->phys_addr + (addr - chunk->start_addr); 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci rcu_read_unlock(); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return paddr; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_virt_to_phys); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/** 23662306a36Sopenharmony_ci * gen_pool_destroy - destroy a special memory pool 23762306a36Sopenharmony_ci * @pool: pool to destroy 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci * Destroy the specified special memory pool. Verifies that there are no 24062306a36Sopenharmony_ci * outstanding allocations. 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_civoid gen_pool_destroy(struct gen_pool *pool) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct list_head *_chunk, *_next_chunk; 24562306a36Sopenharmony_ci struct gen_pool_chunk *chunk; 24662306a36Sopenharmony_ci int order = pool->min_alloc_order; 24762306a36Sopenharmony_ci unsigned long bit, end_bit; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci list_for_each_safe(_chunk, _next_chunk, &pool->chunks) { 25062306a36Sopenharmony_ci chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); 25162306a36Sopenharmony_ci list_del(&chunk->next_chunk); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci end_bit = chunk_size(chunk) >> order; 25462306a36Sopenharmony_ci bit = find_first_bit(chunk->bits, end_bit); 25562306a36Sopenharmony_ci BUG_ON(bit < end_bit); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci vfree(chunk); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci kfree_const(pool->name); 26062306a36Sopenharmony_ci kfree(pool); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_destroy); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/** 26562306a36Sopenharmony_ci * gen_pool_alloc_algo_owner - allocate special memory from the pool 26662306a36Sopenharmony_ci * @pool: pool to allocate from 26762306a36Sopenharmony_ci * @size: number of bytes to allocate from the pool 26862306a36Sopenharmony_ci * @algo: algorithm passed from caller 26962306a36Sopenharmony_ci * @data: data passed to algorithm 27062306a36Sopenharmony_ci * @owner: optionally retrieve the chunk owner 27162306a36Sopenharmony_ci * 27262306a36Sopenharmony_ci * Allocate the requested number of bytes from the specified pool. 27362306a36Sopenharmony_ci * Uses the pool allocation function (with first-fit algorithm by default). 27462306a36Sopenharmony_ci * Can not be used in NMI handler on architectures without 27562306a36Sopenharmony_ci * NMI-safe cmpxchg implementation. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ciunsigned long gen_pool_alloc_algo_owner(struct gen_pool *pool, size_t size, 27862306a36Sopenharmony_ci genpool_algo_t algo, void *data, void **owner) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct gen_pool_chunk *chunk; 28162306a36Sopenharmony_ci unsigned long addr = 0; 28262306a36Sopenharmony_ci int order = pool->min_alloc_order; 28362306a36Sopenharmony_ci unsigned long nbits, start_bit, end_bit, remain; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG 28662306a36Sopenharmony_ci BUG_ON(in_nmi()); 28762306a36Sopenharmony_ci#endif 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (owner) 29062306a36Sopenharmony_ci *owner = NULL; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (size == 0) 29362306a36Sopenharmony_ci return 0; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci nbits = (size + (1UL << order) - 1) >> order; 29662306a36Sopenharmony_ci rcu_read_lock(); 29762306a36Sopenharmony_ci list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) { 29862306a36Sopenharmony_ci if (size > atomic_long_read(&chunk->avail)) 29962306a36Sopenharmony_ci continue; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci start_bit = 0; 30262306a36Sopenharmony_ci end_bit = chunk_size(chunk) >> order; 30362306a36Sopenharmony_ciretry: 30462306a36Sopenharmony_ci start_bit = algo(chunk->bits, end_bit, start_bit, 30562306a36Sopenharmony_ci nbits, data, pool, chunk->start_addr); 30662306a36Sopenharmony_ci if (start_bit >= end_bit) 30762306a36Sopenharmony_ci continue; 30862306a36Sopenharmony_ci remain = bitmap_set_ll(chunk->bits, start_bit, nbits); 30962306a36Sopenharmony_ci if (remain) { 31062306a36Sopenharmony_ci remain = bitmap_clear_ll(chunk->bits, start_bit, 31162306a36Sopenharmony_ci nbits - remain); 31262306a36Sopenharmony_ci BUG_ON(remain); 31362306a36Sopenharmony_ci goto retry; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci addr = chunk->start_addr + ((unsigned long)start_bit << order); 31762306a36Sopenharmony_ci size = nbits << order; 31862306a36Sopenharmony_ci atomic_long_sub(size, &chunk->avail); 31962306a36Sopenharmony_ci if (owner) 32062306a36Sopenharmony_ci *owner = chunk->owner; 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci rcu_read_unlock(); 32462306a36Sopenharmony_ci return addr; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_alloc_algo_owner); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/** 32962306a36Sopenharmony_ci * gen_pool_dma_alloc - allocate special memory from the pool for DMA usage 33062306a36Sopenharmony_ci * @pool: pool to allocate from 33162306a36Sopenharmony_ci * @size: number of bytes to allocate from the pool 33262306a36Sopenharmony_ci * @dma: dma-view physical address return value. Use %NULL if unneeded. 33362306a36Sopenharmony_ci * 33462306a36Sopenharmony_ci * Allocate the requested number of bytes from the specified pool. 33562306a36Sopenharmony_ci * Uses the pool allocation function (with first-fit algorithm by default). 33662306a36Sopenharmony_ci * Can not be used in NMI handler on architectures without 33762306a36Sopenharmony_ci * NMI-safe cmpxchg implementation. 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci * Return: virtual address of the allocated memory, or %NULL on failure 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_civoid *gen_pool_dma_alloc(struct gen_pool *pool, size_t size, dma_addr_t *dma) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci return gen_pool_dma_alloc_algo(pool, size, dma, pool->algo, pool->data); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_alloc); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/** 34862306a36Sopenharmony_ci * gen_pool_dma_alloc_algo - allocate special memory from the pool for DMA 34962306a36Sopenharmony_ci * usage with the given pool algorithm 35062306a36Sopenharmony_ci * @pool: pool to allocate from 35162306a36Sopenharmony_ci * @size: number of bytes to allocate from the pool 35262306a36Sopenharmony_ci * @dma: DMA-view physical address return value. Use %NULL if unneeded. 35362306a36Sopenharmony_ci * @algo: algorithm passed from caller 35462306a36Sopenharmony_ci * @data: data passed to algorithm 35562306a36Sopenharmony_ci * 35662306a36Sopenharmony_ci * Allocate the requested number of bytes from the specified pool. Uses the 35762306a36Sopenharmony_ci * given pool allocation function. Can not be used in NMI handler on 35862306a36Sopenharmony_ci * architectures without NMI-safe cmpxchg implementation. 35962306a36Sopenharmony_ci * 36062306a36Sopenharmony_ci * Return: virtual address of the allocated memory, or %NULL on failure 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_civoid *gen_pool_dma_alloc_algo(struct gen_pool *pool, size_t size, 36362306a36Sopenharmony_ci dma_addr_t *dma, genpool_algo_t algo, void *data) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci unsigned long vaddr; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (!pool) 36862306a36Sopenharmony_ci return NULL; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci vaddr = gen_pool_alloc_algo(pool, size, algo, data); 37162306a36Sopenharmony_ci if (!vaddr) 37262306a36Sopenharmony_ci return NULL; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (dma) 37562306a36Sopenharmony_ci *dma = gen_pool_virt_to_phys(pool, vaddr); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return (void *)vaddr; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_alloc_algo); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/** 38262306a36Sopenharmony_ci * gen_pool_dma_alloc_align - allocate special memory from the pool for DMA 38362306a36Sopenharmony_ci * usage with the given alignment 38462306a36Sopenharmony_ci * @pool: pool to allocate from 38562306a36Sopenharmony_ci * @size: number of bytes to allocate from the pool 38662306a36Sopenharmony_ci * @dma: DMA-view physical address return value. Use %NULL if unneeded. 38762306a36Sopenharmony_ci * @align: alignment in bytes for starting address 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * Allocate the requested number bytes from the specified pool, with the given 39062306a36Sopenharmony_ci * alignment restriction. Can not be used in NMI handler on architectures 39162306a36Sopenharmony_ci * without NMI-safe cmpxchg implementation. 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * Return: virtual address of the allocated memory, or %NULL on failure 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_civoid *gen_pool_dma_alloc_align(struct gen_pool *pool, size_t size, 39662306a36Sopenharmony_ci dma_addr_t *dma, int align) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct genpool_data_align data = { .align = align }; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return gen_pool_dma_alloc_algo(pool, size, dma, 40162306a36Sopenharmony_ci gen_pool_first_fit_align, &data); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_alloc_align); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/** 40662306a36Sopenharmony_ci * gen_pool_dma_zalloc - allocate special zeroed memory from the pool for 40762306a36Sopenharmony_ci * DMA usage 40862306a36Sopenharmony_ci * @pool: pool to allocate from 40962306a36Sopenharmony_ci * @size: number of bytes to allocate from the pool 41062306a36Sopenharmony_ci * @dma: dma-view physical address return value. Use %NULL if unneeded. 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * Allocate the requested number of zeroed bytes from the specified pool. 41362306a36Sopenharmony_ci * Uses the pool allocation function (with first-fit algorithm by default). 41462306a36Sopenharmony_ci * Can not be used in NMI handler on architectures without 41562306a36Sopenharmony_ci * NMI-safe cmpxchg implementation. 41662306a36Sopenharmony_ci * 41762306a36Sopenharmony_ci * Return: virtual address of the allocated zeroed memory, or %NULL on failure 41862306a36Sopenharmony_ci */ 41962306a36Sopenharmony_civoid *gen_pool_dma_zalloc(struct gen_pool *pool, size_t size, dma_addr_t *dma) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci return gen_pool_dma_zalloc_algo(pool, size, dma, pool->algo, pool->data); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_zalloc); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/** 42662306a36Sopenharmony_ci * gen_pool_dma_zalloc_algo - allocate special zeroed memory from the pool for 42762306a36Sopenharmony_ci * DMA usage with the given pool algorithm 42862306a36Sopenharmony_ci * @pool: pool to allocate from 42962306a36Sopenharmony_ci * @size: number of bytes to allocate from the pool 43062306a36Sopenharmony_ci * @dma: DMA-view physical address return value. Use %NULL if unneeded. 43162306a36Sopenharmony_ci * @algo: algorithm passed from caller 43262306a36Sopenharmony_ci * @data: data passed to algorithm 43362306a36Sopenharmony_ci * 43462306a36Sopenharmony_ci * Allocate the requested number of zeroed bytes from the specified pool. Uses 43562306a36Sopenharmony_ci * the given pool allocation function. Can not be used in NMI handler on 43662306a36Sopenharmony_ci * architectures without NMI-safe cmpxchg implementation. 43762306a36Sopenharmony_ci * 43862306a36Sopenharmony_ci * Return: virtual address of the allocated zeroed memory, or %NULL on failure 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_civoid *gen_pool_dma_zalloc_algo(struct gen_pool *pool, size_t size, 44162306a36Sopenharmony_ci dma_addr_t *dma, genpool_algo_t algo, void *data) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci void *vaddr = gen_pool_dma_alloc_algo(pool, size, dma, algo, data); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (vaddr) 44662306a36Sopenharmony_ci memset(vaddr, 0, size); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return vaddr; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_zalloc_algo); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci/** 45362306a36Sopenharmony_ci * gen_pool_dma_zalloc_align - allocate special zeroed memory from the pool for 45462306a36Sopenharmony_ci * DMA usage with the given alignment 45562306a36Sopenharmony_ci * @pool: pool to allocate from 45662306a36Sopenharmony_ci * @size: number of bytes to allocate from the pool 45762306a36Sopenharmony_ci * @dma: DMA-view physical address return value. Use %NULL if unneeded. 45862306a36Sopenharmony_ci * @align: alignment in bytes for starting address 45962306a36Sopenharmony_ci * 46062306a36Sopenharmony_ci * Allocate the requested number of zeroed bytes from the specified pool, 46162306a36Sopenharmony_ci * with the given alignment restriction. Can not be used in NMI handler on 46262306a36Sopenharmony_ci * architectures without NMI-safe cmpxchg implementation. 46362306a36Sopenharmony_ci * 46462306a36Sopenharmony_ci * Return: virtual address of the allocated zeroed memory, or %NULL on failure 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_civoid *gen_pool_dma_zalloc_align(struct gen_pool *pool, size_t size, 46762306a36Sopenharmony_ci dma_addr_t *dma, int align) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct genpool_data_align data = { .align = align }; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci return gen_pool_dma_zalloc_algo(pool, size, dma, 47262306a36Sopenharmony_ci gen_pool_first_fit_align, &data); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_zalloc_align); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci/** 47762306a36Sopenharmony_ci * gen_pool_free_owner - free allocated special memory back to the pool 47862306a36Sopenharmony_ci * @pool: pool to free to 47962306a36Sopenharmony_ci * @addr: starting address of memory to free back to pool 48062306a36Sopenharmony_ci * @size: size in bytes of memory to free 48162306a36Sopenharmony_ci * @owner: private data stashed at gen_pool_add() time 48262306a36Sopenharmony_ci * 48362306a36Sopenharmony_ci * Free previously allocated special memory back to the specified 48462306a36Sopenharmony_ci * pool. Can not be used in NMI handler on architectures without 48562306a36Sopenharmony_ci * NMI-safe cmpxchg implementation. 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_civoid gen_pool_free_owner(struct gen_pool *pool, unsigned long addr, size_t size, 48862306a36Sopenharmony_ci void **owner) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct gen_pool_chunk *chunk; 49162306a36Sopenharmony_ci int order = pool->min_alloc_order; 49262306a36Sopenharmony_ci unsigned long start_bit, nbits, remain; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG 49562306a36Sopenharmony_ci BUG_ON(in_nmi()); 49662306a36Sopenharmony_ci#endif 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (owner) 49962306a36Sopenharmony_ci *owner = NULL; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci nbits = (size + (1UL << order) - 1) >> order; 50262306a36Sopenharmony_ci rcu_read_lock(); 50362306a36Sopenharmony_ci list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) { 50462306a36Sopenharmony_ci if (addr >= chunk->start_addr && addr <= chunk->end_addr) { 50562306a36Sopenharmony_ci BUG_ON(addr + size - 1 > chunk->end_addr); 50662306a36Sopenharmony_ci start_bit = (addr - chunk->start_addr) >> order; 50762306a36Sopenharmony_ci remain = bitmap_clear_ll(chunk->bits, start_bit, nbits); 50862306a36Sopenharmony_ci BUG_ON(remain); 50962306a36Sopenharmony_ci size = nbits << order; 51062306a36Sopenharmony_ci atomic_long_add(size, &chunk->avail); 51162306a36Sopenharmony_ci if (owner) 51262306a36Sopenharmony_ci *owner = chunk->owner; 51362306a36Sopenharmony_ci rcu_read_unlock(); 51462306a36Sopenharmony_ci return; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci rcu_read_unlock(); 51862306a36Sopenharmony_ci BUG(); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_free_owner); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci/** 52362306a36Sopenharmony_ci * gen_pool_for_each_chunk - call func for every chunk of generic memory pool 52462306a36Sopenharmony_ci * @pool: the generic memory pool 52562306a36Sopenharmony_ci * @func: func to call 52662306a36Sopenharmony_ci * @data: additional data used by @func 52762306a36Sopenharmony_ci * 52862306a36Sopenharmony_ci * Call @func for every chunk of generic memory pool. The @func is 52962306a36Sopenharmony_ci * called with rcu_read_lock held. 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_civoid gen_pool_for_each_chunk(struct gen_pool *pool, 53262306a36Sopenharmony_ci void (*func)(struct gen_pool *pool, struct gen_pool_chunk *chunk, void *data), 53362306a36Sopenharmony_ci void *data) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci struct gen_pool_chunk *chunk; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci rcu_read_lock(); 53862306a36Sopenharmony_ci list_for_each_entry_rcu(chunk, &(pool)->chunks, next_chunk) 53962306a36Sopenharmony_ci func(pool, chunk, data); 54062306a36Sopenharmony_ci rcu_read_unlock(); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_for_each_chunk); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci/** 54562306a36Sopenharmony_ci * gen_pool_has_addr - checks if an address falls within the range of a pool 54662306a36Sopenharmony_ci * @pool: the generic memory pool 54762306a36Sopenharmony_ci * @start: start address 54862306a36Sopenharmony_ci * @size: size of the region 54962306a36Sopenharmony_ci * 55062306a36Sopenharmony_ci * Check if the range of addresses falls within the specified pool. Returns 55162306a36Sopenharmony_ci * true if the entire range is contained in the pool and false otherwise. 55262306a36Sopenharmony_ci */ 55362306a36Sopenharmony_cibool gen_pool_has_addr(struct gen_pool *pool, unsigned long start, 55462306a36Sopenharmony_ci size_t size) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci bool found = false; 55762306a36Sopenharmony_ci unsigned long end = start + size - 1; 55862306a36Sopenharmony_ci struct gen_pool_chunk *chunk; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci rcu_read_lock(); 56162306a36Sopenharmony_ci list_for_each_entry_rcu(chunk, &(pool)->chunks, next_chunk) { 56262306a36Sopenharmony_ci if (start >= chunk->start_addr && start <= chunk->end_addr) { 56362306a36Sopenharmony_ci if (end <= chunk->end_addr) { 56462306a36Sopenharmony_ci found = true; 56562306a36Sopenharmony_ci break; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci rcu_read_unlock(); 57062306a36Sopenharmony_ci return found; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_has_addr); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci/** 57562306a36Sopenharmony_ci * gen_pool_avail - get available free space of the pool 57662306a36Sopenharmony_ci * @pool: pool to get available free space 57762306a36Sopenharmony_ci * 57862306a36Sopenharmony_ci * Return available free space of the specified pool. 57962306a36Sopenharmony_ci */ 58062306a36Sopenharmony_cisize_t gen_pool_avail(struct gen_pool *pool) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci struct gen_pool_chunk *chunk; 58362306a36Sopenharmony_ci size_t avail = 0; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci rcu_read_lock(); 58662306a36Sopenharmony_ci list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) 58762306a36Sopenharmony_ci avail += atomic_long_read(&chunk->avail); 58862306a36Sopenharmony_ci rcu_read_unlock(); 58962306a36Sopenharmony_ci return avail; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gen_pool_avail); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci/** 59462306a36Sopenharmony_ci * gen_pool_size - get size in bytes of memory managed by the pool 59562306a36Sopenharmony_ci * @pool: pool to get size 59662306a36Sopenharmony_ci * 59762306a36Sopenharmony_ci * Return size in bytes of memory managed by the pool. 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_cisize_t gen_pool_size(struct gen_pool *pool) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct gen_pool_chunk *chunk; 60262306a36Sopenharmony_ci size_t size = 0; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci rcu_read_lock(); 60562306a36Sopenharmony_ci list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) 60662306a36Sopenharmony_ci size += chunk_size(chunk); 60762306a36Sopenharmony_ci rcu_read_unlock(); 60862306a36Sopenharmony_ci return size; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gen_pool_size); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/** 61362306a36Sopenharmony_ci * gen_pool_set_algo - set the allocation algorithm 61462306a36Sopenharmony_ci * @pool: pool to change allocation algorithm 61562306a36Sopenharmony_ci * @algo: custom algorithm function 61662306a36Sopenharmony_ci * @data: additional data used by @algo 61762306a36Sopenharmony_ci * 61862306a36Sopenharmony_ci * Call @algo for each memory allocation in the pool. 61962306a36Sopenharmony_ci * If @algo is NULL use gen_pool_first_fit as default 62062306a36Sopenharmony_ci * memory allocation function. 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_civoid gen_pool_set_algo(struct gen_pool *pool, genpool_algo_t algo, void *data) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci rcu_read_lock(); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci pool->algo = algo; 62762306a36Sopenharmony_ci if (!pool->algo) 62862306a36Sopenharmony_ci pool->algo = gen_pool_first_fit; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci pool->data = data; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci rcu_read_unlock(); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_set_algo); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/** 63762306a36Sopenharmony_ci * gen_pool_first_fit - find the first available region 63862306a36Sopenharmony_ci * of memory matching the size requirement (no alignment constraint) 63962306a36Sopenharmony_ci * @map: The address to base the search on 64062306a36Sopenharmony_ci * @size: The bitmap size in bits 64162306a36Sopenharmony_ci * @start: The bitnumber to start searching at 64262306a36Sopenharmony_ci * @nr: The number of zeroed bits we're looking for 64362306a36Sopenharmony_ci * @data: additional data - unused 64462306a36Sopenharmony_ci * @pool: pool to find the fit region memory from 64562306a36Sopenharmony_ci * @start_addr: not used in this function 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_ciunsigned long gen_pool_first_fit(unsigned long *map, unsigned long size, 64862306a36Sopenharmony_ci unsigned long start, unsigned int nr, void *data, 64962306a36Sopenharmony_ci struct gen_pool *pool, unsigned long start_addr) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci return bitmap_find_next_zero_area(map, size, start, nr, 0); 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_first_fit); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci/** 65662306a36Sopenharmony_ci * gen_pool_first_fit_align - find the first available region 65762306a36Sopenharmony_ci * of memory matching the size requirement (alignment constraint) 65862306a36Sopenharmony_ci * @map: The address to base the search on 65962306a36Sopenharmony_ci * @size: The bitmap size in bits 66062306a36Sopenharmony_ci * @start: The bitnumber to start searching at 66162306a36Sopenharmony_ci * @nr: The number of zeroed bits we're looking for 66262306a36Sopenharmony_ci * @data: data for alignment 66362306a36Sopenharmony_ci * @pool: pool to get order from 66462306a36Sopenharmony_ci * @start_addr: start addr of alloction chunk 66562306a36Sopenharmony_ci */ 66662306a36Sopenharmony_ciunsigned long gen_pool_first_fit_align(unsigned long *map, unsigned long size, 66762306a36Sopenharmony_ci unsigned long start, unsigned int nr, void *data, 66862306a36Sopenharmony_ci struct gen_pool *pool, unsigned long start_addr) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct genpool_data_align *alignment; 67162306a36Sopenharmony_ci unsigned long align_mask, align_off; 67262306a36Sopenharmony_ci int order; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci alignment = data; 67562306a36Sopenharmony_ci order = pool->min_alloc_order; 67662306a36Sopenharmony_ci align_mask = ((alignment->align + (1UL << order) - 1) >> order) - 1; 67762306a36Sopenharmony_ci align_off = (start_addr & (alignment->align - 1)) >> order; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return bitmap_find_next_zero_area_off(map, size, start, nr, 68062306a36Sopenharmony_ci align_mask, align_off); 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_first_fit_align); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci/** 68562306a36Sopenharmony_ci * gen_pool_fixed_alloc - reserve a specific region 68662306a36Sopenharmony_ci * @map: The address to base the search on 68762306a36Sopenharmony_ci * @size: The bitmap size in bits 68862306a36Sopenharmony_ci * @start: The bitnumber to start searching at 68962306a36Sopenharmony_ci * @nr: The number of zeroed bits we're looking for 69062306a36Sopenharmony_ci * @data: data for alignment 69162306a36Sopenharmony_ci * @pool: pool to get order from 69262306a36Sopenharmony_ci * @start_addr: not used in this function 69362306a36Sopenharmony_ci */ 69462306a36Sopenharmony_ciunsigned long gen_pool_fixed_alloc(unsigned long *map, unsigned long size, 69562306a36Sopenharmony_ci unsigned long start, unsigned int nr, void *data, 69662306a36Sopenharmony_ci struct gen_pool *pool, unsigned long start_addr) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct genpool_data_fixed *fixed_data; 69962306a36Sopenharmony_ci int order; 70062306a36Sopenharmony_ci unsigned long offset_bit; 70162306a36Sopenharmony_ci unsigned long start_bit; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci fixed_data = data; 70462306a36Sopenharmony_ci order = pool->min_alloc_order; 70562306a36Sopenharmony_ci offset_bit = fixed_data->offset >> order; 70662306a36Sopenharmony_ci if (WARN_ON(fixed_data->offset & ((1UL << order) - 1))) 70762306a36Sopenharmony_ci return size; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci start_bit = bitmap_find_next_zero_area(map, size, 71062306a36Sopenharmony_ci start + offset_bit, nr, 0); 71162306a36Sopenharmony_ci if (start_bit != offset_bit) 71262306a36Sopenharmony_ci start_bit = size; 71362306a36Sopenharmony_ci return start_bit; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_fixed_alloc); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci/** 71862306a36Sopenharmony_ci * gen_pool_first_fit_order_align - find the first available region 71962306a36Sopenharmony_ci * of memory matching the size requirement. The region will be aligned 72062306a36Sopenharmony_ci * to the order of the size specified. 72162306a36Sopenharmony_ci * @map: The address to base the search on 72262306a36Sopenharmony_ci * @size: The bitmap size in bits 72362306a36Sopenharmony_ci * @start: The bitnumber to start searching at 72462306a36Sopenharmony_ci * @nr: The number of zeroed bits we're looking for 72562306a36Sopenharmony_ci * @data: additional data - unused 72662306a36Sopenharmony_ci * @pool: pool to find the fit region memory from 72762306a36Sopenharmony_ci * @start_addr: not used in this function 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_ciunsigned long gen_pool_first_fit_order_align(unsigned long *map, 73062306a36Sopenharmony_ci unsigned long size, unsigned long start, 73162306a36Sopenharmony_ci unsigned int nr, void *data, struct gen_pool *pool, 73262306a36Sopenharmony_ci unsigned long start_addr) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci unsigned long align_mask = roundup_pow_of_two(nr) - 1; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci return bitmap_find_next_zero_area(map, size, start, nr, align_mask); 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_first_fit_order_align); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci/** 74162306a36Sopenharmony_ci * gen_pool_best_fit - find the best fitting region of memory 74262306a36Sopenharmony_ci * matching the size requirement (no alignment constraint) 74362306a36Sopenharmony_ci * @map: The address to base the search on 74462306a36Sopenharmony_ci * @size: The bitmap size in bits 74562306a36Sopenharmony_ci * @start: The bitnumber to start searching at 74662306a36Sopenharmony_ci * @nr: The number of zeroed bits we're looking for 74762306a36Sopenharmony_ci * @data: additional data - unused 74862306a36Sopenharmony_ci * @pool: pool to find the fit region memory from 74962306a36Sopenharmony_ci * @start_addr: not used in this function 75062306a36Sopenharmony_ci * 75162306a36Sopenharmony_ci * Iterate over the bitmap to find the smallest free region 75262306a36Sopenharmony_ci * which we can allocate the memory. 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_ciunsigned long gen_pool_best_fit(unsigned long *map, unsigned long size, 75562306a36Sopenharmony_ci unsigned long start, unsigned int nr, void *data, 75662306a36Sopenharmony_ci struct gen_pool *pool, unsigned long start_addr) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci unsigned long start_bit = size; 75962306a36Sopenharmony_ci unsigned long len = size + 1; 76062306a36Sopenharmony_ci unsigned long index; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci index = bitmap_find_next_zero_area(map, size, start, nr, 0); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci while (index < size) { 76562306a36Sopenharmony_ci unsigned long next_bit = find_next_bit(map, size, index + nr); 76662306a36Sopenharmony_ci if ((next_bit - index) < len) { 76762306a36Sopenharmony_ci len = next_bit - index; 76862306a36Sopenharmony_ci start_bit = index; 76962306a36Sopenharmony_ci if (len == nr) 77062306a36Sopenharmony_ci return start_bit; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci index = bitmap_find_next_zero_area(map, size, 77362306a36Sopenharmony_ci next_bit + 1, nr, 0); 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci return start_bit; 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ciEXPORT_SYMBOL(gen_pool_best_fit); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic void devm_gen_pool_release(struct device *dev, void *res) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci gen_pool_destroy(*(struct gen_pool **)res); 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic int devm_gen_pool_match(struct device *dev, void *res, void *data) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci struct gen_pool **p = res; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* NULL data matches only a pool without an assigned name */ 79062306a36Sopenharmony_ci if (!data && !(*p)->name) 79162306a36Sopenharmony_ci return 1; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (!data || !(*p)->name) 79462306a36Sopenharmony_ci return 0; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci return !strcmp((*p)->name, data); 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci/** 80062306a36Sopenharmony_ci * gen_pool_get - Obtain the gen_pool (if any) for a device 80162306a36Sopenharmony_ci * @dev: device to retrieve the gen_pool from 80262306a36Sopenharmony_ci * @name: name of a gen_pool or NULL, identifies a particular gen_pool on device 80362306a36Sopenharmony_ci * 80462306a36Sopenharmony_ci * Returns the gen_pool for the device if one is present, or NULL. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_cistruct gen_pool *gen_pool_get(struct device *dev, const char *name) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct gen_pool **p; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci p = devres_find(dev, devm_gen_pool_release, devm_gen_pool_match, 81162306a36Sopenharmony_ci (void *)name); 81262306a36Sopenharmony_ci if (!p) 81362306a36Sopenharmony_ci return NULL; 81462306a36Sopenharmony_ci return *p; 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gen_pool_get); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci/** 81962306a36Sopenharmony_ci * devm_gen_pool_create - managed gen_pool_create 82062306a36Sopenharmony_ci * @dev: device that provides the gen_pool 82162306a36Sopenharmony_ci * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents 82262306a36Sopenharmony_ci * @nid: node selector for allocated gen_pool, %NUMA_NO_NODE for all nodes 82362306a36Sopenharmony_ci * @name: name of a gen_pool or NULL, identifies a particular gen_pool on device 82462306a36Sopenharmony_ci * 82562306a36Sopenharmony_ci * Create a new special memory pool that can be used to manage special purpose 82662306a36Sopenharmony_ci * memory not managed by the regular kmalloc/kfree interface. The pool will be 82762306a36Sopenharmony_ci * automatically destroyed by the device management code. 82862306a36Sopenharmony_ci */ 82962306a36Sopenharmony_cistruct gen_pool *devm_gen_pool_create(struct device *dev, int min_alloc_order, 83062306a36Sopenharmony_ci int nid, const char *name) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct gen_pool **ptr, *pool; 83362306a36Sopenharmony_ci const char *pool_name = NULL; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* Check that genpool to be created is uniquely addressed on device */ 83662306a36Sopenharmony_ci if (gen_pool_get(dev, name)) 83762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (name) { 84062306a36Sopenharmony_ci pool_name = kstrdup_const(name, GFP_KERNEL); 84162306a36Sopenharmony_ci if (!pool_name) 84262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci ptr = devres_alloc(devm_gen_pool_release, sizeof(*ptr), GFP_KERNEL); 84662306a36Sopenharmony_ci if (!ptr) 84762306a36Sopenharmony_ci goto free_pool_name; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci pool = gen_pool_create(min_alloc_order, nid); 85062306a36Sopenharmony_ci if (!pool) 85162306a36Sopenharmony_ci goto free_devres; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci *ptr = pool; 85462306a36Sopenharmony_ci pool->name = pool_name; 85562306a36Sopenharmony_ci devres_add(dev, ptr); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci return pool; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cifree_devres: 86062306a36Sopenharmony_ci devres_free(ptr); 86162306a36Sopenharmony_cifree_pool_name: 86262306a36Sopenharmony_ci kfree_const(pool_name); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ciEXPORT_SYMBOL(devm_gen_pool_create); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci#ifdef CONFIG_OF 86962306a36Sopenharmony_ci/** 87062306a36Sopenharmony_ci * of_gen_pool_get - find a pool by phandle property 87162306a36Sopenharmony_ci * @np: device node 87262306a36Sopenharmony_ci * @propname: property name containing phandle(s) 87362306a36Sopenharmony_ci * @index: index into the phandle array 87462306a36Sopenharmony_ci * 87562306a36Sopenharmony_ci * Returns the pool that contains the chunk starting at the physical 87662306a36Sopenharmony_ci * address of the device tree node pointed at by the phandle property, 87762306a36Sopenharmony_ci * or NULL if not found. 87862306a36Sopenharmony_ci */ 87962306a36Sopenharmony_cistruct gen_pool *of_gen_pool_get(struct device_node *np, 88062306a36Sopenharmony_ci const char *propname, int index) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct platform_device *pdev; 88362306a36Sopenharmony_ci struct device_node *np_pool, *parent; 88462306a36Sopenharmony_ci const char *name = NULL; 88562306a36Sopenharmony_ci struct gen_pool *pool = NULL; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci np_pool = of_parse_phandle(np, propname, index); 88862306a36Sopenharmony_ci if (!np_pool) 88962306a36Sopenharmony_ci return NULL; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci pdev = of_find_device_by_node(np_pool); 89262306a36Sopenharmony_ci if (!pdev) { 89362306a36Sopenharmony_ci /* Check if named gen_pool is created by parent node device */ 89462306a36Sopenharmony_ci parent = of_get_parent(np_pool); 89562306a36Sopenharmony_ci pdev = of_find_device_by_node(parent); 89662306a36Sopenharmony_ci of_node_put(parent); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci of_property_read_string(np_pool, "label", &name); 89962306a36Sopenharmony_ci if (!name) 90062306a36Sopenharmony_ci name = of_node_full_name(np_pool); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci if (pdev) 90362306a36Sopenharmony_ci pool = gen_pool_get(&pdev->dev, name); 90462306a36Sopenharmony_ci of_node_put(np_pool); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci return pool; 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_gen_pool_get); 90962306a36Sopenharmony_ci#endif /* CONFIG_OF */ 910