linux/sound/synth/util_mem.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>
   4 *
   5 *  Generic memory management routines for soundcard memory allocation
   6 */
   7
   8#include <linux/mutex.h>
   9#include <linux/init.h>
  10#include <linux/slab.h>
  11#include <linux/module.h>
  12#include <sound/core.h>
  13#include <sound/util_mem.h>
  14
  15MODULE_AUTHOR("Takashi Iwai");
  16MODULE_DESCRIPTION("Generic memory management routines for soundcard memory allocation");
  17MODULE_LICENSE("GPL");
  18
  19#define get_memblk(p)   list_entry(p, struct snd_util_memblk, list)
  20
  21/*
  22 * create a new memory manager
  23 */
  24struct snd_util_memhdr *
  25snd_util_memhdr_new(int memsize)
  26{
  27        struct snd_util_memhdr *hdr;
  28
  29        hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
  30        if (hdr == NULL)
  31                return NULL;
  32        hdr->size = memsize;
  33        mutex_init(&hdr->block_mutex);
  34        INIT_LIST_HEAD(&hdr->block);
  35
  36        return hdr;
  37}
  38
  39/*
  40 * free a memory manager
  41 */
  42void snd_util_memhdr_free(struct snd_util_memhdr *hdr)
  43{
  44        struct list_head *p;
  45
  46        if (!hdr)
  47                return;
  48        /* release all blocks */
  49        while ((p = hdr->block.next) != &hdr->block) {
  50                list_del(p);
  51                kfree(get_memblk(p));
  52        }
  53        kfree(hdr);
  54}
  55
  56/*
  57 * allocate a memory block (without mutex)
  58 */
  59struct snd_util_memblk *
  60__snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
  61{
  62        struct snd_util_memblk *blk;
  63        unsigned int units, prev_offset;
  64        struct list_head *p;
  65
  66        if (snd_BUG_ON(!hdr || size <= 0))
  67                return NULL;
  68
  69        /* word alignment */
  70        units = size;
  71        if (units & 1)
  72                units++;
  73        if (units > hdr->size)
  74                return NULL;
  75
  76        /* look for empty block */
  77        prev_offset = 0;
  78        list_for_each(p, &hdr->block) {
  79                blk = get_memblk(p);
  80                if (blk->offset - prev_offset >= units)
  81                        goto __found;
  82                prev_offset = blk->offset + blk->size;
  83        }
  84        if (hdr->size - prev_offset < units)
  85                return NULL;
  86
  87__found:
  88        return __snd_util_memblk_new(hdr, units, p->prev);
  89}
  90
  91
  92/*
  93 * create a new memory block with the given size
  94 * the block is linked next to prev
  95 */
  96struct snd_util_memblk *
  97__snd_util_memblk_new(struct snd_util_memhdr *hdr, unsigned int units,
  98                      struct list_head *prev)
  99{
 100        struct snd_util_memblk *blk;
 101
 102        blk = kmalloc(sizeof(struct snd_util_memblk) + hdr->block_extra_size,
 103                      GFP_KERNEL);
 104        if (blk == NULL)
 105                return NULL;
 106
 107        if (prev == &hdr->block)
 108                blk->offset = 0;
 109        else {
 110                struct snd_util_memblk *p = get_memblk(prev);
 111                blk->offset = p->offset + p->size;
 112        }
 113        blk->size = units;
 114        list_add(&blk->list, prev);
 115        hdr->nblocks++;
 116        hdr->used += units;
 117        return blk;
 118}
 119
 120
 121/*
 122 * allocate a memory block (with mutex)
 123 */
 124struct snd_util_memblk *
 125snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
 126{
 127        struct snd_util_memblk *blk;
 128        mutex_lock(&hdr->block_mutex);
 129        blk = __snd_util_mem_alloc(hdr, size);
 130        mutex_unlock(&hdr->block_mutex);
 131        return blk;
 132}
 133
 134
 135/*
 136 * remove the block from linked-list and free resource
 137 * (without mutex)
 138 */
 139void
 140__snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
 141{
 142        list_del(&blk->list);
 143        hdr->nblocks--;
 144        hdr->used -= blk->size;
 145        kfree(blk);
 146}
 147
 148/*
 149 * free a memory block (with mutex)
 150 */
 151int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
 152{
 153        if (snd_BUG_ON(!hdr || !blk))
 154                return -EINVAL;
 155
 156        mutex_lock(&hdr->block_mutex);
 157        __snd_util_mem_free(hdr, blk);
 158        mutex_unlock(&hdr->block_mutex);
 159        return 0;
 160}
 161
 162/*
 163 * return available memory size
 164 */
 165int snd_util_mem_avail(struct snd_util_memhdr *hdr)
 166{
 167        unsigned int size;
 168        mutex_lock(&hdr->block_mutex);
 169        size = hdr->size - hdr->used;
 170        mutex_unlock(&hdr->block_mutex);
 171        return size;
 172}
 173
 174
 175EXPORT_SYMBOL(snd_util_memhdr_new);
 176EXPORT_SYMBOL(snd_util_memhdr_free);
 177EXPORT_SYMBOL(snd_util_mem_alloc);
 178EXPORT_SYMBOL(snd_util_mem_free);
 179EXPORT_SYMBOL(snd_util_mem_avail);
 180EXPORT_SYMBOL(__snd_util_mem_alloc);
 181EXPORT_SYMBOL(__snd_util_mem_free);
 182EXPORT_SYMBOL(__snd_util_memblk_new);
 183