ARM: S3C64XX: DMA: Callback with correct buffer pointer
buffdone callback should be called per buffer request with pointer
to the latest serviced request.
'next' should point to the one next to currently active.
Signed-off-by: Jassi Brar <jassi.brar@samsung.com>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
diff --git a/arch/arm/plat-s3c64xx/dma.c b/arch/arm/plat-s3c64xx/dma.c
index a94281b..7d12eb8f 100644
--- a/arch/arm/plat-s3c64xx/dma.c
+++ b/arch/arm/plat-s3c64xx/dma.c
@@ -576,6 +576,7 @@
errstat = readl(dmac->regs + PL080_ERR_STATUS);
for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) {
+ struct s3c64xx_dma_buff *buff;
if (!(errstat & bit) && !(tcstat & bit))
continue;
@@ -591,7 +592,33 @@
if (errstat & bit)
writel(bit, dmac->regs + PL080_ERR_CLEAR);
- s3c64xx_dma_bufffdone(chan, chan->curr, res);
+ /* 'next' points to the buffer that is next to the
+ * currently active buffer.
+ * For CIRCULAR queues, 'next' will be same as 'curr'
+ * when 'end' is the active buffer.
+ */
+ buff = chan->curr;
+ while (buff && buff != chan->next
+ && buff->next != chan->next)
+ buff = buff->next;
+
+ if (!buff)
+ BUG();
+
+ if (buff == chan->next)
+ buff = chan->end;
+
+ s3c64xx_dma_bufffdone(chan, buff, res);
+
+ /* Update 'next' */
+ buff = chan->next;
+ if (chan->next == chan->end) {
+ chan->next = chan->curr;
+ if (!(chan->flags & S3C2410_DMAF_CIRCULAR))
+ chan->end = NULL;
+ } else {
+ chan->next = buff->next;
+ }
}
return IRQ_HANDLED;