alsa usb-audio sound corruption caused by cached vmalloc mapping

Takashi Iwai tiwai at suse.de
Mon Feb 4 11:59:19 EST 2013


At Mon, 4 Feb 2013 17:50:27 +0100,
Matthieu CASTET wrote:
> 
> Hi,
> 
> on a armv5 soc, we have audio corruption while using a usb-audio sound card.
> After analysis, it comes from alsa vmalloc mapping.

Yeah, it's a known issue since long time ago...

> in the current kernel vmalloc mapping used by alsa are cached.
> 
> This cause coherency problem on armv5 architecture because the cache are VIVT :
> - alsa kernel driver map a buffer with vmalloc. The memory attribute is cached
> - userspace map vmalloc buffer.  The memory attribute is cached
> 
> But because the cache are VIVT, these two mapping don't share the same cache
> line and won't see the same data.
> This corruption can be hidden by context switch because cache are flushed on
> context switch.
> 
> On x86 or armv7, the cache are PIPT and there is no such problem.
> 
> 
> 
> There was a commit "pcm - Call pgprot_noncached() for vmalloc'ed buffers"
> (c32d977b8157bf67cdf47729ce7dd054a26eb534), that made the userspace mapping not
> cached, but this caused issues because the kernel vmalloc mapping was still cached.
> 
> Instead of revering this commit, we could have made the kernel vmalloc noncached
> (see attached patch). It fix the issue on armv5.
> 
> But on some architecture (armv7 for example) you can't have mapping for the same
> physical memory cached (normal cached) and noncached (device memory).
> So the vmalloc and userspace mapping will conflict with the kernel direct RAM
> mapping.
> 
> A workaround could be to use writecombine protection instead of noncached.
> This work because writecombine is mapped on armv7 as L_PTE_MT_BUFFERABLE (normal
> uncached) that is compatible with cached memory (the same trick is used for
> dmacoherent).
> But that's architecture specific may not work on others architectures.
> 
> 
> 
> What's the best way the fix this issue on all architecture ?

I don't think there is no proper way to fix in the driver side unless
a generic API for mmappable (noncached or such) vmalloc variant.

A simple workaround for now would be to give an option (either
arch-specific ifdef or Kconfig) to make snd-usb-audio driver using the
normal page allocation instead of vmalloc.


Takashi

> 
> 
> Matthieu
> [2 vmalloc_uncached.diff <text/x-diff (7bit)>]
> commit f3d13b6752e20cdd193d0265cc6b8f1d814dd869
> Author: Matthieu CASTET <matthieu.castet at parrot.com>
> Date:   Wed Jan 30 15:27:00 2013 +0100
> 
>     make snd_pcm_lib_alloc_vmalloc_buffer memory uncached
> 
> diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
> index 69e01c4..1740d39 100644
> --- a/sound/core/pcm_memory.c
> +++ b/sound/core/pcm_memory.c
> @@ -425,7 +425,7 @@ int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
>  			return 0; /* already large enough */
>  		vfree(runtime->dma_area);
>  	}
> -	runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL);
> +	runtime->dma_area = __vmalloc(size, gfp_flags, pgprot_noncached(PAGE_KERNEL));
>  	if (!runtime->dma_area)
>  		return -ENOMEM;
>  	runtime->dma_bytes = size;



More information about the linux-arm-kernel mailing list