* [PATCH] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog
@ 2026-07-06 16:17 Daniel Thompson
2026-07-06 16:37 ` sashiko-bot
0 siblings, 1 reply; 2+ messages in thread
From: Daniel Thompson @ 2026-07-06 16:17 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Alexandre Torgue,
Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
John Fastabend, Stanislav Fomichev
Cc: Alex Elder, netdev, linux-stm32, linux-arm-kernel, linux-kernel,
bpf, 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, I was unable to prove that later actions in
stmmac_xdp_release() are safe when there are concurrent interrupts. To
avoid problems let's also move the code to disable DMA interrupts earlier
in the sequence and explicitly sync the interrupts handler(s).
Signed-off-by: Daniel Thompson <daniel@riscstar.com>
---
This patch was 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 so it makes sense to submit it as
a separate patch.
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 61 ++++++++++++++++++-----
1 file changed, 48 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 2a0d7eff88d3ff1ffa57e224c25f9e77bc28ed10..acd145f1f3069fde6043a9118c793758c5c8f4c0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2531,6 +2531,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, 1, 1);
+ spin_unlock_irqrestore(&ch->lock, flags);
+ }
+}
+
/**
* stmmac_start_all_dma - start all RX and TX DMA channels
* @priv: driver private structure
@@ -3814,6 +3831,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)
{
@@ -7108,8 +7152,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);
@@ -7156,10 +7201,8 @@ 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++) {
+ 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);
- }
/* Adjust Split header */
sph_en = (priv->hw->rx_csum > 0) && priv->sph_active;
@@ -7197,10 +7240,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);
@@ -7209,10 +7248,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:
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260706-tc956x-stmmac-no_irq_teardown-8a7592b9f8c1
Best regards,
--
Daniel Thompson <daniel@riscstar.com>
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog
2026-07-06 16:17 [PATCH] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog Daniel Thompson
@ 2026-07-06 16:37 ` sashiko-bot
0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-07-06 16:37 UTC (permalink / raw)
To: Daniel Thompson; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] Removing `stmmac_disable_dma_irq()` during XDP open leaves DMA interrupts unmasked before NAPI is enabled, leading to lost wakeups and potential interrupt storms.
Pre-existing issues:
- [Critical] Concurrent `ndo_xdp_xmit` access during XDP reconfiguration causes UAF of DMA descriptors.
- [High] The return value of `stmmac_xdp_open()` is ignored in `stmmac_xdp_setup_prog()`, leading to a silent network outage if reopening the device fails.
--
commit 28a5a0b2fab7c42eb59936b760afc9e0ec09c6ef
Author: Daniel Thompson <daniel@riscstar.com>
net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog
This commit removes the implicit IRQ synchronization by omitting calls to
stmmac_free_irq() and stmmac_request_irq() during XDP program setup. It
instead explicitly disables DMA interrupts and synchronizes the IRQ handler
to prevent tearing down and restarting IRQ threads, which disrupts TSN
system tuning.
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 2a0d7eff88d3f..acd145f1f3069 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
[ ... ]
> @@ -7108,8 +7152,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: Critical]
This is a pre-existing issue, but does freeing the DMA descriptor rings
shortly after this point (via free_dma_desc_resources) cause a
use-after-free if ndo_xdp_xmit runs concurrently?
While stmmac_xdp_release() calls netif_tx_disable(), this does not stop
stmmac_xdp_xmit() from executing. If an XDP redirect occurs exactly while
the program is being detached, could stmmac_xdp_xmit() proceed and access
the freed tx_q->dma_tx array? It appears stmmac_xdp_xmit() only checks
STMMAC_DOWN, which is not set during XDP reconfiguration.
[ ... ]
> @@ -7156,10 +7201,8 @@ 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++) {
> + 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);
> - }
>
> /* Adjust Split header */
> sph_en = (priv->hw->rx_csum > 0) && priv->sph_active;
[Severity: High]
When stmmac_disable_dma_irq() is removed here, stmmac_init_chan() still
unmasks interrupts at the hardware level. Does this leave the DMA interrupts
unmasked before NAPI is enabled?
Since the OS IRQ is now permanently active (not freed during release), could
a packet arriving right after stmmac_start_all_dma() fire an interrupt
before stmmac_enable_all_queues() has run? It looks like this might cause
the interrupt service routine's call to napi_schedule_prep() to fail,
leading to a lost wakeup or an interrupt storm.
[ ... ]
[Severity: High]
This is a pre-existing issue, but I noticed that in stmmac_xdp_setup_prog()
in drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c, the return value of
stmmac_xdp_open() is ignored:
drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c:stmmac_xdp_setup_prog() {
...
if (if_running && need_update)
stmmac_xdp_open(dev);
if (prog)
xdp_features_set_redirect_target(dev, false);
return 0;
}
If stmmac_xdp_open() fails (for example, due to a memory allocation failure
for DMA rings), it returns a negative error code. Does ignoring this error
mask the initialization failure and leave the interface functionally down,
potentially leading to a silent network outage?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260706-tc956x-stmmac-no_irq_teardown-v1-1-df009d0272bf@riscstar.com?part=1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-06 16:37 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-06 16:17 [PATCH] net: stmmac: Avoid freeing and re-requesting IRQ during XDP set prog Daniel Thompson
2026-07-06 16:37 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox