static const size_t snd_minimum_buffer = 16384;
+static unsigned long max_alloc_per_card = 32UL * 1024UL * 1024UL;
+module_param(max_alloc_per_card, ulong, 0644);
+MODULE_PARM_DESC(max_alloc_per_card, "Max total allocation bytes per card.");
+
+static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
+ size_t size, struct snd_dma_buffer *dmab)
+{
+ int err;
+
+ if (max_alloc_per_card &&
+ card->total_pcm_alloc_bytes + size > max_alloc_per_card)
+ return -ENOMEM;
+ err = snd_dma_alloc_pages(type, dev, size, dmab);
+ if (!err) {
+ mutex_lock(&card->memory_mutex);
+ card->total_pcm_alloc_bytes += dmab->bytes;
+ mutex_unlock(&card->memory_mutex);
+ }
+ return err;
+}
+
+static void do_free_pages(struct snd_card *card, struct snd_dma_buffer *dmab)
+{
+ if (!dmab->area)
+ return;
+ mutex_lock(&card->memory_mutex);
+ WARN_ON(card->total_pcm_alloc_bytes < dmab->bytes);
+ card->total_pcm_alloc_bytes -= dmab->bytes;
+ mutex_unlock(&card->memory_mutex);
+ snd_dma_free_pages(dmab);
+ dmab->area = NULL;
+}
/*
* try to allocate as the large pages as possible.
static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t size)
{
struct snd_dma_buffer *dmab = &substream->dma_buffer;
+ struct snd_card *card = substream->pcm->card;
size_t orig_size = size;
int err;
do {
- if ((err = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev,
- size, dmab)) < 0) {
- if (err != -ENOMEM)
- return err; /* fatal error */
- } else
- return 0;
+ err = do_alloc_pages(card, dmab->dev.type, dmab->dev.dev,
+ size, dmab);
+ if (err != -ENOMEM)
+ return err;
size >>= 1;
} while (size >= snd_minimum_buffer);
dmab->bytes = 0; /* tell error */
*/
static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream)
{
- if (substream->dma_buffer.area == NULL)
- return;
- snd_dma_free_pages(&substream->dma_buffer);
- substream->dma_buffer.area = NULL;
+ do_free_pages(substream->pcm->card, &substream->dma_buffer);
}
/**
struct snd_info_buffer *buffer)
{
struct snd_pcm_substream *substream = entry->private_data;
+ struct snd_card *card = substream->pcm->card;
char line[64], str[64];
size_t size;
struct snd_dma_buffer new_dmab;
memset(&new_dmab, 0, sizeof(new_dmab));
new_dmab.dev = substream->dma_buffer.dev;
if (size > 0) {
- if (snd_dma_alloc_pages(substream->dma_buffer.dev.type,
- substream->dma_buffer.dev.dev,
- size, &new_dmab) < 0) {
+ if (do_alloc_pages(card,
+ substream->dma_buffer.dev.type,
+ substream->dma_buffer.dev.dev,
+ size, &new_dmab) < 0) {
buffer->error = -ENOMEM;
return;
}
substream->buffer_bytes_max = UINT_MAX;
}
if (substream->dma_buffer.area)
- snd_dma_free_pages(&substream->dma_buffer);
+ do_free_pages(card, &substream->dma_buffer);
substream->dma_buffer = new_dmab;
} else {
buffer->error = -EINVAL;
*/
int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
{
+ struct snd_card *card = substream->pcm->card;
struct snd_pcm_runtime *runtime;
struct snd_dma_buffer *dmab = NULL;
if (! dmab)
return -ENOMEM;
dmab->dev = substream->dma_buffer.dev;
- if (snd_dma_alloc_pages(substream->dma_buffer.dev.type,
- substream->dma_buffer.dev.dev,
- size, dmab) < 0) {
+ if (do_alloc_pages(card,
+ substream->dma_buffer.dev.type,
+ substream->dma_buffer.dev.dev,
+ size, dmab) < 0) {
kfree(dmab);
return -ENOMEM;
}
*/
int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
{
+ struct snd_card *card = substream->pcm->card;
struct snd_pcm_runtime *runtime;
if (PCM_RUNTIME_CHECK(substream))
return 0;
if (runtime->dma_buffer_p != &substream->dma_buffer) {
/* it's a newly allocated buffer. release it now. */
- snd_dma_free_pages(runtime->dma_buffer_p);
+ do_free_pages(card, runtime->dma_buffer_p);
kfree(runtime->dma_buffer_p);
}
snd_pcm_set_runtime_buffer(substream, NULL);