xref: /linux-6.15/include/linux/genalloc.h (revision de2dd0eb)
1f14f75b8SJes Sorensen /*
27f184275SHuang Ying  * Basic general purpose allocator for managing special purpose
37f184275SHuang Ying  * memory, for example, memory that is not managed by the regular
47f184275SHuang Ying  * kmalloc/kfree interface.  Uses for this includes on-device special
57f184275SHuang Ying  * memory, uncached memory etc.
67f184275SHuang Ying  *
77f184275SHuang Ying  * It is safe to use the allocator in NMI handlers and other special
87f184275SHuang Ying  * unblockable contexts that could otherwise deadlock on locks.  This
97f184275SHuang Ying  * is implemented by using atomic operations and retries on any
107f184275SHuang Ying  * conflicts.  The disadvantage is that there may be livelocks in
117f184275SHuang Ying  * extreme cases.  For better scalability, one allocator can be used
127f184275SHuang Ying  * for each CPU.
137f184275SHuang Ying  *
147f184275SHuang Ying  * The lockless operation only works if there is enough memory
157f184275SHuang Ying  * available.  If new memory is added to the pool a lock has to be
167f184275SHuang Ying  * still taken.  So any user relying on locklessness has to ensure
177f184275SHuang Ying  * that sufficient memory is preallocated.
187f184275SHuang Ying  *
197f184275SHuang Ying  * The basic atomic operation of this allocator is cmpxchg on long.
207f184275SHuang Ying  * On architectures that don't have NMI-safe cmpxchg implementation,
217f184275SHuang Ying  * the allocator can NOT be used in NMI handler.  So code uses the
227f184275SHuang Ying  * allocator in NMI handler should depend on
237f184275SHuang Ying  * CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG.
24f14f75b8SJes Sorensen  *
25f14f75b8SJes Sorensen  * This source code is licensed under the GNU General Public License,
26f14f75b8SJes Sorensen  * Version 2.  See the file COPYING for more details.
27f14f75b8SJes Sorensen  */
28f14f75b8SJes Sorensen 
29f14f75b8SJes Sorensen 
306aae6e03SJean-Christophe PLAGNIOL-VILLARD #ifndef __GENALLOC_H__
316aae6e03SJean-Christophe PLAGNIOL-VILLARD #define __GENALLOC_H__
329375db07SPhilipp Zabel 
33*de2dd0ebSZhao Qiang #include <linux/types.h>
34b30afea0SShawn Guo #include <linux/spinlock_types.h>
35b30afea0SShawn Guo 
369375db07SPhilipp Zabel struct device;
379375db07SPhilipp Zabel struct device_node;
38*de2dd0ebSZhao Qiang struct gen_pool;
399375db07SPhilipp Zabel 
40ca279cf1SBenjamin Gaignard /**
41ca279cf1SBenjamin Gaignard  * Allocation callback function type definition
42ca279cf1SBenjamin Gaignard  * @map: Pointer to bitmap
43ca279cf1SBenjamin Gaignard  * @size: The bitmap size in bits
44ca279cf1SBenjamin Gaignard  * @start: The bitnumber to start searching at
45ca279cf1SBenjamin Gaignard  * @nr: The number of zeroed bits we're looking for
46ca279cf1SBenjamin Gaignard  * @data: optional additional data used by @genpool_algo_t
47ca279cf1SBenjamin Gaignard  */
48ca279cf1SBenjamin Gaignard typedef unsigned long (*genpool_algo_t)(unsigned long *map,
49ca279cf1SBenjamin Gaignard 			unsigned long size,
50ca279cf1SBenjamin Gaignard 			unsigned long start,
51ca279cf1SBenjamin Gaignard 			unsigned int nr,
52*de2dd0ebSZhao Qiang 			void *data, struct gen_pool *pool);
53ca279cf1SBenjamin Gaignard 
54f14f75b8SJes Sorensen /*
55929f9727SDean Nelson  *  General purpose special memory pool descriptor.
56f14f75b8SJes Sorensen  */
57f14f75b8SJes Sorensen struct gen_pool {
587f184275SHuang Ying 	spinlock_t lock;
59929f9727SDean Nelson 	struct list_head chunks;	/* list of chunks in this pool */
60929f9727SDean Nelson 	int min_alloc_order;		/* minimum allocation order */
61ca279cf1SBenjamin Gaignard 
62ca279cf1SBenjamin Gaignard 	genpool_algo_t algo;		/* allocation function */
63ca279cf1SBenjamin Gaignard 	void *data;
64c98c3635SVladimir Zapolskiy 
65c98c3635SVladimir Zapolskiy 	const char *name;
66f14f75b8SJes Sorensen };
67f14f75b8SJes Sorensen 
68929f9727SDean Nelson /*
69929f9727SDean Nelson  *  General purpose special memory pool chunk descriptor.
70929f9727SDean Nelson  */
71929f9727SDean Nelson struct gen_pool_chunk {
72929f9727SDean Nelson 	struct list_head next_chunk;	/* next chunk in pool */
737f184275SHuang Ying 	atomic_t avail;
743c8f370dSJean-Christophe PLAGNIOL-VILLARD 	phys_addr_t phys_addr;		/* physical starting address of memory chunk */
75674470d9SJoonyoung Shim 	unsigned long start_addr;	/* start address of memory chunk */
76674470d9SJoonyoung Shim 	unsigned long end_addr;		/* end address of memory chunk (inclusive) */
77929f9727SDean Nelson 	unsigned long bits[0];		/* bitmap for allocating memory chunk */
78929f9727SDean Nelson };
79929f9727SDean Nelson 
80*de2dd0ebSZhao Qiang /*
81*de2dd0ebSZhao Qiang  *  gen_pool data descriptor for gen_pool_first_fit_align.
82*de2dd0ebSZhao Qiang  */
83*de2dd0ebSZhao Qiang struct genpool_data_align {
84*de2dd0ebSZhao Qiang 	int align;		/* alignment by bytes for starting address */
85*de2dd0ebSZhao Qiang };
86*de2dd0ebSZhao Qiang 
87929f9727SDean Nelson extern struct gen_pool *gen_pool_create(int, int);
883c8f370dSJean-Christophe PLAGNIOL-VILLARD extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long);
893c8f370dSJean-Christophe PLAGNIOL-VILLARD extern int gen_pool_add_virt(struct gen_pool *, unsigned long, phys_addr_t,
903c8f370dSJean-Christophe PLAGNIOL-VILLARD 			     size_t, int);
913c8f370dSJean-Christophe PLAGNIOL-VILLARD /**
923c8f370dSJean-Christophe PLAGNIOL-VILLARD  * gen_pool_add - add a new chunk of special memory to the pool
933c8f370dSJean-Christophe PLAGNIOL-VILLARD  * @pool: pool to add new memory chunk to
943c8f370dSJean-Christophe PLAGNIOL-VILLARD  * @addr: starting address of memory chunk to add to pool
953c8f370dSJean-Christophe PLAGNIOL-VILLARD  * @size: size in bytes of the memory chunk to add to pool
963c8f370dSJean-Christophe PLAGNIOL-VILLARD  * @nid: node id of the node the chunk structure and bitmap should be
973c8f370dSJean-Christophe PLAGNIOL-VILLARD  *       allocated on, or -1
983c8f370dSJean-Christophe PLAGNIOL-VILLARD  *
993c8f370dSJean-Christophe PLAGNIOL-VILLARD  * Add a new chunk of special memory to the specified pool.
1003c8f370dSJean-Christophe PLAGNIOL-VILLARD  *
1013c8f370dSJean-Christophe PLAGNIOL-VILLARD  * Returns 0 on success or a -ve errno on failure.
1023c8f370dSJean-Christophe PLAGNIOL-VILLARD  */
1033c8f370dSJean-Christophe PLAGNIOL-VILLARD static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
1043c8f370dSJean-Christophe PLAGNIOL-VILLARD 			       size_t size, int nid)
1053c8f370dSJean-Christophe PLAGNIOL-VILLARD {
1063c8f370dSJean-Christophe PLAGNIOL-VILLARD 	return gen_pool_add_virt(pool, addr, -1, size, nid);
1073c8f370dSJean-Christophe PLAGNIOL-VILLARD }
108322acc96SSteve Wise extern void gen_pool_destroy(struct gen_pool *);
109929f9727SDean Nelson extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
110*de2dd0ebSZhao Qiang extern unsigned long gen_pool_alloc_algo(struct gen_pool *, size_t,
111*de2dd0ebSZhao Qiang 		genpool_algo_t algo, void *data);
112684f0d3dSNicolin Chen extern void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size,
113684f0d3dSNicolin Chen 		dma_addr_t *dma);
114929f9727SDean Nelson extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
1157f184275SHuang Ying extern void gen_pool_for_each_chunk(struct gen_pool *,
1167f184275SHuang Ying 	void (*)(struct gen_pool *, struct gen_pool_chunk *, void *), void *);
1177f184275SHuang Ying extern size_t gen_pool_avail(struct gen_pool *);
1187f184275SHuang Ying extern size_t gen_pool_size(struct gen_pool *);
119ca279cf1SBenjamin Gaignard 
120ca279cf1SBenjamin Gaignard extern void gen_pool_set_algo(struct gen_pool *pool, genpool_algo_t algo,
121ca279cf1SBenjamin Gaignard 		void *data);
122ca279cf1SBenjamin Gaignard 
123ca279cf1SBenjamin Gaignard extern unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,
124*de2dd0ebSZhao Qiang 		unsigned long start, unsigned int nr, void *data,
125*de2dd0ebSZhao Qiang 		struct gen_pool *pool);
126*de2dd0ebSZhao Qiang 
127*de2dd0ebSZhao Qiang extern unsigned long gen_pool_first_fit_align(unsigned long *map,
128*de2dd0ebSZhao Qiang 		unsigned long size, unsigned long start, unsigned int nr,
129*de2dd0ebSZhao Qiang 		void *data, struct gen_pool *pool);
130*de2dd0ebSZhao Qiang 
131ca279cf1SBenjamin Gaignard 
132505e3be6SLaura Abbott extern unsigned long gen_pool_first_fit_order_align(unsigned long *map,
133505e3be6SLaura Abbott 		unsigned long size, unsigned long start, unsigned int nr,
134*de2dd0ebSZhao Qiang 		void *data, struct gen_pool *pool);
135505e3be6SLaura Abbott 
136ca279cf1SBenjamin Gaignard extern unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size,
137*de2dd0ebSZhao Qiang 		unsigned long start, unsigned int nr, void *data,
138*de2dd0ebSZhao Qiang 		struct gen_pool *pool);
139*de2dd0ebSZhao Qiang 
140ca279cf1SBenjamin Gaignard 
1419375db07SPhilipp Zabel extern struct gen_pool *devm_gen_pool_create(struct device *dev,
14273858173SVladimir Zapolskiy 		int min_alloc_order, int nid, const char *name);
14373858173SVladimir Zapolskiy extern struct gen_pool *gen_pool_get(struct device *dev, const char *name);
1449375db07SPhilipp Zabel 
1459efb3a42SLaura Abbott bool addr_in_gen_pool(struct gen_pool *pool, unsigned long start,
1469efb3a42SLaura Abbott 			size_t size);
1479efb3a42SLaura Abbott 
1489375db07SPhilipp Zabel #ifdef CONFIG_OF
149abdd4a70SVladimir Zapolskiy extern struct gen_pool *of_gen_pool_get(struct device_node *np,
1509375db07SPhilipp Zabel 	const char *propname, int index);
1519375db07SPhilipp Zabel #else
152abdd4a70SVladimir Zapolskiy static inline struct gen_pool *of_gen_pool_get(struct device_node *np,
1539375db07SPhilipp Zabel 	const char *propname, int index)
1549375db07SPhilipp Zabel {
1559375db07SPhilipp Zabel 	return NULL;
1569375db07SPhilipp Zabel }
1579375db07SPhilipp Zabel #endif
1586aae6e03SJean-Christophe PLAGNIOL-VILLARD #endif /* __GENALLOC_H__ */
159