hc
2024-10-12 a5969cabbb4660eab42b6ef0412cbbd1200cf14d
kernel/sound/core/pcm_memory.c
....@@ -1,22 +1,7 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Digital Audio (PCM) abstract layer
34 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4
- *
5
- *
6
- * This program is free software; you can redistribute it and/or modify
7
- * it under the terms of the GNU General Public License as published by
8
- * the Free Software Foundation; either version 2 of the License, or
9
- * (at your option) any later version.
10
- *
11
- * This program is distributed in the hope that it will be useful,
12
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- * GNU General Public License for more details.
15
- *
16
- * You should have received a copy of the GNU General Public License
17
- * along with this program; if not, write to the Free Software
18
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
- *
205 */
216
227 #include <linux/io.h>
....@@ -30,6 +15,7 @@
3015 #include <sound/pcm.h>
3116 #include <sound/info.h>
3217 #include <sound/initval.h>
18
+#include "pcm_local.h"
3319
3420 static int preallocate_dma = 1;
3521 module_param(preallocate_dma, int, 0444);
....@@ -41,6 +27,67 @@
4127
4228 static const size_t snd_minimum_buffer = 16384;
4329
30
+static unsigned long max_alloc_per_card = 32UL * 1024UL * 1024UL;
31
+module_param(max_alloc_per_card, ulong, 0644);
32
+MODULE_PARM_DESC(max_alloc_per_card, "Max total allocation bytes per card.");
33
+
34
+static void __update_allocated_size(struct snd_card *card, ssize_t bytes)
35
+{
36
+ card->total_pcm_alloc_bytes += bytes;
37
+}
38
+
39
+static void update_allocated_size(struct snd_card *card, ssize_t bytes)
40
+{
41
+ mutex_lock(&card->memory_mutex);
42
+ __update_allocated_size(card, bytes);
43
+ mutex_unlock(&card->memory_mutex);
44
+}
45
+
46
+static void decrease_allocated_size(struct snd_card *card, size_t bytes)
47
+{
48
+ mutex_lock(&card->memory_mutex);
49
+ WARN_ON(card->total_pcm_alloc_bytes < bytes);
50
+ __update_allocated_size(card, -(ssize_t)bytes);
51
+ mutex_unlock(&card->memory_mutex);
52
+}
53
+
54
+static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
55
+ size_t size, struct snd_dma_buffer *dmab)
56
+{
57
+ int err;
58
+
59
+ /* check and reserve the requested size */
60
+ mutex_lock(&card->memory_mutex);
61
+ if (max_alloc_per_card &&
62
+ card->total_pcm_alloc_bytes + size > max_alloc_per_card) {
63
+ mutex_unlock(&card->memory_mutex);
64
+ return -ENOMEM;
65
+ }
66
+ __update_allocated_size(card, size);
67
+ mutex_unlock(&card->memory_mutex);
68
+
69
+ err = snd_dma_alloc_pages(type, dev, size, dmab);
70
+ if (!err) {
71
+ /* the actual allocation size might be bigger than requested,
72
+ * and we need to correct the account
73
+ */
74
+ if (dmab->bytes != size)
75
+ update_allocated_size(card, dmab->bytes - size);
76
+ } else {
77
+ /* take back on allocation failure */
78
+ decrease_allocated_size(card, size);
79
+ }
80
+ return err;
81
+}
82
+
83
+static void do_free_pages(struct snd_card *card, struct snd_dma_buffer *dmab)
84
+{
85
+ if (!dmab->area)
86
+ return;
87
+ decrease_allocated_size(card, dmab->bytes);
88
+ snd_dma_free_pages(dmab);
89
+ dmab->area = NULL;
90
+}
4491
4592 /*
4693 * try to allocate as the large pages as possible.
....@@ -51,16 +98,15 @@
5198 static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t size)
5299 {
53100 struct snd_dma_buffer *dmab = &substream->dma_buffer;
101
+ struct snd_card *card = substream->pcm->card;
54102 size_t orig_size = size;
55103 int err;
56104
57105 do {
58
- if ((err = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev,
59
- size, dmab)) < 0) {
60
- if (err != -ENOMEM)
61
- return err; /* fatal error */
62
- } else
63
- return 0;
106
+ err = do_alloc_pages(card, dmab->dev.type, dmab->dev.dev,
107
+ size, dmab);
108
+ if (err != -ENOMEM)
109
+ return err;
64110 size >>= 1;
65111 } while (size >= snd_minimum_buffer);
66112 dmab->bytes = 0; /* tell error */
....@@ -76,10 +122,7 @@
76122 */
77123 static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream)
78124 {
79
- if (substream->dma_buffer.area == NULL)
80
- return;
81
- snd_dma_free_pages(&substream->dma_buffer);
82
- substream->dma_buffer.area = NULL;
125
+ do_free_pages(substream->pcm->card, &substream->dma_buffer);
83126 }
84127
85128 /**
....@@ -87,19 +130,10 @@
87130 * @substream: the pcm substream instance
88131 *
89132 * Releases the pre-allocated buffer of the given substream.
90
- *
91
- * Return: Zero if successful, or a negative error code on failure.
92133 */
93
-int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
134
+void snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
94135 {
95136 snd_pcm_lib_preallocate_dma_free(substream);
96
-#ifdef CONFIG_SND_VERBOSE_PROCFS
97
- snd_info_free_entry(substream->proc_prealloc_max_entry);
98
- substream->proc_prealloc_max_entry = NULL;
99
- snd_info_free_entry(substream->proc_prealloc_entry);
100
- substream->proc_prealloc_entry = NULL;
101
-#endif
102
- return 0;
103137 }
104138
105139 /**
....@@ -107,10 +141,8 @@
107141 * @pcm: the pcm instance
108142 *
109143 * Releases all the pre-allocated buffers on the given pcm.
110
- *
111
- * Return: Zero if successful, or a negative error code on failure.
112144 */
113
-int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
145
+void snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
114146 {
115147 struct snd_pcm_substream *substream;
116148 int stream;
....@@ -118,7 +150,6 @@
118150 for (stream = 0; stream < 2; stream++)
119151 for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
120152 snd_pcm_lib_preallocate_free(substream);
121
- return 0;
122153 }
123154 EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
124155
....@@ -156,68 +187,66 @@
156187 struct snd_info_buffer *buffer)
157188 {
158189 struct snd_pcm_substream *substream = entry->private_data;
190
+ struct snd_card *card = substream->pcm->card;
159191 char line[64], str[64];
160192 size_t size;
161193 struct snd_dma_buffer new_dmab;
162194
195
+ mutex_lock(&substream->pcm->open_mutex);
163196 if (substream->runtime) {
164197 buffer->error = -EBUSY;
165
- return;
198
+ goto unlock;
166199 }
167200 if (!snd_info_get_line(buffer, line, sizeof(line))) {
168201 snd_info_get_str(str, line, sizeof(str));
169202 size = simple_strtoul(str, NULL, 10) * 1024;
170203 if ((size != 0 && size < 8192) || size > substream->dma_max) {
171204 buffer->error = -EINVAL;
172
- return;
205
+ goto unlock;
173206 }
174207 if (substream->dma_buffer.bytes == size)
175
- return;
208
+ goto unlock;
176209 memset(&new_dmab, 0, sizeof(new_dmab));
177210 new_dmab.dev = substream->dma_buffer.dev;
178211 if (size > 0) {
179
- if (snd_dma_alloc_pages(substream->dma_buffer.dev.type,
180
- substream->dma_buffer.dev.dev,
181
- size, &new_dmab) < 0) {
212
+ if (do_alloc_pages(card,
213
+ substream->dma_buffer.dev.type,
214
+ substream->dma_buffer.dev.dev,
215
+ size, &new_dmab) < 0) {
182216 buffer->error = -ENOMEM;
183
- return;
217
+ goto unlock;
184218 }
185219 substream->buffer_bytes_max = size;
186220 } else {
187221 substream->buffer_bytes_max = UINT_MAX;
188222 }
189223 if (substream->dma_buffer.area)
190
- snd_dma_free_pages(&substream->dma_buffer);
224
+ do_free_pages(card, &substream->dma_buffer);
191225 substream->dma_buffer = new_dmab;
192226 } else {
193227 buffer->error = -EINVAL;
194228 }
229
+ unlock:
230
+ mutex_unlock(&substream->pcm->open_mutex);
195231 }
196232
197233 static inline void preallocate_info_init(struct snd_pcm_substream *substream)
198234 {
199235 struct snd_info_entry *entry;
200236
201
- if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) {
202
- entry->c.text.read = snd_pcm_lib_preallocate_proc_read;
237
+ entry = snd_info_create_card_entry(substream->pcm->card, "prealloc",
238
+ substream->proc_root);
239
+ if (entry) {
240
+ snd_info_set_text_ops(entry, substream,
241
+ snd_pcm_lib_preallocate_proc_read);
203242 entry->c.text.write = snd_pcm_lib_preallocate_proc_write;
204243 entry->mode |= 0200;
205
- entry->private_data = substream;
206
- if (snd_info_register(entry) < 0) {
207
- snd_info_free_entry(entry);
208
- entry = NULL;
209
- }
210244 }
211
- substream->proc_prealloc_entry = entry;
212
- if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) {
213
- entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read;
214
- entry->private_data = substream;
215
- if (snd_info_register(entry) < 0) {
216
- snd_info_free_entry(entry);
217
- entry = NULL;
218
- }
219
- }
220
- substream->proc_prealloc_max_entry = entry;
245
+ entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max",
246
+ substream->proc_root);
247
+ if (entry)
248
+ snd_info_set_text_ops(entry, substream,
249
+ snd_pcm_lib_preallocate_max_proc_read);
221250 }
222251
223252 #else /* !CONFIG_SND_VERBOSE_PROCFS */
....@@ -227,9 +256,15 @@
227256 /*
228257 * pre-allocate the buffer and create a proc file for the substream
229258 */
230
-static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream,
231
- size_t size, size_t max)
259
+static void preallocate_pages(struct snd_pcm_substream *substream,
260
+ int type, struct device *data,
261
+ size_t size, size_t max, bool managed)
232262 {
263
+ if (snd_BUG_ON(substream->dma_buffer.dev.type))
264
+ return;
265
+
266
+ substream->dma_buffer.dev.type = type;
267
+ substream->dma_buffer.dev.dev = data;
233268
234269 if (size > 0 && preallocate_dma && substream->number < maximum_substreams)
235270 preallocate_pcm_pages(substream, size);
....@@ -237,10 +272,25 @@
237272 if (substream->dma_buffer.bytes > 0)
238273 substream->buffer_bytes_max = substream->dma_buffer.bytes;
239274 substream->dma_max = max;
240
- preallocate_info_init(substream);
241
- return 0;
275
+ if (max > 0)
276
+ preallocate_info_init(substream);
277
+ if (managed)
278
+ substream->managed_buffer_alloc = 1;
242279 }
243280
281
+static void preallocate_pages_for_all(struct snd_pcm *pcm, int type,
282
+ void *data, size_t size, size_t max,
283
+ bool managed)
284
+{
285
+ struct snd_pcm_substream *substream;
286
+ int stream;
287
+
288
+ for (stream = 0; stream < 2; stream++)
289
+ for (substream = pcm->streams[stream].substream; substream;
290
+ substream = substream->next)
291
+ preallocate_pages(substream, type, data, size, max,
292
+ managed);
293
+}
244294
245295 /**
246296 * snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type
....@@ -251,16 +301,12 @@
251301 * @max: the max. allowed pre-allocation size
252302 *
253303 * Do pre-allocation for the given DMA buffer type.
254
- *
255
- * Return: Zero if successful, or a negative error code on failure.
256304 */
257
-int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
305
+void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
258306 int type, struct device *data,
259307 size_t size, size_t max)
260308 {
261
- substream->dma_buffer.dev.type = type;
262
- substream->dma_buffer.dev.dev = data;
263
- return snd_pcm_lib_preallocate_pages1(substream, size, max);
309
+ preallocate_pages(substream, type, data, size, max, false);
264310 }
265311 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
266312
....@@ -274,26 +320,62 @@
274320 *
275321 * Do pre-allocation to all substreams of the given pcm for the
276322 * specified DMA type.
277
- *
278
- * Return: Zero if successful, or a negative error code on failure.
279323 */
280
-int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
324
+void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
281325 int type, void *data,
282326 size_t size, size_t max)
283327 {
284
- struct snd_pcm_substream *substream;
285
- int stream, err;
286
-
287
- for (stream = 0; stream < 2; stream++)
288
- for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
289
- if ((err = snd_pcm_lib_preallocate_pages(substream, type, data, size, max)) < 0)
290
- return err;
291
- return 0;
328
+ preallocate_pages_for_all(pcm, type, data, size, max, false);
292329 }
293330 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
294331
295
-#ifdef CONFIG_SND_DMA_SGBUF
296332 /**
333
+ * snd_pcm_set_managed_buffer - set up buffer management for a substream
334
+ * @substream: the pcm substream instance
335
+ * @type: DMA type (SNDRV_DMA_TYPE_*)
336
+ * @data: DMA type dependent data
337
+ * @size: the requested pre-allocation size in bytes
338
+ * @max: the max. allowed pre-allocation size
339
+ *
340
+ * Do pre-allocation for the given DMA buffer type, and set the managed
341
+ * buffer allocation mode to the given substream.
342
+ * In this mode, PCM core will allocate a buffer automatically before PCM
343
+ * hw_params ops call, and release the buffer after PCM hw_free ops call
344
+ * as well, so that the driver doesn't need to invoke the allocation and
345
+ * the release explicitly in its callback.
346
+ * When a buffer is actually allocated before the PCM hw_params call, it
347
+ * turns on the runtime buffer_changed flag for drivers changing their h/w
348
+ * parameters accordingly.
349
+ */
350
+void snd_pcm_set_managed_buffer(struct snd_pcm_substream *substream, int type,
351
+ struct device *data, size_t size, size_t max)
352
+{
353
+ preallocate_pages(substream, type, data, size, max, true);
354
+}
355
+EXPORT_SYMBOL(snd_pcm_set_managed_buffer);
356
+
357
+/**
358
+ * snd_pcm_set_managed_buffer_all - set up buffer management for all substreams
359
+ * for all substreams
360
+ * @pcm: the pcm instance
361
+ * @type: DMA type (SNDRV_DMA_TYPE_*)
362
+ * @data: DMA type dependent data
363
+ * @size: the requested pre-allocation size in bytes
364
+ * @max: the max. allowed pre-allocation size
365
+ *
366
+ * Do pre-allocation to all substreams of the given pcm for the specified DMA
367
+ * type and size, and set the managed_buffer_alloc flag to each substream.
368
+ */
369
+void snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type,
370
+ struct device *data,
371
+ size_t size, size_t max)
372
+{
373
+ preallocate_pages_for_all(pcm, type, data, size, max, true);
374
+}
375
+EXPORT_SYMBOL(snd_pcm_set_managed_buffer_all);
376
+
377
+#ifdef CONFIG_SND_DMA_SGBUF
378
+/*
297379 * snd_pcm_sgbuf_ops_page - get the page struct at the given offset
298380 * @substream: the pcm substream instance
299381 * @offset: the buffer offset
....@@ -311,7 +393,6 @@
311393 return NULL;
312394 return sgbuf->page_table[idx];
313395 }
314
-EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
315396 #endif /* CONFIG_SND_DMA_SGBUF */
316397
317398 /**
....@@ -327,6 +408,7 @@
327408 */
328409 int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
329410 {
411
+ struct snd_card *card;
330412 struct snd_pcm_runtime *runtime;
331413 struct snd_dma_buffer *dmab = NULL;
332414
....@@ -336,6 +418,7 @@
336418 SNDRV_DMA_TYPE_UNKNOWN))
337419 return -EINVAL;
338420 runtime = substream->runtime;
421
+ card = substream->pcm->card;
339422
340423 if (runtime->dma_buffer_p) {
341424 /* perphaps, we might free the large DMA memory region
....@@ -355,9 +438,10 @@
355438 if (! dmab)
356439 return -ENOMEM;
357440 dmab->dev = substream->dma_buffer.dev;
358
- if (snd_dma_alloc_pages(substream->dma_buffer.dev.type,
359
- substream->dma_buffer.dev.dev,
360
- size, dmab) < 0) {
441
+ if (do_alloc_pages(card,
442
+ substream->dma_buffer.dev.type,
443
+ substream->dma_buffer.dev.dev,
444
+ size, dmab) < 0) {
361445 kfree(dmab);
362446 return -ENOMEM;
363447 }
....@@ -386,8 +470,10 @@
386470 if (runtime->dma_area == NULL)
387471 return 0;
388472 if (runtime->dma_buffer_p != &substream->dma_buffer) {
473
+ struct snd_card *card = substream->pcm->card;
474
+
389475 /* it's a newly allocated buffer. release it now. */
390
- snd_dma_free_pages(runtime->dma_buffer_p);
476
+ do_free_pages(card, runtime->dma_buffer_p);
391477 kfree(runtime->dma_buffer_p);
392478 }
393479 snd_pcm_set_runtime_buffer(substream, NULL);
....@@ -408,7 +494,7 @@
408494 return 0; /* already large enough */
409495 vfree(runtime->dma_area);
410496 }
411
- runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL);
497
+ runtime->dma_area = __vmalloc(size, gfp_flags);
412498 if (!runtime->dma_area)
413499 return -ENOMEM;
414500 runtime->dma_bytes = size;