Re: [PATCH] WIP: at_xdmac: fix residue computation

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

 



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



[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