[PATCH 5.15 553/570] dmaengine: sh: rz-dmac: Move CHCTRL updates under spinlock

Greg Kroah-Hartman
2026-04-13T16:41:49Z

From: Claudiu Beznea <claudiu.beznea@tuxon.dev>

[ Upstream commit 89a8567d84bde88cb7cdbbac2ab2299c4f991490 ]

Both rz_dmac_disable_hw() and rz_dmac_irq_handle_channel() update the
CHCTRL register. To avoid concurrency issues when configuring
functionalities exposed by this registers, take the virtual channel lock.
All other CHCTRL updates were already protected by the same lock.

Previously, rz_dmac_disable_hw() disabled and re-enabled local IRQs, before
accessing CHCTRL registers but this does not ensure race-free access.
Remove the local IRQ disable/enable code as well.

Fixes: 5000d37042a6 ("dmaengine: sh: Add DMAC driver for RZ/G2L SoC")
Cc: stable@vger.kernel.org
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Link: https://patch.msgid.link/20260316133252.240348-3-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
[ replaced scoped_guard(spinlock_irqsave, ...) ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/dma/sh/rz-dmac.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -283,13 +283,10 @@ static void rz_dmac_disable_hw(struct rz
{
struct dma_chan *chan = &channel->vc.chan;
struct rz_dmac *dmac = to_rz_dmac(chan->device);
- unsigned long flags;

dev_dbg(dmac->dev, "%s channel %d\n", __func__, channel->index);

- local_irq_save(flags);
rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
- local_irq_restore(flags);
}

static void rz_dmac_set_dmars_register(struct rz_dmac *dmac, int nr, u32 dmars)
@@ -536,8 +533,8 @@ static int rz_dmac_terminate_all(struct
unsigned int i;
LIST_HEAD(head);

- rz_dmac_disable_hw(channel);
spin_lock_irqsave(&channel->vc.lock, flags);
+ rz_dmac_disable_hw(channel);
for (i = 0; i < DMAC_NR_LMDESC; i++)
lmdesc[i].header = 0;

@@ -646,13 +643,17 @@ static void rz_dmac_irq_handle_channel(s
{
struct dma_chan *chan = &channel->vc.chan;
struct rz_dmac *dmac = to_rz_dmac(chan->device);
+ unsigned long flags;
u32 chstat, chctrl;

chstat = rz_dmac_ch_readl(channel, CHSTAT, 1);
if (chstat & CHSTAT_ER) {
dev_err(dmac->dev, "DMAC err CHSTAT_%d = %08X\n",
channel->index, chstat);
+
+ spin_lock_irqsave(&channel->vc.lock, flags);
rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
+ spin_unlock_irqrestore(&channel->vc.lock, flags);
goto done;
}