aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2015-09-14 04:55:36 -0400
committerVinod Koul <vinod.koul@intel.com>2015-09-24 22:21:16 -0400
commit0b23a1ece9be2c3e04c3b8d3594a1ada1fa1ae50 (patch)
treeb72250d28adee020ab9ca2ec7c135466ddbf15a4
parentc1492b4c541e3a382b60f1b5879cd3c4d246ad31 (diff)
dmaengine: idma64: improve residue estimation
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> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/idma64.c16
1 files changed, 8 insertions, 8 deletions
diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
index 18c14e1f1414..48d6d9e94f67 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)
355 struct idma64_desc *desc = idma64c->desc; 355 struct idma64_desc *desc = idma64c->desc;
356 struct idma64_hw_desc *hw; 356 struct idma64_hw_desc *hw;
357 size_t bytes = desc->length; 357 size_t bytes = desc->length;
358 u64 llp; 358 u64 llp = channel_readq(idma64c, LLP);
359 u32 ctlhi; 359 u32 ctlhi = channel_readl(idma64c, CTL_HI);
360 unsigned int i = 0; 360 unsigned int i = 0;
361 361
362 llp = channel_readq(idma64c, LLP);
363 do { 362 do {
364 hw = &desc->hw[i]; 363 hw = &desc->hw[i];
365 } while ((hw->llp != llp) && (++i < desc->ndesc)); 364 if (hw->llp == llp)
365 break;
366 bytes -= hw->len;
367 } while (++i < desc->ndesc);
366 368
367 if (!i) 369 if (!i)
368 return bytes; 370 return bytes;
369 371
370 do { 372 /* The current chunk is not fully transfered yet */
371 bytes -= desc->hw[--i].len; 373 bytes += desc->hw[--i].len;
372 } while (i);
373 374
374 ctlhi = channel_readl(idma64c, CTL_HI);
375 return bytes - IDMA64C_CTLH_BLOCK_TS(ctlhi); 375 return bytes - IDMA64C_CTLH_BLOCK_TS(ctlhi);
376} 376}
377 377