At Fri, 29 Jun 2012 15:53:15 +0530, Laxman Dewangan wrote:
Some of the ARM based soc allocate the writecombine dma buffer for pcm substreams. They have the same codes for managing this buffer. Moving this to the core/pcm files so that they can use that directly.
Remove the code from Tegra PCM and use these new library function.
This is enabled only for ARM specific and can be extended to other architecture if they support the writecombine dma buffer.
This patch is based on detail discussion on patch: [PATCH] ASoC: snd_dmaengine: add common api for pcm_mmap And suggestion from Lars and Takashi.
Looking through your patch, I think an easier integration is just to add writecombine option to memalloc.c which calls dma_alloc_writecombine() instead of dma_alloc_coherent().
The addition for mmap is still an open question. Again, an easier option so far looks like just add the call of dma_alloc_writecombine() in snd_pcm_lib_default_mmap(). Alternatively, we can create an individual mmap pcm_ops as we discussed.
Below is a totally untested patch, but you can imagine what I meant.
After this change, replace with snd_pcm_lib_malloc_pages with SNDRV_DMA_TYPE_DEV_WC, and that's all you need in the driver side.
Takashi
--- diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index c425062..7840340 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -52,6 +52,7 @@ struct snd_dma_device { #else #define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */ #endif +#define SNDRV_DMA_TYPE_DEV_WC 4 /* writecombine pages */
/* * info for buffer allocation diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 6915692..11108e8 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -124,8 +124,12 @@ void snd_free_pages(void *ptr, size_t size) */
#ifdef CONFIG_HAS_DMA -/* allocate the coherent DMA pages */ -static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) +static void *__snd_malloc_dev_pages(struct device *dev, size_t size, + dma_addr_t *dma, + void *(*func)(struct device *dev, + size_t size, + dma_addr_t *dma_handle, + gfp_t flag)) { int pg; void *res; @@ -138,16 +142,18 @@ static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *d | __GFP_COMP /* compound page lets parts be mapped */ | __GFP_NORETRY /* don't trigger OOM-killer */ | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ - res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags); + res = func(dev, PAGE_SIZE << pg, dma, gfp_flags); if (res != NULL) inc_snd_pages(pg);
return res; }
-/* free the coherent DMA pages */ -static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, - dma_addr_t dma) +static void __snd_free_dev_pages(struct device *dev, size_t size, void *ptr, + dma_addr_t dma, + void (*func)(struct device *dev, + size_t size, void *vaddr, + dma_addr_t dma_handle)) { int pg;
@@ -155,8 +161,36 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, return; pg = get_order(size); dec_snd_pages(pg); - dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); + func(dev, PAGE_SIZE << pg, ptr, dma); +} + +/* allocate the coherent DMA pages */ +static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) +{ + return __snd_malloc_dev_pages(dev, size, dma, dma_alloc_coherent); +} + +/* free the coherent DMA pages */ +static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, + dma_addr_t dma) +{ + __snd_free_dev_pages(dev, ptr, dma, dma_free_coherent); } + +#ifdef CONFIG_ARM +/* allocate the writecombine DMA pages */ +static void *snd_malloc_dev_wc_pages(struct device *dev, size_t size, dma_addr_t *dma) +{ + return __snd_malloc_dev_pages(dev, size, dma, dma_alloc_writecombine); +} + +/* free the writecombine DMA pages */ +static void snd_free_dev_wc_pages(struct device *dev, size_t size, void *ptr, + dma_addr_t dma) +{ + __snd_free_dev_pages(dev, ptr, dma, dma_free_writecombine); +} +#endif /* CONFIG_ARM */ #endif /* CONFIG_HAS_DMA */
/* @@ -200,6 +234,11 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, case SNDRV_DMA_TYPE_DEV: dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); break; +#ifdef CONFIG_ARM + case SNDRV_DMA_TYPE_DEV_WC: + dmab->area = snd_malloc_dev_wc_pages(device, size, &dmab->addr); + break; +#endif #endif #ifdef CONFIG_SND_DMA_SGBUF case SNDRV_DMA_TYPE_DEV_SG: @@ -272,6 +311,11 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) case SNDRV_DMA_TYPE_DEV: snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); break; +#ifdef CONFIG_ARM + case SNDRV_DMA_TYPE_DEV_WC: + snd_free_dev_wc_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); + break; +#endif #endif #ifdef CONFIG_SND_DMA_SGBUF case SNDRV_DMA_TYPE_DEV_SG: @@ -378,7 +422,7 @@ static int snd_mem_proc_read(struct seq_file *seq, void *offset) long pages = snd_allocated_pages >> (PAGE_SHIFT-12); struct snd_mem_list *mem; int devno; - static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" }; + static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "WC" };
mutex_lock(&list_mutex); seq_printf(seq, "pages : %li bytes (%li pages per %likB)\n", diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 53b5ada..c499791 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3170,6 +3170,14 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area) { area->vm_flags |= VM_RESERVED; +#ifdef CONFIG_ARM + if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_WC) + return dma_mmap_writecombine(substream->dma_buffer.dev.dev, + area, + substream->runtime->dma_area, + substream->runtime->dma_addr, + area->vm_end - area->vm_start); +#endif #ifdef ARCH_HAS_DMA_MMAP_COHERENT if (!substream->ops->page && substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)