diff options
| -rw-r--r-- | drivers/dma/at_xdmac.c | 54 |
1 files changed, 32 insertions, 22 deletions
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index ba9b0b73fa47..b02494e115fe 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c | |||
| @@ -1400,6 +1400,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, | |||
| 1400 | u32 cur_nda, check_nda, cur_ubc, mask, value; | 1400 | u32 cur_nda, check_nda, cur_ubc, mask, value; |
| 1401 | u8 dwidth = 0; | 1401 | u8 dwidth = 0; |
| 1402 | unsigned long flags; | 1402 | unsigned long flags; |
| 1403 | bool initd; | ||
| 1403 | 1404 | ||
| 1404 | ret = dma_cookie_status(chan, cookie, txstate); | 1405 | ret = dma_cookie_status(chan, cookie, txstate); |
| 1405 | if (ret == DMA_COMPLETE) | 1406 | if (ret == DMA_COMPLETE) |
| @@ -1435,34 +1436,43 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, | |||
| 1435 | } | 1436 | } |
| 1436 | 1437 | ||
| 1437 | /* | 1438 | /* |
| 1438 | * When processing the residue, we need to read two registers but we | 1439 | * The easiest way to compute the residue should be to pause the DMA |
| 1439 | * can't do it in an atomic way. AT_XDMAC_CNDA is used to find where | 1440 | * but doing this can lead to miss some data as some devices don't |
| 1440 | * we stand in the descriptor list and AT_XDMAC_CUBC is used | 1441 | * have FIFO. |
| 1441 | * to know how many data are remaining for the current descriptor. | 1442 | * We need to read several registers because: |
| 1442 | * Since the dma channel is not paused to not loose data, between the | 1443 | * - DMA is running therefore a descriptor change is possible while |
| 1443 | * AT_XDMAC_CNDA and AT_XDMAC_CUBC read, we may have change of | 1444 | * reading these registers |
| 1444 | * descriptor. | 1445 | * - When the block transfer is done, the value of the CUBC register |
| 1445 | * For that reason, after reading AT_XDMAC_CUBC, we check if we are | 1446 | * is set to its initial value until the fetch of the next descriptor. |
| 1446 | * still using the same descriptor by reading a second time | 1447 | * This value will corrupt the residue calculation so we have to skip |
| 1447 | * AT_XDMAC_CNDA. If AT_XDMAC_CNDA has changed, it means we have to | 1448 | * it. |
| 1448 | * read again AT_XDMAC_CUBC. | 1449 | * |
| 1450 | * INITD -------- ------------ | ||
| 1451 | * |____________________| | ||
| 1452 | * _______________________ _______________ | ||
| 1453 | * NDA @desc2 \/ @desc3 | ||
| 1454 | * _______________________/\_______________ | ||
| 1455 | * __________ ___________ _______________ | ||
| 1456 | * CUBC 0 \/ MAX desc1 \/ MAX desc2 | ||
| 1457 | * __________/\___________/\_______________ | ||
| 1458 | * | ||
| 1459 | * Since descriptors are aligned on 64 bits, we can assume that | ||
| 1460 | * the update of NDA and CUBC is atomic. | ||
| 1449 | * Memory barriers are used to ensure the read order of the registers. | 1461 | * Memory barriers are used to ensure the read order of the registers. |
| 1450 | * A max number of retries is set because unlikely it can never ends if | 1462 | * A max number of retries is set because unlikely it could never ends. |
| 1451 | * we are transferring a lot of data with small buffers. | ||
| 1452 | */ | 1463 | */ |
| 1453 | cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; | ||
| 1454 | rmb(); | ||
| 1455 | cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); | ||
| 1456 | for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) { | 1464 | for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) { |
| 1457 | rmb(); | ||
| 1458 | check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; | 1465 | check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; |
| 1459 | 1466 | rmb(); | |
| 1460 | if (likely(cur_nda == check_nda)) | 1467 | initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD); |
| 1461 | break; | ||
| 1462 | |||
| 1463 | cur_nda = check_nda; | ||
| 1464 | rmb(); | 1468 | rmb(); |
| 1465 | cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); | 1469 | cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); |
| 1470 | rmb(); | ||
| 1471 | cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; | ||
| 1472 | rmb(); | ||
| 1473 | |||
| 1474 | if ((check_nda == cur_nda) && initd) | ||
| 1475 | break; | ||
| 1466 | } | 1476 | } |
| 1467 | 1477 | ||
| 1468 | if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) { | 1478 | if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) { |
