Re: ALSA on MIPS platform

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



At Wed, 25 Jan 2006 23:50:07 +0900 (JST),
Atsushi Nemoto wrote:
> 
> Hi.  I'm using PCI Sound cards on MIPS platform which has noncoherent
> DMA.  There are some issues in ALSA for these platform.
> 
> (This topic comes from linux-mips ML.
> http://www.linux-mips.org/cgi-bin/mesg.cgi?a=linux-mips&i=20060124030725.GA14063%40deprecation.cyrius.com)
> 
> 
> 1. virt_to_page vs. dma_alloc_coherent problem.
> 
> ALSA uses virt_to_page() to get 'struct page' for DMA area which was
> allocated using dma_alloc_coherent().  On MIPS with
> CONFIG_DMA_NONCOHERENT, typically physical address range
> 0x0-0x1fffffff are mapped to 0x8000000-0x9fffffff with cached and
> mapped to 0xa0000000-0xbfffffff with uncached.  If we got physical
> address 0x01000000 for DMA, the virtual address is 0xa1000000.  On the
> other hand, virt_to_page() expects normal(cached) virtual address.  So
> we can use virt_to_page() with kmalloc() or dma_alloc_noncoherent(),
> but not with dma_alloc_coherent().
> 
> Here is some fragments from kernel code.  You can see what I mean exactly.
> 
> /* from include/asm-mips/mach-generic/spaces.h */
> #define CAC_BASE		0x80000000
> #define UNCAC_BASE		0xa0000000
> #define PAGE_OFFSET		0x80000000UL
> /* from include/asm-mips/page.h */
> #define __pa(x)			((unsigned long) (x) - PAGE_OFFSET)
> #define __va(x)			((void *)((unsigned long) (x) + PAGE_OFFSET))
> #define pfn_to_page(pfn)	(mem_map + (pfn))
> #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
> #define UNCAC_ADDR(addr)	((addr) - PAGE_OFFSET + UNCAC_BASE)
> #define CAC_ADDR(addr)		((addr) - UNCAC_BASE + PAGE_OFFSET)
> /* from arch/mips/mm/dma-noncoherent.c */
> void *dma_alloc_coherent(struct device *dev, size_t size,
> 	dma_addr_t * dma_handle, gfp_t gfp)
> {
> 	void *ret;
> 
> 	ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp);
> 	if (ret) {
> 		dma_cache_wback_inv((unsigned long) ret, size);
> 		ret = UNCAC_ADDR(ret);
> 	}
> 
> 	return ret;
> }
> 
> How do we fix this?
> 
> A.  hack sound/core/memalloc.c, pcm_native.c, sgbuf.c
> 
> something like:
> #if defined(__mips__) && defined(CONFIG_DMA_NONCOHERENT)
> 		mark_pages(virt_to_page(CAC_ADDR(res)), pg); /* should be dma_to_page() */
> #else
> 		mark_pages(virt_to_page(res), pg); /* should be dma_to_page() */
> #endif
> 
> It's ugly.
> 
> B.  fix mips virt_to_page()
> 
> #define TO_PHYS_MASK 0x1fffffff
> #define virt_to_page(kaddr)	pfn_to_page(((kaddr) & TO_PHYS_MASK) >> PAGE_SHIFT)
> 
> a bit slower.  MIPS need one instruction to create 0x80000000
> constant, two instruction for 0x1fffffff.  There are many usage of
> virt_to_page() in mm/slab.c so its performance might be important.
> 
> C.  introduce dma_to_page() which returns struct page * for dma_addr_t.
> 
> The comment in ALSA code (/* should be dma_to_page() */) mean this?
> 
> For MIPS, it would be:
> #define dma_to_page(addr) pfn_to_page((addr) >> PAGE_SHIFT)
> But I do not know for other platform.
> 
> 
> Which is preferred, or is there other good way?
> 
> 
> 2. mmapping DMA area.
> 
> As described above, DMA area is uncached on those platform.  So mmap
> should ensure user programs do not cache these area.
> snd_pcm_default_mmap() is used for mmapping the DMA area but its
> vm_page_prot is not configured as uncached.  On the other hand,
> snd_pcm_lib_mmap_iomem() do it using pgprot_noncached().
> 
> snd_pcm_default_mmap() should do same thing for those MIPS platform.
> 
> static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
> 				struct vm_area_struct *area)
> {
> #if defined(__mips__) && defined(CONFIG_DMA_NONCOHERENT)
> 	area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
> #endif
> 	area->vm_ops = &snd_pcm_vm_ops_data;
> 
> Is this a right fix?  Are there any platform which have same problem?

The right fix is, IMO, to port dma_mmap_coherent() to all archs.
Currently, it's only on ARM.


Takashi
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux