On Wed, 16 May 2007 16:28:49 +0200, Martin Michlmayr <tbm@cyrius.com> wrote:
> > There are know problems with PCI soundcard on noncoherent MIPS
> > platform (including cobalt) and some patches are floating around. For
> > example:
> > http://www.linux-mips.org/archives/linux-mips/2007-04/msg00072.html
> >
> > This is a long standing issue and I wonder why your soundcard _did_
> > work with debian sid. The kernel of sid contains fixes for this
> > issue?
>
> I don't think it ever worked with 2.6, but it certainly worked with
> 2.4. Is it much work to get 2.6 working again? This problem comes up
> from time to time, so it seems it's hitting a number of users.
Did the 2.4 kernel use ALSA or OSS? I think ALSA for kernel 2.4 had
same problem.
And this is a minimal patch for current git tree. But I'm not sure if
this patch really fixes the reported segfault.
There are two problem.
1. virt_to_page() can not be used for a buffer returned by
dma_alloc_coherent().
2. mmap() for a buffer returned by dma_alloc_coherent() should be
uncached.
This patch is actually ugly and would not be acceptable as is.
So we need a plan to how to fix them _right_ way.
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a96733a..2d3660c 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3138,6 +3138,9 @@ static struct page *snd_pcm_mmap_data_nopage(struct
vm_area_struct *area,
return NOPAGE_OOM; /* XXX: is this really due to OOM? */
} else {
vaddr = runtime->dma_area + offset;
+#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
+ vaddr = CAC_ADDR(vaddr);
+#endif
page = virt_to_page(vaddr);
}
get_page(page);
@@ -3159,6 +3162,10 @@ static struct vm_operations_struct snd_pcm_vm_ops_data =
static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
+#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
+ /* use uncached access for dma_area */
+ area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
+#endif
area->vm_ops = &snd_pcm_vm_ops_data;
area->vm_private_data = substream;
area->vm_flags |= VM_RESERVED;
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index cefd228..1dd1c9e 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -91,12 +91,21 @@ void *snd_malloc_sgbuf_pages(struct device *device,
}
sgbuf->table[i].buf = tmpb.area;
sgbuf->table[i].addr = tmpb.addr;
+#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
+ sgbuf->page_table[i] = virt_to_page(CAC_ADDR(tmpb.area));
+#else
sgbuf->page_table[i] = virt_to_page(tmpb.area);
+#endif
sgbuf->pages++;
}
sgbuf->size = size;
+#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
+ dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP,
+ PAGE_KERNEL_UNCACHED);
+#else
dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
+#endif
if (! dmab->area)
goto _failed;
return dmab->area;
|