lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ