Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  * Basic general purpose allocator for managing special purpose
0004  * memory, for example, memory that is not managed by the regular
0005  * kmalloc/kfree interface.  Uses for this includes on-device special
0006  * memory, uncached memory etc.
0007  *
0008  * It is safe to use the allocator in NMI handlers and other special
0009  * unblockable contexts that could otherwise deadlock on locks.  This
0010  * is implemented by using atomic operations and retries on any
0011  * conflicts.  The disadvantage is that there may be livelocks in
0012  * extreme cases.  For better scalability, one allocator can be used
0013  * for each CPU.
0014  *
0015  * The lockless operation only works if there is enough memory
0016  * available.  If new memory is added to the pool a lock has to be
0017  * still taken.  So any user relying on locklessness has to ensure
0018  * that sufficient memory is preallocated.
0019  *
0020  * The basic atomic operation of this allocator is cmpxchg on long.
0021  * On architectures that don't have NMI-safe cmpxchg implementation,
0022  * the allocator can NOT be used in NMI handler.  So code uses the
0023  * allocator in NMI handler should depend on
0024  * CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG.
0025  */
0026 
0027 
0028 #ifndef __GENALLOC_H__
0029 #define __GENALLOC_H__
0030 
0031 #include <linux/types.h>
0032 #include <linux/spinlock_types.h>
0033 #include <linux/atomic.h>
0034 
0035 struct device;
0036 struct device_node;
0037 struct gen_pool;
0038 
0039 /**
0040  * typedef genpool_algo_t: Allocation callback function type definition
0041  * @map: Pointer to bitmap
0042  * @size: The bitmap size in bits
0043  * @start: The bitnumber to start searching at
0044  * @nr: The number of zeroed bits we're looking for
0045  * @data: optional additional data used by the callback
0046  * @pool: the pool being allocated from
0047  */
0048 typedef unsigned long (*genpool_algo_t)(unsigned long *map,
0049             unsigned long size,
0050             unsigned long start,
0051             unsigned int nr,
0052             void *data, struct gen_pool *pool,
0053             unsigned long start_addr);
0054 
0055 /*
0056  *  General purpose special memory pool descriptor.
0057  */
0058 struct gen_pool {
0059     spinlock_t lock;
0060     struct list_head chunks;    /* list of chunks in this pool */
0061     int min_alloc_order;        /* minimum allocation order */
0062 
0063     genpool_algo_t algo;        /* allocation function */
0064     void *data;
0065 
0066     const char *name;
0067 };
0068 
0069 /*
0070  *  General purpose special memory pool chunk descriptor.
0071  */
0072 struct gen_pool_chunk {
0073     struct list_head next_chunk;    /* next chunk in pool */
0074     atomic_long_t avail;
0075     phys_addr_t phys_addr;      /* physical starting address of memory chunk */
0076     void *owner;            /* private data to retrieve at alloc time */
0077     unsigned long start_addr;   /* start address of memory chunk */
0078     unsigned long end_addr;     /* end address of memory chunk (inclusive) */
0079     unsigned long bits[];       /* bitmap for allocating memory chunk */
0080 };
0081 
0082 /*
0083  *  gen_pool data descriptor for gen_pool_first_fit_align.
0084  */
0085 struct genpool_data_align {
0086     int align;      /* alignment by bytes for starting address */
0087 };
0088 
0089 /*
0090  *  gen_pool data descriptor for gen_pool_fixed_alloc.
0091  */
0092 struct genpool_data_fixed {
0093     unsigned long offset;       /* The offset of the specific region */
0094 };
0095 
0096 extern struct gen_pool *gen_pool_create(int, int);
0097 extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long);
0098 extern int gen_pool_add_owner(struct gen_pool *, unsigned long, phys_addr_t,
0099                  size_t, int, void *);
0100 
0101 static inline int gen_pool_add_virt(struct gen_pool *pool, unsigned long addr,
0102         phys_addr_t phys, size_t size, int nid)
0103 {
0104     return gen_pool_add_owner(pool, addr, phys, size, nid, NULL);
0105 }
0106 
0107 /**
0108  * gen_pool_add - add a new chunk of special memory to the pool
0109  * @pool: pool to add new memory chunk to
0110  * @addr: starting address of memory chunk to add to pool
0111  * @size: size in bytes of the memory chunk to add to pool
0112  * @nid: node id of the node the chunk structure and bitmap should be
0113  *       allocated on, or -1
0114  *
0115  * Add a new chunk of special memory to the specified pool.
0116  *
0117  * Returns 0 on success or a -ve errno on failure.
0118  */
0119 static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
0120                    size_t size, int nid)
0121 {
0122     return gen_pool_add_virt(pool, addr, -1, size, nid);
0123 }
0124 extern void gen_pool_destroy(struct gen_pool *);
0125 unsigned long gen_pool_alloc_algo_owner(struct gen_pool *pool, size_t size,
0126         genpool_algo_t algo, void *data, void **owner);
0127 
0128 static inline unsigned long gen_pool_alloc_owner(struct gen_pool *pool,
0129         size_t size, void **owner)
0130 {
0131     return gen_pool_alloc_algo_owner(pool, size, pool->algo, pool->data,
0132             owner);
0133 }
0134 
0135 static inline unsigned long gen_pool_alloc_algo(struct gen_pool *pool,
0136         size_t size, genpool_algo_t algo, void *data)
0137 {
0138     return gen_pool_alloc_algo_owner(pool, size, algo, data, NULL);
0139 }
0140 
0141 /**
0142  * gen_pool_alloc - allocate special memory from the pool
0143  * @pool: pool to allocate from
0144  * @size: number of bytes to allocate from the pool
0145  *
0146  * Allocate the requested number of bytes from the specified pool.
0147  * Uses the pool allocation function (with first-fit algorithm by default).
0148  * Can not be used in NMI handler on architectures without
0149  * NMI-safe cmpxchg implementation.
0150  */
0151 static inline unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
0152 {
0153     return gen_pool_alloc_algo(pool, size, pool->algo, pool->data);
0154 }
0155 
0156 extern void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size,
0157         dma_addr_t *dma);
0158 extern void *gen_pool_dma_alloc_algo(struct gen_pool *pool, size_t size,
0159         dma_addr_t *dma, genpool_algo_t algo, void *data);
0160 extern void *gen_pool_dma_alloc_align(struct gen_pool *pool, size_t size,
0161         dma_addr_t *dma, int align);
0162 extern void *gen_pool_dma_zalloc(struct gen_pool *pool, size_t size, dma_addr_t *dma);
0163 extern void *gen_pool_dma_zalloc_algo(struct gen_pool *pool, size_t size,
0164         dma_addr_t *dma, genpool_algo_t algo, void *data);
0165 extern void *gen_pool_dma_zalloc_align(struct gen_pool *pool, size_t size,
0166         dma_addr_t *dma, int align);
0167 extern void gen_pool_free_owner(struct gen_pool *pool, unsigned long addr,
0168         size_t size, void **owner);
0169 static inline void gen_pool_free(struct gen_pool *pool, unsigned long addr,
0170                 size_t size)
0171 {
0172     gen_pool_free_owner(pool, addr, size, NULL);
0173 }
0174 
0175 extern void gen_pool_for_each_chunk(struct gen_pool *,
0176     void (*)(struct gen_pool *, struct gen_pool_chunk *, void *), void *);
0177 extern size_t gen_pool_avail(struct gen_pool *);
0178 extern size_t gen_pool_size(struct gen_pool *);
0179 
0180 extern void gen_pool_set_algo(struct gen_pool *pool, genpool_algo_t algo,
0181         void *data);
0182 
0183 extern unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,
0184         unsigned long start, unsigned int nr, void *data,
0185         struct gen_pool *pool, unsigned long start_addr);
0186 
0187 extern unsigned long gen_pool_fixed_alloc(unsigned long *map,
0188         unsigned long size, unsigned long start, unsigned int nr,
0189         void *data, struct gen_pool *pool, unsigned long start_addr);
0190 
0191 extern unsigned long gen_pool_first_fit_align(unsigned long *map,
0192         unsigned long size, unsigned long start, unsigned int nr,
0193         void *data, struct gen_pool *pool, unsigned long start_addr);
0194 
0195 
0196 extern unsigned long gen_pool_first_fit_order_align(unsigned long *map,
0197         unsigned long size, unsigned long start, unsigned int nr,
0198         void *data, struct gen_pool *pool, unsigned long start_addr);
0199 
0200 extern unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size,
0201         unsigned long start, unsigned int nr, void *data,
0202         struct gen_pool *pool, unsigned long start_addr);
0203 
0204 
0205 extern struct gen_pool *devm_gen_pool_create(struct device *dev,
0206         int min_alloc_order, int nid, const char *name);
0207 extern struct gen_pool *gen_pool_get(struct device *dev, const char *name);
0208 
0209 extern bool gen_pool_has_addr(struct gen_pool *pool, unsigned long start,
0210             size_t size);
0211 
0212 #ifdef CONFIG_OF
0213 extern struct gen_pool *of_gen_pool_get(struct device_node *np,
0214     const char *propname, int index);
0215 #else
0216 static inline struct gen_pool *of_gen_pool_get(struct device_node *np,
0217     const char *propname, int index)
0218 {
0219     return NULL;
0220 }
0221 #endif
0222 #endif /* __GENALLOC_H__ */