diff mbox

[v1,1/6] dmaengine: idma64: improve residue estimation

Message ID 1442220941-15487-2-git-send-email-andriy.shevchenko@linux.intel.com (mailing list archive)
State Accepted
Headers show

Commit Message

Andy Shevchenko Sept. 14, 2015, 8:55 a.m. UTC
The residue calculation may provide a wrong estimation when the transfer is
started. There are possible scenarios we have to separate:

	1) the transfer is not started yet; residue is equal to the total
	   length;

	2) the transfer is just started (first chunk is ongoing); residue is
	   equal to the total length without already transfered bytes;

	3) the transfer is ongoing and we already sent few chunks of data;
	   residue is equal to the total length without fully transfered chunks
	   and already sent bytes.

Mistakenly the calculation in cases 2) and 3) was done in the similar way and
the result is equal to -bytes that have been transfered, i.e. quite big since
size_t type can't keep negative values.

Rewrite the calculation algorithm to be one pass and have a correct result.

Besides above in case user asks for a status of the active DMA descriptor
without pausing an ongoing transfer the residue will be estimated based on the
register value, though it's still racy. Since the transfer is active the value
is continuously being changed. Here we have to read two registers at a time. To
minimize an error make those reads close to each other.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/idma64.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
diff mbox

Patch

diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
index 18c14e1..48d6d9e 100644
--- a/drivers/dma/idma64.c
+++ b/drivers/dma/idma64.c
@@ -355,23 +355,23 @@  static size_t idma64_active_desc_size(struct idma64_chan *idma64c)
 	struct idma64_desc *desc = idma64c->desc;
 	struct idma64_hw_desc *hw;
 	size_t bytes = desc->length;
-	u64 llp;
-	u32 ctlhi;
+	u64 llp = channel_readq(idma64c, LLP);
+	u32 ctlhi = channel_readl(idma64c, CTL_HI);
 	unsigned int i = 0;
 
-	llp = channel_readq(idma64c, LLP);
 	do {
 		hw = &desc->hw[i];
-	} while ((hw->llp != llp) && (++i < desc->ndesc));
+		if (hw->llp == llp)
+			break;
+		bytes -= hw->len;
+	} while (++i < desc->ndesc);
 
 	if (!i)
 		return bytes;
 
-	do {
-		bytes -= desc->hw[--i].len;
-	} while (i);
+	/* The current chunk is not fully transfered yet */
+	bytes += desc->hw[--i].len;
 
-	ctlhi = channel_readl(idma64c, CTL_HI);
 	return bytes - IDMA64C_CTLH_BLOCK_TS(ctlhi);
 }