1
2
3
4
5
6
7#include <linux/io.h>
8#include <linux/time.h>
9#include <linux/init.h>
10#include <linux/slab.h>
11#include <linux/moduleparam.h>
12#include <linux/vmalloc.h>
13#include <linux/export.h>
14#include <sound/core.h>
15#include <sound/pcm.h>
16#include <sound/info.h>
17#include <sound/initval.h>
18#include "pcm_local.h"
19
20static int preallocate_dma = 1;
21module_param(preallocate_dma, int, 0444);
22MODULE_PARM_DESC(preallocate_dma, "Preallocate DMA memory when the PCM devices are initialized.");
23
24static int maximum_substreams = 4;
25module_param(maximum_substreams, int, 0444);
26MODULE_PARM_DESC(maximum_substreams, "Maximum substreams with preallocated DMA memory.");
27
28static const size_t snd_minimum_buffer = 16384;
29
30static unsigned long max_alloc_per_card = 32UL * 1024UL * 1024UL;
31module_param(max_alloc_per_card, ulong, 0644);
32MODULE_PARM_DESC(max_alloc_per_card, "Max total allocation bytes per card.");
33
34static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
35 size_t size, struct snd_dma_buffer *dmab)
36{
37 int err;
38
39 if (max_alloc_per_card &&
40 card->total_pcm_alloc_bytes + size > max_alloc_per_card)
41 return -ENOMEM;
42
43 err = snd_dma_alloc_pages(type, dev, size, dmab);
44 if (!err) {
45 mutex_lock(&card->memory_mutex);
46 card->total_pcm_alloc_bytes += dmab->bytes;
47 mutex_unlock(&card->memory_mutex);
48 }
49 return err;
50}
51
52static void do_free_pages(struct snd_card *card, struct snd_dma_buffer *dmab)
53{
54 if (!dmab->area)
55 return;
56 mutex_lock(&card->memory_mutex);
57 WARN_ON(card->total_pcm_alloc_bytes < dmab->bytes);
58 card->total_pcm_alloc_bytes -= dmab->bytes;
59 mutex_unlock(&card->memory_mutex);
60 snd_dma_free_pages(dmab);
61 dmab->area = NULL;
62}
63
64
65
66
67
68
69
70static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t size)
71{
72 struct snd_dma_buffer *dmab = &substream->dma_buffer;
73 struct snd_card *card = substream->pcm->card;
74 size_t orig_size = size;
75 int err;
76
77 do {
78 err = do_alloc_pages(card, dmab->dev.type, dmab->dev.dev,
79 size, dmab);
80 if (err != -ENOMEM)
81 return err;
82 size >>= 1;
83 } while (size >= snd_minimum_buffer);
84 dmab->bytes = 0;
85 pr_warn("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n",
86 substream->pcm->card->number, substream->pcm->device,
87 substream->stream ? 'c' : 'p', substream->number,
88 substream->pcm->name, orig_size);
89 return 0;
90}
91
92
93
94
95
96
97
98void snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
99{
100 do_free_pages(substream->pcm->card, &substream->dma_buffer);
101}
102
103
104
105
106
107
108
109void snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
110{
111 struct snd_pcm_substream *substream;
112 int stream;
113
114 for (stream = 0; stream < 2; stream++)
115 for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
116 snd_pcm_lib_preallocate_free(substream);
117}
118EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
119
120#ifdef CONFIG_SND_VERBOSE_PROCFS
121
122
123
124
125
126static void snd_pcm_lib_preallocate_proc_read(struct snd_info_entry *entry,
127 struct snd_info_buffer *buffer)
128{
129 struct snd_pcm_substream *substream = entry->private_data;
130 snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_buffer.bytes / 1024);
131}
132
133
134
135
136
137
138static void snd_pcm_lib_preallocate_max_proc_read(struct snd_info_entry *entry,
139 struct snd_info_buffer *buffer)
140{
141 struct snd_pcm_substream *substream = entry->private_data;
142 snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_max / 1024);
143}
144
145
146
147
148
149
150static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
151 struct snd_info_buffer *buffer)
152{
153 struct snd_pcm_substream *substream = entry->private_data;
154 struct snd_card *card = substream->pcm->card;
155 char line[64], str[64];
156 size_t size;
157 struct snd_dma_buffer new_dmab;
158
159 if (substream->runtime) {
160 buffer->error = -EBUSY;
161 return;
162 }
163 if (!snd_info_get_line(buffer, line, sizeof(line))) {
164 snd_info_get_str(str, line, sizeof(str));
165 size = simple_strtoul(str, NULL, 10) * 1024;
166 if ((size != 0 && size < 8192) || size > substream->dma_max) {
167 buffer->error = -EINVAL;
168 return;
169 }
170 if (substream->dma_buffer.bytes == size)
171 return;
172 memset(&new_dmab, 0, sizeof(new_dmab));
173 new_dmab.dev = substream->dma_buffer.dev;
174 if (size > 0) {
175 if (do_alloc_pages(card,
176 substream->dma_buffer.dev.type,
177 substream->dma_buffer.dev.dev,
178 size, &new_dmab) < 0) {
179 buffer->error = -ENOMEM;
180 return;
181 }
182 substream->buffer_bytes_max = size;
183 } else {
184 substream->buffer_bytes_max = UINT_MAX;
185 }
186 if (substream->dma_buffer.area)
187 do_free_pages(card, &substream->dma_buffer);
188 substream->dma_buffer = new_dmab;
189 } else {
190 buffer->error = -EINVAL;
191 }
192}
193
194static inline void preallocate_info_init(struct snd_pcm_substream *substream)
195{
196 struct snd_info_entry *entry;
197
198 entry = snd_info_create_card_entry(substream->pcm->card, "prealloc",
199 substream->proc_root);
200 if (entry) {
201 snd_info_set_text_ops(entry, substream,
202 snd_pcm_lib_preallocate_proc_read);
203 entry->c.text.write = snd_pcm_lib_preallocate_proc_write;
204 entry->mode |= 0200;
205 }
206 entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max",
207 substream->proc_root);
208 if (entry)
209 snd_info_set_text_ops(entry, substream,
210 snd_pcm_lib_preallocate_max_proc_read);
211}
212
213#else
214#define preallocate_info_init(s)
215#endif
216
217
218
219
220static void preallocate_pages(struct snd_pcm_substream *substream,
221 int type, struct device *data,
222 size_t size, size_t max, bool managed)
223{
224 if (snd_BUG_ON(substream->dma_buffer.dev.type))
225 return;
226
227 substream->dma_buffer.dev.type = type;
228 substream->dma_buffer.dev.dev = data;
229
230 if (size > 0 && preallocate_dma && substream->number < maximum_substreams)
231 preallocate_pcm_pages(substream, size);
232
233 if (substream->dma_buffer.bytes > 0)
234 substream->buffer_bytes_max = substream->dma_buffer.bytes;
235 substream->dma_max = max;
236 if (max > 0)
237 preallocate_info_init(substream);
238 if (managed)
239 substream->managed_buffer_alloc = 1;
240}
241
242static void preallocate_pages_for_all(struct snd_pcm *pcm, int type,
243 void *data, size_t size, size_t max,
244 bool managed)
245{
246 struct snd_pcm_substream *substream;
247 int stream;
248
249 for (stream = 0; stream < 2; stream++)
250 for (substream = pcm->streams[stream].substream; substream;
251 substream = substream->next)
252 preallocate_pages(substream, type, data, size, max,
253 managed);
254}
255
256
257
258
259
260
261
262
263
264
265
266void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
267 int type, struct device *data,
268 size_t size, size_t max)
269{
270 preallocate_pages(substream, type, data, size, max, false);
271}
272EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
273
274
275
276
277
278
279
280
281
282
283
284
285void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
286 int type, void *data,
287 size_t size, size_t max)
288{
289 preallocate_pages_for_all(pcm, type, data, size, max, false);
290}
291EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311void snd_pcm_set_managed_buffer(struct snd_pcm_substream *substream, int type,
312 struct device *data, size_t size, size_t max)
313{
314 preallocate_pages(substream, type, data, size, max, true);
315}
316EXPORT_SYMBOL(snd_pcm_set_managed_buffer);
317
318
319
320
321
322
323
324
325
326
327
328
329
330void snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type,
331 struct device *data,
332 size_t size, size_t max)
333{
334 preallocate_pages_for_all(pcm, type, data, size, max, true);
335}
336EXPORT_SYMBOL(snd_pcm_set_managed_buffer_all);
337
338#ifdef CONFIG_SND_DMA_SGBUF
339
340
341
342
343
344
345
346
347
348struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset)
349{
350 struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
351
352 unsigned int idx = offset >> PAGE_SHIFT;
353 if (idx >= (unsigned int)sgbuf->pages)
354 return NULL;
355 return sgbuf->page_table[idx];
356}
357#endif
358
359
360
361
362
363
364
365
366
367
368
369
370int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
371{
372 struct snd_card *card;
373 struct snd_pcm_runtime *runtime;
374 struct snd_dma_buffer *dmab = NULL;
375
376 if (PCM_RUNTIME_CHECK(substream))
377 return -EINVAL;
378 if (snd_BUG_ON(substream->dma_buffer.dev.type ==
379 SNDRV_DMA_TYPE_UNKNOWN))
380 return -EINVAL;
381 runtime = substream->runtime;
382 card = substream->pcm->card;
383
384 if (runtime->dma_buffer_p) {
385
386
387
388 if (runtime->dma_buffer_p->bytes >= size) {
389 runtime->dma_bytes = size;
390 return 0;
391 }
392 snd_pcm_lib_free_pages(substream);
393 }
394 if (substream->dma_buffer.area != NULL &&
395 substream->dma_buffer.bytes >= size) {
396 dmab = &substream->dma_buffer;
397 } else {
398 dmab = kzalloc(sizeof(*dmab), GFP_KERNEL);
399 if (! dmab)
400 return -ENOMEM;
401 dmab->dev = substream->dma_buffer.dev;
402 if (do_alloc_pages(card,
403 substream->dma_buffer.dev.type,
404 substream->dma_buffer.dev.dev,
405 size, dmab) < 0) {
406 kfree(dmab);
407 return -ENOMEM;
408 }
409 }
410 snd_pcm_set_runtime_buffer(substream, dmab);
411 runtime->dma_bytes = size;
412 return 1;
413}
414EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
415
416
417
418
419
420
421
422
423
424int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
425{
426 struct snd_card *card = substream->pcm->card;
427 struct snd_pcm_runtime *runtime;
428
429 if (PCM_RUNTIME_CHECK(substream))
430 return -EINVAL;
431 runtime = substream->runtime;
432 if (runtime->dma_area == NULL)
433 return 0;
434 if (runtime->dma_buffer_p != &substream->dma_buffer) {
435
436 do_free_pages(card, runtime->dma_buffer_p);
437 kfree(runtime->dma_buffer_p);
438 }
439 snd_pcm_set_runtime_buffer(substream, NULL);
440 return 0;
441}
442EXPORT_SYMBOL(snd_pcm_lib_free_pages);
443
444int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
445 size_t size, gfp_t gfp_flags)
446{
447 struct snd_pcm_runtime *runtime;
448
449 if (PCM_RUNTIME_CHECK(substream))
450 return -EINVAL;
451 runtime = substream->runtime;
452 if (runtime->dma_area) {
453 if (runtime->dma_bytes >= size)
454 return 0;
455 vfree(runtime->dma_area);
456 }
457 runtime->dma_area = __vmalloc(size, gfp_flags);
458 if (!runtime->dma_area)
459 return -ENOMEM;
460 runtime->dma_bytes = size;
461 return 1;
462}
463EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer);
464
465
466
467
468
469
470
471
472int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream)
473{
474 struct snd_pcm_runtime *runtime;
475
476 if (PCM_RUNTIME_CHECK(substream))
477 return -EINVAL;
478 runtime = substream->runtime;
479 vfree(runtime->dma_area);
480 runtime->dma_area = NULL;
481 return 0;
482}
483EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer);
484
485
486
487
488
489
490
491
492
493
494
495struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
496 unsigned long offset)
497{
498 return vmalloc_to_page(substream->runtime->dma_area + offset);
499}
500EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page);
501