dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware
authorTudor Ambarus <tudor.ambarus@microchip.com>
Tue, 25 Oct 2022 09:02:45 +0000 (12:02 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 16 Nov 2022 08:58:29 +0000 (09:58 +0100)
commit ba2423633ba646e1df20e30cb3cf35495c16f173 upstream.

As it was before, the descriptor was issued to the hardware without adding
it to the active (issued) list. This could result in a completion of other
descriptor, or/and in the descriptor never being completed.

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Link: https://lore.kernel.org/r/20221025090306.297886-1-tudor.ambarus@microchip.com
Link: https://lore.kernel.org/r/20221025090306.297886-12-tudor.ambarus@microchip.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/dma/at_hdmac.c

index 7f19e96..4cb768f 100644 (file)
@@ -510,8 +510,11 @@ static void atc_advance_work(struct at_dma_chan *atchan)
 
        /* advance work */
        spin_lock_irqsave(&atchan->lock, flags);
-       if (!list_empty(&atchan->active_list))
-               atc_dostart(atchan, atc_first_active(atchan));
+       if (!list_empty(&atchan->active_list)) {
+               desc = atc_first_queued(atchan);
+               list_move_tail(&desc->desc_node, &atchan->active_list);
+               atc_dostart(atchan, desc);
+       }
        spin_unlock_irqrestore(&atchan->lock, flags);
 }
 
@@ -523,6 +526,7 @@ static void atc_advance_work(struct at_dma_chan *atchan)
 static void atc_handle_error(struct at_dma_chan *atchan)
 {
        struct at_desc *bad_desc;
+       struct at_desc *desc;
        struct at_desc *child;
        unsigned long flags;
 
@@ -540,8 +544,11 @@ static void atc_handle_error(struct at_dma_chan *atchan)
        list_splice_init(&atchan->queue, atchan->active_list.prev);
 
        /* Try to restart the controller */
-       if (!list_empty(&atchan->active_list))
-               atc_dostart(atchan, atc_first_active(atchan));
+       if (!list_empty(&atchan->active_list)) {
+               desc = atc_first_queued(atchan);
+               list_move_tail(&desc->desc_node, &atchan->active_list);
+               atc_dostart(atchan, desc);
+       }
 
        /*
         * KERN_CRITICAL may seem harsh, but since this only happens