Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/core/memalloc.c
10814 views
1
/*
2
* Copyright (c) by Jaroslav Kysela <[email protected]>
3
* Takashi Iwai <[email protected]>
4
*
5
* Generic memory allocators
6
*
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
*
22
*/
23
24
#include <linux/module.h>
25
#include <linux/proc_fs.h>
26
#include <linux/init.h>
27
#include <linux/pci.h>
28
#include <linux/slab.h>
29
#include <linux/mm.h>
30
#include <linux/seq_file.h>
31
#include <asm/uaccess.h>
32
#include <linux/dma-mapping.h>
33
#include <linux/moduleparam.h>
34
#include <linux/mutex.h>
35
#include <sound/memalloc.h>
36
37
38
MODULE_AUTHOR("Takashi Iwai <[email protected]>, Jaroslav Kysela <[email protected]>");
39
MODULE_DESCRIPTION("Memory allocator for ALSA system.");
40
MODULE_LICENSE("GPL");
41
42
43
/*
44
*/
45
46
static DEFINE_MUTEX(list_mutex);
47
static LIST_HEAD(mem_list_head);
48
49
/* buffer preservation list */
50
struct snd_mem_list {
51
struct snd_dma_buffer buffer;
52
unsigned int id;
53
struct list_head list;
54
};
55
56
/* id for pre-allocated buffers */
57
#define SNDRV_DMA_DEVICE_UNUSED (unsigned int)-1
58
59
/*
60
*
61
* Generic memory allocators
62
*
63
*/
64
65
static long snd_allocated_pages; /* holding the number of allocated pages */
66
67
static inline void inc_snd_pages(int order)
68
{
69
snd_allocated_pages += 1 << order;
70
}
71
72
static inline void dec_snd_pages(int order)
73
{
74
snd_allocated_pages -= 1 << order;
75
}
76
77
/**
78
* snd_malloc_pages - allocate pages with the given size
79
* @size: the size to allocate in bytes
80
* @gfp_flags: the allocation conditions, GFP_XXX
81
*
82
* Allocates the physically contiguous pages with the given size.
83
*
84
* Returns the pointer of the buffer, or NULL if no enoguh memory.
85
*/
86
void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
87
{
88
int pg;
89
void *res;
90
91
if (WARN_ON(!size))
92
return NULL;
93
if (WARN_ON(!gfp_flags))
94
return NULL;
95
gfp_flags |= __GFP_COMP; /* compound page lets parts be mapped */
96
pg = get_order(size);
97
if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL)
98
inc_snd_pages(pg);
99
return res;
100
}
101
102
/**
103
* snd_free_pages - release the pages
104
* @ptr: the buffer pointer to release
105
* @size: the allocated buffer size
106
*
107
* Releases the buffer allocated via snd_malloc_pages().
108
*/
109
void snd_free_pages(void *ptr, size_t size)
110
{
111
int pg;
112
113
if (ptr == NULL)
114
return;
115
pg = get_order(size);
116
dec_snd_pages(pg);
117
free_pages((unsigned long) ptr, pg);
118
}
119
120
/*
121
*
122
* Bus-specific memory allocators
123
*
124
*/
125
126
#ifdef CONFIG_HAS_DMA
127
/* allocate the coherent DMA pages */
128
static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma)
129
{
130
int pg;
131
void *res;
132
gfp_t gfp_flags;
133
134
if (WARN_ON(!dma))
135
return NULL;
136
pg = get_order(size);
137
gfp_flags = GFP_KERNEL
138
| __GFP_COMP /* compound page lets parts be mapped */
139
| __GFP_NORETRY /* don't trigger OOM-killer */
140
| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
141
res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
142
if (res != NULL)
143
inc_snd_pages(pg);
144
145
return res;
146
}
147
148
/* free the coherent DMA pages */
149
static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
150
dma_addr_t dma)
151
{
152
int pg;
153
154
if (ptr == NULL)
155
return;
156
pg = get_order(size);
157
dec_snd_pages(pg);
158
dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
159
}
160
#endif /* CONFIG_HAS_DMA */
161
162
/*
163
*
164
* ALSA generic memory management
165
*
166
*/
167
168
169
/**
170
* snd_dma_alloc_pages - allocate the buffer area according to the given type
171
* @type: the DMA buffer type
172
* @device: the device pointer
173
* @size: the buffer size to allocate
174
* @dmab: buffer allocation record to store the allocated data
175
*
176
* Calls the memory-allocator function for the corresponding
177
* buffer type.
178
*
179
* Returns zero if the buffer with the given size is allocated successfuly,
180
* other a negative value at error.
181
*/
182
int snd_dma_alloc_pages(int type, struct device *device, size_t size,
183
struct snd_dma_buffer *dmab)
184
{
185
if (WARN_ON(!size))
186
return -ENXIO;
187
if (WARN_ON(!dmab))
188
return -ENXIO;
189
190
dmab->dev.type = type;
191
dmab->dev.dev = device;
192
dmab->bytes = 0;
193
switch (type) {
194
case SNDRV_DMA_TYPE_CONTINUOUS:
195
dmab->area = snd_malloc_pages(size,
196
(__force gfp_t)(unsigned long)device);
197
dmab->addr = 0;
198
break;
199
#ifdef CONFIG_HAS_DMA
200
case SNDRV_DMA_TYPE_DEV:
201
dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
202
break;
203
#endif
204
#ifdef CONFIG_SND_DMA_SGBUF
205
case SNDRV_DMA_TYPE_DEV_SG:
206
snd_malloc_sgbuf_pages(device, size, dmab, NULL);
207
break;
208
#endif
209
default:
210
printk(KERN_ERR "snd-malloc: invalid device type %d\n", type);
211
dmab->area = NULL;
212
dmab->addr = 0;
213
return -ENXIO;
214
}
215
if (! dmab->area)
216
return -ENOMEM;
217
dmab->bytes = size;
218
return 0;
219
}
220
221
/**
222
* snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback
223
* @type: the DMA buffer type
224
* @device: the device pointer
225
* @size: the buffer size to allocate
226
* @dmab: buffer allocation record to store the allocated data
227
*
228
* Calls the memory-allocator function for the corresponding
229
* buffer type. When no space is left, this function reduces the size and
230
* tries to allocate again. The size actually allocated is stored in
231
* res_size argument.
232
*
233
* Returns zero if the buffer with the given size is allocated successfuly,
234
* other a negative value at error.
235
*/
236
int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
237
struct snd_dma_buffer *dmab)
238
{
239
int err;
240
241
while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) {
242
size_t aligned_size;
243
if (err != -ENOMEM)
244
return err;
245
if (size <= PAGE_SIZE)
246
return -ENOMEM;
247
aligned_size = PAGE_SIZE << get_order(size);
248
if (size != aligned_size)
249
size = aligned_size;
250
else
251
size >>= 1;
252
}
253
if (! dmab->area)
254
return -ENOMEM;
255
return 0;
256
}
257
258
259
/**
260
* snd_dma_free_pages - release the allocated buffer
261
* @dmab: the buffer allocation record to release
262
*
263
* Releases the allocated buffer via snd_dma_alloc_pages().
264
*/
265
void snd_dma_free_pages(struct snd_dma_buffer *dmab)
266
{
267
switch (dmab->dev.type) {
268
case SNDRV_DMA_TYPE_CONTINUOUS:
269
snd_free_pages(dmab->area, dmab->bytes);
270
break;
271
#ifdef CONFIG_HAS_DMA
272
case SNDRV_DMA_TYPE_DEV:
273
snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
274
break;
275
#endif
276
#ifdef CONFIG_SND_DMA_SGBUF
277
case SNDRV_DMA_TYPE_DEV_SG:
278
snd_free_sgbuf_pages(dmab);
279
break;
280
#endif
281
default:
282
printk(KERN_ERR "snd-malloc: invalid device type %d\n", dmab->dev.type);
283
}
284
}
285
286
287
/**
288
* snd_dma_get_reserved - get the reserved buffer for the given device
289
* @dmab: the buffer allocation record to store
290
* @id: the buffer id
291
*
292
* Looks for the reserved-buffer list and re-uses if the same buffer
293
* is found in the list. When the buffer is found, it's removed from the free list.
294
*
295
* Returns the size of buffer if the buffer is found, or zero if not found.
296
*/
297
size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
298
{
299
struct snd_mem_list *mem;
300
301
if (WARN_ON(!dmab))
302
return 0;
303
304
mutex_lock(&list_mutex);
305
list_for_each_entry(mem, &mem_list_head, list) {
306
if (mem->id == id &&
307
(mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
308
! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
309
struct device *dev = dmab->dev.dev;
310
list_del(&mem->list);
311
*dmab = mem->buffer;
312
if (dmab->dev.dev == NULL)
313
dmab->dev.dev = dev;
314
kfree(mem);
315
mutex_unlock(&list_mutex);
316
return dmab->bytes;
317
}
318
}
319
mutex_unlock(&list_mutex);
320
return 0;
321
}
322
323
/**
324
* snd_dma_reserve_buf - reserve the buffer
325
* @dmab: the buffer to reserve
326
* @id: the buffer id
327
*
328
* Reserves the given buffer as a reserved buffer.
329
*
330
* Returns zero if successful, or a negative code at error.
331
*/
332
int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id)
333
{
334
struct snd_mem_list *mem;
335
336
if (WARN_ON(!dmab))
337
return -EINVAL;
338
mem = kmalloc(sizeof(*mem), GFP_KERNEL);
339
if (! mem)
340
return -ENOMEM;
341
mutex_lock(&list_mutex);
342
mem->buffer = *dmab;
343
mem->id = id;
344
list_add_tail(&mem->list, &mem_list_head);
345
mutex_unlock(&list_mutex);
346
return 0;
347
}
348
349
/*
350
* purge all reserved buffers
351
*/
352
static void free_all_reserved_pages(void)
353
{
354
struct list_head *p;
355
struct snd_mem_list *mem;
356
357
mutex_lock(&list_mutex);
358
while (! list_empty(&mem_list_head)) {
359
p = mem_list_head.next;
360
mem = list_entry(p, struct snd_mem_list, list);
361
list_del(p);
362
snd_dma_free_pages(&mem->buffer);
363
kfree(mem);
364
}
365
mutex_unlock(&list_mutex);
366
}
367
368
369
#ifdef CONFIG_PROC_FS
370
/*
371
* proc file interface
372
*/
373
#define SND_MEM_PROC_FILE "driver/snd-page-alloc"
374
static struct proc_dir_entry *snd_mem_proc;
375
376
static int snd_mem_proc_read(struct seq_file *seq, void *offset)
377
{
378
long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
379
struct snd_mem_list *mem;
380
int devno;
381
static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" };
382
383
mutex_lock(&list_mutex);
384
seq_printf(seq, "pages : %li bytes (%li pages per %likB)\n",
385
pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
386
devno = 0;
387
list_for_each_entry(mem, &mem_list_head, list) {
388
devno++;
389
seq_printf(seq, "buffer %d : ID %08x : type %s\n",
390
devno, mem->id, types[mem->buffer.dev.type]);
391
seq_printf(seq, " addr = 0x%lx, size = %d bytes\n",
392
(unsigned long)mem->buffer.addr,
393
(int)mem->buffer.bytes);
394
}
395
mutex_unlock(&list_mutex);
396
return 0;
397
}
398
399
static int snd_mem_proc_open(struct inode *inode, struct file *file)
400
{
401
return single_open(file, snd_mem_proc_read, NULL);
402
}
403
404
/* FIXME: for pci only - other bus? */
405
#ifdef CONFIG_PCI
406
#define gettoken(bufp) strsep(bufp, " \t\n")
407
408
static ssize_t snd_mem_proc_write(struct file *file, const char __user * buffer,
409
size_t count, loff_t * ppos)
410
{
411
char buf[128];
412
char *token, *p;
413
414
if (count > sizeof(buf) - 1)
415
return -EINVAL;
416
if (copy_from_user(buf, buffer, count))
417
return -EFAULT;
418
buf[count] = '\0';
419
420
p = buf;
421
token = gettoken(&p);
422
if (! token || *token == '#')
423
return count;
424
if (strcmp(token, "add") == 0) {
425
char *endp;
426
int vendor, device, size, buffers;
427
long mask;
428
int i, alloced;
429
struct pci_dev *pci;
430
431
if ((token = gettoken(&p)) == NULL ||
432
(vendor = simple_strtol(token, NULL, 0)) <= 0 ||
433
(token = gettoken(&p)) == NULL ||
434
(device = simple_strtol(token, NULL, 0)) <= 0 ||
435
(token = gettoken(&p)) == NULL ||
436
(mask = simple_strtol(token, NULL, 0)) < 0 ||
437
(token = gettoken(&p)) == NULL ||
438
(size = memparse(token, &endp)) < 64*1024 ||
439
size > 16*1024*1024 /* too big */ ||
440
(token = gettoken(&p)) == NULL ||
441
(buffers = simple_strtol(token, NULL, 0)) <= 0 ||
442
buffers > 4) {
443
printk(KERN_ERR "snd-page-alloc: invalid proc write format\n");
444
return count;
445
}
446
vendor &= 0xffff;
447
device &= 0xffff;
448
449
alloced = 0;
450
pci = NULL;
451
while ((pci = pci_get_device(vendor, device, pci)) != NULL) {
452
if (mask > 0 && mask < 0xffffffff) {
453
if (pci_set_dma_mask(pci, mask) < 0 ||
454
pci_set_consistent_dma_mask(pci, mask) < 0) {
455
printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device);
456
pci_dev_put(pci);
457
return count;
458
}
459
}
460
for (i = 0; i < buffers; i++) {
461
struct snd_dma_buffer dmab;
462
memset(&dmab, 0, sizeof(dmab));
463
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
464
size, &dmab) < 0) {
465
printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
466
pci_dev_put(pci);
467
return count;
468
}
469
snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
470
}
471
alloced++;
472
}
473
if (! alloced) {
474
for (i = 0; i < buffers; i++) {
475
struct snd_dma_buffer dmab;
476
memset(&dmab, 0, sizeof(dmab));
477
/* FIXME: We can allocate only in ZONE_DMA
478
* without a device pointer!
479
*/
480
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL,
481
size, &dmab) < 0) {
482
printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
483
break;
484
}
485
snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device));
486
}
487
}
488
} else if (strcmp(token, "erase") == 0)
489
/* FIXME: need for releasing each buffer chunk? */
490
free_all_reserved_pages();
491
else
492
printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n");
493
return count;
494
}
495
#endif /* CONFIG_PCI */
496
497
static const struct file_operations snd_mem_proc_fops = {
498
.owner = THIS_MODULE,
499
.open = snd_mem_proc_open,
500
.read = seq_read,
501
#ifdef CONFIG_PCI
502
.write = snd_mem_proc_write,
503
#endif
504
.llseek = seq_lseek,
505
.release = single_release,
506
};
507
508
#endif /* CONFIG_PROC_FS */
509
510
/*
511
* module entry
512
*/
513
514
static int __init snd_mem_init(void)
515
{
516
#ifdef CONFIG_PROC_FS
517
snd_mem_proc = proc_create(SND_MEM_PROC_FILE, 0644, NULL,
518
&snd_mem_proc_fops);
519
#endif
520
return 0;
521
}
522
523
static void __exit snd_mem_exit(void)
524
{
525
remove_proc_entry(SND_MEM_PROC_FILE, NULL);
526
free_all_reserved_pages();
527
if (snd_allocated_pages > 0)
528
printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages);
529
}
530
531
532
module_init(snd_mem_init)
533
module_exit(snd_mem_exit)
534
535
536
/*
537
* exports
538
*/
539
EXPORT_SYMBOL(snd_dma_alloc_pages);
540
EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
541
EXPORT_SYMBOL(snd_dma_free_pages);
542
543
EXPORT_SYMBOL(snd_dma_get_reserved_buf);
544
EXPORT_SYMBOL(snd_dma_reserve_buf);
545
546
EXPORT_SYMBOL(snd_malloc_pages);
547
EXPORT_SYMBOL(snd_free_pages);
548
549