dmaengine: at_xdmac: Fix concurrency over xfers_list
authorTudor Ambarus <tudor.ambarus@microchip.com>
Wed, 15 Dec 2021 11:01:10 +0000 (13:01 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jan 2022 10:05:37 +0000 (11:05 +0100)
commit 18deddea9184b62941395889ff7659529c877326 upstream.

Since tx_submit can be called from a hard IRQ, xfers_list must be
protected with a lock to avoid concurency on the list's elements.
Since at_xdmac_handle_cyclic() is called from a tasklet, spin_lock_irq
is enough to protect from a hard IRQ.

Fixes: e1f7c9eee707 ("dmaengine: at_xdmac: creation of the atmel eXtended DMA Controller driver")
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Link: https://lore.kernel.org/r/20211215110115.191749-8-tudor.ambarus@microchip.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/dma/at_xdmac.c

index 83a5c8f..7b3be3e 100644 (file)
@@ -1619,14 +1619,17 @@ static void at_xdmac_handle_cyclic(struct at_xdmac_chan *atchan)
        struct at_xdmac_desc            *desc;
        struct dma_async_tx_descriptor  *txd;
 
-       if (!list_empty(&atchan->xfers_list)) {
-               desc = list_first_entry(&atchan->xfers_list,
-                                       struct at_xdmac_desc, xfer_node);
-               txd = &desc->tx_dma_desc;
-
-               if (txd->flags & DMA_PREP_INTERRUPT)
-                       dmaengine_desc_get_callback_invoke(txd, NULL);
+       spin_lock_irq(&atchan->lock);
+       if (list_empty(&atchan->xfers_list)) {
+               spin_unlock_irq(&atchan->lock);
+               return;
        }
+       desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc,
+                               xfer_node);
+       spin_unlock_irq(&atchan->lock);
+       txd = &desc->tx_dma_desc;
+       if (txd->flags & DMA_PREP_INTERRUPT)
+               dmaengine_desc_get_callback_invoke(txd, NULL);
 }
 
 static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)