Skip to content

Commit aded153

Browse files
pcercueinunojsa
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 <paul@crapouillou.net> Link: https://lore.kernel.org/r/20231215131313.23840-6-paul@crapouillou.net Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent b725725 commit aded153

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
@@ -288,12 +288,14 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
288288

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

298300
if (chan->hw_partial_xfer)
299301
flags |= AXI_DMAC_FLAG_PARTIAL_REPORT;
@@ -414,7 +416,6 @@ static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan,
414416
if (chan->hw_sg) {
415417
if (active->cyclic) {
416418
vchan_cyclic_callback(&active->vdesc);
417-
start_next = true;
418419
} else {
419420
list_del(&active->vdesc.node);
420421
vchan_cookie_complete(&active->vdesc);
@@ -690,7 +691,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
690691
{
691692
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
692693
struct axi_dmac_desc *desc;
693-
unsigned int num_periods, num_segments;
694+
unsigned int num_periods, num_segments, num_sgs;
694695

695696
if (direction != chan->direction)
696697
return NULL;
@@ -704,11 +705,16 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
704705

705706
num_periods = buf_len / period_len;
706707
num_segments = DIV_ROUND_UP(period_len, chan->max_length);
708+
num_sgs = num_periods * num_segments;
707709

708-
desc = axi_dmac_alloc_desc(chan, num_periods * num_segments);
710+
desc = axi_dmac_alloc_desc(chan, num_sgs);
709711
if (!desc)
710712
return NULL;
711713

714+
/* Chain the last descriptor to the first, and remove its "last" flag */
715+
desc->sg[num_sgs - 1].hw->next_sg_addr = desc->sg[0].hw_phys;
716+
desc->sg[num_sgs - 1].hw->flags &= ~AXI_DMAC_HW_FLAG_LAST;
717+
712718
axi_dmac_fill_linear_sg(chan, direction, buf_addr, num_periods,
713719
period_len, desc->sg);
714720

0 commit comments

Comments
 (0)