Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>
0004  *
0005  *  Generic memory management routines for soundcard memory allocation
0006  */
0007 
0008 #include <linux/mutex.h>
0009 #include <linux/init.h>
0010 #include <linux/slab.h>
0011 #include <linux/module.h>
0012 #include <sound/core.h>
0013 #include <sound/util_mem.h>
0014 
0015 MODULE_AUTHOR("Takashi Iwai");
0016 MODULE_DESCRIPTION("Generic memory management routines for soundcard memory allocation");
0017 MODULE_LICENSE("GPL");
0018 
0019 #define get_memblk(p)   list_entry(p, struct snd_util_memblk, list)
0020 
0021 /*
0022  * create a new memory manager
0023  */
0024 struct snd_util_memhdr *
0025 snd_util_memhdr_new(int memsize)
0026 {
0027     struct snd_util_memhdr *hdr;
0028 
0029     hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
0030     if (hdr == NULL)
0031         return NULL;
0032     hdr->size = memsize;
0033     mutex_init(&hdr->block_mutex);
0034     INIT_LIST_HEAD(&hdr->block);
0035 
0036     return hdr;
0037 }
0038 
0039 /*
0040  * free a memory manager
0041  */
0042 void snd_util_memhdr_free(struct snd_util_memhdr *hdr)
0043 {
0044     struct list_head *p;
0045 
0046     if (!hdr)
0047         return;
0048     /* release all blocks */
0049     while ((p = hdr->block.next) != &hdr->block) {
0050         list_del(p);
0051         kfree(get_memblk(p));
0052     }
0053     kfree(hdr);
0054 }
0055 
0056 /*
0057  * allocate a memory block (without mutex)
0058  */
0059 struct snd_util_memblk *
0060 __snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
0061 {
0062     struct snd_util_memblk *blk;
0063     unsigned int units, prev_offset;
0064     struct list_head *p;
0065 
0066     if (snd_BUG_ON(!hdr || size <= 0))
0067         return NULL;
0068 
0069     /* word alignment */
0070     units = size;
0071     if (units & 1)
0072         units++;
0073     if (units > hdr->size)
0074         return NULL;
0075 
0076     /* look for empty block */
0077     prev_offset = 0;
0078     list_for_each(p, &hdr->block) {
0079         blk = get_memblk(p);
0080         if (blk->offset - prev_offset >= units)
0081             goto __found;
0082         prev_offset = blk->offset + blk->size;
0083     }
0084     if (hdr->size - prev_offset < units)
0085         return NULL;
0086 
0087 __found:
0088     return __snd_util_memblk_new(hdr, units, p->prev);
0089 }
0090 
0091 
0092 /*
0093  * create a new memory block with the given size
0094  * the block is linked next to prev
0095  */
0096 struct snd_util_memblk *
0097 __snd_util_memblk_new(struct snd_util_memhdr *hdr, unsigned int units,
0098               struct list_head *prev)
0099 {
0100     struct snd_util_memblk *blk;
0101 
0102     blk = kmalloc(sizeof(struct snd_util_memblk) + hdr->block_extra_size,
0103               GFP_KERNEL);
0104     if (blk == NULL)
0105         return NULL;
0106 
0107     if (prev == &hdr->block)
0108         blk->offset = 0;
0109     else {
0110         struct snd_util_memblk *p = get_memblk(prev);
0111         blk->offset = p->offset + p->size;
0112     }
0113     blk->size = units;
0114     list_add(&blk->list, prev);
0115     hdr->nblocks++;
0116     hdr->used += units;
0117     return blk;
0118 }
0119 
0120 
0121 /*
0122  * allocate a memory block (with mutex)
0123  */
0124 struct snd_util_memblk *
0125 snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
0126 {
0127     struct snd_util_memblk *blk;
0128     mutex_lock(&hdr->block_mutex);
0129     blk = __snd_util_mem_alloc(hdr, size);
0130     mutex_unlock(&hdr->block_mutex);
0131     return blk;
0132 }
0133 
0134 
0135 /*
0136  * remove the block from linked-list and free resource
0137  * (without mutex)
0138  */
0139 void
0140 __snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
0141 {
0142     list_del(&blk->list);
0143     hdr->nblocks--;
0144     hdr->used -= blk->size;
0145     kfree(blk);
0146 }
0147 
0148 /*
0149  * free a memory block (with mutex)
0150  */
0151 int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
0152 {
0153     if (snd_BUG_ON(!hdr || !blk))
0154         return -EINVAL;
0155 
0156     mutex_lock(&hdr->block_mutex);
0157     __snd_util_mem_free(hdr, blk);
0158     mutex_unlock(&hdr->block_mutex);
0159     return 0;
0160 }
0161 
0162 /*
0163  * return available memory size
0164  */
0165 int snd_util_mem_avail(struct snd_util_memhdr *hdr)
0166 {
0167     unsigned int size;
0168     mutex_lock(&hdr->block_mutex);
0169     size = hdr->size - hdr->used;
0170     mutex_unlock(&hdr->block_mutex);
0171     return size;
0172 }
0173 
0174 
0175 EXPORT_SYMBOL(snd_util_memhdr_new);
0176 EXPORT_SYMBOL(snd_util_memhdr_free);
0177 EXPORT_SYMBOL(snd_util_mem_alloc);
0178 EXPORT_SYMBOL(snd_util_mem_free);
0179 EXPORT_SYMBOL(snd_util_mem_avail);
0180 EXPORT_SYMBOL(__snd_util_mem_alloc);
0181 EXPORT_SYMBOL(__snd_util_mem_free);
0182 EXPORT_SYMBOL(__snd_util_memblk_new);