[alsa-devel] To disable dma_area caching (twice)
Takashi Iwai
tiwai at suse.de
Fri May 25 09:28:33 CEST 2012
At Fri, 18 May 2012 14:18:57 +0900,
MASAO TAKAHASHI wrote:
>
> Hi everybody.
> Please advice me to solve my problem.
> 1. My environment
> Hardware Alpha-project MS104-SH4AG with SH7764
> kernel sh-linux-2.6.29
> ALSA driver sh7764-pcm.c developped
> by Manuel Lauss <mano at roarinelk.homelinux.net>
>
> 2. My problem
> I am using the above ALSA driver for SH7764 SSI.
> I have found the runtime->dma_area address refers DMA area
> via D-cache.
> So, playback start is too late after executing
> snd_pcm_writei().
> Until D-cache writeback is done, sound data stays in D-cache.
> I want to read and write from/to main memory
> without D-cache.
>
> 3. My idea to solve this problem
> 3-1 change allocating type of DMA area as follows
> snd_pcm_lib_preallocate_pages_for_all(
> pcm, SNDRV_DMA_TYPE_CONTINUOUS,
> snd_dma_continuous_data(GFP_KERNEL),
> 64*1024, 64*1024);
>
> is changed to
>
> snd_pcm_lib_preallocate_pages_for_all(
> pcm, SNDRV_DMA_TYPE_DEV, <----------- here
> snd_dma_continuous_data(GFP_KERNEL),
> 64*1024, 64*1024);
> to let dma_addr pointing P2SEG area without caching
>
> 3-2 program internal DMA controller start address
> with dma_addr
>
> ssidma_outl(sd, (virt_to_phys)(u32)runtime->dma_addr,
> SSIRDMADR);
>
>
> 3-3 add mmap_data_fault routine
> static int sh7764_mmap_data_fault(
> structvm_area_struct*area,
> struct vm_fault *vmf)
> {
> struct snd_pcm_substream *substream = area->vm_private_data;
> struct snd_pcm_runtime *runtime;
> unsigned long offset;
> struct page * page;
> void *vaddr;
> size_t dma_bytes;
>
> pr_debug("mmap_data_fault\n");
> if (substream == NULL)
> return VM_FAULT_SIGBUS;
> runtime = substream->runtime;
> offset = vmf->pgoff << PAGE_SHIFT;
> dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
> if (offset > dma_bytes - PAGE_SIZE)
> return VM_FAULT_SIGBUS;
> if (substream->ops->page) {
> page = substream->ops->page(substream, offset);
> if (!page)
> return VM_FAULT_SIGBUS;
> } else {
> vaddr = runtime->dma_addr + offset;
> page = virt_to_page(vaddr);
> }
> get_page(page);
> vmf->page = page;
> pr_debug("mmap_data_fault:page = %x\n", (unsigned int)page);
> return 0;
> }
> static struct vm_operations_struct sh7764_pcm_vm_ops_data =
> {
> .open = snd_pcm_mmap_data_open,
> .close = snd_pcm_mmap_data_close,
> .fault = sh7764_mmap_data_fault,
> };
>
> 3-3 add sh7764_pcm_mmap routine
> static int sh7764_pcm_mmap(
> struct snd_pcm_substream *substream,
> struct vm_area_struct *area)
> {
> unsigned long offset;
> unsigned long mp;
> unsigned long virt;
> int map_size;
> struct page *map, *mapend, *ip;
> struct snd_pcm_runtime *runtime;
> int ret;
> #ifdef pgprot_noncached
> area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
> #endif
> offset = area->vm_pgoff << PAGE_SHIFT;
> runtime = substream->runtime;
> map_size = runtime->dma_bytes;
> mp = virt_to_phys((unsigned long)runtime->dma_addr));
> map = virt_to_page(mp);
> mapend = virt_to_page(mp+map_size - 1);
> for (ip = map; ip <= mapend; ip++){
> SetPageReserved(ip);
> area->vm_ops = &sh7764_pcm_vm_ops_data;
> area->vm_private_data = substream;
> area->vm_flags |= VM_IO;
> ret = io_remap_pfn_range(area, area->vm_start,
> mp>>PAGE_SHIFT,
> area->vm_end - area->vm_start,
> area->vm_page_prot);
>
> if (ret ){
> pr_debug("sh7764-pcm.c:remap_pfn_range returned EAGAIN\n");
> return -EAGAIN;
> }
> atomic_inc(&substream->mmap_count);
> pr_debug("mmap_count=%u\n", substream->mmap_count);
> return 0;
> }
>
> static struct snd_pcm_ops sh7764_ssidma_ops = {
> .open = sh7764_ssidma_open,
> .close = sh7764_ssidma_close,
> .ioctl = snd_pcm_lib_ioctl,
> .hw_params = sh7764_hw_params,
> .hw_free = sh7764_hw_free,
> .prepare = sh7764_prepare,
> .trigger = sh7764_trigger,
> .pointer = sh7764_pos,
> .mmap = sh7764_pcm_mmap,
> };
> ------------------------------------------------------------
> Sorry, so long contents.
>
> My solution is right?
> or
> Is there any better solution ?
The "right" fix would be to implement a proper dma_mmap_coherent() for
SH architecture. It's found for ARM and some PPC variants, but for
neither SH nor MIPS.
thanks,
Takashi
More information about the Alsa-devel
mailing list