aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/at_xdmac.c
diff options
context:
space:
mode:
authorCyrille Pitchen <cyrille.pitchen@atmel.com>2014-11-13 05:52:41 -0500
committerVinod Koul <vinod.koul@intel.com>2014-11-17 03:37:20 -0500
commit4e0978208d67730a316066911201a6252158d2fd (patch)
tree05341217bedf4933e44f47ab2e4157a13b048e62 /drivers/dma/at_xdmac.c
parent77e6c9bfaa622183c5fe9aa23be4822dd21038d1 (diff)
dmaengine: at_xdmac: fix software lockup at_xdmac_tx_status()
According to the Atmel eXtended DMA controller datasheet, requesting a DMA transfer flush for a channel is only revelant when this transfer is source peripheral synchronized. So we have to check this condition before requesting a channel flush by writing the channel bit into the Global channel SoftWare Flush (GSWF) register then waiting for flush to complete by monitoring the end of Flush Interrupt Status (FIS) bit in the Channel Interrupt Status (CIS) register. Indeed, for non source peripheral synchronized transfer, writing the channel bit into the GSWF register does nothing. Especially, the FIS bit is never set into the CIS register. The former code looped forever waiting for this bit to be set. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/at_xdmac.c')
-rw-r--r--drivers/dma/at_xdmac.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index fcecbaddb351..fa9d75adf4d7 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -879,7 +879,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
879 struct list_head *descs_list; 879 struct list_head *descs_list;
880 enum dma_status ret; 880 enum dma_status ret;
881 int residue; 881 int residue;
882 u32 cur_nda; 882 u32 cur_nda, mask, value;
883 u8 dwidth = at_xdmac_get_dwidth(atchan->cfg[AT_XDMAC_CUR_CFG]); 883 u8 dwidth = at_xdmac_get_dwidth(atchan->cfg[AT_XDMAC_CUR_CFG]);
884 884
885 ret = dma_cookie_status(chan, cookie, txstate); 885 ret = dma_cookie_status(chan, cookie, txstate);
@@ -903,10 +903,17 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
903 } 903 }
904 904
905 residue = desc->xfer_size; 905 residue = desc->xfer_size;
906 /* Flush FIFO. */ 906 /*
907 at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask); 907 * Flush FIFO: only relevant when the transfer is source peripheral
908 while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS)) 908 * synchronized.
909 cpu_relax(); 909 */
910 mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC;
911 value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM;
912 if ((atchan->cfg[AT_XDMAC_CUR_CFG] & mask) == value) {
913 at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask);
914 while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS))
915 cpu_relax();
916 }
910 917
911 cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; 918 cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
912 /* 919 /*