Skip to content

Commit b63e5cb

Browse files
ambarusvinodkoul
authored andcommitted
dmaengine: at_xdmac: Fix race for the tx desc callback
The transfer descriptors were wrongly moved to the free descriptors list before calling the tx desc callback. As the DMA engine drivers drop any locks before calling the callback function, txd could be taken again, resulting in its callback called prematurely. Fix the race for the tx desc callback by moving the xfer desc into the free desc list after the callback is invoked. Fixes: e1f7c9e ("dmaengine: at_xdmac: creation of the atmel eXtended DMA Controller driver") Signed-off-by: Tudor Ambarus <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 506875c commit b63e5cb

File tree

1 file changed

+8
-17
lines changed

1 file changed

+8
-17
lines changed

drivers/dma/at_xdmac.c

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,20 +1582,6 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
15821582
return ret;
15831583
}
15841584

1585-
/* Call must be protected by lock. */
1586-
static void at_xdmac_remove_xfer(struct at_xdmac_chan *atchan,
1587-
struct at_xdmac_desc *desc)
1588-
{
1589-
dev_dbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc);
1590-
1591-
/*
1592-
* Remove the transfer from the transfer list then move the transfer
1593-
* descriptors into the free descriptors list.
1594-
*/
1595-
list_del(&desc->xfer_node);
1596-
list_splice_init(&desc->descs_list, &atchan->free_descs_list);
1597-
}
1598-
15991585
static void at_xdmac_advance_work(struct at_xdmac_chan *atchan)
16001586
{
16011587
struct at_xdmac_desc *desc;
@@ -1704,7 +1690,8 @@ static void at_xdmac_tasklet(struct tasklet_struct *t)
17041690

17051691
txd = &desc->tx_dma_desc;
17061692
dma_cookie_complete(txd);
1707-
at_xdmac_remove_xfer(atchan, desc);
1693+
/* Remove the transfer from the transfer list. */
1694+
list_del(&desc->xfer_node);
17081695
spin_unlock_irq(&atchan->lock);
17091696

17101697
if (txd->flags & DMA_PREP_INTERRUPT)
@@ -1713,6 +1700,8 @@ static void at_xdmac_tasklet(struct tasklet_struct *t)
17131700
dma_run_dependencies(txd);
17141701

17151702
spin_lock_irq(&atchan->lock);
1703+
/* Move the xfer descriptors into the free descriptors list. */
1704+
list_splice_init(&desc->descs_list, &atchan->free_descs_list);
17161705
at_xdmac_advance_work(atchan);
17171706
spin_unlock_irq(&atchan->lock);
17181707
}
@@ -1859,8 +1848,10 @@ static int at_xdmac_device_terminate_all(struct dma_chan *chan)
18591848
cpu_relax();
18601849

18611850
/* Cancel all pending transfers. */
1862-
list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node)
1863-
at_xdmac_remove_xfer(atchan, desc);
1851+
list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node) {
1852+
list_del(&desc->xfer_node);
1853+
list_splice_init(&desc->descs_list, &atchan->free_descs_list);
1854+
}
18641855

18651856
clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
18661857
clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status);

0 commit comments

Comments
 (0)