aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyo Kataoka <ryo.kataoka.wt@renesas.com>2019-03-22 20:50:18 +0900
committerRyo Kataoka <ryo.kataoka.wt@renesas.com>2019-03-22 20:50:18 +0900
commit06b0b90a4d223c158cd460d430207f823c1ef8b7 (patch)
tree79dffe7e06426a18a28735bde2714c6bcb597f8d
parent0043eec1e00e4ed5265fca2fb36385c9b184bf75 (diff)
parent083b06046249b84eea2cf19476cd5b8afd7cea4f (diff)
downloadrenesas-bsp-06b0b90a4d223c158cd460d430207f823c1ef8b7.tar.gz
Merge branch 'rcar-3.9.2/dmae.rc1' into v4.14.75-ltsi/rcar-3.9.3
* rcar-3.9.2/dmae.rc1: dmaengine: sh: rcar-dmac: Fix glitch in dmaengine_tx_status dmaengine: sh: rcar-dmac: With cyclic DMA residue 0 is valid
-rw-r--r--drivers/dma/sh/rcar-dmac.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 218c5b0e9569d..979efc62cca6e 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -1291,6 +1291,9 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
enum dma_status status;
unsigned int residue = 0;
unsigned int dptr = 0;
+ unsigned int chcrb;
+ unsigned int tcrb;
+ unsigned int i;
if (!desc)
return 0;
@@ -1339,14 +1342,31 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
}
/*
+ * We need to read two registers.
+ * Make sure the control register does not skip to next chunk
+ * while reading the counter.
+ * Trying it 3 times should be enough: Initial read, retry, retry
+ * for the paranoid.
+ */
+ for (i = 0; i < 3; i++) {
+ chcrb = rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
+ RCAR_DMACHCRB_DPTR_MASK;
+ tcrb = rcar_dmac_chan_read(chan, RCAR_DMATCRB);
+ /* Still the same? */
+ if (chcrb == (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
+ RCAR_DMACHCRB_DPTR_MASK))
+ break;
+ }
+ WARN_ONCE(i >= 3, "residue might be not continuous!");
+
+ /*
* In descriptor mode the descriptor running pointer is not maintained
* by the interrupt handler, find the running descriptor from the
* descriptor pointer field in the CHCRB register. In non-descriptor
* mode just use the running descriptor pointer.
*/
if (desc->hwdescs.use) {
- dptr = (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
- RCAR_DMACHCRB_DPTR_MASK) >> RCAR_DMACHCRB_DPTR_SHIFT;
+ dptr = chcrb >> RCAR_DMACHCRB_DPTR_SHIFT;
if (dptr == 0)
dptr = desc->nchunks;
dptr--;
@@ -1364,7 +1384,7 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
}
/* Add the residue for the current chunk. */
- residue += rcar_dmac_chan_read(chan, RCAR_DMATCRB) << desc->xfer_shift;
+ residue += tcrb << desc->xfer_shift;
return residue;
}
@@ -1387,7 +1407,7 @@ static enum dma_status rcar_dmac_tx_status(struct dma_chan *chan,
spin_unlock_irqrestore(&rchan->lock, flags);
/* if there's no residue, the cookie is complete */
- if (!residue)
+ if (!residue && !rchan->desc.running->cyclic)
return DMA_COMPLETE;
dma_set_residue(txstate, residue);