Skip to content

Commit 25c5e96

Browse files
ldesrochesVinod Koul
authored andcommitted
dmaengine: at_xdmac: fix residue computation
When computing the residue we need two pieces of information: the current descriptor and the remaining data of the current descriptor. To get that information, we need to read consecutively two registers but we can't do it in an atomic way. For that reason, we have to check manually that current descriptor has not changed. Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Suggested-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> Reported-by: David Engraf <david.engraf@sysgo.com> Tested-by: David Engraf <david.engraf@sysgo.com> Fixes: e1f7c9e ("dmaengine: at_xdmac: creation of the atmel eXtended DMA Controller driver") Cc: stable@vger.kernel.org #4.1 and later Signed-off-by: Vinod Koul <vinod.koul@intel.com>
1 parent a9af316 commit 25c5e96

File tree

1 file changed

+39
-3
lines changed

1 file changed

+39
-3
lines changed

drivers/dma/at_xdmac.c

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@
176176
#define AT_XDMAC_MAX_CHAN 0x20
177177
#define AT_XDMAC_MAX_CSIZE 16 /* 16 data */
178178
#define AT_XDMAC_MAX_DWIDTH 8 /* 64 bits */
179+
#define AT_XDMAC_RESIDUE_MAX_RETRIES 5
179180

180181
#define AT_XDMAC_DMA_BUSWIDTHS\
181182
(BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
@@ -1395,8 +1396,8 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
13951396
struct at_xdmac_desc *desc, *_desc;
13961397
struct list_head *descs_list;
13971398
enum dma_status ret;
1398-
int residue;
1399-
u32 cur_nda, mask, value;
1399+
int residue, retry;
1400+
u32 cur_nda, check_nda, cur_ubc, mask, value;
14001401
u8 dwidth = 0;
14011402
unsigned long flags;
14021403

@@ -1433,7 +1434,42 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
14331434
cpu_relax();
14341435
}
14351436

1437+
/*
1438+
* When processing the residue, we need to read two registers but we
1439+
* can't do it in an atomic way. AT_XDMAC_CNDA is used to find where
1440+
* we stand in the descriptor list and AT_XDMAC_CUBC is used
1441+
* to know how many data are remaining for the current descriptor.
1442+
* Since the dma channel is not paused to not loose data, between the
1443+
* AT_XDMAC_CNDA and AT_XDMAC_CUBC read, we may have change of
1444+
* descriptor.
1445+
* For that reason, after reading AT_XDMAC_CUBC, we check if we are
1446+
* still using the same descriptor by reading a second time
1447+
* AT_XDMAC_CNDA. If AT_XDMAC_CNDA has changed, it means we have to
1448+
* read again AT_XDMAC_CUBC.
1449+
* Memory barriers are used to ensure the read order of the registers.
1450+
* A max number of retries is set because unlikely it can never ends if
1451+
* we are transferring a lot of data with small buffers.
1452+
*/
14361453
cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
1454+
rmb();
1455+
cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
1456+
for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) {
1457+
rmb();
1458+
check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
1459+
1460+
if (likely(cur_nda == check_nda))
1461+
break;
1462+
1463+
cur_nda = check_nda;
1464+
rmb();
1465+
cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
1466+
}
1467+
1468+
if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) {
1469+
ret = DMA_ERROR;
1470+
goto spin_unlock;
1471+
}
1472+
14371473
/*
14381474
* Remove size of all microblocks already transferred and the current
14391475
* one. Then add the remaining size to transfer of the current
@@ -1446,7 +1482,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
14461482
if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda)
14471483
break;
14481484
}
1449-
residue += at_xdmac_chan_read(atchan, AT_XDMAC_CUBC) << dwidth;
1485+
residue += cur_ubc << dwidth;
14501486

14511487
dma_set_residue(txstate, residue);
14521488

0 commit comments

Comments
 (0)