summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorTomasz Figa <tomasz.figa@gmail.com>2013-08-11 19:59:21 +0200
committerChanho Park <chanho61.park@samsung.com>2014-11-18 11:47:26 +0900
commit24ab37a6b044518f10d1266794f3460be743e621 (patch)
treeb569686d8a528afe44d3fdee918fa403b299ce31 /arch
parentd87e337e636ea8ece17715af4318cdd2aacac1cd (diff)
downloadlinux-3.10-24ab37a6b044518f10d1266794f3460be743e621.tar.gz
linux-3.10-24ab37a6b044518f10d1266794f3460be743e621.tar.bz2
linux-3.10-24ab37a6b044518f10d1266794f3460be743e621.zip
ASoC: Samsung: Do not queue cyclic buffers multiple times
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. Change-Id: Ib9e656c40ef71e2e90af3f008959eeae19ce7d7e 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>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/plat-samsung/s3c-dma-ops.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c
index 0cc40aea3f5..98b10ba67dc 100644
--- a/arch/arm/plat-samsung/s3c-dma-ops.c
+++ b/arch/arm/plat-samsung/s3c-dma-ops.c
@@ -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)
@@ -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;
}