Re: Sound error: Couldn't allocate DMA buffer

Mark Gray (markgray@iago.nac.net)
12 Apr 1999 09:08:07 -0400


jumeaux lists <lists@jumeaux.bc.ca> writes:
>
> > > Hi there. I keep getting this sort of thing in my syslog when
> > > something's trying to play through /dev/dsp:
> > >
> > > Apr 9 13:11:29 odin kernel: Sound error: Couldn't allocate DMA buffer
> > > Apr 9 13:12:00 odin last message repeated 48 times
> > > Apr 9 13:13:01 odin last message repeated 121 times
> >
> > You are out of big physically contigious blobs of memory under 16MBs for
> > DMA buffers. You can put in dmabuf=1 as an option to sound.o or set a
> > config param at compile time if you dont use modules.
>
> thanks - thought it might be something to do with fragmentation, but i
> wasn't aware of the <16mb restrictions on isa cards.
>
> *but*, does this solution apply to kernel 2.0.36? i see it in the docs
> for 2.2, but not 2.0, and when i try adding

I have a quick and dirty patch that I have been using for 2.0.36 since
November without problems ("Haven't got sick once"). If anyone is
going to use it, they should understand it first, then take out the
debugging printk's when and if they get some confidence in it: (Notice
I use dmahack=1 instead of 2.2.*'s dmabuf=1)

-------------------cut here----------------------
--- drivers/sound/soundcard.c.ORIG Wed Aug 21 02:18:09 1996
+++ drivers/sound/soundcard.c Wed Nov 25 12:16:58 1998
@@ -296,7 +296,7 @@

vma_set_inode (vma, inode);
inode_inc_count (inode);
-
+ printk (KERN_DEBUG "sound: mmap being done.\n");
dmap->mapping_flags |= DMA_MAP_MAPPED;

memset (dmap->raw_buf,
@@ -389,6 +389,14 @@
static int sound[20] =
{0};

+static int dmahack = 0; /* Non-zero to hold onto dma buffer */
+
+static struct {
+ char *buf;
+ int buffsize;
+ int sz;
+} dmasave = { NULL, 0, 0 }; /* If dmahack != 0 one dmabuffer saved here */
+
int
init_module (void)
{
@@ -470,6 +478,13 @@
sound_free_dma (i);
}

+ if ( (dmahack != 0) && (dmasave.buf != NULL) )
+ {
+ printk (KERN_DEBUG "sound: returning saved dma buffer at %p of size %u.\n",
+ dmasave.buf, dmasave.sz);
+ free_pages ((unsigned long) dmasave.buf, dmasave.sz);
+ dmasave.buf = NULL; /* better safe than sorry */
+ }

}
#endif
@@ -633,6 +648,20 @@
if (dmap->raw_buf != NULL)
return 0; /* Already done */

+ /*
+ * Here we must decide to call __get_dma_pages to try to get a new buffer or
+ * reuse the buffer last saved by sound_free_dmap to address dmasave.buf
+ * iff dmahack != 0
+ */
+ if ( (dmahack != 0) && (dmasave.buf != NULL) )
+ {
+ start_addr = dmasave.buf;
+ dmasave.buf = NULL; /* better safe than sorry */
+ audio_devs[dev]->buffsize = dmasave.buffsize;
+ end_addr = start_addr + audio_devs[dev]->buffsize - 1;
+ goto gotbuffer;
+ }
+
if (dma_buffsize < 4096)
dma_buffsize = 4096;

@@ -667,11 +696,13 @@
sz++, size <<= 1);

audio_devs[dev]->buffsize = PAGE_SIZE * (1 << sz);
+ printk (KERN_DEBUG "sound: Trying buffsize[%d] = %lu\n", dev, audio_devs[dev]->buffsize);

if ((start_addr = (char *) __get_dma_pages (GFP_ATOMIC, sz)) == NULL)
audio_devs[dev]->buffsize /= 2;
}

+ printk (KERN_DEBUG "sound: Got buffer of %lu at %p\n", audio_devs[dev]->buffsize, start_addr);
if (start_addr == NULL)
{
printk ("Sound error: Couldn't allocate DMA buffer\n");
@@ -699,6 +730,8 @@
return -(EFAULT);
}
}
+
+ gotbuffer:
dmap->raw_buf = start_addr;
dmap->raw_buf_phys = virt_to_bus (start_addr);

@@ -719,8 +752,10 @@
if (dmap->raw_buf == NULL)
return;

- if (dmap->mapping_flags & DMA_MAP_MAPPED)
+ if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+ printk (KERN_DEBUG "sound: mmapped buffer at %p not returned.\n", dmap->raw_buf);
return; /* Don't free mmapped buffer. Will use it next time */
+ }

for (sz = 0, size = PAGE_SIZE;
size < audio_devs[dev]->buffsize;
@@ -733,7 +768,21 @@
{
mem_map_unreserve (i);
}
-
+ /*
+ * Here we must either free or keep the dma pages based on dmahack
+ * If dmahack is zero, really free now, otherwise save address to
+ * dmasave.buf for next call to sound_alloc_dmap iff dmahack != 0
+ */
+ if ( (dmahack != 0) && (dmasave.buf == NULL) )
+ {
+ printk (KERN_DEBUG "sound: keeping buffer at %p of size %u.\n", dmap->raw_buf, sz);
+ dmasave.buf = dmap->raw_buf;
+ dmasave.buffsize = audio_devs[dev]->buffsize;
+ dmasave.sz = sz;
+ dmap->raw_buf = NULL;
+ return;
+ }
+ printk (KERN_DEBUG "sound: returning buffer at %p of size %u.\n", dmap->raw_buf, sz);
free_pages ((unsigned long) dmap->raw_buf, sz);
dmap->raw_buf = NULL;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/