Messages in this thread Patch in this message | | | Date | Tue, 14 Nov 2023 13:22:06 +0100 | From | Thomas Pfaff <> | Subject | [PATCH RFC 1/2 stable-6.1] dmaengine: at_hdmac: get next dma transfer from the right list |
| |
From: Thomas Pfaff <tpfaff@pcs.com>
In kernel 6.1, atc_advance_work and atc_handle_error are checking for the next dma transfer inside active list, but the descriptor is taken from the queue instead.
Signed-off-by: Thomas Pfaff <tpfaff@pcs.com> --- diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 858bd64f1313..68c1bfbefc5c 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -490,6 +490,27 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) } } +/** + * atc_start_next - start next pending transaction if any + * @atchan: channel where the transaction ended + * + * Called with atchan->lock held + */ +static void atc_start_next(struct at_dma_chan *atchan) +{ + struct at_desc *desc = NULL; + + if (!list_empty(&atchan->active_list)) + desc = atc_first_active(atchan); + else if (!list_empty(&atchan->queue)) { + desc = atc_first_queued(atchan); + list_move_tail(&desc->desc_node, &atchan->active_list); + } + + if (desc) + atc_dostart(atchan, desc); +} + /** * atc_advance_work - at the end of a transaction, move forward * @atchan: channel where the transaction ended @@ -513,11 +534,7 @@ static void atc_advance_work(struct at_dma_chan *atchan) /* advance work */ spin_lock_irqsave(&atchan->lock, flags); - if (!list_empty(&atchan->active_list)) { - desc = atc_first_queued(atchan); - list_move_tail(&desc->desc_node, &atchan->active_list); - atc_dostart(atchan, desc); - } + atc_start_next(atchan); spin_unlock_irqrestore(&atchan->lock, flags); } @@ -529,7 +546,6 @@ 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; @@ -543,11 +559,7 @@ static void atc_handle_error(struct at_dma_chan *atchan) list_del_init(&bad_desc->desc_node); /* Try to restart the controller */ - if (!list_empty(&atchan->active_list)) { - desc = atc_first_queued(atchan); - list_move_tail(&desc->desc_node, &atchan->active_list); - atc_dostart(atchan, desc); - } + atc_start_next(atchan); /* * KERN_CRITICAL may seem harsh, but since this only happens
| |