xref: /linux-6.15/include/linux/genalloc.h (revision 9375db07)
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__
32*9375db07SPhilipp Zabel 
33*9375db07SPhilipp Zabel struct device;
34*9375db07SPhilipp Zabel struct device_node;
35*9375db07SPhilipp Zabel 
36ca279cf1SBenjamin Gaignard /**
37ca279cf1SBenjamin Gaignard  * Allocation callback function type definition
38ca279cf1SBenjamin Gaignard  * @map: Pointer to bitmap
39ca279cf1SBenjamin Gaignard  * @size: The bitmap size in bits
40ca279cf1SBenjamin Gaignard  * @start: The bitnumber to start searching at
41ca279cf1SBenjamin Gaignard  * @nr: The number of zeroed bits we're looking for
42ca279cf1SBenjamin Gaignard  * @data: optional additional data used by @genpool_algo_t
43ca279cf1SBenjamin Gaignard  */
44ca279cf1SBenjamin Gaignard typedef unsigned long (*genpool_algo_t)(unsigned long *map,
45ca279cf1SBenjamin Gaignard 			unsigned long size,
46ca279cf1SBenjamin Gaignard 			unsigned long start,
47ca279cf1SBenjamin Gaignard 			unsigned int nr,
48ca279cf1SBenjamin Gaignard 			void *data);
49ca279cf1SBenjamin Gaignard 
50f14f75b8SJes Sorensen /*
51929f9727SDean Nelson  *  General purpose special memory pool descriptor.
52f14f75b8SJes Sorensen  */
53f14f75b8SJes Sorensen struct gen_pool {
547f184275SHuang Ying 	spinlock_t lock;
55929f9727SDean Nelson 	struct list_head chunks;	/* list of chunks in this pool */
56929f9727SDean Nelson 	int min_alloc_order;		/* minimum allocation order */
57ca279cf1SBenjamin Gaignard 
58ca279cf1SBenjamin Gaignard 	genpool_algo_t algo;		/* allocation function */
59ca279cf1SBenjamin Gaignard 	void *data;
60f14f75b8SJes Sorensen };
61f14f75b8SJes Sorensen 
62929f9727SDean Nelson /*
63929f9727SDean Nelson  *  General purpose special memory pool chunk descriptor.
64929f9727SDean Nelson  */
65929f9727SDean Nelson struct gen_pool_chunk {
66929f9727SDean Nelson 	struct list_head next_chunk;	/* next chunk in pool */
677f184275SHuang Ying 	atomic_t avail;
683c8f370dSJean-Christophe PLAGNIOL-VILLARD 	phys_addr_t phys_addr;		/* physical starting address of memory chunk */
69929f9727SDean Nelson 	unsigned long start_addr;	/* starting address of memory chunk */
70929f9727SDean Nelson 	unsigned long end_addr;		/* ending address of memory chunk */
71929f9727SDean Nelson 	unsigned long bits[0];		/* bitmap for allocating memory chunk */
72929f9727SDean Nelson };
73929f9727SDean Nelson 
74929f9727SDean Nelson extern struct gen_pool *gen_pool_create(int, int);
753c8f370dSJean-Christophe PLAGNIOL-VILLARD extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long);
763c8f370dSJean-Christophe PLAGNIOL-VILLARD extern int gen_pool_add_virt(struct gen_pool *, unsigned long, phys_addr_t,
773c8f370dSJean-Christophe PLAGNIOL-VILLARD 			     size_t, int);
783c8f370dSJean-Christophe PLAGNIOL-VILLARD /**
793c8f370dSJean-Christophe PLAGNIOL-VILLARD  * gen_pool_add - add a new chunk of special memory to the pool
803c8f370dSJean-Christophe PLAGNIOL-VILLARD  * @pool: pool to add new memory chunk to
813c8f370dSJean-Christophe PLAGNIOL-VILLARD  * @addr: starting address of memory chunk to add to pool
823c8f370dSJean-Christophe PLAGNIOL-VILLARD  * @size: size in bytes of the memory chunk to add to pool
833c8f370dSJean-Christophe PLAGNIOL-VILLARD  * @nid: node id of the node the chunk structure and bitmap should be
843c8f370dSJean-Christophe PLAGNIOL-VILLARD  *       allocated on, or -1
853c8f370dSJean-Christophe PLAGNIOL-VILLARD  *
863c8f370dSJean-Christophe PLAGNIOL-VILLARD  * Add a new chunk of special memory to the specified pool.
873c8f370dSJean-Christophe PLAGNIOL-VILLARD  *
883c8f370dSJean-Christophe PLAGNIOL-VILLARD  * Returns 0 on success or a -ve errno on failure.
893c8f370dSJean-Christophe PLAGNIOL-VILLARD  */
903c8f370dSJean-Christophe PLAGNIOL-VILLARD static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
913c8f370dSJean-Christophe PLAGNIOL-VILLARD 			       size_t size, int nid)
923c8f370dSJean-Christophe PLAGNIOL-VILLARD {
933c8f370dSJean-Christophe PLAGNIOL-VILLARD 	return gen_pool_add_virt(pool, addr, -1, size, nid);
943c8f370dSJean-Christophe PLAGNIOL-VILLARD }
95322acc96SSteve Wise extern void gen_pool_destroy(struct gen_pool *);
96929f9727SDean Nelson extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
97929f9727SDean Nelson extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
987f184275SHuang Ying extern void gen_pool_for_each_chunk(struct gen_pool *,
997f184275SHuang Ying 	void (*)(struct gen_pool *, struct gen_pool_chunk *, void *), void *);
1007f184275SHuang Ying extern size_t gen_pool_avail(struct gen_pool *);
1017f184275SHuang Ying extern size_t gen_pool_size(struct gen_pool *);
102ca279cf1SBenjamin Gaignard 
103ca279cf1SBenjamin Gaignard extern void gen_pool_set_algo(struct gen_pool *pool, genpool_algo_t algo,
104ca279cf1SBenjamin Gaignard 		void *data);
105ca279cf1SBenjamin Gaignard 
106ca279cf1SBenjamin Gaignard extern unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,
107ca279cf1SBenjamin Gaignard 		unsigned long start, unsigned int nr, void *data);
108ca279cf1SBenjamin Gaignard 
109ca279cf1SBenjamin Gaignard extern unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size,
110ca279cf1SBenjamin Gaignard 		unsigned long start, unsigned int nr, void *data);
111ca279cf1SBenjamin Gaignard 
112*9375db07SPhilipp Zabel extern struct gen_pool *devm_gen_pool_create(struct device *dev,
113*9375db07SPhilipp Zabel 		int min_alloc_order, int nid);
114*9375db07SPhilipp Zabel extern struct gen_pool *dev_get_gen_pool(struct device *dev);
115*9375db07SPhilipp Zabel 
116*9375db07SPhilipp Zabel #ifdef CONFIG_OF
117*9375db07SPhilipp Zabel extern struct gen_pool *of_get_named_gen_pool(struct device_node *np,
118*9375db07SPhilipp Zabel 	const char *propname, int index);
119*9375db07SPhilipp Zabel #else
120*9375db07SPhilipp Zabel static inline struct gen_pool *of_get_named_gen_pool(struct device_node *np,
121*9375db07SPhilipp Zabel 	const char *propname, int index)
122*9375db07SPhilipp Zabel {
123*9375db07SPhilipp Zabel 	return NULL;
124*9375db07SPhilipp Zabel }
125*9375db07SPhilipp Zabel #endif
1266aae6e03SJean-Christophe PLAGNIOL-VILLARD #endif /* __GENALLOC_H__ */
127