18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Basic general purpose allocator for managing special purpose
48c2ecf20Sopenharmony_ci * memory, for example, memory that is not managed by the regular
58c2ecf20Sopenharmony_ci * kmalloc/kfree interface.  Uses for this includes on-device special
68c2ecf20Sopenharmony_ci * memory, uncached memory etc.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * It is safe to use the allocator in NMI handlers and other special
98c2ecf20Sopenharmony_ci * unblockable contexts that could otherwise deadlock on locks.  This
108c2ecf20Sopenharmony_ci * is implemented by using atomic operations and retries on any
118c2ecf20Sopenharmony_ci * conflicts.  The disadvantage is that there may be livelocks in
128c2ecf20Sopenharmony_ci * extreme cases.  For better scalability, one allocator can be used
138c2ecf20Sopenharmony_ci * for each CPU.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * The lockless operation only works if there is enough memory
168c2ecf20Sopenharmony_ci * available.  If new memory is added to the pool a lock has to be
178c2ecf20Sopenharmony_ci * still taken.  So any user relying on locklessness has to ensure
188c2ecf20Sopenharmony_ci * that sufficient memory is preallocated.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * The basic atomic operation of this allocator is cmpxchg on long.
218c2ecf20Sopenharmony_ci * On architectures that don't have NMI-safe cmpxchg implementation,
228c2ecf20Sopenharmony_ci * the allocator can NOT be used in NMI handler.  So code uses the
238c2ecf20Sopenharmony_ci * allocator in NMI handler should depend on
248c2ecf20Sopenharmony_ci * CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * Copyright 2005 (C) Jes Sorensen <jes@trained-monkey.org>
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <linux/slab.h>
308c2ecf20Sopenharmony_ci#include <linux/export.h>
318c2ecf20Sopenharmony_ci#include <linux/bitmap.h>
328c2ecf20Sopenharmony_ci#include <linux/rculist.h>
338c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
348c2ecf20Sopenharmony_ci#include <linux/genalloc.h>
358c2ecf20Sopenharmony_ci#include <linux/of_device.h>
368c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic inline size_t chunk_size(const struct gen_pool_chunk *chunk)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	return chunk->end_addr - chunk->start_addr + 1;
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic int set_bits_ll(unsigned long *addr, unsigned long mask_to_set)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	unsigned long val, nval;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	nval = *addr;
488c2ecf20Sopenharmony_ci	do {
498c2ecf20Sopenharmony_ci		val = nval;
508c2ecf20Sopenharmony_ci		if (val & mask_to_set)
518c2ecf20Sopenharmony_ci			return -EBUSY;
528c2ecf20Sopenharmony_ci		cpu_relax();
538c2ecf20Sopenharmony_ci	} while ((nval = cmpxchg(addr, val, val | mask_to_set)) != val);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return 0;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int clear_bits_ll(unsigned long *addr, unsigned long mask_to_clear)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	unsigned long val, nval;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	nval = *addr;
638c2ecf20Sopenharmony_ci	do {
648c2ecf20Sopenharmony_ci		val = nval;
658c2ecf20Sopenharmony_ci		if ((val & mask_to_clear) != mask_to_clear)
668c2ecf20Sopenharmony_ci			return -EBUSY;
678c2ecf20Sopenharmony_ci		cpu_relax();
688c2ecf20Sopenharmony_ci	} while ((nval = cmpxchg(addr, val, val & ~mask_to_clear)) != val);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	return 0;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/*
748c2ecf20Sopenharmony_ci * bitmap_set_ll - set the specified number of bits at the specified position
758c2ecf20Sopenharmony_ci * @map: pointer to a bitmap
768c2ecf20Sopenharmony_ci * @start: a bit position in @map
778c2ecf20Sopenharmony_ci * @nr: number of bits to set
788c2ecf20Sopenharmony_ci *
798c2ecf20Sopenharmony_ci * Set @nr bits start from @start in @map lock-lessly. Several users
808c2ecf20Sopenharmony_ci * can set/clear the same bitmap simultaneously without lock. If two
818c2ecf20Sopenharmony_ci * users set the same bit, one user will return remain bits, otherwise
828c2ecf20Sopenharmony_ci * return 0.
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_cistatic int bitmap_set_ll(unsigned long *map, unsigned long start, unsigned long nr)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	unsigned long *p = map + BIT_WORD(start);
878c2ecf20Sopenharmony_ci	const unsigned long size = start + nr;
888c2ecf20Sopenharmony_ci	int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
898c2ecf20Sopenharmony_ci	unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	while (nr >= bits_to_set) {
928c2ecf20Sopenharmony_ci		if (set_bits_ll(p, mask_to_set))
938c2ecf20Sopenharmony_ci			return nr;
948c2ecf20Sopenharmony_ci		nr -= bits_to_set;
958c2ecf20Sopenharmony_ci		bits_to_set = BITS_PER_LONG;
968c2ecf20Sopenharmony_ci		mask_to_set = ~0UL;
978c2ecf20Sopenharmony_ci		p++;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci	if (nr) {
1008c2ecf20Sopenharmony_ci		mask_to_set &= BITMAP_LAST_WORD_MASK(size);
1018c2ecf20Sopenharmony_ci		if (set_bits_ll(p, mask_to_set))
1028c2ecf20Sopenharmony_ci			return nr;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/*
1098c2ecf20Sopenharmony_ci * bitmap_clear_ll - clear the specified number of bits at the specified position
1108c2ecf20Sopenharmony_ci * @map: pointer to a bitmap
1118c2ecf20Sopenharmony_ci * @start: a bit position in @map
1128c2ecf20Sopenharmony_ci * @nr: number of bits to set
1138c2ecf20Sopenharmony_ci *
1148c2ecf20Sopenharmony_ci * Clear @nr bits start from @start in @map lock-lessly. Several users
1158c2ecf20Sopenharmony_ci * can set/clear the same bitmap simultaneously without lock. If two
1168c2ecf20Sopenharmony_ci * users clear the same bit, one user will return remain bits,
1178c2ecf20Sopenharmony_ci * otherwise return 0.
1188c2ecf20Sopenharmony_ci */
1198c2ecf20Sopenharmony_cistatic unsigned long
1208c2ecf20Sopenharmony_cibitmap_clear_ll(unsigned long *map, unsigned long start, unsigned long nr)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	unsigned long *p = map + BIT_WORD(start);
1238c2ecf20Sopenharmony_ci	const unsigned long size = start + nr;
1248c2ecf20Sopenharmony_ci	int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
1258c2ecf20Sopenharmony_ci	unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	while (nr >= bits_to_clear) {
1288c2ecf20Sopenharmony_ci		if (clear_bits_ll(p, mask_to_clear))
1298c2ecf20Sopenharmony_ci			return nr;
1308c2ecf20Sopenharmony_ci		nr -= bits_to_clear;
1318c2ecf20Sopenharmony_ci		bits_to_clear = BITS_PER_LONG;
1328c2ecf20Sopenharmony_ci		mask_to_clear = ~0UL;
1338c2ecf20Sopenharmony_ci		p++;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci	if (nr) {
1368c2ecf20Sopenharmony_ci		mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
1378c2ecf20Sopenharmony_ci		if (clear_bits_ll(p, mask_to_clear))
1388c2ecf20Sopenharmony_ci			return nr;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	return 0;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/**
1458c2ecf20Sopenharmony_ci * gen_pool_create - create a new special memory pool
1468c2ecf20Sopenharmony_ci * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents
1478c2ecf20Sopenharmony_ci * @nid: node id of the node the pool structure should be allocated on, or -1
1488c2ecf20Sopenharmony_ci *
1498c2ecf20Sopenharmony_ci * Create a new special memory pool that can be used to manage special purpose
1508c2ecf20Sopenharmony_ci * memory not managed by the regular kmalloc/kfree interface.
1518c2ecf20Sopenharmony_ci */
1528c2ecf20Sopenharmony_cistruct gen_pool *gen_pool_create(int min_alloc_order, int nid)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct gen_pool *pool;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	pool = kmalloc_node(sizeof(struct gen_pool), GFP_KERNEL, nid);
1578c2ecf20Sopenharmony_ci	if (pool != NULL) {
1588c2ecf20Sopenharmony_ci		spin_lock_init(&pool->lock);
1598c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&pool->chunks);
1608c2ecf20Sopenharmony_ci		pool->min_alloc_order = min_alloc_order;
1618c2ecf20Sopenharmony_ci		pool->algo = gen_pool_first_fit;
1628c2ecf20Sopenharmony_ci		pool->data = NULL;
1638c2ecf20Sopenharmony_ci		pool->name = NULL;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci	return pool;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_create);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/**
1708c2ecf20Sopenharmony_ci * gen_pool_add_owner- add a new chunk of special memory to the pool
1718c2ecf20Sopenharmony_ci * @pool: pool to add new memory chunk to
1728c2ecf20Sopenharmony_ci * @virt: virtual starting address of memory chunk to add to pool
1738c2ecf20Sopenharmony_ci * @phys: physical starting address of memory chunk to add to pool
1748c2ecf20Sopenharmony_ci * @size: size in bytes of the memory chunk to add to pool
1758c2ecf20Sopenharmony_ci * @nid: node id of the node the chunk structure and bitmap should be
1768c2ecf20Sopenharmony_ci *       allocated on, or -1
1778c2ecf20Sopenharmony_ci * @owner: private data the publisher would like to recall at alloc time
1788c2ecf20Sopenharmony_ci *
1798c2ecf20Sopenharmony_ci * Add a new chunk of special memory to the specified pool.
1808c2ecf20Sopenharmony_ci *
1818c2ecf20Sopenharmony_ci * Returns 0 on success or a -ve errno on failure.
1828c2ecf20Sopenharmony_ci */
1838c2ecf20Sopenharmony_ciint gen_pool_add_owner(struct gen_pool *pool, unsigned long virt, phys_addr_t phys,
1848c2ecf20Sopenharmony_ci		 size_t size, int nid, void *owner)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct gen_pool_chunk *chunk;
1878c2ecf20Sopenharmony_ci	unsigned long nbits = size >> pool->min_alloc_order;
1888c2ecf20Sopenharmony_ci	unsigned long nbytes = sizeof(struct gen_pool_chunk) +
1898c2ecf20Sopenharmony_ci				BITS_TO_LONGS(nbits) * sizeof(long);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	chunk = vzalloc_node(nbytes, nid);
1928c2ecf20Sopenharmony_ci	if (unlikely(chunk == NULL))
1938c2ecf20Sopenharmony_ci		return -ENOMEM;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	chunk->phys_addr = phys;
1968c2ecf20Sopenharmony_ci	chunk->start_addr = virt;
1978c2ecf20Sopenharmony_ci	chunk->end_addr = virt + size - 1;
1988c2ecf20Sopenharmony_ci	chunk->owner = owner;
1998c2ecf20Sopenharmony_ci	atomic_long_set(&chunk->avail, size);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	spin_lock(&pool->lock);
2028c2ecf20Sopenharmony_ci	list_add_rcu(&chunk->next_chunk, &pool->chunks);
2038c2ecf20Sopenharmony_ci	spin_unlock(&pool->lock);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	return 0;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_add_owner);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/**
2108c2ecf20Sopenharmony_ci * gen_pool_virt_to_phys - return the physical address of memory
2118c2ecf20Sopenharmony_ci * @pool: pool to allocate from
2128c2ecf20Sopenharmony_ci * @addr: starting address of memory
2138c2ecf20Sopenharmony_ci *
2148c2ecf20Sopenharmony_ci * Returns the physical address on success, or -1 on error.
2158c2ecf20Sopenharmony_ci */
2168c2ecf20Sopenharmony_ciphys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct gen_pool_chunk *chunk;
2198c2ecf20Sopenharmony_ci	phys_addr_t paddr = -1;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	rcu_read_lock();
2228c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
2238c2ecf20Sopenharmony_ci		if (addr >= chunk->start_addr && addr <= chunk->end_addr) {
2248c2ecf20Sopenharmony_ci			paddr = chunk->phys_addr + (addr - chunk->start_addr);
2258c2ecf20Sopenharmony_ci			break;
2268c2ecf20Sopenharmony_ci		}
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci	rcu_read_unlock();
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	return paddr;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_virt_to_phys);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci/**
2358c2ecf20Sopenharmony_ci * gen_pool_destroy - destroy a special memory pool
2368c2ecf20Sopenharmony_ci * @pool: pool to destroy
2378c2ecf20Sopenharmony_ci *
2388c2ecf20Sopenharmony_ci * Destroy the specified special memory pool. Verifies that there are no
2398c2ecf20Sopenharmony_ci * outstanding allocations.
2408c2ecf20Sopenharmony_ci */
2418c2ecf20Sopenharmony_civoid gen_pool_destroy(struct gen_pool *pool)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct list_head *_chunk, *_next_chunk;
2448c2ecf20Sopenharmony_ci	struct gen_pool_chunk *chunk;
2458c2ecf20Sopenharmony_ci	int order = pool->min_alloc_order;
2468c2ecf20Sopenharmony_ci	unsigned long bit, end_bit;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
2498c2ecf20Sopenharmony_ci		chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
2508c2ecf20Sopenharmony_ci		list_del(&chunk->next_chunk);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		end_bit = chunk_size(chunk) >> order;
2538c2ecf20Sopenharmony_ci		bit = find_next_bit(chunk->bits, end_bit, 0);
2548c2ecf20Sopenharmony_ci		BUG_ON(bit < end_bit);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci		vfree(chunk);
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci	kfree_const(pool->name);
2598c2ecf20Sopenharmony_ci	kfree(pool);
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_destroy);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci/**
2648c2ecf20Sopenharmony_ci * gen_pool_alloc_algo_owner - allocate special memory from the pool
2658c2ecf20Sopenharmony_ci * @pool: pool to allocate from
2668c2ecf20Sopenharmony_ci * @size: number of bytes to allocate from the pool
2678c2ecf20Sopenharmony_ci * @algo: algorithm passed from caller
2688c2ecf20Sopenharmony_ci * @data: data passed to algorithm
2698c2ecf20Sopenharmony_ci * @owner: optionally retrieve the chunk owner
2708c2ecf20Sopenharmony_ci *
2718c2ecf20Sopenharmony_ci * Allocate the requested number of bytes from the specified pool.
2728c2ecf20Sopenharmony_ci * Uses the pool allocation function (with first-fit algorithm by default).
2738c2ecf20Sopenharmony_ci * Can not be used in NMI handler on architectures without
2748c2ecf20Sopenharmony_ci * NMI-safe cmpxchg implementation.
2758c2ecf20Sopenharmony_ci */
2768c2ecf20Sopenharmony_ciunsigned long gen_pool_alloc_algo_owner(struct gen_pool *pool, size_t size,
2778c2ecf20Sopenharmony_ci		genpool_algo_t algo, void *data, void **owner)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct gen_pool_chunk *chunk;
2808c2ecf20Sopenharmony_ci	unsigned long addr = 0;
2818c2ecf20Sopenharmony_ci	int order = pool->min_alloc_order;
2828c2ecf20Sopenharmony_ci	unsigned long nbits, start_bit, end_bit, remain;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
2858c2ecf20Sopenharmony_ci	BUG_ON(in_nmi());
2868c2ecf20Sopenharmony_ci#endif
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (owner)
2898c2ecf20Sopenharmony_ci		*owner = NULL;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (size == 0)
2928c2ecf20Sopenharmony_ci		return 0;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	nbits = (size + (1UL << order) - 1) >> order;
2958c2ecf20Sopenharmony_ci	rcu_read_lock();
2968c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
2978c2ecf20Sopenharmony_ci		if (size > atomic_long_read(&chunk->avail))
2988c2ecf20Sopenharmony_ci			continue;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		start_bit = 0;
3018c2ecf20Sopenharmony_ci		end_bit = chunk_size(chunk) >> order;
3028c2ecf20Sopenharmony_ciretry:
3038c2ecf20Sopenharmony_ci		start_bit = algo(chunk->bits, end_bit, start_bit,
3048c2ecf20Sopenharmony_ci				 nbits, data, pool, chunk->start_addr);
3058c2ecf20Sopenharmony_ci		if (start_bit >= end_bit)
3068c2ecf20Sopenharmony_ci			continue;
3078c2ecf20Sopenharmony_ci		remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
3088c2ecf20Sopenharmony_ci		if (remain) {
3098c2ecf20Sopenharmony_ci			remain = bitmap_clear_ll(chunk->bits, start_bit,
3108c2ecf20Sopenharmony_ci						 nbits - remain);
3118c2ecf20Sopenharmony_ci			BUG_ON(remain);
3128c2ecf20Sopenharmony_ci			goto retry;
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		addr = chunk->start_addr + ((unsigned long)start_bit << order);
3168c2ecf20Sopenharmony_ci		size = nbits << order;
3178c2ecf20Sopenharmony_ci		atomic_long_sub(size, &chunk->avail);
3188c2ecf20Sopenharmony_ci		if (owner)
3198c2ecf20Sopenharmony_ci			*owner = chunk->owner;
3208c2ecf20Sopenharmony_ci		break;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci	rcu_read_unlock();
3238c2ecf20Sopenharmony_ci	return addr;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_alloc_algo_owner);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci/**
3288c2ecf20Sopenharmony_ci * gen_pool_dma_alloc - allocate special memory from the pool for DMA usage
3298c2ecf20Sopenharmony_ci * @pool: pool to allocate from
3308c2ecf20Sopenharmony_ci * @size: number of bytes to allocate from the pool
3318c2ecf20Sopenharmony_ci * @dma: dma-view physical address return value.  Use %NULL if unneeded.
3328c2ecf20Sopenharmony_ci *
3338c2ecf20Sopenharmony_ci * Allocate the requested number of bytes from the specified pool.
3348c2ecf20Sopenharmony_ci * Uses the pool allocation function (with first-fit algorithm by default).
3358c2ecf20Sopenharmony_ci * Can not be used in NMI handler on architectures without
3368c2ecf20Sopenharmony_ci * NMI-safe cmpxchg implementation.
3378c2ecf20Sopenharmony_ci *
3388c2ecf20Sopenharmony_ci * Return: virtual address of the allocated memory, or %NULL on failure
3398c2ecf20Sopenharmony_ci */
3408c2ecf20Sopenharmony_civoid *gen_pool_dma_alloc(struct gen_pool *pool, size_t size, dma_addr_t *dma)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	return gen_pool_dma_alloc_algo(pool, size, dma, pool->algo, pool->data);
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_alloc);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci/**
3478c2ecf20Sopenharmony_ci * gen_pool_dma_alloc_algo - allocate special memory from the pool for DMA
3488c2ecf20Sopenharmony_ci * usage with the given pool algorithm
3498c2ecf20Sopenharmony_ci * @pool: pool to allocate from
3508c2ecf20Sopenharmony_ci * @size: number of bytes to allocate from the pool
3518c2ecf20Sopenharmony_ci * @dma: DMA-view physical address return value. Use %NULL if unneeded.
3528c2ecf20Sopenharmony_ci * @algo: algorithm passed from caller
3538c2ecf20Sopenharmony_ci * @data: data passed to algorithm
3548c2ecf20Sopenharmony_ci *
3558c2ecf20Sopenharmony_ci * Allocate the requested number of bytes from the specified pool. Uses the
3568c2ecf20Sopenharmony_ci * given pool allocation function. Can not be used in NMI handler on
3578c2ecf20Sopenharmony_ci * architectures without NMI-safe cmpxchg implementation.
3588c2ecf20Sopenharmony_ci *
3598c2ecf20Sopenharmony_ci * Return: virtual address of the allocated memory, or %NULL on failure
3608c2ecf20Sopenharmony_ci */
3618c2ecf20Sopenharmony_civoid *gen_pool_dma_alloc_algo(struct gen_pool *pool, size_t size,
3628c2ecf20Sopenharmony_ci		dma_addr_t *dma, genpool_algo_t algo, void *data)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	unsigned long vaddr;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (!pool)
3678c2ecf20Sopenharmony_ci		return NULL;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	vaddr = gen_pool_alloc_algo(pool, size, algo, data);
3708c2ecf20Sopenharmony_ci	if (!vaddr)
3718c2ecf20Sopenharmony_ci		return NULL;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (dma)
3748c2ecf20Sopenharmony_ci		*dma = gen_pool_virt_to_phys(pool, vaddr);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	return (void *)vaddr;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_alloc_algo);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci/**
3818c2ecf20Sopenharmony_ci * gen_pool_dma_alloc_align - allocate special memory from the pool for DMA
3828c2ecf20Sopenharmony_ci * usage with the given alignment
3838c2ecf20Sopenharmony_ci * @pool: pool to allocate from
3848c2ecf20Sopenharmony_ci * @size: number of bytes to allocate from the pool
3858c2ecf20Sopenharmony_ci * @dma: DMA-view physical address return value. Use %NULL if unneeded.
3868c2ecf20Sopenharmony_ci * @align: alignment in bytes for starting address
3878c2ecf20Sopenharmony_ci *
3888c2ecf20Sopenharmony_ci * Allocate the requested number bytes from the specified pool, with the given
3898c2ecf20Sopenharmony_ci * alignment restriction. Can not be used in NMI handler on architectures
3908c2ecf20Sopenharmony_ci * without NMI-safe cmpxchg implementation.
3918c2ecf20Sopenharmony_ci *
3928c2ecf20Sopenharmony_ci * Return: virtual address of the allocated memory, or %NULL on failure
3938c2ecf20Sopenharmony_ci */
3948c2ecf20Sopenharmony_civoid *gen_pool_dma_alloc_align(struct gen_pool *pool, size_t size,
3958c2ecf20Sopenharmony_ci		dma_addr_t *dma, int align)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	struct genpool_data_align data = { .align = align };
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	return gen_pool_dma_alloc_algo(pool, size, dma,
4008c2ecf20Sopenharmony_ci			gen_pool_first_fit_align, &data);
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_alloc_align);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci/**
4058c2ecf20Sopenharmony_ci * gen_pool_dma_zalloc - allocate special zeroed memory from the pool for
4068c2ecf20Sopenharmony_ci * DMA usage
4078c2ecf20Sopenharmony_ci * @pool: pool to allocate from
4088c2ecf20Sopenharmony_ci * @size: number of bytes to allocate from the pool
4098c2ecf20Sopenharmony_ci * @dma: dma-view physical address return value.  Use %NULL if unneeded.
4108c2ecf20Sopenharmony_ci *
4118c2ecf20Sopenharmony_ci * Allocate the requested number of zeroed bytes from the specified pool.
4128c2ecf20Sopenharmony_ci * Uses the pool allocation function (with first-fit algorithm by default).
4138c2ecf20Sopenharmony_ci * Can not be used in NMI handler on architectures without
4148c2ecf20Sopenharmony_ci * NMI-safe cmpxchg implementation.
4158c2ecf20Sopenharmony_ci *
4168c2ecf20Sopenharmony_ci * Return: virtual address of the allocated zeroed memory, or %NULL on failure
4178c2ecf20Sopenharmony_ci */
4188c2ecf20Sopenharmony_civoid *gen_pool_dma_zalloc(struct gen_pool *pool, size_t size, dma_addr_t *dma)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	return gen_pool_dma_zalloc_algo(pool, size, dma, pool->algo, pool->data);
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_zalloc);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci/**
4258c2ecf20Sopenharmony_ci * gen_pool_dma_zalloc_algo - allocate special zeroed memory from the pool for
4268c2ecf20Sopenharmony_ci * DMA usage with the given pool algorithm
4278c2ecf20Sopenharmony_ci * @pool: pool to allocate from
4288c2ecf20Sopenharmony_ci * @size: number of bytes to allocate from the pool
4298c2ecf20Sopenharmony_ci * @dma: DMA-view physical address return value. Use %NULL if unneeded.
4308c2ecf20Sopenharmony_ci * @algo: algorithm passed from caller
4318c2ecf20Sopenharmony_ci * @data: data passed to algorithm
4328c2ecf20Sopenharmony_ci *
4338c2ecf20Sopenharmony_ci * Allocate the requested number of zeroed bytes from the specified pool. Uses
4348c2ecf20Sopenharmony_ci * the given pool allocation function. Can not be used in NMI handler on
4358c2ecf20Sopenharmony_ci * architectures without NMI-safe cmpxchg implementation.
4368c2ecf20Sopenharmony_ci *
4378c2ecf20Sopenharmony_ci * Return: virtual address of the allocated zeroed memory, or %NULL on failure
4388c2ecf20Sopenharmony_ci */
4398c2ecf20Sopenharmony_civoid *gen_pool_dma_zalloc_algo(struct gen_pool *pool, size_t size,
4408c2ecf20Sopenharmony_ci		dma_addr_t *dma, genpool_algo_t algo, void *data)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	void *vaddr = gen_pool_dma_alloc_algo(pool, size, dma, algo, data);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (vaddr)
4458c2ecf20Sopenharmony_ci		memset(vaddr, 0, size);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	return vaddr;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_zalloc_algo);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci/**
4528c2ecf20Sopenharmony_ci * gen_pool_dma_zalloc_align - allocate special zeroed memory from the pool for
4538c2ecf20Sopenharmony_ci * DMA usage with the given alignment
4548c2ecf20Sopenharmony_ci * @pool: pool to allocate from
4558c2ecf20Sopenharmony_ci * @size: number of bytes to allocate from the pool
4568c2ecf20Sopenharmony_ci * @dma: DMA-view physical address return value. Use %NULL if unneeded.
4578c2ecf20Sopenharmony_ci * @align: alignment in bytes for starting address
4588c2ecf20Sopenharmony_ci *
4598c2ecf20Sopenharmony_ci * Allocate the requested number of zeroed bytes from the specified pool,
4608c2ecf20Sopenharmony_ci * with the given alignment restriction. Can not be used in NMI handler on
4618c2ecf20Sopenharmony_ci * architectures without NMI-safe cmpxchg implementation.
4628c2ecf20Sopenharmony_ci *
4638c2ecf20Sopenharmony_ci * Return: virtual address of the allocated zeroed memory, or %NULL on failure
4648c2ecf20Sopenharmony_ci */
4658c2ecf20Sopenharmony_civoid *gen_pool_dma_zalloc_align(struct gen_pool *pool, size_t size,
4668c2ecf20Sopenharmony_ci		dma_addr_t *dma, int align)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	struct genpool_data_align data = { .align = align };
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	return gen_pool_dma_zalloc_algo(pool, size, dma,
4718c2ecf20Sopenharmony_ci			gen_pool_first_fit_align, &data);
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_dma_zalloc_align);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci/**
4768c2ecf20Sopenharmony_ci * gen_pool_free_owner - free allocated special memory back to the pool
4778c2ecf20Sopenharmony_ci * @pool: pool to free to
4788c2ecf20Sopenharmony_ci * @addr: starting address of memory to free back to pool
4798c2ecf20Sopenharmony_ci * @size: size in bytes of memory to free
4808c2ecf20Sopenharmony_ci * @owner: private data stashed at gen_pool_add() time
4818c2ecf20Sopenharmony_ci *
4828c2ecf20Sopenharmony_ci * Free previously allocated special memory back to the specified
4838c2ecf20Sopenharmony_ci * pool.  Can not be used in NMI handler on architectures without
4848c2ecf20Sopenharmony_ci * NMI-safe cmpxchg implementation.
4858c2ecf20Sopenharmony_ci */
4868c2ecf20Sopenharmony_civoid gen_pool_free_owner(struct gen_pool *pool, unsigned long addr, size_t size,
4878c2ecf20Sopenharmony_ci		void **owner)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	struct gen_pool_chunk *chunk;
4908c2ecf20Sopenharmony_ci	int order = pool->min_alloc_order;
4918c2ecf20Sopenharmony_ci	unsigned long start_bit, nbits, remain;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
4948c2ecf20Sopenharmony_ci	BUG_ON(in_nmi());
4958c2ecf20Sopenharmony_ci#endif
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (owner)
4988c2ecf20Sopenharmony_ci		*owner = NULL;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	nbits = (size + (1UL << order) - 1) >> order;
5018c2ecf20Sopenharmony_ci	rcu_read_lock();
5028c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
5038c2ecf20Sopenharmony_ci		if (addr >= chunk->start_addr && addr <= chunk->end_addr) {
5048c2ecf20Sopenharmony_ci			BUG_ON(addr + size - 1 > chunk->end_addr);
5058c2ecf20Sopenharmony_ci			start_bit = (addr - chunk->start_addr) >> order;
5068c2ecf20Sopenharmony_ci			remain = bitmap_clear_ll(chunk->bits, start_bit, nbits);
5078c2ecf20Sopenharmony_ci			BUG_ON(remain);
5088c2ecf20Sopenharmony_ci			size = nbits << order;
5098c2ecf20Sopenharmony_ci			atomic_long_add(size, &chunk->avail);
5108c2ecf20Sopenharmony_ci			if (owner)
5118c2ecf20Sopenharmony_ci				*owner = chunk->owner;
5128c2ecf20Sopenharmony_ci			rcu_read_unlock();
5138c2ecf20Sopenharmony_ci			return;
5148c2ecf20Sopenharmony_ci		}
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci	rcu_read_unlock();
5178c2ecf20Sopenharmony_ci	BUG();
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_free_owner);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci/**
5228c2ecf20Sopenharmony_ci * gen_pool_for_each_chunk - call func for every chunk of generic memory pool
5238c2ecf20Sopenharmony_ci * @pool:	the generic memory pool
5248c2ecf20Sopenharmony_ci * @func:	func to call
5258c2ecf20Sopenharmony_ci * @data:	additional data used by @func
5268c2ecf20Sopenharmony_ci *
5278c2ecf20Sopenharmony_ci * Call @func for every chunk of generic memory pool.  The @func is
5288c2ecf20Sopenharmony_ci * called with rcu_read_lock held.
5298c2ecf20Sopenharmony_ci */
5308c2ecf20Sopenharmony_civoid gen_pool_for_each_chunk(struct gen_pool *pool,
5318c2ecf20Sopenharmony_ci	void (*func)(struct gen_pool *pool, struct gen_pool_chunk *chunk, void *data),
5328c2ecf20Sopenharmony_ci	void *data)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct gen_pool_chunk *chunk;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	rcu_read_lock();
5378c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(chunk, &(pool)->chunks, next_chunk)
5388c2ecf20Sopenharmony_ci		func(pool, chunk, data);
5398c2ecf20Sopenharmony_ci	rcu_read_unlock();
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_for_each_chunk);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci/**
5448c2ecf20Sopenharmony_ci * gen_pool_has_addr - checks if an address falls within the range of a pool
5458c2ecf20Sopenharmony_ci * @pool:	the generic memory pool
5468c2ecf20Sopenharmony_ci * @start:	start address
5478c2ecf20Sopenharmony_ci * @size:	size of the region
5488c2ecf20Sopenharmony_ci *
5498c2ecf20Sopenharmony_ci * Check if the range of addresses falls within the specified pool. Returns
5508c2ecf20Sopenharmony_ci * true if the entire range is contained in the pool and false otherwise.
5518c2ecf20Sopenharmony_ci */
5528c2ecf20Sopenharmony_cibool gen_pool_has_addr(struct gen_pool *pool, unsigned long start,
5538c2ecf20Sopenharmony_ci			size_t size)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	bool found = false;
5568c2ecf20Sopenharmony_ci	unsigned long end = start + size - 1;
5578c2ecf20Sopenharmony_ci	struct gen_pool_chunk *chunk;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	rcu_read_lock();
5608c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(chunk, &(pool)->chunks, next_chunk) {
5618c2ecf20Sopenharmony_ci		if (start >= chunk->start_addr && start <= chunk->end_addr) {
5628c2ecf20Sopenharmony_ci			if (end <= chunk->end_addr) {
5638c2ecf20Sopenharmony_ci				found = true;
5648c2ecf20Sopenharmony_ci				break;
5658c2ecf20Sopenharmony_ci			}
5668c2ecf20Sopenharmony_ci		}
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci	rcu_read_unlock();
5698c2ecf20Sopenharmony_ci	return found;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_has_addr);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci/**
5748c2ecf20Sopenharmony_ci * gen_pool_avail - get available free space of the pool
5758c2ecf20Sopenharmony_ci * @pool: pool to get available free space
5768c2ecf20Sopenharmony_ci *
5778c2ecf20Sopenharmony_ci * Return available free space of the specified pool.
5788c2ecf20Sopenharmony_ci */
5798c2ecf20Sopenharmony_cisize_t gen_pool_avail(struct gen_pool *pool)
5808c2ecf20Sopenharmony_ci{
5818c2ecf20Sopenharmony_ci	struct gen_pool_chunk *chunk;
5828c2ecf20Sopenharmony_ci	size_t avail = 0;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	rcu_read_lock();
5858c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk)
5868c2ecf20Sopenharmony_ci		avail += atomic_long_read(&chunk->avail);
5878c2ecf20Sopenharmony_ci	rcu_read_unlock();
5888c2ecf20Sopenharmony_ci	return avail;
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(gen_pool_avail);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci/**
5938c2ecf20Sopenharmony_ci * gen_pool_size - get size in bytes of memory managed by the pool
5948c2ecf20Sopenharmony_ci * @pool: pool to get size
5958c2ecf20Sopenharmony_ci *
5968c2ecf20Sopenharmony_ci * Return size in bytes of memory managed by the pool.
5978c2ecf20Sopenharmony_ci */
5988c2ecf20Sopenharmony_cisize_t gen_pool_size(struct gen_pool *pool)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	struct gen_pool_chunk *chunk;
6018c2ecf20Sopenharmony_ci	size_t size = 0;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	rcu_read_lock();
6048c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk)
6058c2ecf20Sopenharmony_ci		size += chunk_size(chunk);
6068c2ecf20Sopenharmony_ci	rcu_read_unlock();
6078c2ecf20Sopenharmony_ci	return size;
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(gen_pool_size);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci/**
6128c2ecf20Sopenharmony_ci * gen_pool_set_algo - set the allocation algorithm
6138c2ecf20Sopenharmony_ci * @pool: pool to change allocation algorithm
6148c2ecf20Sopenharmony_ci * @algo: custom algorithm function
6158c2ecf20Sopenharmony_ci * @data: additional data used by @algo
6168c2ecf20Sopenharmony_ci *
6178c2ecf20Sopenharmony_ci * Call @algo for each memory allocation in the pool.
6188c2ecf20Sopenharmony_ci * If @algo is NULL use gen_pool_first_fit as default
6198c2ecf20Sopenharmony_ci * memory allocation function.
6208c2ecf20Sopenharmony_ci */
6218c2ecf20Sopenharmony_civoid gen_pool_set_algo(struct gen_pool *pool, genpool_algo_t algo, void *data)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	rcu_read_lock();
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	pool->algo = algo;
6268c2ecf20Sopenharmony_ci	if (!pool->algo)
6278c2ecf20Sopenharmony_ci		pool->algo = gen_pool_first_fit;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	pool->data = data;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	rcu_read_unlock();
6328c2ecf20Sopenharmony_ci}
6338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_set_algo);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci/**
6368c2ecf20Sopenharmony_ci * gen_pool_first_fit - find the first available region
6378c2ecf20Sopenharmony_ci * of memory matching the size requirement (no alignment constraint)
6388c2ecf20Sopenharmony_ci * @map: The address to base the search on
6398c2ecf20Sopenharmony_ci * @size: The bitmap size in bits
6408c2ecf20Sopenharmony_ci * @start: The bitnumber to start searching at
6418c2ecf20Sopenharmony_ci * @nr: The number of zeroed bits we're looking for
6428c2ecf20Sopenharmony_ci * @data: additional data - unused
6438c2ecf20Sopenharmony_ci * @pool: pool to find the fit region memory from
6448c2ecf20Sopenharmony_ci */
6458c2ecf20Sopenharmony_ciunsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,
6468c2ecf20Sopenharmony_ci		unsigned long start, unsigned int nr, void *data,
6478c2ecf20Sopenharmony_ci		struct gen_pool *pool, unsigned long start_addr)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	return bitmap_find_next_zero_area(map, size, start, nr, 0);
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_first_fit);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci/**
6548c2ecf20Sopenharmony_ci * gen_pool_first_fit_align - find the first available region
6558c2ecf20Sopenharmony_ci * of memory matching the size requirement (alignment constraint)
6568c2ecf20Sopenharmony_ci * @map: The address to base the search on
6578c2ecf20Sopenharmony_ci * @size: The bitmap size in bits
6588c2ecf20Sopenharmony_ci * @start: The bitnumber to start searching at
6598c2ecf20Sopenharmony_ci * @nr: The number of zeroed bits we're looking for
6608c2ecf20Sopenharmony_ci * @data: data for alignment
6618c2ecf20Sopenharmony_ci * @pool: pool to get order from
6628c2ecf20Sopenharmony_ci */
6638c2ecf20Sopenharmony_ciunsigned long gen_pool_first_fit_align(unsigned long *map, unsigned long size,
6648c2ecf20Sopenharmony_ci		unsigned long start, unsigned int nr, void *data,
6658c2ecf20Sopenharmony_ci		struct gen_pool *pool, unsigned long start_addr)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	struct genpool_data_align *alignment;
6688c2ecf20Sopenharmony_ci	unsigned long align_mask, align_off;
6698c2ecf20Sopenharmony_ci	int order;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	alignment = data;
6728c2ecf20Sopenharmony_ci	order = pool->min_alloc_order;
6738c2ecf20Sopenharmony_ci	align_mask = ((alignment->align + (1UL << order) - 1) >> order) - 1;
6748c2ecf20Sopenharmony_ci	align_off = (start_addr & (alignment->align - 1)) >> order;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	return bitmap_find_next_zero_area_off(map, size, start, nr,
6778c2ecf20Sopenharmony_ci					      align_mask, align_off);
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_first_fit_align);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci/**
6828c2ecf20Sopenharmony_ci * gen_pool_fixed_alloc - reserve a specific region
6838c2ecf20Sopenharmony_ci * @map: The address to base the search on
6848c2ecf20Sopenharmony_ci * @size: The bitmap size in bits
6858c2ecf20Sopenharmony_ci * @start: The bitnumber to start searching at
6868c2ecf20Sopenharmony_ci * @nr: The number of zeroed bits we're looking for
6878c2ecf20Sopenharmony_ci * @data: data for alignment
6888c2ecf20Sopenharmony_ci * @pool: pool to get order from
6898c2ecf20Sopenharmony_ci */
6908c2ecf20Sopenharmony_ciunsigned long gen_pool_fixed_alloc(unsigned long *map, unsigned long size,
6918c2ecf20Sopenharmony_ci		unsigned long start, unsigned int nr, void *data,
6928c2ecf20Sopenharmony_ci		struct gen_pool *pool, unsigned long start_addr)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	struct genpool_data_fixed *fixed_data;
6958c2ecf20Sopenharmony_ci	int order;
6968c2ecf20Sopenharmony_ci	unsigned long offset_bit;
6978c2ecf20Sopenharmony_ci	unsigned long start_bit;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	fixed_data = data;
7008c2ecf20Sopenharmony_ci	order = pool->min_alloc_order;
7018c2ecf20Sopenharmony_ci	offset_bit = fixed_data->offset >> order;
7028c2ecf20Sopenharmony_ci	if (WARN_ON(fixed_data->offset & ((1UL << order) - 1)))
7038c2ecf20Sopenharmony_ci		return size;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	start_bit = bitmap_find_next_zero_area(map, size,
7068c2ecf20Sopenharmony_ci			start + offset_bit, nr, 0);
7078c2ecf20Sopenharmony_ci	if (start_bit != offset_bit)
7088c2ecf20Sopenharmony_ci		start_bit = size;
7098c2ecf20Sopenharmony_ci	return start_bit;
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_fixed_alloc);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci/**
7148c2ecf20Sopenharmony_ci * gen_pool_first_fit_order_align - find the first available region
7158c2ecf20Sopenharmony_ci * of memory matching the size requirement. The region will be aligned
7168c2ecf20Sopenharmony_ci * to the order of the size specified.
7178c2ecf20Sopenharmony_ci * @map: The address to base the search on
7188c2ecf20Sopenharmony_ci * @size: The bitmap size in bits
7198c2ecf20Sopenharmony_ci * @start: The bitnumber to start searching at
7208c2ecf20Sopenharmony_ci * @nr: The number of zeroed bits we're looking for
7218c2ecf20Sopenharmony_ci * @data: additional data - unused
7228c2ecf20Sopenharmony_ci * @pool: pool to find the fit region memory from
7238c2ecf20Sopenharmony_ci */
7248c2ecf20Sopenharmony_ciunsigned long gen_pool_first_fit_order_align(unsigned long *map,
7258c2ecf20Sopenharmony_ci		unsigned long size, unsigned long start,
7268c2ecf20Sopenharmony_ci		unsigned int nr, void *data, struct gen_pool *pool,
7278c2ecf20Sopenharmony_ci		unsigned long start_addr)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	unsigned long align_mask = roundup_pow_of_two(nr) - 1;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	return bitmap_find_next_zero_area(map, size, start, nr, align_mask);
7328c2ecf20Sopenharmony_ci}
7338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_first_fit_order_align);
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci/**
7368c2ecf20Sopenharmony_ci * gen_pool_best_fit - find the best fitting region of memory
7378c2ecf20Sopenharmony_ci * macthing the size requirement (no alignment constraint)
7388c2ecf20Sopenharmony_ci * @map: The address to base the search on
7398c2ecf20Sopenharmony_ci * @size: The bitmap size in bits
7408c2ecf20Sopenharmony_ci * @start: The bitnumber to start searching at
7418c2ecf20Sopenharmony_ci * @nr: The number of zeroed bits we're looking for
7428c2ecf20Sopenharmony_ci * @data: additional data - unused
7438c2ecf20Sopenharmony_ci * @pool: pool to find the fit region memory from
7448c2ecf20Sopenharmony_ci *
7458c2ecf20Sopenharmony_ci * Iterate over the bitmap to find the smallest free region
7468c2ecf20Sopenharmony_ci * which we can allocate the memory.
7478c2ecf20Sopenharmony_ci */
7488c2ecf20Sopenharmony_ciunsigned long gen_pool_best_fit(unsigned long *map, unsigned long size,
7498c2ecf20Sopenharmony_ci		unsigned long start, unsigned int nr, void *data,
7508c2ecf20Sopenharmony_ci		struct gen_pool *pool, unsigned long start_addr)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	unsigned long start_bit = size;
7538c2ecf20Sopenharmony_ci	unsigned long len = size + 1;
7548c2ecf20Sopenharmony_ci	unsigned long index;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	index = bitmap_find_next_zero_area(map, size, start, nr, 0);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	while (index < size) {
7598c2ecf20Sopenharmony_ci		unsigned long next_bit = find_next_bit(map, size, index + nr);
7608c2ecf20Sopenharmony_ci		if ((next_bit - index) < len) {
7618c2ecf20Sopenharmony_ci			len = next_bit - index;
7628c2ecf20Sopenharmony_ci			start_bit = index;
7638c2ecf20Sopenharmony_ci			if (len == nr)
7648c2ecf20Sopenharmony_ci				return start_bit;
7658c2ecf20Sopenharmony_ci		}
7668c2ecf20Sopenharmony_ci		index = bitmap_find_next_zero_area(map, size,
7678c2ecf20Sopenharmony_ci						   next_bit + 1, nr, 0);
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	return start_bit;
7718c2ecf20Sopenharmony_ci}
7728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gen_pool_best_fit);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_cistatic void devm_gen_pool_release(struct device *dev, void *res)
7758c2ecf20Sopenharmony_ci{
7768c2ecf20Sopenharmony_ci	gen_pool_destroy(*(struct gen_pool **)res);
7778c2ecf20Sopenharmony_ci}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_cistatic int devm_gen_pool_match(struct device *dev, void *res, void *data)
7808c2ecf20Sopenharmony_ci{
7818c2ecf20Sopenharmony_ci	struct gen_pool **p = res;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	/* NULL data matches only a pool without an assigned name */
7848c2ecf20Sopenharmony_ci	if (!data && !(*p)->name)
7858c2ecf20Sopenharmony_ci		return 1;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	if (!data || !(*p)->name)
7888c2ecf20Sopenharmony_ci		return 0;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	return !strcmp((*p)->name, data);
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci/**
7948c2ecf20Sopenharmony_ci * gen_pool_get - Obtain the gen_pool (if any) for a device
7958c2ecf20Sopenharmony_ci * @dev: device to retrieve the gen_pool from
7968c2ecf20Sopenharmony_ci * @name: name of a gen_pool or NULL, identifies a particular gen_pool on device
7978c2ecf20Sopenharmony_ci *
7988c2ecf20Sopenharmony_ci * Returns the gen_pool for the device if one is present, or NULL.
7998c2ecf20Sopenharmony_ci */
8008c2ecf20Sopenharmony_cistruct gen_pool *gen_pool_get(struct device *dev, const char *name)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct gen_pool **p;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	p = devres_find(dev, devm_gen_pool_release, devm_gen_pool_match,
8058c2ecf20Sopenharmony_ci			(void *)name);
8068c2ecf20Sopenharmony_ci	if (!p)
8078c2ecf20Sopenharmony_ci		return NULL;
8088c2ecf20Sopenharmony_ci	return *p;
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(gen_pool_get);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci/**
8138c2ecf20Sopenharmony_ci * devm_gen_pool_create - managed gen_pool_create
8148c2ecf20Sopenharmony_ci * @dev: device that provides the gen_pool
8158c2ecf20Sopenharmony_ci * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents
8168c2ecf20Sopenharmony_ci * @nid: node selector for allocated gen_pool, %NUMA_NO_NODE for all nodes
8178c2ecf20Sopenharmony_ci * @name: name of a gen_pool or NULL, identifies a particular gen_pool on device
8188c2ecf20Sopenharmony_ci *
8198c2ecf20Sopenharmony_ci * Create a new special memory pool that can be used to manage special purpose
8208c2ecf20Sopenharmony_ci * memory not managed by the regular kmalloc/kfree interface. The pool will be
8218c2ecf20Sopenharmony_ci * automatically destroyed by the device management code.
8228c2ecf20Sopenharmony_ci */
8238c2ecf20Sopenharmony_cistruct gen_pool *devm_gen_pool_create(struct device *dev, int min_alloc_order,
8248c2ecf20Sopenharmony_ci				      int nid, const char *name)
8258c2ecf20Sopenharmony_ci{
8268c2ecf20Sopenharmony_ci	struct gen_pool **ptr, *pool;
8278c2ecf20Sopenharmony_ci	const char *pool_name = NULL;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	/* Check that genpool to be created is uniquely addressed on device */
8308c2ecf20Sopenharmony_ci	if (gen_pool_get(dev, name))
8318c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (name) {
8348c2ecf20Sopenharmony_ci		pool_name = kstrdup_const(name, GFP_KERNEL);
8358c2ecf20Sopenharmony_ci		if (!pool_name)
8368c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOMEM);
8378c2ecf20Sopenharmony_ci	}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	ptr = devres_alloc(devm_gen_pool_release, sizeof(*ptr), GFP_KERNEL);
8408c2ecf20Sopenharmony_ci	if (!ptr)
8418c2ecf20Sopenharmony_ci		goto free_pool_name;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	pool = gen_pool_create(min_alloc_order, nid);
8448c2ecf20Sopenharmony_ci	if (!pool)
8458c2ecf20Sopenharmony_ci		goto free_devres;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	*ptr = pool;
8488c2ecf20Sopenharmony_ci	pool->name = pool_name;
8498c2ecf20Sopenharmony_ci	devres_add(dev, ptr);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	return pool;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cifree_devres:
8548c2ecf20Sopenharmony_ci	devres_free(ptr);
8558c2ecf20Sopenharmony_cifree_pool_name:
8568c2ecf20Sopenharmony_ci	kfree_const(pool_name);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	return ERR_PTR(-ENOMEM);
8598c2ecf20Sopenharmony_ci}
8608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devm_gen_pool_create);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
8638c2ecf20Sopenharmony_ci/**
8648c2ecf20Sopenharmony_ci * of_gen_pool_get - find a pool by phandle property
8658c2ecf20Sopenharmony_ci * @np: device node
8668c2ecf20Sopenharmony_ci * @propname: property name containing phandle(s)
8678c2ecf20Sopenharmony_ci * @index: index into the phandle array
8688c2ecf20Sopenharmony_ci *
8698c2ecf20Sopenharmony_ci * Returns the pool that contains the chunk starting at the physical
8708c2ecf20Sopenharmony_ci * address of the device tree node pointed at by the phandle property,
8718c2ecf20Sopenharmony_ci * or NULL if not found.
8728c2ecf20Sopenharmony_ci */
8738c2ecf20Sopenharmony_cistruct gen_pool *of_gen_pool_get(struct device_node *np,
8748c2ecf20Sopenharmony_ci	const char *propname, int index)
8758c2ecf20Sopenharmony_ci{
8768c2ecf20Sopenharmony_ci	struct platform_device *pdev;
8778c2ecf20Sopenharmony_ci	struct device_node *np_pool, *parent;
8788c2ecf20Sopenharmony_ci	const char *name = NULL;
8798c2ecf20Sopenharmony_ci	struct gen_pool *pool = NULL;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	np_pool = of_parse_phandle(np, propname, index);
8828c2ecf20Sopenharmony_ci	if (!np_pool)
8838c2ecf20Sopenharmony_ci		return NULL;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	pdev = of_find_device_by_node(np_pool);
8868c2ecf20Sopenharmony_ci	if (!pdev) {
8878c2ecf20Sopenharmony_ci		/* Check if named gen_pool is created by parent node device */
8888c2ecf20Sopenharmony_ci		parent = of_get_parent(np_pool);
8898c2ecf20Sopenharmony_ci		pdev = of_find_device_by_node(parent);
8908c2ecf20Sopenharmony_ci		of_node_put(parent);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci		of_property_read_string(np_pool, "label", &name);
8938c2ecf20Sopenharmony_ci		if (!name)
8948c2ecf20Sopenharmony_ci			name = np_pool->name;
8958c2ecf20Sopenharmony_ci	}
8968c2ecf20Sopenharmony_ci	if (pdev)
8978c2ecf20Sopenharmony_ci		pool = gen_pool_get(&pdev->dev, name);
8988c2ecf20Sopenharmony_ci	of_node_put(np_pool);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	return pool;
9018c2ecf20Sopenharmony_ci}
9028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_gen_pool_get);
9038c2ecf20Sopenharmony_ci#endif /* CONFIG_OF */
904