Skip to content

Commit f60dfe0

Browse files
pcercueivinodkoul
authored andcommitted
dmaengine: axi-dmac: Improve cyclic DMA transfers in SG mode
For cyclic transfers, chain the last descriptor to the first one, and disable IRQ generation if there is no callback registered with the cyclic transfer. Signed-off-by: Paul Cercueil <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 238f68a commit f60dfe0

File tree

1 file changed

+14
-8
lines changed

1 file changed

+14
-8
lines changed

drivers/dma/dma-axi-dmac.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -285,12 +285,14 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
285285

286286
/*
287287
* If the hardware supports cyclic transfers and there is no callback to
288-
* call and only a single segment, enable hw cyclic mode to avoid
289-
* unnecessary interrupts.
288+
* call, enable hw cyclic mode to avoid unnecessary interrupts.
290289
*/
291-
if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback &&
292-
desc->num_sgs == 1)
293-
flags |= AXI_DMAC_FLAG_CYCLIC;
290+
if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback) {
291+
if (chan->hw_sg)
292+
desc->sg[desc->num_sgs - 1].hw->flags &= ~AXI_DMAC_HW_FLAG_IRQ;
293+
else if (desc->num_sgs == 1)
294+
flags |= AXI_DMAC_FLAG_CYCLIC;
295+
}
294296

295297
if (chan->hw_partial_xfer)
296298
flags |= AXI_DMAC_FLAG_PARTIAL_REPORT;
@@ -411,7 +413,6 @@ static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan,
411413
if (chan->hw_sg) {
412414
if (active->cyclic) {
413415
vchan_cyclic_callback(&active->vdesc);
414-
start_next = true;
415416
} else {
416417
list_del(&active->vdesc.node);
417418
vchan_cookie_complete(&active->vdesc);
@@ -667,7 +668,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
667668
{
668669
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
669670
struct axi_dmac_desc *desc;
670-
unsigned int num_periods, num_segments;
671+
unsigned int num_periods, num_segments, num_sgs;
671672

672673
if (direction != chan->direction)
673674
return NULL;
@@ -681,11 +682,16 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
681682

682683
num_periods = buf_len / period_len;
683684
num_segments = DIV_ROUND_UP(period_len, chan->max_length);
685+
num_sgs = num_periods * num_segments;
684686

685-
desc = axi_dmac_alloc_desc(chan, num_periods * num_segments);
687+
desc = axi_dmac_alloc_desc(chan, num_sgs);
686688
if (!desc)
687689
return NULL;
688690

691+
/* Chain the last descriptor to the first, and remove its "last" flag */
692+
desc->sg[num_sgs - 1].hw->next_sg_addr = desc->sg[0].hw_phys;
693+
desc->sg[num_sgs - 1].hw->flags &= ~AXI_DMAC_HW_FLAG_LAST;
694+
689695
axi_dmac_fill_linear_sg(chan, direction, buf_addr, num_periods,
690696
period_len, desc->sg);
691697

0 commit comments

Comments
 (0)