[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251217151609.3162665-23-den@valinux.co.jp>
Date: Thu, 18 Dec 2025 00:15:56 +0900
From: Koichiro Den <den@...inux.co.jp>
To: Frank.Li@....com,
dave.jiang@...el.com,
ntb@...ts.linux.dev,
linux-pci@...r.kernel.org,
dmaengine@...r.kernel.org,
linux-renesas-soc@...r.kernel.org,
netdev@...r.kernel.org,
linux-kernel@...r.kernel.org
Cc: mani@...nel.org,
kwilczynski@...nel.org,
kishon@...nel.org,
bhelgaas@...gle.com,
corbet@....net,
geert+renesas@...der.be,
magnus.damm@...il.com,
robh@...nel.org,
krzk+dt@...nel.org,
conor+dt@...nel.org,
vkoul@...nel.org,
joro@...tes.org,
will@...nel.org,
robin.murphy@....com,
jdmason@...zu.us,
allenbh@...il.com,
andrew+netdev@...n.ch,
davem@...emloft.net,
edumazet@...gle.com,
kuba@...nel.org,
pabeni@...hat.com,
Basavaraj.Natikar@....com,
Shyam-sundar.S-k@....com,
kurt.schwemmer@...rosemi.com,
logang@...tatee.com,
jingoohan1@...il.com,
lpieralisi@...nel.org,
utkarsh02t@...il.com,
jbrunet@...libre.com,
dlemoal@...nel.org,
arnd@...db.de,
elfring@...rs.sourceforge.net,
den@...inux.co.jp
Subject: [RFC PATCH v3 22/35] dmaengine: dw-edma: Serialize RMW on shared interrupt registers
The per-direction int_mask and linked_list_err_en registers are shared
between all channels. Updating them requires a read-modify-write
sequence, which can lose concurrent updates when multiple channels are
started in parallel. This may leave interrupts masked and stall
transfers under high load.
Protect the RMW sequences with dw->lock.
Signed-off-by: Koichiro Den <den@...inux.co.jp>
---
drivers/dma/dw-edma/dw-edma-core.h | 3 ++-
drivers/dma/dw-edma/dw-edma-v0-core.c | 13 ++++++++++---
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index f652d2e38843..d393976a8bfc 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -118,7 +118,8 @@ struct dw_edma {
struct dw_edma_chan *chan;
- raw_spinlock_t lock; /* Only for legacy */
+ /* For legacy + shared regs RMW among channels */
+ raw_spinlock_t lock;
struct dw_edma_chip *chip;
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 42a254eb9379..770b011ba3e4 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -369,7 +369,8 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
{
struct dw_edma_chan *chan = chunk->chan;
struct dw_edma *dw = chan->dw;
- u32 tmp;
+ unsigned long flags;
+ u32 tmp, orig;
dw_edma_v0_core_write_chunk(chunk);
@@ -413,7 +414,9 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
}
}
/* Interrupt mask/unmask - done, abort */
+ raw_spin_lock_irqsave(&dw->lock, flags);
tmp = GET_RW_32(dw, chan->dir, int_mask);
+ orig = tmp;
if (chan->irq_mode == DW_EDMA_CH_IRQ_REMOTE) {
tmp |= FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
tmp |= FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
@@ -421,11 +424,15 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
}
- SET_RW_32(dw, chan->dir, int_mask, tmp);
+ if (tmp != orig)
+ SET_RW_32(dw, chan->dir, int_mask, tmp);
/* Linked list error */
tmp = GET_RW_32(dw, chan->dir, linked_list_err_en);
+ orig = tmp;
tmp |= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK, BIT(chan->id));
- SET_RW_32(dw, chan->dir, linked_list_err_en, tmp);
+ if (tmp != orig)
+ SET_RW_32(dw, chan->dir, linked_list_err_en, tmp);
+ raw_spin_unlock_irqrestore(&dw->lock, flags);
/* Channel control */
SET_CH_32(dw, chan->dir, chan->id, ch_control1,
(DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
--
2.51.0
Powered by blists - more mailing lists