2016-12-02 10:50:26 +00:00
|
|
|
From 42504be159b0fd85d705265dceec01c74d853478 Mon Sep 17 00:00:00 2001
|
2016-07-07 07:22:07 +00:00
|
|
|
From: Eric Anholt <eric@anholt.net>
|
|
|
|
Date: Fri, 3 Jun 2016 19:29:11 -0700
|
2016-09-10 12:54:26 +00:00
|
|
|
Subject: [PATCH] dmaengine: bcm2835: Fix polling for completion of DMA with
|
|
|
|
interrupts masked.
|
2016-07-07 07:22:07 +00:00
|
|
|
|
|
|
|
The tx_status hook is supposed to be safe to call from interrupt
|
|
|
|
context, but it wouldn't ever return completion for the last transfer,
|
|
|
|
meaning you couldn't poll for DMA completion with interrupts masked.
|
|
|
|
|
|
|
|
This fixes IRQ handling for bcm2835's DSI1, which requires using the
|
|
|
|
DMA engine to write its registers due to a bug in the AXI bridge.
|
|
|
|
|
|
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
|
|
---
|
|
|
|
drivers/dma/bcm2835-dma.c | 24 +++++++++++++++++++-----
|
|
|
|
1 file changed, 19 insertions(+), 5 deletions(-)
|
|
|
|
|
|
|
|
--- a/drivers/dma/bcm2835-dma.c
|
|
|
|
+++ b/drivers/dma/bcm2835-dma.c
|
|
|
|
@@ -588,16 +588,16 @@ static enum dma_status bcm2835_dma_tx_st
|
|
|
|
struct virt_dma_desc *vd;
|
|
|
|
enum dma_status ret;
|
|
|
|
unsigned long flags;
|
|
|
|
+ u32 residue;
|
|
|
|
|
|
|
|
ret = dma_cookie_status(chan, cookie, txstate);
|
|
|
|
- if (ret == DMA_COMPLETE || !txstate)
|
|
|
|
+ if (ret == DMA_COMPLETE)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&c->vc.lock, flags);
|
|
|
|
vd = vchan_find_desc(&c->vc, cookie);
|
|
|
|
if (vd) {
|
|
|
|
- txstate->residue =
|
|
|
|
- bcm2835_dma_desc_size(to_bcm2835_dma_desc(&vd->tx));
|
|
|
|
+ residue = bcm2835_dma_desc_size(to_bcm2835_dma_desc(&vd->tx));
|
|
|
|
} else if (c->desc && c->desc->vd.tx.cookie == cookie) {
|
|
|
|
struct bcm2835_desc *d = c->desc;
|
|
|
|
dma_addr_t pos;
|
|
|
|
@@ -609,11 +609,25 @@ static enum dma_status bcm2835_dma_tx_st
|
|
|
|
else
|
|
|
|
pos = 0;
|
|
|
|
|
|
|
|
- txstate->residue = bcm2835_dma_desc_size_pos(d, pos);
|
|
|
|
+ residue = bcm2835_dma_desc_size_pos(d, pos);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If our non-cyclic transfer is done, then report
|
|
|
|
+ * complete and trigger the next tx now. This lets
|
|
|
|
+ * the dmaengine API be used synchronously from an IRQ
|
|
|
|
+ * handler.
|
|
|
|
+ */
|
|
|
|
+ if (!d->cyclic && residue == 0) {
|
|
|
|
+ vchan_cookie_complete(&c->desc->vd);
|
|
|
|
+ bcm2835_dma_start_desc(c);
|
|
|
|
+ ret = dma_cookie_status(chan, cookie, txstate);
|
|
|
|
+ }
|
|
|
|
} else {
|
|
|
|
- txstate->residue = 0;
|
|
|
|
+ residue = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ dma_set_residue(txstate, residue);
|
|
|
|
+
|
|
|
|
spin_unlock_irqrestore(&c->vc.lock, flags);
|
|
|
|
|
|
|
|
return ret;
|