Re: [alsa-devel] [PATCH 2/2] ASoC: tegra: use sound pcm library for substream dma buffer
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
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.
participants (2)
-
Mark Brown
-
Takashi Iwai