ARM Sunxi Platform Development
 help / color / mirror / Atom feed
* [PATCH net-next v3 0/2] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog
@ 2026-10-15 14:55 Daniel Thompson
  2026-10-15 14:55 ` [PATCH net-next v3 1/2] net: stmmac: Introduce group arguments for enable/disable_dma_irq Daniel Thompson
  2026-10-15 14:55 ` [PATCH net-next v3 2/2] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog Daniel Thompson
  0 siblings, 2 replies; 5+ messages in thread
From: Daniel Thompson @ 2026-10-15 14:55 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Maxime Coquelin, Alexandre Torgue, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, Maxime Chevallier, Eric Dumazet, Chen-Yu Tsai,
	Jernej Skrabec, Samuel Holland, Eric Dumazet
  Cc: Alex Elder, netdev, linux-stm32, linux-arm-kernel, linux-kernel,
	bpf, linux-sunxi, Daniel Thompson

Currently stmmac will run a full cycle of IRQ tear down and setup when
setting up a new XDP program. This makes tuning TSN systems difficult
because whenever a new XDP program is installed then the irq threads will
be stopped and restarted which will undo any thread tuning.

This series addresses this issue by replacing the free_irq() with a disable of
DMA interrupts in the XDP paths. The series consists of a preparative patch that
extends the DMA interrupt enable/disable functions and then follows with the
meaningful change.

These changes were developed (and tested) as part of the TC956x work that
Alex Elder and I have been working on. However the change should work with
any driver that uses the stmmac core and there is no dependency between these
changes that that work.

Signed-off-by: Daniel Thompson <daniel@riscstar.com>
---
Changes in v3:
- Switch to more aggressive interrupt masking to avoid problems with
  concurrent normal/abnormal DMA interrupts.
- Changed the enable_dma_irq/disable_dma_irq ops prototype (to support the
  above)
- Link to v2: https://lore.kernel.org/r/20260730-tc956x-stmmac-no_irq_teardown-v2-1-a6c31932ba84@riscstar.com

Changes in v2:
- Added net-next prefix
- Remove stmmac_init_chan() from stmmac_xdp_open() because it will re-enable
  interrupts
- Link to v1: https://lore.kernel.org/r/20260706-tc956x-stmmac-no_irq_teardown-v1-1-df009d0272bf@riscstar.com

---
Daniel Thompson (2):
      net: stmmac: Introduce group arguments for enable/disable_dma_irq
      net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog

 drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c  | 12 +--
 drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h   |  4 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c   | 29 ++++---
 drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h    |  4 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c    | 29 ++++---
 drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 29 ++++---
 drivers/net/ethernet/stmicro/stmmac/hwif.h         | 10 ++-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 89 +++++++++++++++-------
 8 files changed, 135 insertions(+), 71 deletions(-)
---
base-commit: 24a19b953e2a3d0ea5a8c4951a0ab8f32720c907
change-id: 20260706-tc956x-stmmac-no_irq_teardown-8a7592b9f8c1

Best regards,
-- 
Daniel Thompson <daniel@riscstar.com>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net-next v3 1/2] net: stmmac: Introduce group arguments for enable/disable_dma_irq
  2026-10-15 14:55 [PATCH net-next v3 0/2] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog Daniel Thompson
@ 2026-10-15 14:55 ` Daniel Thompson
  2026-10-16 14:58   ` sashiko-bot
  2026-10-15 14:55 ` [PATCH net-next v3 2/2] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog Daniel Thompson
  1 sibling, 1 reply; 5+ messages in thread
From: Daniel Thompson @ 2026-10-15 14:55 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Maxime Coquelin, Alexandre Torgue, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, Maxime Chevallier, Eric Dumazet, Chen-Yu Tsai,
	Jernej Skrabec, Samuel Holland, Eric Dumazet
  Cc: Alex Elder, netdev, linux-stm32, linux-arm-kernel, linux-kernel,
	bpf, linux-sunxi, Daniel Thompson

The enable_dma_irq/disasble_dma_irq functions take two booleans, rx and
tx that identify which interrupts should be disabled. Replace these
with a single bitflag argument, group. This allows a third group to be
added which is used to enable/disable other sources of DMA interrupt,
specifically normal and abnormal summary interrupts which are grouped
together as "other".

These changes certainly improve callsite readability, although the real
motivation for the change if to support future changes that need to
mask "other" DMA IRQ interrupts.

There is a very subtle difference introduced by this patch. The sites
that use STMMAC_DMA_IRQ_ALL would previously only have enabled
STMMAC_DMA_IRQ_RXTX. This will not cause any change of behaviour
because the other interrupts are already enabled in all these cases.
STMMAC_DMA_IRQ_ALL has been used in each of these cases to provide
clarify of intent.

Signed-off-by: Daniel Thompson <daniel@riscstar.com>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c  | 12 ++++-----
 drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h   |  4 +--
 drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c   | 29 ++++++++++++++--------
 drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h    |  4 +--
 drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c    | 29 ++++++++++++++--------
 drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 29 ++++++++++++++--------
 drivers/net/ethernet/stmicro/stmmac/hwif.h         | 10 ++++++--
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 26 +++++++++----------
 8 files changed, 88 insertions(+), 55 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 48c52eb9623356b12b39e5c0105d745e237007d6..af7acfc7a26fa4f00bad0901b9fb91d9ce532854 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -347,13 +347,13 @@ static void sun8i_dwmac_dump_mac_regs(struct mac_device_info *hw,
 
 static void sun8i_dwmac_enable_dma_irq(struct stmmac_priv *priv,
 				       void __iomem *ioaddr, u32 chan,
-				       bool rx, bool tx)
+				       u32 flags)
 {
 	u32 value = readl(ioaddr + EMAC_INT_EN);
 
-	if (rx)
+	if (flags & STMMAC_DMA_IRQ_RX)
 		value |= EMAC_RX_INT;
-	if (tx)
+	if (flags & STMMAC_DMA_IRQ_TX)
 		value |= EMAC_TX_INT;
 
 	writel(value, ioaddr + EMAC_INT_EN);
@@ -361,13 +361,13 @@ static void sun8i_dwmac_enable_dma_irq(struct stmmac_priv *priv,
 
 static void sun8i_dwmac_disable_dma_irq(struct stmmac_priv *priv,
 					void __iomem *ioaddr, u32 chan,
-					bool rx, bool tx)
+					u32 flags)
 {
 	u32 value = readl(ioaddr + EMAC_INT_EN);
 
-	if (rx)
+	if (flags & STMMAC_DMA_IRQ_RX)
 		value &= ~EMAC_RX_INT;
-	if (tx)
+	if (flags & STMMAC_DMA_IRQ_TX)
 		value &= ~EMAC_TX_INT;
 
 	writel(value, ioaddr + EMAC_INT_EN);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index 43b036d4e95bdde882ab79e57e7cf6e0b9cb2e39..ca8caade68079252de0d2c4805387f8e07a56f22 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -175,9 +175,9 @@ static inline u32 dma_chanx_base_addr(const struct dwmac4_addrs *addrs,
 
 int dwmac4_dma_reset(void __iomem *ioaddr);
 void dwmac4_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
-			   u32 chan, bool rx, bool tx);
+			   u32 chan, u32 group);
 void dwmac4_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
-			    u32 chan, bool rx, bool tx);
+			    u32 chan, u32 group);
 void dwmac4_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
 			 u32 chan);
 void dwmac4_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
index a0249715fafafdf8c93d1535a15b73daed1168cb..7c5881ca61e8bb586b6d6f791a3fb1c122c814bb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -109,30 +109,39 @@ void dwmac4_set_rx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr,
 	writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(dwmac4_addrs, chan));
 }
 
+static u32 dwmac4_enable_dma_mask(u32 group)
+{
+	u32 mask = 0;
+
+	if (group & STMMAC_DMA_IRQ_RX)
+		mask |= DMA_CHAN_INTR_ENA_RIE;
+	if (group & STMMAC_DMA_IRQ_TX)
+		mask |= DMA_CHAN_INTR_ENA_TIE;
+	if (group & STMMAC_DMA_IRQ_OTHER)
+		mask |= DMA_CHAN_INTR_DEFAULT_MASK &
+			~(DMA_CHAN_INTR_ENA_RIE | DMA_CHAN_INTR_ENA_TIE);
+
+	return mask;
+}
+
 void dwmac4_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
-			   u32 chan, bool rx, bool tx)
+			   u32 chan, u32 group)
 {
 	const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
 	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
 
-	if (rx)
-		value |= DMA_CHAN_INTR_ENA_RIE;
-	if (tx)
-		value |= DMA_CHAN_INTR_ENA_TIE;
+	value |= dwmac4_enable_dma_mask(group);
 
 	writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
 }
 
 void dwmac4_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
-			    u32 chan, bool rx, bool tx)
+			    u32 chan, u32 group)
 {
 	const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
 	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
 
-	if (rx)
-		value &= ~DMA_CHAN_INTR_ENA_RIE;
-	if (tx)
-		value &= ~DMA_CHAN_INTR_ENA_TIE;
+	value &= ~dwmac4_enable_dma_mask(group);
 
 	writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
 }
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index e1c37ac2c99d2ff5be3aa64cab4812821ec60e91..6b4cad57610ca7f391a9baa0871ef7060df29896 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -145,9 +145,9 @@ static inline u32 dma_chan_base_addr(u32 base, u32 chan)
 void dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan);
 void dwmac_enable_dma_reception(void __iomem *ioaddr, u32 chan);
 void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
-			  u32 chan, bool rx, bool tx);
+			  u32 chan, u32 group);
 void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
-			   u32 chan, bool rx, bool tx);
+			   u32 chan, u32 group);
 void dwmac_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
 			u32 chan);
 void dwmac_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index a0383f9486c2db08bff5a62006857c335721966a..d7465271985466c6cbd867c35ebc57a661fce64b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -38,28 +38,37 @@ void dwmac_enable_dma_reception(void __iomem *ioaddr, u32 chan)
 	writel(1, ioaddr + DMA_CHAN_RCV_POLL_DEMAND(chan));
 }
 
+static u32 dwmac_enable_dma_mask(u32 group)
+{
+	u32 mask = 0;
+
+	if (group & STMMAC_DMA_IRQ_RX)
+		mask |= DMA_INTR_DEFAULT_RX;
+	if (group & STMMAC_DMA_IRQ_TX)
+		mask |= DMA_INTR_DEFAULT_TX;
+	if (group & STMMAC_DMA_IRQ_OTHER)
+		mask |= DMA_INTR_DEFAULT_MASK &
+			~(DMA_INTR_DEFAULT_RX | DMA_INTR_DEFAULT_TX);
+
+	return mask;
+}
+
 void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
-			  u32 chan, bool rx, bool tx)
+			  u32 chan, u32 group)
 {
 	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
 
-	if (rx)
-		value |= DMA_INTR_DEFAULT_RX;
-	if (tx)
-		value |= DMA_INTR_DEFAULT_TX;
+	value |= dwmac_enable_dma_mask(group);
 
 	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
 }
 
 void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
-			   u32 chan, bool rx, bool tx)
+			   u32 chan, u32 group)
 {
 	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
 
-	if (rx)
-		value &= ~DMA_INTR_DEFAULT_RX;
-	if (tx)
-		value &= ~DMA_INTR_DEFAULT_TX;
+	value &= ~dwmac_enable_dma_mask(group);
 
 	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
 }
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index ff83858ebc1f33aa8092a2d83018bd5f96b7eead..63459d1a73a95b4fecedc39dbcde31c21a87dc47 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -228,30 +228,39 @@ static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
 	writel(value, ioaddr +  XGMAC_MTL_TXQ_OPMODE(channel));
 }
 
+static u32 dwxgmac2_enable_dma_mask(u32 group)
+{
+	u32 mask = 0;
+
+	if (group & STMMAC_DMA_IRQ_RX)
+		mask |= XGMAC_DMA_INT_DEFAULT_RX;
+	if (group & STMMAC_DMA_IRQ_TX)
+		mask |= XGMAC_DMA_INT_DEFAULT_TX;
+	if (group & STMMAC_DMA_IRQ_OTHER)
+		mask |= XGMAC_DMA_INT_DEFAULT_EN &
+			~(XGMAC_DMA_INT_DEFAULT_RX | XGMAC_DMA_INT_DEFAULT_TX);
+
+	return mask;
+}
+
 static void dwxgmac2_enable_dma_irq(struct stmmac_priv *priv,
 				    void __iomem *ioaddr, u32 chan,
-				    bool rx, bool tx)
+				    u32 group)
 {
 	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
 
-	if (rx)
-		value |= XGMAC_DMA_INT_DEFAULT_RX;
-	if (tx)
-		value |= XGMAC_DMA_INT_DEFAULT_TX;
+	value |= dwxgmac2_enable_dma_mask(group);
 
 	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
 }
 
 static void dwxgmac2_disable_dma_irq(struct stmmac_priv *priv,
 				     void __iomem *ioaddr, u32 chan,
-				     bool rx, bool tx)
+				     u32 group)
 {
 	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
 
-	if (rx)
-		value &= ~XGMAC_DMA_INT_DEFAULT_RX;
-	if (tx)
-		value &= ~XGMAC_DMA_INT_DEFAULT_TX;
+	value &= ~dwxgmac2_enable_dma_mask(group);
 
 	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
 }
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 5e2654c91b4171da0e6143671dade4d62c750e2f..766a36e4fab6619a031e0baeae965f3794b1cbe1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -163,6 +163,12 @@ struct stmmac_desc_ops {
 struct stmmac_dma_cfg;
 struct dma_features;
 
+#define STMMAC_DMA_IRQ_RX BIT(0)
+#define STMMAC_DMA_IRQ_TX BIT(1)
+#define STMMAC_DMA_IRQ_OTHER BIT(2)
+#define STMMAC_DMA_IRQ_TXRX (STMMAC_DMA_IRQ_TX | STMMAC_DMA_IRQ_RX)
+#define STMMAC_DMA_IRQ_ALL (STMMAC_DMA_IRQ_TXRX | STMMAC_DMA_IRQ_OTHER)
+
 /* Specific DMA helpers */
 struct stmmac_dma_ops {
 	/* DMA core initialization */
@@ -194,9 +200,9 @@ struct stmmac_dma_ops {
 	void (*enable_dma_transmission)(void __iomem *ioaddr, u32 chan);
 	void (*enable_dma_reception)(void __iomem *ioaddr, u32 chan);
 	void (*enable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
-			       u32 chan, bool rx, bool tx);
+			       u32 chan, u32 group);
 	void (*disable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
-				u32 chan, bool rx, bool tx);
+				u32 chan, u32 group);
 	void (*start_tx)(struct stmmac_priv *priv, void __iomem *ioaddr,
 			 u32 chan);
 	void (*stop_tx)(struct stmmac_priv *priv, void __iomem *ioaddr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index b837e8e27a352e15c0967cc12773fe18a100a2a5..7b80fe66cf199adbd31b79a484b2970aef211b51 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2515,7 +2515,7 @@ static void stmmac_enable_all_dma_irq(struct stmmac_priv *priv)
 		unsigned long flags;
 
 		spin_lock_irqsave(&ch->lock, flags);
-		stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 1, 1);
+		stmmac_enable_dma_irq(priv, priv->ioaddr, chan, STMMAC_DMA_IRQ_ALL);
 		spin_unlock_irqrestore(&ch->lock, flags);
 	}
 }
@@ -3088,7 +3088,7 @@ static int stmmac_napi_check(struct stmmac_priv *priv, u32 chan, u32 dir)
 	if ((status & handle_rx) && (chan < priv->plat->rx_queues_to_use)) {
 		if (napi_schedule_prep(rx_napi)) {
 			spin_lock_irqsave(&ch->lock, flags);
-			stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 1, 0);
+			stmmac_disable_dma_irq(priv, priv->ioaddr, chan, STMMAC_DMA_IRQ_RX);
 			spin_unlock_irqrestore(&ch->lock, flags);
 			__napi_schedule(rx_napi);
 		}
@@ -3097,7 +3097,7 @@ static int stmmac_napi_check(struct stmmac_priv *priv, u32 chan, u32 dir)
 	if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use)) {
 		if (napi_schedule_prep(tx_napi)) {
 			spin_lock_irqsave(&ch->lock, flags);
-			stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 0, 1);
+			stmmac_disable_dma_irq(priv, priv->ioaddr, chan, STMMAC_DMA_IRQ_TX);
 			spin_unlock_irqrestore(&ch->lock, flags);
 			__napi_schedule(tx_napi);
 		}
@@ -3291,7 +3291,7 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
 	/* DMA CSR Channel configuration */
 	for (chan = 0; chan < dma_csr_ch; chan++) {
 		stmmac_init_chan(priv, priv->ioaddr, priv->plat->dma_cfg, chan);
-		stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 1, 1);
+		stmmac_disable_dma_irq(priv, priv->ioaddr, chan, STMMAC_DMA_IRQ_TXRX);
 	}
 
 	/* DMA RX Channel Configuration */
@@ -3365,7 +3365,7 @@ static enum hrtimer_restart stmmac_tx_timer(struct hrtimer *t)
 		unsigned long flags;
 
 		spin_lock_irqsave(&ch->lock, flags);
-		stmmac_disable_dma_irq(priv, priv->ioaddr, ch->index, 0, 1);
+		stmmac_disable_dma_irq(priv, priv->ioaddr, ch->index, STMMAC_DMA_IRQ_TX);
 		spin_unlock_irqrestore(&ch->lock, flags);
 		__napi_schedule(napi);
 	}
@@ -6013,7 +6013,7 @@ static int stmmac_napi_poll_rx(struct napi_struct *napi, int budget)
 		unsigned long flags;
 
 		spin_lock_irqsave(&ch->lock, flags);
-		stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 1, 0);
+		stmmac_enable_dma_irq(priv, priv->ioaddr, chan, STMMAC_DMA_IRQ_RX);
 		spin_unlock_irqrestore(&ch->lock, flags);
 	}
 
@@ -6042,7 +6042,7 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget)
 		unsigned long flags;
 
 		spin_lock_irqsave(&ch->lock, flags);
-		stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 0, 1);
+		stmmac_enable_dma_irq(priv, priv->ioaddr, chan, STMMAC_DMA_IRQ_TX);
 		spin_unlock_irqrestore(&ch->lock, flags);
 	}
 
@@ -6095,7 +6095,7 @@ static int stmmac_napi_poll_rxtx(struct napi_struct *napi, int budget)
 		/* Both RX and TX work done are complete,
 		 * so enable both RX & TX IRQs.
 		 */
-		stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 1, 1);
+		stmmac_enable_dma_irq(priv, priv->ioaddr, chan, STMMAC_DMA_IRQ_TXRX);
 		spin_unlock_irqrestore(&ch->lock, flags);
 	}
 
@@ -7032,7 +7032,7 @@ void stmmac_disable_rx_queue(struct stmmac_priv *priv, u32 queue)
 	unsigned long flags;
 
 	spin_lock_irqsave(&ch->lock, flags);
-	stmmac_disable_dma_irq(priv, priv->ioaddr, queue, 1, 0);
+	stmmac_disable_dma_irq(priv, priv->ioaddr, queue, STMMAC_DMA_IRQ_RX);
 	spin_unlock_irqrestore(&ch->lock, flags);
 
 	stmmac_stop_rx_dma(priv, queue);
@@ -7072,7 +7072,7 @@ void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue)
 	stmmac_start_rx_dma(priv, queue);
 
 	spin_lock_irqsave(&ch->lock, flags);
-	stmmac_enable_dma_irq(priv, priv->ioaddr, queue, 1, 0);
+	stmmac_enable_dma_irq(priv, priv->ioaddr, queue, STMMAC_DMA_IRQ_RX);
 	spin_unlock_irqrestore(&ch->lock, flags);
 }
 
@@ -7082,7 +7082,7 @@ void stmmac_disable_tx_queue(struct stmmac_priv *priv, u32 queue)
 	unsigned long flags;
 
 	spin_lock_irqsave(&ch->lock, flags);
-	stmmac_disable_dma_irq(priv, priv->ioaddr, queue, 0, 1);
+	stmmac_disable_dma_irq(priv, priv->ioaddr, queue, STMMAC_DMA_IRQ_TX);
 	spin_unlock_irqrestore(&ch->lock, flags);
 
 	stmmac_stop_tx_dma(priv, queue);
@@ -7123,7 +7123,7 @@ void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue)
 	stmmac_start_tx_dma(priv, queue);
 
 	spin_lock_irqsave(&ch->lock, flags);
-	stmmac_enable_dma_irq(priv, priv->ioaddr, queue, 0, 1);
+	stmmac_enable_dma_irq(priv, priv->ioaddr, queue, STMMAC_DMA_IRQ_TX);
 	spin_unlock_irqrestore(&ch->lock, flags);
 }
 
@@ -7191,7 +7191,7 @@ int stmmac_xdp_open(struct net_device *dev)
 	/* DMA CSR Channel configuration */
 	for (chan = 0; chan < dma_csr_ch; chan++) {
 		stmmac_init_chan(priv, priv->ioaddr, priv->plat->dma_cfg, chan);
-		stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 1, 1);
+		stmmac_disable_dma_irq(priv, priv->ioaddr, chan, STMMAC_DMA_IRQ_TXRX);
 	}
 
 	/* Adjust Split header */

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net-next v3 2/2] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog
  2026-10-15 14:55 [PATCH net-next v3 0/2] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog Daniel Thompson
  2026-10-15 14:55 ` [PATCH net-next v3 1/2] net: stmmac: Introduce group arguments for enable/disable_dma_irq Daniel Thompson
@ 2026-10-15 14:55 ` Daniel Thompson
  2026-10-16 14:58   ` sashiko-bot
  1 sibling, 1 reply; 5+ messages in thread
From: Daniel Thompson @ 2026-10-15 14:55 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Jakub Kicinski, Paolo Abeni,
	Maxime Coquelin, Alexandre Torgue, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, Maxime Chevallier, Eric Dumazet, Chen-Yu Tsai,
	Jernej Skrabec, Samuel Holland, Eric Dumazet
  Cc: Alex Elder, netdev, linux-stm32, linux-arm-kernel, linux-kernel,
	bpf, linux-sunxi, Daniel Thompson

Currently stmmac will run a full cycle of IRQ tear down and setup when
setting up a new XDP program. This makes tuning TSN systems difficult
because whenever a new XDP program is installed then the irq threads will
be stopped and restarted which will undo any thread tuning.

The problem is avoided by removing stmmac_free_irq()/stmmac_request_irq()
from stmmac_xdp_release()/stmmac_xdp_open().

stmmac_free_irq() implicitly synchronizes interrupts and, with that
removed, nothing else disables interrupts or makes later actions by
stmmac_xdp_release() safe when there are concurrent interrupts. Thus we
must replace the code to free the IRQ with code to disable (and sync) DMA
interrupts. We also need to avoid re-initializing the DMA channel. Happily
the reinit is redundant, it is sufficient to rely on the re-enabling
of interrupts at the end of stmmac_xdp_open().

Signed-off-by: Daniel Thompson <daniel@riscstar.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 65 +++++++++++++++++------
 1 file changed, 48 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7b80fe66cf199adbd31b79a484b2970aef211b51..f1359637007e211b505dd74577232cdc079baf46 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -144,6 +144,7 @@ static const char *stmmac_dwxgmac_phyif[4] = {
 	[PHY_INTF_RGMII]	= "RGMII",
 };
 
+static void stmmac_synchronize_irq(struct net_device *dev);
 static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
 /* For MSI interrupts handling */
 static irqreturn_t stmmac_mac_interrupt(int irq, void *dev_id);
@@ -2520,6 +2521,23 @@ static void stmmac_enable_all_dma_irq(struct stmmac_priv *priv)
 	}
 }
 
+static void stmmac_disable_all_dma_irq(struct stmmac_priv *priv)
+{
+	u8 rx_channels_count = priv->plat->rx_queues_to_use;
+	u8 tx_channels_count = priv->plat->tx_queues_to_use;
+	u8 dma_csr_ch = max(rx_channels_count, tx_channels_count);
+	u8 chan;
+
+	for (chan = 0; chan < dma_csr_ch; chan++) {
+		struct stmmac_channel *ch = &priv->channel[chan];
+		unsigned long flags;
+
+		spin_lock_irqsave(&ch->lock, flags);
+		stmmac_disable_dma_irq(priv, priv->ioaddr, chan, STMMAC_DMA_IRQ_ALL);
+		spin_unlock_irqrestore(&ch->lock, flags);
+	}
+}
+
 /**
  * stmmac_start_all_dma - start all RX and TX DMA channels
  * @priv: driver private structure
@@ -3816,6 +3834,33 @@ static void stmmac_free_irq(struct net_device *dev,
 	}
 }
 
+static void stmmac_synchronize_irq(struct net_device *dev)
+{
+	struct stmmac_priv *priv = netdev_priv(dev);
+	struct stmmac_msi *msi = priv->msi;
+	int j;
+
+	for (j = priv->plat->tx_queues_to_use - 1; msi && j >= 0; j--) {
+		if (msi->tx_irq[j] > 0)
+			synchronize_irq(msi->tx_irq[j]);
+	}
+
+	for (j = priv->plat->rx_queues_to_use - 1; msi && j >= 0; j--) {
+		if (msi->rx_irq[j] > 0)
+			synchronize_irq(msi->rx_irq[j]);
+	}
+
+	if (msi && msi->sfty_ue_irq > 0 && msi->sfty_ue_irq != dev->irq)
+		synchronize_irq(msi->sfty_ue_irq);
+	if (msi && msi->sfty_ce_irq > 0 && msi->sfty_ce_irq != dev->irq)
+		synchronize_irq(msi->sfty_ce_irq);
+	if (priv->wol_irq > 0 && priv->wol_irq != dev->irq)
+		synchronize_irq(priv->wol_irq);
+	if (priv->sfty_irq > 0 && priv->sfty_irq != dev->irq)
+		synchronize_irq(priv->sfty_irq);
+	synchronize_irq(dev->irq);
+}
+
 static int stmmac_msi_init(struct stmmac_priv *priv,
 			   struct stmmac_resources *res)
 {
@@ -7141,8 +7186,9 @@ void stmmac_xdp_release(struct net_device *dev)
 	for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++)
 		hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer);
 
-	/* Free the IRQ lines */
-	stmmac_free_irq(dev, REQ_IRQ_ERR_ALL, 0);
+	/* Silence DMA interrupts */
+	stmmac_disable_all_dma_irq(priv);
+	stmmac_synchronize_irq(dev);
 
 	/* Stop TX/RX DMA channels */
 	stmmac_stop_all_dma(priv);
@@ -7165,7 +7211,6 @@ int stmmac_xdp_open(struct net_device *dev)
 	struct stmmac_priv *priv = netdev_priv(dev);
 	u8 rx_cnt = priv->plat->rx_queues_to_use;
 	u8 tx_cnt = priv->plat->tx_queues_to_use;
-	u8 dma_csr_ch = max(rx_cnt, tx_cnt);
 	struct stmmac_rx_queue *rx_q;
 	struct stmmac_tx_queue *tx_q;
 	bool sph_en;
@@ -7188,12 +7233,6 @@ int stmmac_xdp_open(struct net_device *dev)
 
 	stmmac_reset_queues_param(priv);
 
-	/* DMA CSR Channel configuration */
-	for (chan = 0; chan < dma_csr_ch; chan++) {
-		stmmac_init_chan(priv, priv->ioaddr, priv->plat->dma_cfg, chan);
-		stmmac_disable_dma_irq(priv, priv->ioaddr, chan, STMMAC_DMA_IRQ_TXRX);
-	}
-
 	/* Adjust Split header */
 	sph_en = (priv->hw->rx_csum > 0) && priv->sph_active;
 
@@ -7230,10 +7269,6 @@ int stmmac_xdp_open(struct net_device *dev)
 	/* Start Rx & Tx DMA Channels */
 	stmmac_start_all_dma(priv);
 
-	ret = stmmac_request_irq(dev);
-	if (ret)
-		goto irq_error;
-
 	/* Enable NAPI process*/
 	stmmac_enable_all_queues(priv);
 	netif_carrier_on(dev);
@@ -7242,10 +7277,6 @@ int stmmac_xdp_open(struct net_device *dev)
 
 	return 0;
 
-irq_error:
-	for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++)
-		hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer);
-
 init_error:
 	free_dma_desc_resources(priv, &priv->dma_conf);
 dma_desc_error:

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next v3 1/2] net: stmmac: Introduce group arguments for enable/disable_dma_irq
  2026-10-15 14:55 ` [PATCH net-next v3 1/2] net: stmmac: Introduce group arguments for enable/disable_dma_irq Daniel Thompson
@ 2026-10-16 14:58   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-10-16 14:58 UTC (permalink / raw)
  To: Daniel Thompson; +Cc: bpf, linux-sunxi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] net: stmmac: hardcoded generic OTHER masks break variant-specific IRQs
--

commit 6b53d33b472c115af2d55abc75c5663ee8048b05
Author: Daniel Thompson <daniel@riscstar.com>

net: stmmac: Introduce group arguments for enable/disable_dma_irq

The enable_dma_irq/disable_dma_irq functions take two booleans, rx and tx,
that identify which interrupts should be disabled. Replace these with a single
bitflag argument, group. This allows a third group to be added which is used to
enable/disable other sources of DMA interrupt.

> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
> index a0249715fafaf..7c5881ca61e8b 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
[ ... ]
> @@ -109,30 +109,39 @@ void dwmac4_set_rx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr,
>  	writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(dwmac4_addrs, chan));
>  }
>  
> +static u32 dwmac4_enable_dma_mask(u32 group)
> +{
> +	u32 mask = 0;
> +
> +	if (group & STMMAC_DMA_IRQ_RX)
> +		mask |= DMA_CHAN_INTR_ENA_RIE;
> +	if (group & STMMAC_DMA_IRQ_TX)
> +		mask |= DMA_CHAN_INTR_ENA_TIE;
> +	if (group & STMMAC_DMA_IRQ_OTHER)
> +		mask |= DMA_CHAN_INTR_DEFAULT_MASK &
> +			~(DMA_CHAN_INTR_ENA_RIE | DMA_CHAN_INTR_ENA_TIE);
> +
> +	return mask;
> +}

[Severity: High]
Does hardcoding DMA_CHAN_INTR_DEFAULT_MASK here cause a regression for
hardware variants that require different bit layouts for summary and abnormal
interrupts?

For example, 4.10a uses a different mask DMA_CHAN_INTR_DEFAULT_MASK_4_10
during channel initialization, where AIE is BIT 14 rather than BIT 15. Since
the generic mask is used here, an attempt to disable STMMAC_DMA_IRQ_OTHER
interrupts could fail to clear the AIE bit on 4.10a hardware, potentially
causing an interrupt storm or use-after-free if unmasked interrupts fire
during XDP ring reconfiguration.

[ ... ]
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
> index a0383f9486c2d..d746527198546 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
[ ... ]
> +static u32 dwmac_enable_dma_mask(u32 group)
> +{
> +	u32 mask = 0;
> +
> +	if (group & STMMAC_DMA_IRQ_RX)
> +		mask |= DMA_INTR_DEFAULT_RX;
> +	if (group & STMMAC_DMA_IRQ_TX)
> +		mask |= DMA_INTR_DEFAULT_TX;
> +	if (group & STMMAC_DMA_IRQ_OTHER)
> +		mask |= DMA_INTR_DEFAULT_MASK &
> +			~(DMA_INTR_DEFAULT_RX | DMA_INTR_DEFAULT_TX);

[Severity: High]
Could this hardcoded mask also cause a regression for Loongson MACs?

Loongson hardware uses a custom mask layout DMA_INTR_DEFAULT_MASK_LOONGSON
because it has specific bits like NIS_TX (BIT 18) and NIS_RX (BIT 17). This
generic mask does not cover those bits, meaning they might remain enabled
when attempting to mask STMMAC_DMA_IRQ_OTHER interrupts.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261015-tc956x-stmmac-no_irq_teardown-v3-0-8189870be545@riscstar.com?part=1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next v3 2/2] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog
  2026-10-15 14:55 ` [PATCH net-next v3 2/2] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog Daniel Thompson
@ 2026-10-16 14:58   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-10-16 14:58 UTC (permalink / raw)
  To: Daniel Thompson; +Cc: bpf, linux-sunxi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] net: stmmac: Use-After-Free in stmmac_tx_err() due to active ISR after DMA descriptors freed
--

commit 4c2320440039ed3235615c60f92cbcfdc0584d5a
Author: Daniel Thompson <daniel@riscstar.com>

net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog

This commit changes the XDP setup process to avoid completely freeing and
re-requesting IRQs, which disrupts TSN thread tuning. Instead of calling
stmmac_free_irq(), it masks the DMA interrupts and synchronizes them during
XDP release.

> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 7b80fe66cf199..f1359637007e2 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
[ ... ]
> @@ -7141,8 +7186,9 @@ void stmmac_xdp_release(struct net_device *dev)
>  	for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++)
>  		hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer);
>  
> -	/* Free the IRQ lines */
> -	stmmac_free_irq(dev, REQ_IRQ_ERR_ALL, 0);
> +	/* Silence DMA interrupts */
> +	stmmac_disable_all_dma_irq(priv);
> +	stmmac_synchronize_irq(dev);
>  
>  	/* Stop TX/RX DMA channels */
>  	stmmac_stop_all_dma(priv);

[Severity: High]
Could this change introduce a use-after-free when setting up an XDP program?

Since the ISR stmmac_interrupt() remains registered after replacing
stmmac_free_irq(), the interrupt handler can still run if a shared IRQ or
unmasked MAC interrupt fires.

When stmmac_stop_all_dma() stops the TX DMA, it sets the TPS (Tx Process
Stopped) bit in the hardware DMA status register.

Immediately after this in stmmac_xdp_release(), free_dma_desc_resources()
is called, which frees the descriptor memory without assigning NULL.

If an interrupt fires at this point, stmmac_interrupt() reads the raw DMA
status and evaluates TPS regardless of whether DMA interrupts are masked:

drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c:dwmac4_dma_interrupt() {
    ...
    if (unlikely(intr_status & DMA_CHAN_STATUS_TPS)) {
        x->tx_process_stopped_irq++;
        ret = tx_hard_error;
    }
    ...
}

This unconditionally returns tx_hard_error, which then triggers
stmmac_tx_err() to execute.

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c:stmmac_tx_err() {
    ...
    dma_free_tx_skbufs(priv, &priv->dma_conf, chan);
    stmmac_clear_tx_descriptors(priv, &priv->dma_conf, chan);
    ...
}

Will stmmac_tx_err() then try to clear and re-free the already freed
descriptors, resulting in a use-after-free?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261015-tc956x-stmmac-no_irq_teardown-v3-0-8189870be545@riscstar.com?part=2

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-10-16 14:58 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-15 14:55 [PATCH net-next v3 0/2] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog Daniel Thompson
2026-10-15 14:55 ` [PATCH net-next v3 1/2] net: stmmac: Introduce group arguments for enable/disable_dma_irq Daniel Thompson
2026-10-16 14:58   ` sashiko-bot
2026-10-15 14:55 ` [PATCH net-next v3 2/2] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog Daniel Thompson
2026-10-16 14:58   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox