diff options
author | Ryo Kataoka <ryo.kataoka.wt@renesas.com> | 2019-03-22 20:50:18 +0900 |
---|---|---|
committer | Ryo Kataoka <ryo.kataoka.wt@renesas.com> | 2019-03-22 20:50:18 +0900 |
commit | 06b0b90a4d223c158cd460d430207f823c1ef8b7 (patch) | |
tree | 79dffe7e06426a18a28735bde2714c6bcb597f8d | |
parent | 0043eec1e00e4ed5265fca2fb36385c9b184bf75 (diff) | |
parent | 083b06046249b84eea2cf19476cd5b8afd7cea4f (diff) | |
download | renesas-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.c | 28 |
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); |