| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 
|---|
| 2 | /* | 
|---|
| 3 | *  Digital Audio (PCM) abstract layer | 
|---|
| 4 | *  Copyright (c) by Jaroslav Kysela <perex@perex.cz> | 
|---|
| 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/export.h> | 
|---|
| 13 | #include <sound/core.h> | 
|---|
| 14 | #include <sound/pcm.h> | 
|---|
| 15 | #include <sound/info.h> | 
|---|
| 16 | #include <sound/initval.h> | 
|---|
| 17 | #include "pcm_local.h" | 
|---|
| 18 |  | 
|---|
| 19 | static int preallocate_dma = 1; | 
|---|
| 20 | module_param(preallocate_dma, int, 0444); | 
|---|
| 21 | MODULE_PARM_DESC(preallocate_dma, "Preallocate DMA memory when the PCM devices are initialized."); | 
|---|
| 22 |  | 
|---|
| 23 | static int maximum_substreams = 4; | 
|---|
| 24 | module_param(maximum_substreams, int, 0444); | 
|---|
| 25 | MODULE_PARM_DESC(maximum_substreams, "Maximum substreams with preallocated DMA memory."); | 
|---|
| 26 |  | 
|---|
| 27 | static const size_t snd_minimum_buffer = 16384; | 
|---|
| 28 |  | 
|---|
| 29 | static unsigned long max_alloc_per_card = 32UL * 1024UL * 1024UL; | 
|---|
| 30 | module_param(max_alloc_per_card, ulong, 0644); | 
|---|
| 31 | MODULE_PARM_DESC(max_alloc_per_card, "Max total allocation bytes per card."); | 
|---|
| 32 |  | 
|---|
| 33 | static void __update_allocated_size(struct snd_card *card, ssize_t bytes) | 
|---|
| 34 | { | 
|---|
| 35 | card->total_pcm_alloc_bytes += bytes; | 
|---|
| 36 | } | 
|---|
| 37 |  | 
|---|
| 38 | static void update_allocated_size(struct snd_card *card, ssize_t bytes) | 
|---|
| 39 | { | 
|---|
| 40 | guard(mutex)(T: &card->memory_mutex); | 
|---|
| 41 | __update_allocated_size(card, bytes); | 
|---|
| 42 | } | 
|---|
| 43 |  | 
|---|
| 44 | static void decrease_allocated_size(struct snd_card *card, size_t bytes) | 
|---|
| 45 | { | 
|---|
| 46 | guard(mutex)(T: &card->memory_mutex); | 
|---|
| 47 | WARN_ON(card->total_pcm_alloc_bytes < bytes); | 
|---|
| 48 | __update_allocated_size(card, bytes: -(ssize_t)bytes); | 
|---|
| 49 | } | 
|---|
| 50 |  | 
|---|
| 51 | static int do_alloc_pages(struct snd_card *card, int type, struct device *dev, | 
|---|
| 52 | int str, size_t size, struct snd_dma_buffer *dmab) | 
|---|
| 53 | { | 
|---|
| 54 | enum dma_data_direction dir; | 
|---|
| 55 | int err; | 
|---|
| 56 |  | 
|---|
| 57 | /* check and reserve the requested size */ | 
|---|
| 58 | scoped_guard(mutex, &card->memory_mutex) { | 
|---|
| 59 | if (max_alloc_per_card && | 
|---|
| 60 | card->total_pcm_alloc_bytes + size > max_alloc_per_card) | 
|---|
| 61 | return -ENOMEM; | 
|---|
| 62 | __update_allocated_size(card, bytes: size); | 
|---|
| 63 | } | 
|---|
| 64 |  | 
|---|
| 65 | if (str == SNDRV_PCM_STREAM_PLAYBACK) | 
|---|
| 66 | dir = DMA_TO_DEVICE; | 
|---|
| 67 | else | 
|---|
| 68 | dir = DMA_FROM_DEVICE; | 
|---|
| 69 | err = snd_dma_alloc_dir_pages(type, dev, dir, 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, bytes: dmab->bytes - size); | 
|---|
| 76 | } else { | 
|---|
| 77 | /* take back on allocation failure */ | 
|---|
| 78 | decrease_allocated_size(card, bytes: 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, bytes: dmab->bytes); | 
|---|
| 88 | snd_dma_free_pages(dmab); | 
|---|
| 89 | dmab->area = NULL; | 
|---|
| 90 | } | 
|---|
| 91 |  | 
|---|
| 92 | /* | 
|---|
| 93 | * try to allocate as the large pages as possible. | 
|---|
| 94 | * stores the resultant memory size in *res_size. | 
|---|
| 95 | * | 
|---|
| 96 | * the minimum size is snd_minimum_buffer.  it should be power of 2. | 
|---|
| 97 | */ | 
|---|
| 98 | static int preallocate_pcm_pages(struct snd_pcm_substream *substream, | 
|---|
| 99 | size_t size, bool no_fallback) | 
|---|
| 100 | { | 
|---|
| 101 | struct snd_dma_buffer *dmab = &substream->dma_buffer; | 
|---|
| 102 | struct snd_card *card = substream->pcm->card; | 
|---|
| 103 | size_t orig_size = size; | 
|---|
| 104 | int err; | 
|---|
| 105 |  | 
|---|
| 106 | do { | 
|---|
| 107 | err = do_alloc_pages(card, type: dmab->dev.type, dev: dmab->dev.dev, | 
|---|
| 108 | str: substream->stream, size, dmab); | 
|---|
| 109 | if (err != -ENOMEM) | 
|---|
| 110 | return err; | 
|---|
| 111 | if (no_fallback) | 
|---|
| 112 | break; | 
|---|
| 113 | size >>= 1; | 
|---|
| 114 | } while (size >= snd_minimum_buffer); | 
|---|
| 115 | dmab->bytes = 0; /* tell error */ | 
|---|
| 116 | pr_warn( "ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n", | 
|---|
| 117 | substream->pcm->card->number, substream->pcm->device, | 
|---|
| 118 | substream->stream ? 'c' : 'p', substream->number, | 
|---|
| 119 | substream->pcm->name, orig_size); | 
|---|
| 120 | return -ENOMEM; | 
|---|
| 121 | } | 
|---|
| 122 |  | 
|---|
| 123 | /** | 
|---|
| 124 | * snd_pcm_lib_preallocate_free - release the preallocated buffer of the specified substream. | 
|---|
| 125 | * @substream: the pcm substream instance | 
|---|
| 126 | * | 
|---|
| 127 | * Releases the pre-allocated buffer of the given substream. | 
|---|
| 128 | */ | 
|---|
| 129 | void snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) | 
|---|
| 130 | { | 
|---|
| 131 | do_free_pages(card: substream->pcm->card, dmab: &substream->dma_buffer); | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | /** | 
|---|
| 135 | * snd_pcm_lib_preallocate_free_for_all - release all pre-allocated buffers on the pcm | 
|---|
| 136 | * @pcm: the pcm instance | 
|---|
| 137 | * | 
|---|
| 138 | * Releases all the pre-allocated buffers on the given pcm. | 
|---|
| 139 | */ | 
|---|
| 140 | void snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) | 
|---|
| 141 | { | 
|---|
| 142 | struct snd_pcm_substream *substream; | 
|---|
| 143 | int stream; | 
|---|
| 144 |  | 
|---|
| 145 | for_each_pcm_substream(pcm, stream, substream) | 
|---|
| 146 | snd_pcm_lib_preallocate_free(substream); | 
|---|
| 147 | } | 
|---|
| 148 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); | 
|---|
| 149 |  | 
|---|
| 150 | #ifdef CONFIG_SND_VERBOSE_PROCFS | 
|---|
| 151 | /* | 
|---|
| 152 | * read callback for prealloc proc file | 
|---|
| 153 | * | 
|---|
| 154 | * prints the current allocated size in kB. | 
|---|
| 155 | */ | 
|---|
| 156 | static void snd_pcm_lib_preallocate_proc_read(struct snd_info_entry *entry, | 
|---|
| 157 | struct snd_info_buffer *buffer) | 
|---|
| 158 | { | 
|---|
| 159 | struct snd_pcm_substream *substream = entry->private_data; | 
|---|
| 160 | snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_buffer.bytes / 1024); | 
|---|
| 161 | } | 
|---|
| 162 |  | 
|---|
| 163 | /* | 
|---|
| 164 | * read callback for prealloc_max proc file | 
|---|
| 165 | * | 
|---|
| 166 | * prints the maximum allowed size in kB. | 
|---|
| 167 | */ | 
|---|
| 168 | static void snd_pcm_lib_preallocate_max_proc_read(struct snd_info_entry *entry, | 
|---|
| 169 | struct snd_info_buffer *buffer) | 
|---|
| 170 | { | 
|---|
| 171 | struct snd_pcm_substream *substream = entry->private_data; | 
|---|
| 172 | snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_max / 1024); | 
|---|
| 173 | } | 
|---|
| 174 |  | 
|---|
| 175 | /* | 
|---|
| 176 | * write callback for prealloc proc file | 
|---|
| 177 | * | 
|---|
| 178 | * accepts the preallocation size in kB. | 
|---|
| 179 | */ | 
|---|
| 180 | static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, | 
|---|
| 181 | struct snd_info_buffer *buffer) | 
|---|
| 182 | { | 
|---|
| 183 | struct snd_pcm_substream *substream = entry->private_data; | 
|---|
| 184 | struct snd_card *card = substream->pcm->card; | 
|---|
| 185 | char line[64], str[64]; | 
|---|
| 186 | unsigned long size; | 
|---|
| 187 | struct snd_dma_buffer new_dmab; | 
|---|
| 188 |  | 
|---|
| 189 | guard(mutex)(T: &substream->pcm->open_mutex); | 
|---|
| 190 | if (substream->runtime) { | 
|---|
| 191 | buffer->error = -EBUSY; | 
|---|
| 192 | return; | 
|---|
| 193 | } | 
|---|
| 194 | if (!snd_info_get_line(buffer, line, len: sizeof(line))) { | 
|---|
| 195 | snd_info_get_str(dest: str, src: line, len: sizeof(str)); | 
|---|
| 196 | buffer->error = kstrtoul(s: str, base: 10, res: &size); | 
|---|
| 197 | if (buffer->error != 0) | 
|---|
| 198 | return; | 
|---|
| 199 | size *= 1024; | 
|---|
| 200 | if ((size != 0 && size < 8192) || size > substream->dma_max) { | 
|---|
| 201 | buffer->error = -EINVAL; | 
|---|
| 202 | return; | 
|---|
| 203 | } | 
|---|
| 204 | if (substream->dma_buffer.bytes == size) | 
|---|
| 205 | return; | 
|---|
| 206 | memset(s: &new_dmab, c: 0, n: sizeof(new_dmab)); | 
|---|
| 207 | new_dmab.dev = substream->dma_buffer.dev; | 
|---|
| 208 | if (size > 0) { | 
|---|
| 209 | if (do_alloc_pages(card, | 
|---|
| 210 | type: substream->dma_buffer.dev.type, | 
|---|
| 211 | dev: substream->dma_buffer.dev.dev, | 
|---|
| 212 | str: substream->stream, | 
|---|
| 213 | size, dmab: &new_dmab) < 0) { | 
|---|
| 214 | buffer->error = -ENOMEM; | 
|---|
| 215 | pr_debug( "ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %lu\n", | 
|---|
| 216 | substream->pcm->card->number, substream->pcm->device, | 
|---|
| 217 | substream->stream ? 'c' : 'p', substream->number, | 
|---|
| 218 | substream->pcm->name, size); | 
|---|
| 219 | return; | 
|---|
| 220 | } | 
|---|
| 221 | substream->buffer_bytes_max = size; | 
|---|
| 222 | } else { | 
|---|
| 223 | substream->buffer_bytes_max = UINT_MAX; | 
|---|
| 224 | } | 
|---|
| 225 | if (substream->dma_buffer.area) | 
|---|
| 226 | do_free_pages(card, dmab: &substream->dma_buffer); | 
|---|
| 227 | substream->dma_buffer = new_dmab; | 
|---|
| 228 | } else { | 
|---|
| 229 | buffer->error = -EINVAL; | 
|---|
| 230 | } | 
|---|
| 231 | } | 
|---|
| 232 |  | 
|---|
| 233 | static inline void preallocate_info_init(struct snd_pcm_substream *substream) | 
|---|
| 234 | { | 
|---|
| 235 | struct snd_info_entry *entry; | 
|---|
| 236 |  | 
|---|
| 237 | entry = snd_info_create_card_entry(card: substream->pcm->card, name: "prealloc", | 
|---|
| 238 | parent: substream->proc_root); | 
|---|
| 239 | if (entry) { | 
|---|
| 240 | snd_info_set_text_ops(entry, private_data: substream, | 
|---|
| 241 | read: snd_pcm_lib_preallocate_proc_read); | 
|---|
| 242 | entry->c.text.write = snd_pcm_lib_preallocate_proc_write; | 
|---|
| 243 | entry->mode |= 0200; | 
|---|
| 244 | } | 
|---|
| 245 | entry = snd_info_create_card_entry(card: substream->pcm->card, name: "prealloc_max", | 
|---|
| 246 | parent: substream->proc_root); | 
|---|
| 247 | if (entry) | 
|---|
| 248 | snd_info_set_text_ops(entry, private_data: substream, | 
|---|
| 249 | read: snd_pcm_lib_preallocate_max_proc_read); | 
|---|
| 250 | } | 
|---|
| 251 |  | 
|---|
| 252 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ | 
|---|
| 253 | static inline void preallocate_info_init(struct snd_pcm_substream *substream) | 
|---|
| 254 | { | 
|---|
| 255 | } | 
|---|
| 256 | #endif /* CONFIG_SND_VERBOSE_PROCFS */ | 
|---|
| 257 |  | 
|---|
| 258 | /* | 
|---|
| 259 | * pre-allocate the buffer and create a proc file for the substream | 
|---|
| 260 | */ | 
|---|
| 261 | static int preallocate_pages(struct snd_pcm_substream *substream, | 
|---|
| 262 | int type, struct device *data, | 
|---|
| 263 | size_t size, size_t max, bool managed) | 
|---|
| 264 | { | 
|---|
| 265 | int err; | 
|---|
| 266 |  | 
|---|
| 267 | if (snd_BUG_ON(substream->dma_buffer.dev.type)) | 
|---|
| 268 | return -EINVAL; | 
|---|
| 269 |  | 
|---|
| 270 | substream->dma_buffer.dev.type = type; | 
|---|
| 271 | substream->dma_buffer.dev.dev = data; | 
|---|
| 272 |  | 
|---|
| 273 | if (size > 0) { | 
|---|
| 274 | if (!max) { | 
|---|
| 275 | /* no fallback, only also inform -ENOMEM */ | 
|---|
| 276 | err = preallocate_pcm_pages(substream, size, no_fallback: true); | 
|---|
| 277 | if (err < 0) | 
|---|
| 278 | return err; | 
|---|
| 279 | } else if (preallocate_dma && | 
|---|
| 280 | substream->number < maximum_substreams) { | 
|---|
| 281 | err = preallocate_pcm_pages(substream, size, no_fallback: false); | 
|---|
| 282 | if (err < 0 && err != -ENOMEM) | 
|---|
| 283 | return err; | 
|---|
| 284 | } | 
|---|
| 285 | } | 
|---|
| 286 |  | 
|---|
| 287 | if (substream->dma_buffer.bytes > 0) | 
|---|
| 288 | substream->buffer_bytes_max = substream->dma_buffer.bytes; | 
|---|
| 289 | substream->dma_max = max; | 
|---|
| 290 | if (max > 0) | 
|---|
| 291 | preallocate_info_init(substream); | 
|---|
| 292 | if (managed) | 
|---|
| 293 | substream->managed_buffer_alloc = 1; | 
|---|
| 294 | return 0; | 
|---|
| 295 | } | 
|---|
| 296 |  | 
|---|
| 297 | static int preallocate_pages_for_all(struct snd_pcm *pcm, int type, | 
|---|
| 298 | void *data, size_t size, size_t max, | 
|---|
| 299 | bool managed) | 
|---|
| 300 | { | 
|---|
| 301 | struct snd_pcm_substream *substream; | 
|---|
| 302 | int stream, err; | 
|---|
| 303 |  | 
|---|
| 304 | for_each_pcm_substream(pcm, stream, substream) { | 
|---|
| 305 | err = preallocate_pages(substream, type, data, size, max, managed); | 
|---|
| 306 | if (err < 0) | 
|---|
| 307 | return err; | 
|---|
| 308 | } | 
|---|
| 309 | return 0; | 
|---|
| 310 | } | 
|---|
| 311 |  | 
|---|
| 312 | /** | 
|---|
| 313 | * snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type | 
|---|
| 314 | * @substream: the pcm substream instance | 
|---|
| 315 | * @type: DMA type (SNDRV_DMA_TYPE_*) | 
|---|
| 316 | * @data: DMA type dependent data | 
|---|
| 317 | * @size: the requested pre-allocation size in bytes | 
|---|
| 318 | * @max: the max. allowed pre-allocation size | 
|---|
| 319 | * | 
|---|
| 320 | * Do pre-allocation for the given DMA buffer type. | 
|---|
| 321 | */ | 
|---|
| 322 | void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, | 
|---|
| 323 | int type, struct device *data, | 
|---|
| 324 | size_t size, size_t max) | 
|---|
| 325 | { | 
|---|
| 326 | preallocate_pages(substream, type, data, size, max, managed: false); | 
|---|
| 327 | } | 
|---|
| 328 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); | 
|---|
| 329 |  | 
|---|
| 330 | /** | 
|---|
| 331 | * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continuous memory type (all substreams) | 
|---|
| 332 | * @pcm: the pcm instance | 
|---|
| 333 | * @type: DMA type (SNDRV_DMA_TYPE_*) | 
|---|
| 334 | * @data: DMA type dependent data | 
|---|
| 335 | * @size: the requested pre-allocation size in bytes | 
|---|
| 336 | * @max: the max. allowed pre-allocation size | 
|---|
| 337 | * | 
|---|
| 338 | * Do pre-allocation to all substreams of the given pcm for the | 
|---|
| 339 | * specified DMA type. | 
|---|
| 340 | */ | 
|---|
| 341 | void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, | 
|---|
| 342 | int type, void *data, | 
|---|
| 343 | size_t size, size_t max) | 
|---|
| 344 | { | 
|---|
| 345 | preallocate_pages_for_all(pcm, type, data, size, max, managed: false); | 
|---|
| 346 | } | 
|---|
| 347 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); | 
|---|
| 348 |  | 
|---|
| 349 | /** | 
|---|
| 350 | * snd_pcm_set_managed_buffer - set up buffer management for a substream | 
|---|
| 351 | * @substream: the pcm substream instance | 
|---|
| 352 | * @type: DMA type (SNDRV_DMA_TYPE_*) | 
|---|
| 353 | * @data: DMA type dependent data | 
|---|
| 354 | * @size: the requested pre-allocation size in bytes | 
|---|
| 355 | * @max: the max. allowed pre-allocation size | 
|---|
| 356 | * | 
|---|
| 357 | * Do pre-allocation for the given DMA buffer type, and set the managed | 
|---|
| 358 | * buffer allocation mode to the given substream. | 
|---|
| 359 | * In this mode, PCM core will allocate a buffer automatically before PCM | 
|---|
| 360 | * hw_params ops call, and release the buffer after PCM hw_free ops call | 
|---|
| 361 | * as well, so that the driver doesn't need to invoke the allocation and | 
|---|
| 362 | * the release explicitly in its callback. | 
|---|
| 363 | * When a buffer is actually allocated before the PCM hw_params call, it | 
|---|
| 364 | * turns on the runtime buffer_changed flag for drivers changing their h/w | 
|---|
| 365 | * parameters accordingly. | 
|---|
| 366 | * | 
|---|
| 367 | * When @size is non-zero and @max is zero, this tries to allocate for only | 
|---|
| 368 | * the exact buffer size without fallback, and may return -ENOMEM. | 
|---|
| 369 | * Otherwise, the function tries to allocate smaller chunks if the allocation | 
|---|
| 370 | * fails.  This is the behavior of snd_pcm_set_fixed_buffer(). | 
|---|
| 371 | * | 
|---|
| 372 | * When both @size and @max are zero, the function only sets up the buffer | 
|---|
| 373 | * for later dynamic allocations. It's used typically for buffers with | 
|---|
| 374 | * SNDRV_DMA_TYPE_VMALLOC type. | 
|---|
| 375 | * | 
|---|
| 376 | * Upon successful buffer allocation and setup, the function returns 0. | 
|---|
| 377 | * | 
|---|
| 378 | * Return: zero if successful, or a negative error code | 
|---|
| 379 | */ | 
|---|
| 380 | int snd_pcm_set_managed_buffer(struct snd_pcm_substream *substream, int type, | 
|---|
| 381 | struct device *data, size_t size, size_t max) | 
|---|
| 382 | { | 
|---|
| 383 | return preallocate_pages(substream, type, data, size, max, managed: true); | 
|---|
| 384 | } | 
|---|
| 385 | EXPORT_SYMBOL(snd_pcm_set_managed_buffer); | 
|---|
| 386 |  | 
|---|
| 387 | /** | 
|---|
| 388 | * snd_pcm_set_managed_buffer_all - set up buffer management for all substreams | 
|---|
| 389 | *	for all substreams | 
|---|
| 390 | * @pcm: the pcm instance | 
|---|
| 391 | * @type: DMA type (SNDRV_DMA_TYPE_*) | 
|---|
| 392 | * @data: DMA type dependent data | 
|---|
| 393 | * @size: the requested pre-allocation size in bytes | 
|---|
| 394 | * @max: the max. allowed pre-allocation size | 
|---|
| 395 | * | 
|---|
| 396 | * Do pre-allocation to all substreams of the given pcm for the specified DMA | 
|---|
| 397 | * type and size, and set the managed_buffer_alloc flag to each substream. | 
|---|
| 398 | * | 
|---|
| 399 | * Return: zero if successful, or a negative error code | 
|---|
| 400 | */ | 
|---|
| 401 | int snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type, | 
|---|
| 402 | struct device *data, | 
|---|
| 403 | size_t size, size_t max) | 
|---|
| 404 | { | 
|---|
| 405 | return preallocate_pages_for_all(pcm, type, data, size, max, managed: true); | 
|---|
| 406 | } | 
|---|
| 407 | EXPORT_SYMBOL(snd_pcm_set_managed_buffer_all); | 
|---|
| 408 |  | 
|---|
| 409 | /** | 
|---|
| 410 | * snd_pcm_lib_malloc_pages - allocate the DMA buffer | 
|---|
| 411 | * @substream: the substream to allocate the DMA buffer to | 
|---|
| 412 | * @size: the requested buffer size in bytes | 
|---|
| 413 | * | 
|---|
| 414 | * Allocates the DMA buffer on the BUS type given earlier to | 
|---|
| 415 | * snd_pcm_lib_preallocate_xxx_pages(). | 
|---|
| 416 | * | 
|---|
| 417 | * Return: 1 if the buffer is changed, 0 if not changed, or a negative | 
|---|
| 418 | * code on failure. | 
|---|
| 419 | */ | 
|---|
| 420 | int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) | 
|---|
| 421 | { | 
|---|
| 422 | struct snd_card *card; | 
|---|
| 423 | struct snd_pcm_runtime *runtime; | 
|---|
| 424 | struct snd_dma_buffer *dmab = NULL; | 
|---|
| 425 |  | 
|---|
| 426 | if (PCM_RUNTIME_CHECK(substream)) | 
|---|
| 427 | return -EINVAL; | 
|---|
| 428 | if (snd_BUG_ON(substream->dma_buffer.dev.type == | 
|---|
| 429 | SNDRV_DMA_TYPE_UNKNOWN)) | 
|---|
| 430 | return -EINVAL; | 
|---|
| 431 | runtime = substream->runtime; | 
|---|
| 432 | card = substream->pcm->card; | 
|---|
| 433 |  | 
|---|
| 434 | if (runtime->dma_buffer_p) { | 
|---|
| 435 | /* perphaps, we might free the large DMA memory region | 
|---|
| 436 | to save some space here, but the actual solution | 
|---|
| 437 | costs us less time */ | 
|---|
| 438 | if (runtime->dma_buffer_p->bytes >= size) { | 
|---|
| 439 | runtime->dma_bytes = size; | 
|---|
| 440 | return 0;	/* ok, do not change */ | 
|---|
| 441 | } | 
|---|
| 442 | snd_pcm_lib_free_pages(substream); | 
|---|
| 443 | } | 
|---|
| 444 | if (substream->dma_buffer.area != NULL && | 
|---|
| 445 | substream->dma_buffer.bytes >= size) { | 
|---|
| 446 | dmab = &substream->dma_buffer; /* use the pre-allocated buffer */ | 
|---|
| 447 | } else { | 
|---|
| 448 | /* dma_max=0 means the fixed size preallocation */ | 
|---|
| 449 | if (substream->dma_buffer.area && !substream->dma_max) | 
|---|
| 450 | return -ENOMEM; | 
|---|
| 451 | dmab = kzalloc(sizeof(*dmab), GFP_KERNEL); | 
|---|
| 452 | if (! dmab) | 
|---|
| 453 | return -ENOMEM; | 
|---|
| 454 | dmab->dev = substream->dma_buffer.dev; | 
|---|
| 455 | if (do_alloc_pages(card, | 
|---|
| 456 | type: substream->dma_buffer.dev.type, | 
|---|
| 457 | dev: substream->dma_buffer.dev.dev, | 
|---|
| 458 | str: substream->stream, | 
|---|
| 459 | size, dmab) < 0) { | 
|---|
| 460 | kfree(objp: dmab); | 
|---|
| 461 | pr_debug( "ALSA pcmC%dD%d%c,%d:%s: cannot allocate for size %zu\n", | 
|---|
| 462 | substream->pcm->card->number, substream->pcm->device, | 
|---|
| 463 | substream->stream ? 'c' : 'p', substream->number, | 
|---|
| 464 | substream->pcm->name, size); | 
|---|
| 465 | return -ENOMEM; | 
|---|
| 466 | } | 
|---|
| 467 | } | 
|---|
| 468 | snd_pcm_set_runtime_buffer(substream, bufp: dmab); | 
|---|
| 469 | runtime->dma_bytes = size; | 
|---|
| 470 | return 1;			/* area was changed */ | 
|---|
| 471 | } | 
|---|
| 472 | EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); | 
|---|
| 473 |  | 
|---|
| 474 | /** | 
|---|
| 475 | * snd_pcm_lib_free_pages - release the allocated DMA buffer. | 
|---|
| 476 | * @substream: the substream to release the DMA buffer | 
|---|
| 477 | * | 
|---|
| 478 | * Releases the DMA buffer allocated via snd_pcm_lib_malloc_pages(). | 
|---|
| 479 | * | 
|---|
| 480 | * Return: Zero if successful, or a negative error code on failure. | 
|---|
| 481 | */ | 
|---|
| 482 | int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) | 
|---|
| 483 | { | 
|---|
| 484 | struct snd_pcm_runtime *runtime; | 
|---|
| 485 |  | 
|---|
| 486 | if (PCM_RUNTIME_CHECK(substream)) | 
|---|
| 487 | return -EINVAL; | 
|---|
| 488 | runtime = substream->runtime; | 
|---|
| 489 | if (runtime->dma_area == NULL) | 
|---|
| 490 | return 0; | 
|---|
| 491 | if (runtime->dma_buffer_p != &substream->dma_buffer) { | 
|---|
| 492 | struct snd_card *card = substream->pcm->card; | 
|---|
| 493 |  | 
|---|
| 494 | /* it's a newly allocated buffer.  release it now. */ | 
|---|
| 495 | do_free_pages(card, dmab: runtime->dma_buffer_p); | 
|---|
| 496 | kfree(objp: runtime->dma_buffer_p); | 
|---|
| 497 | } | 
|---|
| 498 | snd_pcm_set_runtime_buffer(substream, NULL); | 
|---|
| 499 | return 0; | 
|---|
| 500 | } | 
|---|
| 501 | EXPORT_SYMBOL(snd_pcm_lib_free_pages); | 
|---|
| 502 |  | 
|---|