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

From: Takashi Iwai
Date: Mon Jul 02 2012 - 05:14:52 EST


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@xxxxxxxxxx>
> ---
> 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
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/