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