FAILED: patch "[PATCH] dmaengine: sh: rz-dmac: Protect the driver specific lists" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x abb863e6213dc41a58ef8bb3289b7e77460dabf3
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026033033-anaconda-untruth-e995@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From abb863e6213dc41a58ef8bb3289b7e77460dabf3 Mon Sep 17 00:00:00 2001
From: Claudiu Beznea <[email protected]>
Date: Mon, 16 Mar 2026 15:32:45 +0200
Subject: [PATCH] dmaengine: sh: rz-dmac: Protect the driver specific lists
The driver lists (ld_free, ld_queue) are used in rz_dmac_free_chan_resources(), rz_dmac_terminate_all(), rz_dmac_issue_pending(), and rz_dmac_irq_handler_thread(), all under the virtual channel lock. Take the same lock in rz_dmac_prep_slave_sg() and rz_dmac_prep_dma_memcpy() as well to avoid concurrency issues, since these functions also check whether the lists are empty and update or remove list entries.
drivers/dma/sh/rz-dmac.c +33 -26
@@ -10,6 +10,7 @@*/ #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/interrupt.h>
@@ -447,6 +448,7 @@ static int rz_dmac_alloc_chan_resources(struct dma_chan *chan)if (!desc)break ; +/* No need to lock. This is called only for the 1st client. */ list_add_tail (&desc->node, &channel->ld_free); channel->descs_allocated++; }
@@ -502,18 +504,21 @@ rz_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,dev_dbg (dmac->dev,"%s channel: %d src=0x%pad dst=0x%pad len=%zu\n" , __func__, channel->index, &src, &dest, len); -if (list_empty (&channel->ld_free)) -return NULL ; + scoped_guard(spinlock_irqsave, &channel->vc.lock) { +if (list_empty (&channel->ld_free)) +return NULL ; - desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); + desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); - desc->type =RZ_DMAC_DESC_MEMCPY ; - desc->src = src; - desc->dest = dest; - desc->len = len; - desc->direction =DMA_MEM_TO_MEM ; + desc->type =RZ_DMAC_DESC_MEMCPY ; + desc->src = src; + desc->dest = dest; + desc->len = len; + desc->direction =DMA_MEM_TO_MEM ; + +list_move_tail (channel->ld_free.next, &channel->ld_queue); + } -list_move_tail (channel->ld_free.next, &channel->ld_queue);return vchan_tx_prep (&channel->vc, &desc->vd, flags); }
@@ -529,27 +534,29 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,int dma_length =0 ;int i =0 ; -if (list_empty (&channel->ld_free)) -return NULL ; + scoped_guard(spinlock_irqsave, &channel->vc.lock) { +if (list_empty (&channel->ld_free)) +return NULL ; - desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); + desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); -for_each_sg (sgl, sg, sg_len, i) { - dma_length +=sg_dma_len (sg); +for_each_sg (sgl, sg, sg_len, i) + dma_length +=sg_dma_len (sg); + + desc->type =RZ_DMAC_DESC_SLAVE_SG ; + desc->sg = sgl; + desc->sgcount = sg_len; + desc->len = dma_length; + desc->direction = direction; + +if (direction ==DMA_DEV_TO_MEM ) + desc->src = channel->src_per_address; +else + desc->dest = channel->dst_per_address; + +list_move_tail (channel->ld_free.next, &channel->ld_queue); } - desc->type =RZ_DMAC_DESC_SLAVE_SG ; - desc->sg = sgl; - desc->sgcount = sg_len; - desc->len = dma_length; - desc->direction = direction; - -if (direction ==DMA_DEV_TO_MEM ) - desc->src = channel->src_per_address; -else - desc->dest = channel->dst_per_address; - -list_move_tail (channel->ld_free.next, &channel->ld_queue);return vchan_tx_prep (&channel->vc, &desc->vd, flags); }
Sasha Levin
maintainerPATCH 1/1 dmaengine: sh: rz-dmac: Protect the driver specific lists
From: Claudiu Beznea <[email protected]>
[ Upstream commit abb863e6213dc41a58ef8bb3289b7e77460dabf3 ]
The driver lists (ld_free, ld_queue) are used in rz_dmac_free_chan_resources(), rz_dmac_terminate_all(), rz_dmac_issue_pending(), and rz_dmac_irq_handler_thread(), all under the virtual channel lock. Take the same lock in rz_dmac_prep_slave_sg() and rz_dmac_prep_dma_memcpy() as well to avoid concurrency issues, since these functions also check whether the lists are empty and update or remove list entries.
--- drivers/dma/sh/rz-dmac.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-)
drivers/dma/sh/rz-dmac.c +20 -4
@@ -422,6 +422,7 @@ static int rz_dmac_alloc_chan_resources(struct dma_chan *chan)if (!desc)break ; +/* No need to lock. This is called only for the 1st client. */ list_add_tail (&desc->node, &channel->ld_free); channel->descs_allocated++; }
@@ -473,12 +474,17 @@ rz_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,struct rz_dmac_chan *channel =to_rz_dmac_chan (chan);struct rz_dmac *dmac =to_rz_dmac (chan->device);struct rz_dmac_desc *desc; +unsigned long irqflags;dev_dbg (dmac->dev,"%s channel: %d src=0x%pad dst=0x%pad len=%zu\n" , __func__, channel->index, &src, &dest, len); -if (list_empty (&channel->ld_free)) +spin_lock_irqsave (&channel->vc.lock, irqflags); + +if (list_empty (&channel->ld_free)) { +spin_unlock_irqrestore (&channel->vc.lock, irqflags);return NULL ; + } desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
@@ -489,6 +495,9 @@ rz_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, desc->direction =DMA_MEM_TO_MEM ;list_move_tail (channel->ld_free.next, &channel->ld_queue); + +spin_unlock_irqrestore (&channel->vc.lock, irqflags); +return vchan_tx_prep (&channel->vc, &desc->vd, flags); }
@@ -501,17 +510,21 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,struct rz_dmac_chan *channel =to_rz_dmac_chan (chan);struct rz_dmac_desc *desc;struct scatterlist *sg; +unsigned long irqflags;int dma_length =0 ;int i =0 ; -if (list_empty (&channel->ld_free)) +spin_lock_irqsave (&channel->vc.lock, irqflags); + +if (list_empty (&channel->ld_free)) { +spin_unlock_irqrestore (&channel->vc.lock, irqflags);return NULL ; + } desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); -for_each_sg (sgl, sg, sg_len, i) { +for_each_sg (sgl, sg, sg_len, i) dma_length +=sg_dma_len (sg); - } desc->type =RZ_DMAC_DESC_SLAVE_SG ; desc->sg = sgl;
@@ -525,6 +538,9 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc->dest = channel->dst_per_address;list_move_tail (channel->ld_free.next, &channel->ld_queue); + +spin_unlock_irqrestore (&channel->vc.lock, irqflags); +return vchan_tx_prep (&channel->vc, &desc->vd, flags); }
Signature · 1 line
2.53.0