@@ -285,12 +285,14 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
285
285
286
286
/*
287
287
* 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.
290
289
*/
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
+ }
294
296
295
297
if (chan -> hw_partial_xfer )
296
298
flags |= AXI_DMAC_FLAG_PARTIAL_REPORT ;
@@ -411,7 +413,6 @@ static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan,
411
413
if (chan -> hw_sg ) {
412
414
if (active -> cyclic ) {
413
415
vchan_cyclic_callback (& active -> vdesc );
414
- start_next = true;
415
416
} else {
416
417
list_del (& active -> vdesc .node );
417
418
vchan_cookie_complete (& active -> vdesc );
@@ -667,7 +668,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
667
668
{
668
669
struct axi_dmac_chan * chan = to_axi_dmac_chan (c );
669
670
struct axi_dmac_desc * desc ;
670
- unsigned int num_periods , num_segments ;
671
+ unsigned int num_periods , num_segments , num_sgs ;
671
672
672
673
if (direction != chan -> direction )
673
674
return NULL ;
@@ -681,11 +682,16 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
681
682
682
683
num_periods = buf_len / period_len ;
683
684
num_segments = DIV_ROUND_UP (period_len , chan -> max_length );
685
+ num_sgs = num_periods * num_segments ;
684
686
685
- desc = axi_dmac_alloc_desc (chan , num_periods * num_segments );
687
+ desc = axi_dmac_alloc_desc (chan , num_sgs );
686
688
if (!desc )
687
689
return NULL ;
688
690
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
+
689
695
axi_dmac_fill_linear_sg (chan , direction , buf_addr , num_periods ,
690
696
period_len , desc -> sg );
691
697
0 commit comments