[PATCH] at_xdmac fix status read in cyclic mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I encountered an issue when using atmel_serial.c driver with at_xdmac.c on a SAMA5D4 board. The serial driver uses a cyclic DMA receive buffer. While doing tests with a high baudrate and high data load, at_xdmac_tx_status() sometimes returns an invalid value for residue. This happens when the serial driver calls dmaengine_tx_status() while the DMA is still in progress (DMA_IN_PROGRESS). In this case, going through the microblock list is not save because the content might be modified. This may happen when AT_XDMAC_CNDA has been changed while going through the list.

The only reliable solution working in my test scenario was to pause and resume the DMA channel when it is in progress.


Signed-off-by: David Engraf <david.engraf@xxxxxxxxx>

diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 64f5d1b..295a06a 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -254,6 +254,9 @@ struct at_xdmac_desc {
 	struct list_head		xfer_node;
 };
 
+static int at_xdmac_device_pause(struct dma_chan *chan);
+static int at_xdmac_device_resume(struct dma_chan *chan);
+
 static inline void __iomem *at_xdmac_chan_reg_base(struct at_xdmac *atxdmac, unsigned int chan_nb)
 {
 	return atxdmac->regs + (AT_XDMAC_CHAN_REG_BASE + chan_nb * 0x40);
@@ -1407,6 +1410,11 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
 	if (!txstate)
 		return ret;
 
+	if (ret == DMA_IN_PROGRESS) {
+		/* pause DMA while calculating residue */
+		at_xdmac_device_pause(chan);
+	}
+
 	spin_lock_irqsave(&atchan->lock, flags);
 
 	desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc, xfer_node);
@@ -1456,6 +1464,10 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
 
 spin_unlock:
 	spin_unlock_irqrestore(&atchan->lock, flags);
+
+	if (ret == DMA_IN_PROGRESS)
+		at_xdmac_device_resume(chan);
+
 	return ret;
 }
 

[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux PCI]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux