diff options
| -rw-r--r-- | drivers/dma/sh/rcar-dmac.c | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 54810ffd95e2..e2a5398f89b5 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c | |||
| @@ -1282,6 +1282,9 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan, | |||
| 1282 | enum dma_status status; | 1282 | enum dma_status status; |
| 1283 | unsigned int residue = 0; | 1283 | unsigned int residue = 0; |
| 1284 | unsigned int dptr = 0; | 1284 | unsigned int dptr = 0; |
| 1285 | unsigned int chcrb; | ||
| 1286 | unsigned int tcrb; | ||
| 1287 | unsigned int i; | ||
| 1285 | 1288 | ||
| 1286 | if (!desc) | 1289 | if (!desc) |
| 1287 | return 0; | 1290 | return 0; |
| @@ -1330,14 +1333,31 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan, | |||
| 1330 | } | 1333 | } |
| 1331 | 1334 | ||
| 1332 | /* | 1335 | /* |
| 1336 | * We need to read two registers. | ||
| 1337 | * Make sure the control register does not skip to next chunk | ||
| 1338 | * while reading the counter. | ||
| 1339 | * Trying it 3 times should be enough: Initial read, retry, retry | ||
| 1340 | * for the paranoid. | ||
| 1341 | */ | ||
| 1342 | for (i = 0; i < 3; i++) { | ||
| 1343 | chcrb = rcar_dmac_chan_read(chan, RCAR_DMACHCRB) & | ||
| 1344 | RCAR_DMACHCRB_DPTR_MASK; | ||
| 1345 | tcrb = rcar_dmac_chan_read(chan, RCAR_DMATCRB); | ||
| 1346 | /* Still the same? */ | ||
| 1347 | if (chcrb == (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) & | ||
| 1348 | RCAR_DMACHCRB_DPTR_MASK)) | ||
| 1349 | break; | ||
| 1350 | } | ||
| 1351 | WARN_ONCE(i >= 3, "residue might be not continuous!"); | ||
| 1352 | |||
| 1353 | /* | ||
| 1333 | * In descriptor mode the descriptor running pointer is not maintained | 1354 | * In descriptor mode the descriptor running pointer is not maintained |
| 1334 | * by the interrupt handler, find the running descriptor from the | 1355 | * by the interrupt handler, find the running descriptor from the |
| 1335 | * descriptor pointer field in the CHCRB register. In non-descriptor | 1356 | * descriptor pointer field in the CHCRB register. In non-descriptor |
| 1336 | * mode just use the running descriptor pointer. | 1357 | * mode just use the running descriptor pointer. |
| 1337 | */ | 1358 | */ |
| 1338 | if (desc->hwdescs.use) { | 1359 | if (desc->hwdescs.use) { |
| 1339 | dptr = (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) & | 1360 | dptr = chcrb >> RCAR_DMACHCRB_DPTR_SHIFT; |
| 1340 | RCAR_DMACHCRB_DPTR_MASK) >> RCAR_DMACHCRB_DPTR_SHIFT; | ||
| 1341 | if (dptr == 0) | 1361 | if (dptr == 0) |
| 1342 | dptr = desc->nchunks; | 1362 | dptr = desc->nchunks; |
| 1343 | dptr--; | 1363 | dptr--; |
| @@ -1355,7 +1375,7 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan, | |||
| 1355 | } | 1375 | } |
| 1356 | 1376 | ||
| 1357 | /* Add the residue for the current chunk. */ | 1377 | /* Add the residue for the current chunk. */ |
| 1358 | residue += rcar_dmac_chan_read(chan, RCAR_DMATCRB) << desc->xfer_shift; | 1378 | residue += tcrb << desc->xfer_shift; |
| 1359 | 1379 | ||
| 1360 | return residue; | 1380 | return residue; |
| 1361 | } | 1381 | } |
