提交 9295c41d 编写于 作者: L Ludovic Desroches 提交者: Vinod Koul

dmaengine: at_xdmac: double FIFO flush needed to compute residue

Due to the way CUBC register is updated, a double flush is needed to
compute an accurate residue. First flush aim is to get data from the DMA
FIFO and second one ensures that we won't report data which are not in
memory.
Signed-off-by: NLudovic Desroches <ludovic.desroches@atmel.com>
Fixes: e1f7c9ee ("dmaengine: at_xdmac: creation of the atmel
eXtended DMA Controller driver")
Cc: stable@vger.kernel.org #v4.1 and later
Reviewed-by: NNicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: NVinod Koul <vinod.koul@intel.com>
上级 53398f48
...@@ -1425,7 +1425,16 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, ...@@ -1425,7 +1425,16 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
residue = desc->xfer_size; residue = desc->xfer_size;
/* /*
* Flush FIFO: only relevant when the transfer is source peripheral * Flush FIFO: only relevant when the transfer is source peripheral
* synchronized. * synchronized. Flush is needed before reading CUBC because data in
* the FIFO are not reported by CUBC. Reporting a residue of the
* transfer length while we have data in FIFO can cause issue.
* Usecase: atmel USART has a timeout which means I have received
* characters but there is no more character received for a while. On
* timeout, it requests the residue. If the data are in the DMA FIFO,
* we will return a residue of the transfer length. It means no data
* received. If an application is waiting for these data, it will hang
* since we won't have another USART timeout without receiving new
* data.
*/ */
mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC; mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC;
value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM; value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM;
...@@ -1480,6 +1489,19 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, ...@@ -1480,6 +1489,19 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
goto spin_unlock; goto spin_unlock;
} }
/*
* Flush FIFO: only relevant when the transfer is source peripheral
* synchronized. Another flush is needed here because CUBC is updated
* when the controller sends the data write command. It can lead to
* report data that are not written in the memory or the device. The
* FIFO flush ensures that data are really written.
*/
if ((desc->lld.mbr_cfg & mask) == value) {
at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask);
while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS))
cpu_relax();
}
/* /*
* Remove size of all microblocks already transferred and the current * Remove size of all microblocks already transferred and the current
* one. Then add the remaining size to transfer of the current * one. Then add the remaining size to transfer of the current
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册