diff options
author | Jassi Brar <jassi.brar@samsung.com> | 2009-11-05 07:44:33 +0300 |
---|---|---|
committer | Ben Dooks <ben-linux@fluff.org> | 2009-11-10 02:51:03 +0300 |
commit | 9b08284bf22f438baa2d6b68015ff17ddb431a61 (patch) | |
tree | e264f4a7dcaaac278f7978390f062cc8a663ab99 /arch/arm | |
parent | 7507f39c57d4a285aea11c379fbc65c2b3f375ef (diff) | |
download | linux-9b08284bf22f438baa2d6b68015ff17ddb431a61.tar.xz |
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>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/plat-s3c64xx/dma.c | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/arch/arm/plat-s3c64xx/dma.c b/arch/arm/plat-s3c64xx/dma.c index a94281bb84d6..7d12eb8fa58d 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; |