Hi Ludovic, Am 18.02.2016 um 11:48 schrieb Ludovic Desroches:
--- drivers/dma/at_xdmac.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) Hi David, I tried to adpat the fix Cyrille did for at_hdmac. I think it was exactly the same issue. We have to read two registers, one to know the descriptor currently used and one to know the residue for this descriptor. Unfortunately, between the two reads, the descriptor currently used can change. Could you try this draft patch?
It works as well with your patch. I did several runs without loosing any bytes or a wrong residue. I've also checked how often the loop needs to retry when check_nda and cur_nda is different and in all cases one more read was enough. So trying up to 5 times is a good value.
Tested-by: David Engraf <david.engraf@xxxxxxxxx> Best regards - David
Regards Ludovic diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 6b512a2..a38356e 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1395,8 +1395,8 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct at_xdmac_desc *desc, *_desc; struct list_head *descs_list; enum dma_status ret; - int residue; - u32 cur_nda, mask, value; + int residue, i; + u32 cur_nda, check_nda, cur_ubc, mask, value; u8 dwidth = 0; unsigned long flags; @@ -1434,6 +1434,25 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, } cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; + rmb(); + cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); + for (i = 0; i < 5; i++) { + rmb(); + check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; + + if (likely (cur_nda == check_nda)) + break; + + cur_nda = check_nda; + rmb(); + cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); + } + + if (unlikely(i >= 5)) { + ret = DMA_ERROR; + goto spin_unlock; + } + /* * Remove size of all microblocks already transferred and the current * one. Then add the remaining size to transfer of the current @@ -1446,7 +1465,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda) break; } - residue += at_xdmac_chan_read(atchan, AT_XDMAC_CUBC) << dwidth; + residue += cur_ubc << dwidth; dma_set_residue(txstate, residue);
-- To unsubscribe from this list: send the line "unsubscribe dmaengine" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html