[alsa-devel] [PATCH 2/2] ASoC: tegra: use sound pcm library for substream dma buffer

Takashi Iwai tiwai at suse.de
Mon Jul 2 11:14:55 CEST 2012


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 at 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
> 


More information about the Alsa-devel mailing list