Skip to content

Commit

Permalink
ASoC: Samsung: Do not queue cyclic buffers multiple times
Browse files Browse the repository at this point in the history
The legacy S3C-DMA API required every period of a cyclic buffer to be
queued separately. After conversion of Samsung ASoC to Samsung DMA
wrappers somebody made an assumption that the same is needed for DMA
engine API, which is not true.

In effect, Samsung ASoC DMA code was queuing the whole cyclic buffer
multiple times with a shift of one period per iteration, leading to:
  a) severe memory waste - up to 13x times more DMA transfer descriptors
     are allocated than needed,
  b) possible memory corruption, because further cyclic buffers were out
     of the original buffers, due to the offset.

This patch fixes this problem by making the legacy S3C-DMA API use the
same semantics as DMA engine (the whole cyclic buffer is enqueued at
once) and modifying users of Samsung DMA wrappers in cyclic mode to
behave appropriately.

Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Mark Brown <broonie@linaro.org>
  • Loading branch information
Tomasz Figa authored and Mark Brown committed Aug 29, 2013
1 parent 06b10ff commit 9b9ae16
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 2 deletions.
13 changes: 11 additions & 2 deletions arch/arm/plat-samsung/s3c-dma-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ static int s3c_dma_config(unsigned ch, struct samsung_dma_config *param)
static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
{
struct cb_data *data;
int len = (param->cap == DMA_CYCLIC) ? param->period : param->len;
dma_addr_t pos = param->buf;
dma_addr_t end = param->buf + param->len;

list_for_each_entry(data, &dma_list, node)
if (data->ch == ch)
Expand All @@ -94,7 +95,15 @@ static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
data->fp_param = param->fp_param;
}

s3c2410_dma_enqueue(ch, (void *)data, param->buf, len);
if (param->cap != DMA_CYCLIC) {
s3c2410_dma_enqueue(ch, (void *)data, param->buf, param->len);
return 0;
}

while (pos < end) {
s3c2410_dma_enqueue(ch, (void *)data, pos, param->period);
pos += param->period;
}

return 0;
}
Expand Down
7 changes: 7 additions & 0 deletions sound/soc/samsung/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ static void dma_enqueue(struct snd_pcm_substream *substream)
dma_info.period = prtd->dma_period;
dma_info.len = prtd->dma_period*limit;

if (dma_info.cap == DMA_CYCLIC) {
dma_info.buf = pos;
prtd->params->ops->prepare(prtd->params->ch, &dma_info);
prtd->dma_loaded += limit;
return;
}

while (prtd->dma_loaded < limit) {
pr_debug("dma_loaded: %d\n", prtd->dma_loaded);

Expand Down

0 comments on commit 9b9ae16

Please sign in to comment.