Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/synth/util_mem.c
29265 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (C) 2000 Takashi Iwai <[email protected]>
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
15
MODULE_AUTHOR("Takashi Iwai");
16
MODULE_DESCRIPTION("Generic memory management routines for soundcard memory allocation");
17
MODULE_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
*/
24
struct snd_util_memhdr *
25
snd_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
*/
42
void 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
*/
59
struct 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
*/
96
struct 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
*/
124
struct snd_util_memblk *
125
snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
126
{
127
guard(mutex)(&hdr->block_mutex);
128
return __snd_util_mem_alloc(hdr, size);
129
}
130
131
132
/*
133
* remove the block from linked-list and free resource
134
* (without mutex)
135
*/
136
void
137
__snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
138
{
139
list_del(&blk->list);
140
hdr->nblocks--;
141
hdr->used -= blk->size;
142
kfree(blk);
143
}
144
145
/*
146
* free a memory block (with mutex)
147
*/
148
int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk)
149
{
150
if (snd_BUG_ON(!hdr || !blk))
151
return -EINVAL;
152
153
guard(mutex)(&hdr->block_mutex);
154
__snd_util_mem_free(hdr, blk);
155
return 0;
156
}
157
158
/*
159
* return available memory size
160
*/
161
int snd_util_mem_avail(struct snd_util_memhdr *hdr)
162
{
163
guard(mutex)(&hdr->block_mutex);
164
return hdr->size - hdr->used;
165
}
166
167
168
EXPORT_SYMBOL(snd_util_memhdr_new);
169
EXPORT_SYMBOL(snd_util_memhdr_free);
170
EXPORT_SYMBOL(snd_util_mem_alloc);
171
EXPORT_SYMBOL(snd_util_mem_free);
172
EXPORT_SYMBOL(snd_util_mem_avail);
173
EXPORT_SYMBOL(__snd_util_mem_alloc);
174
EXPORT_SYMBOL(__snd_util_mem_free);
175
EXPORT_SYMBOL(__snd_util_memblk_new);
176
177