Skip to content

Commit 16614f4

Browse files
ldesrochesDinh Nguyen
authored andcommitted
dmaengine: at_xdmac: fix residue computation
[ Upstream commit 25c5e96 ] 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 <[email protected]> Suggested-by: Cyrille Pitchen <[email protected]> Reported-by: David Engraf <[email protected]> Tested-by: David Engraf <[email protected]> Fixes: e1f7c9e ("dmaengine: at_xdmac: creation of the atmel eXtended DMA Controller driver") Cc: [email protected] #4.1 and later Signed-off-by: Vinod Koul <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent c6b7921 commit 16614f4

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) |\
@@ -925,8 +926,8 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
925926
struct at_xdmac_desc *desc, *_desc;
926927
struct list_head *descs_list;
927928
enum dma_status ret;
928-
int residue;
929-
u32 cur_nda, mask, value;
929+
int residue, retry;
930+
u32 cur_nda, check_nda, cur_ubc, mask, value;
930931
u8 dwidth = 0;
931932
unsigned long flags;
932933

@@ -963,7 +964,42 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
963964
cpu_relax();
964965
}
965966

967+
/*
968+
* When processing the residue, we need to read two registers but we
969+
* can't do it in an atomic way. AT_XDMAC_CNDA is used to find where
970+
* we stand in the descriptor list and AT_XDMAC_CUBC is used
971+
* to know how many data are remaining for the current descriptor.
972+
* Since the dma channel is not paused to not loose data, between the
973+
* AT_XDMAC_CNDA and AT_XDMAC_CUBC read, we may have change of
974+
* descriptor.
975+
* For that reason, after reading AT_XDMAC_CUBC, we check if we are
976+
* still using the same descriptor by reading a second time
977+
* AT_XDMAC_CNDA. If AT_XDMAC_CNDA has changed, it means we have to
978+
* read again AT_XDMAC_CUBC.
979+
* Memory barriers are used to ensure the read order of the registers.
980+
* A max number of retries is set because unlikely it can never ends if
981+
* we are transferring a lot of data with small buffers.
982+
*/
966983
cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
984+
rmb();
985+
cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
986+
for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) {
987+
rmb();
988+
check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
989+
990+
if (likely(cur_nda == check_nda))
991+
break;
992+
993+
cur_nda = check_nda;
994+
rmb();
995+
cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
996+
}
997+
998+
if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) {
999+
ret = DMA_ERROR;
1000+
goto spin_unlock;
1001+
}
1002+
9671003
/*
9681004
* Remove size of all microblocks already transferred and the current
9691005
* one. Then add the remaining size to transfer of the current
@@ -976,7 +1012,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
9761012
if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda)
9771013
break;
9781014
}
979-
residue += at_xdmac_chan_read(atchan, AT_XDMAC_CUBC) << dwidth;
1015+
residue += cur_ubc << dwidth;
9801016

9811017
dma_set_residue(txstate, residue);
9821018

0 commit comments

Comments
 (0)