public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2 0/2]  ASoC: Move pcm writecombine dma buffer allocation to core
@ 2012-07-02  8:54 Laxman Dewangan
  2012-07-02  8:54 ` [PATCH V2 1/2] ALSA: Support writecombine DMA buffer memory page alloc/free Laxman Dewangan
  2012-07-02  8:54 ` [PATCH 2/2] ASoC: tegra: use sound pcm library for substream dma buffer Laxman Dewangan
  0 siblings, 2 replies; 6+ messages in thread
From: Laxman Dewangan @ 2012-07-02  8:54 UTC (permalink / raw)
  To: tiwai, lrg, broonie, lars, swarren, perex, clemens
  Cc: alsa-devel, linux-kernel, Laxman Dewangan

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 memory librray so that they can use that
directly.

Remove the code from Tegra PCM and use these new feature from 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.

Changes from V1:
Takashi had send the sample code to integrate the writecombine with
dma coherant and this is based on that code.
Also change the tegra-pcm driver accordingly.


Laxman Dewangan (2):
  ALSA: Support writecombine DMA buffer memory page alloc/free
  ASoC: tegra: use sound pcm library for substream dma buffer

 include/sound/memalloc.h    |    1 +
 sound/core/memalloc.c       |   70 ++++++++++++++++++++++++---
 sound/core/pcm_native.c     |   10 ++++
 sound/soc/tegra/tegra_pcm.c |  112 ++++++++++--------------------------------
 4 files changed, 100 insertions(+), 93 deletions(-)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH V2 1/2] ALSA: Support writecombine DMA buffer memory page alloc/free
  2012-07-02  8:54 [PATCH V2 0/2] ASoC: Move pcm writecombine dma buffer allocation to core Laxman Dewangan
@ 2012-07-02  8:54 ` Laxman Dewangan
  2012-07-02  9:09   ` Takashi Iwai
  2012-07-02  8:54 ` [PATCH 2/2] ASoC: tegra: use sound pcm library for substream dma buffer Laxman Dewangan
  1 sibling, 1 reply; 6+ messages in thread
From: Laxman Dewangan @ 2012-07-02  8:54 UTC (permalink / raw)
  To: tiwai, lrg, broonie, lars, swarren, perex, clemens
  Cc: alsa-devel, linux-kernel, Laxman Dewangan

Some of architecture like ARM support the writecombine DMA
buffer which is used for pcm substream DMA buffer.

Supporting writecombine DMA buffer allocation/free/mmap
through the sound library memory management.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
---
Changes from V1:
Integrate the changes from Takashi's sample code for supporting
writecombine.

 include/sound/memalloc.h |    1 +
 sound/core/memalloc.c    |   74 +++++++++++++++++++++++++++++++++++++++++-----
 sound/core/pcm_native.c  |   10 ++++++
 3 files changed, 77 insertions(+), 8 deletions(-)

diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
index c425062..0328e37 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 page */
 
 /*
  * info for buffer allocation
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 6915692..7468251 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -124,8 +124,10 @@ 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 *(*alloc_func)(struct device *dev, size_t size,
+			dma_addr_t *dma, gfp_t gfp_flags))
 {
 	int pg;
 	void *res;
@@ -138,16 +140,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 = alloc_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 (*free_func)(struct device *dev,
+					size_t size, void *vaddr,
+					dma_addr_t dma_handle))
 {
 	int pg;
 
@@ -155,8 +159,51 @@ 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);
+	free_func(dev, PAGE_SIZE << pg, ptr, dma);
+}
+
+static void *_dma_alloc_coherent(struct device *dev, size_t size,
+		dma_addr_t *dma_handle, gfp_t flag)
+{
+	return dma_alloc_coherent(dev, size, dma_handle, flag);
+}
+
+static void _dma_free_coherent(struct device *dev, size_t size,
+			void *vaddr, dma_addr_t dma_handle)
+{
+	dma_free_coherent(dev, size, vaddr, dma_handle);
+}
+
+
+/* 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, size, 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, size, ptr, dma, dma_free_writecombine);
+}
+#endif
 #endif /* CONFIG_HAS_DMA */
 
 /*
@@ -200,6 +247,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 +324,12 @@ 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 +436,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..28d949c 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3170,6 +3170,16 @@ 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)
-- 
1.7.1.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] ASoC: tegra: use sound pcm library for substream dma buffer
  2012-07-02  8:54 [PATCH V2 0/2] ASoC: Move pcm writecombine dma buffer allocation to core Laxman Dewangan
  2012-07-02  8:54 ` [PATCH V2 1/2] ALSA: Support writecombine DMA buffer memory page alloc/free Laxman Dewangan
@ 2012-07-02  8:54 ` Laxman Dewangan
  2012-07-02  9:14   ` Takashi Iwai
  1 sibling, 1 reply; 6+ messages in thread
From: Laxman Dewangan @ 2012-07-02  8:54 UTC (permalink / raw)
  To: tiwai, lrg, broonie, lars, swarren, perex, clemens
  Cc: alsa-devel, linux-kernel, Laxman Dewangan

The sound pcm library support the writecombine DMA buffer
allocation/deallocation/mapping and hence using the APIs
form sound pcm library inplace of implementing the same
locally.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
---
Changes from V1:
Changes done to use the existing APIs for sound pcm memory management
which is now supporting writecombine.

 sound/soc/tegra/tegra_pcm.c |  112 ++++++++++--------------------------------
 1 files changed, 27 insertions(+), 85 deletions(-)

diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 127348d..ec1fa25 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -202,8 +202,14 @@ static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct tegra_runtime_data *prtd = runtime->private_data;
+	int ret;
 
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	ret = snd_pcm_lib_malloc_pages(substream,
+				params_buffer_bytes(params));
+	if (ret < 0) {
+		pr_err("page allocation failed, err %d\n", ret);
+		return ret;
+	}
 
 	prtd->dma_req[0].size = params_period_bytes(params);
 	prtd->dma_req[1].size = prtd->dma_req[0].size;
@@ -213,9 +219,7 @@ static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-	snd_pcm_set_runtime_buffer(substream, NULL);
-
-	return 0;
+	return snd_pcm_lib_free_pages(substream);
 }
 
 static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -263,18 +267,6 @@ static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream)
 	return prtd->period_index * runtime->period_size;
 }
 
-
-static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
-				struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-					runtime->dma_area,
-					runtime->dma_addr,
-					runtime->dma_bytes);
-}
-
 static struct snd_pcm_ops tegra_pcm_ops = {
 	.open		= tegra_pcm_open,
 	.close		= tegra_pcm_close,
@@ -283,87 +275,37 @@ static struct snd_pcm_ops tegra_pcm_ops = {
 	.hw_free	= tegra_pcm_hw_free,
 	.trigger	= tegra_pcm_trigger,
 	.pointer	= tegra_pcm_pointer,
-	.mmap		= tegra_pcm_mmap,
+	.mmap		= snd_pcm_lib_default_mmap,
 };
 
-static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = tegra_pcm_hardware.buffer_bytes_max;
-
-	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-						&buf->addr, GFP_KERNEL);
-	if (!buf->area)
-		return -ENOMEM;
-
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->private_data = NULL;
-	buf->bytes = size;
-
-	return 0;
-}
-
-static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-
-	substream = pcm->streams[stream].substream;
-	if (!substream)
-		return;
-
-	buf = &substream->dma_buffer;
-	if (!buf->area)
-		return;
-
-	dma_free_writecombine(pcm->card->dev, buf->bytes,
-				buf->area, buf->addr);
-	buf->area = NULL;
-}
-
-static u64 tegra_dma_mask = DMA_BIT_MASK(32);
-
+#define TEGRA_PCM_PREALLOC_BUFFER	(32 * 1024)
+#define TEGRA_PCM_PREALLOC_BUFFER_MAX	(32 * 1024)
 static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_card *card = rtd->card->snd_card;
 	struct snd_pcm *pcm = rtd->pcm;
-	int ret = 0;
-
-	if (!card->dev->dma_mask)
-		card->dev->dma_mask = &tegra_dma_mask;
-	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
-	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-		ret = tegra_pcm_preallocate_dma_buffer(pcm,
-						SNDRV_PCM_STREAM_PLAYBACK);
-		if (ret)
-			goto err;
-	}
-
-	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-		ret = tegra_pcm_preallocate_dma_buffer(pcm,
-						SNDRV_PCM_STREAM_CAPTURE);
-		if (ret)
-			goto err_free_play;
+	struct snd_card *card = rtd->card->snd_card;
+	int retval = 0;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
+			pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
+				SNDRV_DMA_TYPE_DEV_WC,
+				card->dev,
+				TEGRA_PCM_PREALLOC_BUFFER,
+				TEGRA_PCM_PREALLOC_BUFFER_MAX);
+		if (retval < 0)
+			dev_err(card->dev,
+				"dma buffer pre-alloc failied %d\n", retval);
 	}
-
-	return 0;
-
-err_free_play:
-	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
-err:
-	return ret;
+	return retval;
 }
 
 static void tegra_pcm_free(struct snd_pcm *pcm)
 {
-	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
-	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+	snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
+
 static struct snd_soc_platform_driver tegra_pcm_platform = {
 	.ops		= &tegra_pcm_ops,
 	.pcm_new	= tegra_pcm_new,
-- 
1.7.1.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH V2 1/2] ALSA: Support writecombine DMA buffer memory page alloc/free
  2012-07-02  8:54 ` [PATCH V2 1/2] ALSA: Support writecombine DMA buffer memory page alloc/free Laxman Dewangan
@ 2012-07-02  9:09   ` Takashi Iwai
  0 siblings, 0 replies; 6+ messages in thread
From: Takashi Iwai @ 2012-07-02  9:09 UTC (permalink / raw)
  To: Laxman Dewangan
  Cc: lrg, broonie, lars, swarren, perex, clemens, alsa-devel,
	linux-kernel

At Mon, 2 Jul 2012 14:24:32 +0530,
Laxman Dewangan wrote:
> 
> Some of architecture like ARM support the writecombine DMA
> buffer which is used for pcm substream DMA buffer.
> 
> Supporting writecombine DMA buffer allocation/free/mmap
> through the sound library memory management.
> 
> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
> ---
> Changes from V1:
> Integrate the changes from Takashi's sample code for supporting
> writecombine.

Could you give a short comment in each file that ifdef CONFIG_ARM is a
workaround?


thanks,

Takashi

> 
>  include/sound/memalloc.h |    1 +
>  sound/core/memalloc.c    |   74 +++++++++++++++++++++++++++++++++++++++++-----
>  sound/core/pcm_native.c  |   10 ++++++
>  3 files changed, 77 insertions(+), 8 deletions(-)
> 
> diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
> index c425062..0328e37 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 page */
>  
>  /*
>   * info for buffer allocation
> diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
> index 6915692..7468251 100644
> --- a/sound/core/memalloc.c
> +++ b/sound/core/memalloc.c
> @@ -124,8 +124,10 @@ 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 *(*alloc_func)(struct device *dev, size_t size,
> +			dma_addr_t *dma, gfp_t gfp_flags))
>  {
>  	int pg;
>  	void *res;
> @@ -138,16 +140,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 = alloc_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 (*free_func)(struct device *dev,
> +					size_t size, void *vaddr,
> +					dma_addr_t dma_handle))
>  {
>  	int pg;
>  
> @@ -155,8 +159,51 @@ 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);
> +	free_func(dev, PAGE_SIZE << pg, ptr, dma);
> +}
> +
> +static void *_dma_alloc_coherent(struct device *dev, size_t size,
> +		dma_addr_t *dma_handle, gfp_t flag)
> +{
> +	return dma_alloc_coherent(dev, size, dma_handle, flag);
> +}
> +
> +static void _dma_free_coherent(struct device *dev, size_t size,
> +			void *vaddr, dma_addr_t dma_handle)
> +{
> +	dma_free_coherent(dev, size, vaddr, dma_handle);
> +}
> +
> +
> +/* 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, size, 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, size, ptr, dma, dma_free_writecombine);
> +}
> +#endif
>  #endif /* CONFIG_HAS_DMA */
>  
>  /*
> @@ -200,6 +247,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 +324,12 @@ 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 +436,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..28d949c 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -3170,6 +3170,16 @@ 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)
> -- 
> 1.7.1.1
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] ASoC: tegra: use sound pcm library for substream dma buffer
  2012-07-02  8:54 ` [PATCH 2/2] ASoC: tegra: use sound pcm library for substream dma buffer Laxman Dewangan
@ 2012-07-02  9:14   ` Takashi Iwai
  2012-07-02  9:56     ` Mark Brown
  0 siblings, 1 reply; 6+ messages in thread
From: Takashi Iwai @ 2012-07-02  9:14 UTC (permalink / raw)
  To: Laxman Dewangan
  Cc: lrg, broonie, lars, swarren, perex, clemens, alsa-devel,
	linux-kernel

At Mon, 2 Jul 2012 14:24:33 +0530,
Laxman Dewangan wrote:
> 
> The sound pcm library support the writecombine DMA buffer
> allocation/deallocation/mapping and hence using the APIs
> form sound pcm library inplace of implementing the same
> locally.
> 
> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
> ---
> Changes from V1:
> Changes done to use the existing APIs for sound pcm memory management
> which is now supporting writecombine.
> 
>  sound/soc/tegra/tegra_pcm.c |  112 ++++++++++--------------------------------
>  1 files changed, 27 insertions(+), 85 deletions(-)
> 
> diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
> index 127348d..ec1fa25 100644
> --- a/sound/soc/tegra/tegra_pcm.c
> +++ b/sound/soc/tegra/tegra_pcm.c
> @@ -202,8 +202,14 @@ static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
>  {
>  	struct snd_pcm_runtime *runtime = substream->runtime;
>  	struct tegra_runtime_data *prtd = runtime->private_data;
> +	int ret;
>  
> -	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
> +	ret = snd_pcm_lib_malloc_pages(substream,
> +				params_buffer_bytes(params));
> +	if (ret < 0) {
> +		pr_err("page allocation failed, err %d\n", ret);

Do you really want to spew error messages at each time?

> +		return ret;
> +	}
>  
>  	prtd->dma_req[0].size = params_period_bytes(params);
>  	prtd->dma_req[1].size = prtd->dma_req[0].size;
> @@ -213,9 +219,7 @@ static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
>  
>  static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
>  {
> -	snd_pcm_set_runtime_buffer(substream, NULL);
> -
> -	return 0;
> +	return snd_pcm_lib_free_pages(substream);
>  }
>  
>  static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
> @@ -263,18 +267,6 @@ static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream)
>  	return prtd->period_index * runtime->period_size;
>  }
>  
> -
> -static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
> -				struct vm_area_struct *vma)
> -{
> -	struct snd_pcm_runtime *runtime = substream->runtime;
> -
> -	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
> -					runtime->dma_area,
> -					runtime->dma_addr,
> -					runtime->dma_bytes);
> -}
> -
>  static struct snd_pcm_ops tegra_pcm_ops = {
>  	.open		= tegra_pcm_open,
>  	.close		= tegra_pcm_close,
> @@ -283,87 +275,37 @@ static struct snd_pcm_ops tegra_pcm_ops = {
>  	.hw_free	= tegra_pcm_hw_free,
>  	.trigger	= tegra_pcm_trigger,
>  	.pointer	= tegra_pcm_pointer,
> -	.mmap		= tegra_pcm_mmap,
> +	.mmap		= snd_pcm_lib_default_mmap,

You can simply remove .mmap definition.  NULL falls back to the
default mmap handler.

>  };
>  
> -static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
> -{
> -	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
> -	struct snd_dma_buffer *buf = &substream->dma_buffer;
> -	size_t size = tegra_pcm_hardware.buffer_bytes_max;
> -
> -	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
> -						&buf->addr, GFP_KERNEL);
> -	if (!buf->area)
> -		return -ENOMEM;
> -
> -	buf->dev.type = SNDRV_DMA_TYPE_DEV;
> -	buf->dev.dev = pcm->card->dev;
> -	buf->private_data = NULL;
> -	buf->bytes = size;
> -
> -	return 0;
> -}
> -
> -static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
> -{
> -	struct snd_pcm_substream *substream;
> -	struct snd_dma_buffer *buf;
> -
> -	substream = pcm->streams[stream].substream;
> -	if (!substream)
> -		return;
> -
> -	buf = &substream->dma_buffer;
> -	if (!buf->area)
> -		return;
> -
> -	dma_free_writecombine(pcm->card->dev, buf->bytes,
> -				buf->area, buf->addr);
> -	buf->area = NULL;
> -}
> -
> -static u64 tegra_dma_mask = DMA_BIT_MASK(32);
> -
> +#define TEGRA_PCM_PREALLOC_BUFFER	(32 * 1024)
> +#define TEGRA_PCM_PREALLOC_BUFFER_MAX	(32 * 1024)
>  static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
>  {
> -	struct snd_card *card = rtd->card->snd_card;
>  	struct snd_pcm *pcm = rtd->pcm;
> -	int ret = 0;
> -
> -	if (!card->dev->dma_mask)
> -		card->dev->dma_mask = &tegra_dma_mask;
> -	if (!card->dev->coherent_dma_mask)
> -		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);

The mask setup is still required even if you use the preallocation
helper.

> -	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
> -		ret = tegra_pcm_preallocate_dma_buffer(pcm,
> -						SNDRV_PCM_STREAM_PLAYBACK);
> -		if (ret)
> -			goto err;
> -	}
> -
> -	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
> -		ret = tegra_pcm_preallocate_dma_buffer(pcm,
> -						SNDRV_PCM_STREAM_CAPTURE);
> -		if (ret)
> -			goto err_free_play;
> +	struct snd_card *card = rtd->card->snd_card;
> +	int retval = 0;
> +
> +	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
> +			pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {

You can omit this check.  snd_pcm_lib_preallocate_pages_for_all() will
ignore the streams that have no substreams assigned.


Takashi


> +		retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
> +				SNDRV_DMA_TYPE_DEV_WC,
> +				card->dev,
> +				TEGRA_PCM_PREALLOC_BUFFER,
> +				TEGRA_PCM_PREALLOC_BUFFER_MAX);
> +		if (retval < 0)
> +			dev_err(card->dev,
> +				"dma buffer pre-alloc failied %d\n", retval);
>  	}
> -
> -	return 0;
> -
> -err_free_play:
> -	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
> -err:
> -	return ret;
> +	return retval;
>  }
>  
>  static void tegra_pcm_free(struct snd_pcm *pcm)
>  {
> -	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
> -	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
> +	snd_pcm_lib_preallocate_free_for_all(pcm);
>  }
>  
> +
>  static struct snd_soc_platform_driver tegra_pcm_platform = {
>  	.ops		= &tegra_pcm_ops,
>  	.pcm_new	= tegra_pcm_new,
> -- 
> 1.7.1.1
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] ASoC: tegra: use sound pcm library for substream dma buffer
  2012-07-02  9:14   ` Takashi Iwai
@ 2012-07-02  9:56     ` Mark Brown
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2012-07-02  9:56 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Laxman Dewangan, lrg, lars, swarren, perex, clemens, alsa-devel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 541 bytes --]

On Mon, Jul 02, 2012 at 11:14:55AM +0200, Takashi Iwai wrote:
> Laxman Dewangan wrote:

> > -	if (!card->dev->dma_mask)
> > -		card->dev->dma_mask = &tegra_dma_mask;
> > -	if (!card->dev->coherent_dma_mask)
> > -		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);

> The mask setup is still required even if you use the preallocation
> helper.

Though that code is at least notionally buggy anyway, it should be the
DMA controller device that's used to obtain the DMA mask rather than the
card device which is basically unconnected with DMA.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2012-07-02  9:56 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-07-02  8:54 [PATCH V2 0/2] ASoC: Move pcm writecombine dma buffer allocation to core Laxman Dewangan
2012-07-02  8:54 ` [PATCH V2 1/2] ALSA: Support writecombine DMA buffer memory page alloc/free Laxman Dewangan
2012-07-02  9:09   ` Takashi Iwai
2012-07-02  8:54 ` [PATCH 2/2] ASoC: tegra: use sound pcm library for substream dma buffer Laxman Dewangan
2012-07-02  9:14   ` Takashi Iwai
2012-07-02  9:56     ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox