summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJassi Brar <jassi.brar@samsung.com>2009-11-05 13:44:33 +0900
committerBen Dooks <ben-linux@fluff.org>2009-11-09 23:51:03 +0000
commit9b08284bf22f438baa2d6b68015ff17ddb431a61 (patch)
treee264f4a7dcaaac278f7978390f062cc8a663ab99
parent7507f39c57d4a285aea11c379fbc65c2b3f375ef (diff)
downloadop-kernel-dev-9b08284bf22f438baa2d6b68015ff17ddb431a61.zip
op-kernel-dev-9b08284bf22f438baa2d6b68015ff17ddb431a61.tar.gz
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>
-rw-r--r--arch/arm/plat-s3c64xx/dma.c29
1 files changed, 28 insertions, 1 deletions
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 @@ static irqreturn_t s3c64xx_dma_irq(int irq, void *pw)
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 @@ static irqreturn_t s3c64xx_dma_irq(int irq, void *pw)
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;
OpenPOWER on IntegriCloud