Skip to content

Commit bdf6c79

Browse files
Torsten FleischerVinod Koul
Torsten Fleischer
authored and
Vinod Koul
committed
dmaengine: at_hdmac: Fix calculation of the residual bytes
This patch fixes the following issues regarding to the calculation of the residue: 1. The residue is always calculated for the current transfer even if the cookie is associated to a pending transfer. 2. For scatter/gather DMA the calculation of the residue for the current transfer doesn't include the bytes of the child descriptors that are already transferred. It only calculates the difference between the transfer's total length minus the number of bytes that are already transferred for the current child descriptor. For example: There is a scatter/gather DMA transfer with a total length of 1 MByte. Getting the residue several times while the transfer is running shows something like that: 1: residue = 975584 2: residue = 1002766 3: residue = 992627 4: residue = 983767 5: residue = 985694 6: residue = 1008094 7: residue = 1009741 8: residue = 1011195 3. The driver stores the residue but never resets it when starting a new transfer. For example: If there are two subsequent DMA transfers. The first one with a total length of 1 MByte and the second one with a total length of 1 kByte. Getting the residue for both transfers shows something like that: transfer 1: residue = 975584 transfer 2: residue = 1048380 Changes from V1: * Fixed coding style of the multi-line comments. * Improved accuracy of the residue calculation when the transfer for the first descriptor is active. Changes from V2: * Member 'tx_width' of 'struct at_desc' restored, because the transfer width can't be derived from the source width when using "slave_sg". The transfer width is needed for the calculation of the residue if either the transfer of the first or the last descriptor is in progress. In the case of a "memory_to_memory_sg" transfer (part of this patch series) the transfer width of both descriptors may differ. Thus it is required to additionally set 'tx_width' of the last descriptor. * Added functions for multiply used calculations. Signed-off-by: Torsten Fleischer <[email protected]> Acked-by: Nicolas Ferre <[email protected]> Signed-off-by: Vinod Koul <[email protected]>
1 parent 9eccca0 commit bdf6c79

File tree

2 files changed

+115
-76
lines changed

2 files changed

+115
-76
lines changed

drivers/dma/at_hdmac.c

+112-72
Original file line numberDiff line numberDiff line change
@@ -238,93 +238,126 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
238238
}
239239

240240
/*
241-
* atc_get_current_descriptors -
242-
* locate the descriptor which equal to physical address in DSCR
243-
* @atchan: the channel we want to start
244-
* @dscr_addr: physical descriptor address in DSCR
241+
* atc_get_desc_by_cookie - get the descriptor of a cookie
242+
* @atchan: the DMA channel
243+
* @cookie: the cookie to get the descriptor for
245244
*/
246-
static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan,
247-
u32 dscr_addr)
245+
static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
246+
dma_cookie_t cookie)
248247
{
249-
struct at_desc *desc, *_desc, *child, *desc_cur = NULL;
248+
struct at_desc *desc, *_desc;
250249

251-
list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
252-
if (desc->lli.dscr == dscr_addr) {
253-
desc_cur = desc;
254-
break;
255-
}
250+
list_for_each_entry_safe(desc, _desc, &atchan->queue, desc_node) {
251+
if (desc->txd.cookie == cookie)
252+
return desc;
253+
}
256254

257-
list_for_each_entry(child, &desc->tx_list, desc_node) {
258-
if (child->lli.dscr == dscr_addr) {
259-
desc_cur = child;
260-
break;
261-
}
262-
}
255+
list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
256+
if (desc->txd.cookie == cookie)
257+
return desc;
263258
}
264259

265-
return desc_cur;
260+
return NULL;
266261
}
267262

268-
/*
269-
* atc_get_bytes_left -
270-
* Get the number of bytes residue in dma buffer,
271-
* @chan: the channel we want to start
263+
/**
264+
* atc_calc_bytes_left - calculates the number of bytes left according to the
265+
* value read from CTRLA.
266+
*
267+
* @current_len: the number of bytes left before reading CTRLA
268+
* @ctrla: the value of CTRLA
269+
* @desc: the descriptor containing the transfer width
270+
*/
271+
static inline int atc_calc_bytes_left(int current_len, u32 ctrla,
272+
struct at_desc *desc)
273+
{
274+
return current_len - ((ctrla & ATC_BTSIZE_MAX) << desc->tx_width);
275+
}
276+
277+
/**
278+
* atc_calc_bytes_left_from_reg - calculates the number of bytes left according
279+
* to the current value of CTRLA.
280+
*
281+
* @current_len: the number of bytes left before reading CTRLA
282+
* @atchan: the channel to read CTRLA for
283+
* @desc: the descriptor containing the transfer width
284+
*/
285+
static inline int atc_calc_bytes_left_from_reg(int current_len,
286+
struct at_dma_chan *atchan, struct at_desc *desc)
287+
{
288+
u32 ctrla = channel_readl(atchan, CTRLA);
289+
290+
return atc_calc_bytes_left(current_len, ctrla, desc);
291+
}
292+
293+
/**
294+
* atc_get_bytes_left - get the number of bytes residue for a cookie
295+
* @chan: DMA channel
296+
* @cookie: transaction identifier to check status of
272297
*/
273-
static int atc_get_bytes_left(struct dma_chan *chan)
298+
static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
274299
{
275300
struct at_dma_chan *atchan = to_at_dma_chan(chan);
276-
struct at_dma *atdma = to_at_dma(chan->device);
277-
int chan_id = atchan->chan_common.chan_id;
278301
struct at_desc *desc_first = atc_first_active(atchan);
279-
struct at_desc *desc_cur;
280-
int ret = 0, count = 0;
302+
struct at_desc *desc;
303+
int ret;
304+
u32 ctrla, dscr;
281305

282306
/*
283-
* Initialize necessary values in the first time.
284-
* remain_desc record remain desc length.
307+
* If the cookie doesn't match to the currently running transfer then
308+
* we can return the total length of the associated DMA transfer,
309+
* because it is still queued.
285310
*/
286-
if (atchan->remain_desc == 0)
287-
/* First descriptor embedds the transaction length */
288-
atchan->remain_desc = desc_first->len;
311+
desc = atc_get_desc_by_cookie(atchan, cookie);
312+
if (desc == NULL)
313+
return -EINVAL;
314+
else if (desc != desc_first)
315+
return desc->total_len;
289316

290-
/*
291-
* This happens when current descriptor transfer complete.
292-
* The residual buffer size should reduce current descriptor length.
293-
*/
294-
if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) {
295-
clear_bit(ATC_IS_BTC, &atchan->status);
296-
desc_cur = atc_get_current_descriptors(atchan,
297-
channel_readl(atchan, DSCR));
298-
if (!desc_cur) {
299-
ret = -EINVAL;
300-
goto out;
301-
}
317+
/* cookie matches to the currently running transfer */
318+
ret = desc_first->total_len;
302319

303-
count = (desc_cur->lli.ctrla & ATC_BTSIZE_MAX)
304-
<< desc_first->tx_width;
305-
if (atchan->remain_desc < count) {
306-
ret = -EINVAL;
307-
goto out;
320+
if (desc_first->lli.dscr) {
321+
/* hardware linked list transfer */
322+
323+
/*
324+
* Calculate the residue by removing the length of the child
325+
* descriptors already transferred from the total length.
326+
* To get the current child descriptor we can use the value of
327+
* the channel's DSCR register and compare it against the value
328+
* of the hardware linked list structure of each child
329+
* descriptor.
330+
*/
331+
332+
ctrla = channel_readl(atchan, CTRLA);
333+
rmb(); /* ensure CTRLA is read before DSCR */
334+
dscr = channel_readl(atchan, DSCR);
335+
336+
/* for the first descriptor we can be more accurate */
337+
if (desc_first->lli.dscr == dscr)
338+
return atc_calc_bytes_left(ret, ctrla, desc_first);
339+
340+
ret -= desc_first->len;
341+
list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
342+
if (desc->lli.dscr == dscr)
343+
break;
344+
345+
ret -= desc->len;
308346
}
309347

310-
atchan->remain_desc -= count;
311-
ret = atchan->remain_desc;
312-
} else {
313348
/*
314-
* Get residual bytes when current
315-
* descriptor transfer in progress.
349+
* For the last descriptor in the chain we can calculate
350+
* the remaining bytes using the channel's register.
351+
* Note that the transfer width of the first and last
352+
* descriptor may differ.
316353
*/
317-
count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX)
318-
<< (desc_first->tx_width);
319-
ret = atchan->remain_desc - count;
354+
if (!desc->lli.dscr)
355+
ret = atc_calc_bytes_left_from_reg(ret, atchan, desc);
356+
} else {
357+
/* single transfer */
358+
ret = atc_calc_bytes_left_from_reg(ret, atchan, desc_first);
320359
}
321-
/*
322-
* Check fifo empty.
323-
*/
324-
if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id)))
325-
atc_issue_pending(chan);
326360

327-
out:
328361
return ret;
329362
}
330363

@@ -539,8 +572,6 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
539572
/* Give information to tasklet */
540573
set_bit(ATC_IS_ERROR, &atchan->status);
541574
}
542-
if (pending & AT_DMA_BTC(i))
543-
set_bit(ATC_IS_BTC, &atchan->status);
544575
tasklet_schedule(&atchan->tasklet);
545576
ret = IRQ_HANDLED;
546577
}
@@ -653,14 +684,18 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
653684
desc->lli.ctrlb = ctrlb;
654685

655686
desc->txd.cookie = 0;
687+
desc->len = xfer_count << src_width;
656688

657689
atc_desc_chain(&first, &prev, desc);
658690
}
659691

660692
/* First descriptor of the chain embedds additional information */
661693
first->txd.cookie = -EBUSY;
662-
first->len = len;
694+
first->total_len = len;
695+
696+
/* set transfer width for the calculation of the residue */
663697
first->tx_width = src_width;
698+
prev->tx_width = src_width;
664699

665700
/* set end-of-link to the last link descriptor of list*/
666701
set_desc_eol(desc);
@@ -752,6 +787,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
752787
| ATC_SRC_WIDTH(mem_width)
753788
| len >> mem_width;
754789
desc->lli.ctrlb = ctrlb;
790+
desc->len = len;
755791

756792
atc_desc_chain(&first, &prev, desc);
757793
total_len += len;
@@ -792,6 +828,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
792828
| ATC_DST_WIDTH(mem_width)
793829
| len >> reg_width;
794830
desc->lli.ctrlb = ctrlb;
831+
desc->len = len;
795832

796833
atc_desc_chain(&first, &prev, desc);
797834
total_len += len;
@@ -806,8 +843,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
806843

807844
/* First descriptor of the chain embedds additional information */
808845
first->txd.cookie = -EBUSY;
809-
first->len = total_len;
846+
first->total_len = total_len;
847+
848+
/* set transfer width for the calculation of the residue */
810849
first->tx_width = reg_width;
850+
prev->tx_width = reg_width;
811851

812852
/* first link descriptor of list is responsible of flags */
813853
first->txd.flags = flags; /* client is in control of this ack */
@@ -872,6 +912,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
872912
| ATC_FC_MEM2PER
873913
| ATC_SIF(atchan->mem_if)
874914
| ATC_DIF(atchan->per_if);
915+
desc->len = period_len;
875916
break;
876917

877918
case DMA_DEV_TO_MEM:
@@ -883,6 +924,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
883924
| ATC_FC_PER2MEM
884925
| ATC_SIF(atchan->per_if)
885926
| ATC_DIF(atchan->mem_if);
927+
desc->len = period_len;
886928
break;
887929

888930
default:
@@ -964,7 +1006,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
9641006

9651007
/* First descriptor of the chain embedds additional information */
9661008
first->txd.cookie = -EBUSY;
967-
first->len = buf_len;
1009+
first->total_len = buf_len;
9681010
first->tx_width = reg_width;
9691011

9701012
return &first->txd;
@@ -1118,7 +1160,7 @@ atc_tx_status(struct dma_chan *chan,
11181160
spin_lock_irqsave(&atchan->lock, flags);
11191161

11201162
/* Get number of bytes left in the active transactions */
1121-
bytes = atc_get_bytes_left(chan);
1163+
bytes = atc_get_bytes_left(chan, cookie);
11221164

11231165
spin_unlock_irqrestore(&atchan->lock, flags);
11241166

@@ -1214,7 +1256,6 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
12141256

12151257
spin_lock_irqsave(&atchan->lock, flags);
12161258
atchan->descs_allocated = i;
1217-
atchan->remain_desc = 0;
12181259
list_splice(&tmp_list, &atchan->free_list);
12191260
dma_cookie_init(chan);
12201261
spin_unlock_irqrestore(&atchan->lock, flags);
@@ -1257,7 +1298,6 @@ static void atc_free_chan_resources(struct dma_chan *chan)
12571298
list_splice_init(&atchan->free_list, &list);
12581299
atchan->descs_allocated = 0;
12591300
atchan->status = 0;
1260-
atchan->remain_desc = 0;
12611301

12621302
dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
12631303
}

drivers/dma/at_hdmac_regs.h

+3-4
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,9 @@ struct at_lli {
181181
* @at_lli: hardware lli structure
182182
* @txd: support for the async_tx api
183183
* @desc_node: node on the channed descriptors list
184-
* @len: total transaction bytecount
184+
* @len: descriptor byte count
185185
* @tx_width: transfer width
186+
* @total_len: total transaction byte count
186187
*/
187188
struct at_desc {
188189
/* FIRST values the hardware uses */
@@ -194,6 +195,7 @@ struct at_desc {
194195
struct list_head desc_node;
195196
size_t len;
196197
u32 tx_width;
198+
size_t total_len;
197199
};
198200

199201
static inline struct at_desc *
@@ -213,7 +215,6 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
213215
enum atc_status {
214216
ATC_IS_ERROR = 0,
215217
ATC_IS_PAUSED = 1,
216-
ATC_IS_BTC = 2,
217218
ATC_IS_CYCLIC = 24,
218219
};
219220

@@ -231,7 +232,6 @@ enum atc_status {
231232
* @save_cfg: configuration register that is saved on suspend/resume cycle
232233
* @save_dscr: for cyclic operations, preserve next descriptor address in
233234
* the cyclic list on suspend/resume cycle
234-
* @remain_desc: to save remain desc length
235235
* @dma_sconfig: configuration for slave transfers, passed via
236236
* .device_config
237237
* @lock: serializes enqueue/dequeue operations to descriptors lists
@@ -251,7 +251,6 @@ struct at_dma_chan {
251251
struct tasklet_struct tasklet;
252252
u32 save_cfg;
253253
u32 save_dscr;
254-
u32 remain_desc;
255254
struct dma_slave_config dma_sconfig;
256255

257256
spinlock_t lock;

0 commit comments

Comments
 (0)