Re: [PATCH v10 0/5] Support multi-channel IRQs in stmmac platform drivers

From: Russell King (Oracle)

Date: Wed Mar 11 2026 - 09:33:53 EST


On Wed, Mar 11, 2026 at 11:17:57AM +0100, Jan Petrous via B4 Relay wrote:
> The stmmac core supports two interrupt modes, controlled by the
> flag STMMAC_FLAG_MULTI_MSI_EN:
>
> - When the flag is set, the driver uses multi-channel IRQ mode (Multi-IRQ).
> - Otherwise, a single IRQ line is requested (aka MAC-IRQ):

Please can you test with this patch included - it's bubbled up near to
the top of my patch queue for net-next.

8<===
From: "Russell King (Oracle)" <rmk+kernel@xxxxxxxxxxxxxxx>
Subject: [PATCH net-next] net: stmmac: move MSI data out of struct stmmac_priv

Only three platforms supprt MSIs, which means having all the strings
and interrupt arrays always allocated wastes space. None of this data
is performance critical - this data is only used when requesting and
releasing the MSI interrupts.

Move the MSI data out of struct stmmac_priv into its own separately
allocated structure, and move its initialisation to a separate
function.

This removes 768 bytes from struct stmmac_priv.

Link: https://lore.kernel.org/r/aYtq4ypxXTvn_Is6@xxxxxxxxxxxxxxxxxxxxx
Signed-off-by: Russell King (Oracle) <rmk+kernel@xxxxxxxxxxxxxxx>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 31 +++---
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 96 ++++++++++++-------
2 files changed, 77 insertions(+), 50 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index bba9bb9c95bf..7a66edba8f66 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -243,6 +243,23 @@ struct stmmac_est {
u32 max_sdu[MTL_MAX_TX_QUEUES];
};

+struct stmmac_msi {
+ int sfty_ce_irq;
+ int sfty_ue_irq;
+ int rx_irq[MTL_MAX_RX_QUEUES];
+ int tx_irq[MTL_MAX_TX_QUEUES];
+
+ /*irq name */
+ char int_name_mac[IFNAMSIZ + 9];
+ char int_name_wol[IFNAMSIZ + 9];
+ char int_name_lpi[IFNAMSIZ + 9];
+ char int_name_sfty[IFNAMSIZ + 10];
+ char int_name_sfty_ce[IFNAMSIZ + 10];
+ char int_name_sfty_ue[IFNAMSIZ + 10];
+ char int_name_rx_irq[MTL_MAX_RX_QUEUES][IFNAMSIZ + 14];
+ char int_name_tx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 18];
+};
+
struct stmmac_priv {
/* Frequently used values are kept adjacent for cache effect */
u32 tx_coal_frames[MTL_MAX_TX_QUEUES];
@@ -329,19 +346,7 @@ struct stmmac_priv {
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
unsigned int num_double_vlans;
int sfty_irq;
- int sfty_ce_irq;
- int sfty_ue_irq;
- int rx_irq[MTL_MAX_RX_QUEUES];
- int tx_irq[MTL_MAX_TX_QUEUES];
- /*irq name */
- char int_name_mac[IFNAMSIZ + 9];
- char int_name_wol[IFNAMSIZ + 9];
- char int_name_lpi[IFNAMSIZ + 9];
- char int_name_sfty[IFNAMSIZ + 10];
- char int_name_sfty_ce[IFNAMSIZ + 10];
- char int_name_sfty_ue[IFNAMSIZ + 10];
- char int_name_rx_irq[MTL_MAX_RX_QUEUES][IFNAMSIZ + 14];
- char int_name_tx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 18];
+ struct stmmac_msi *msi;

#ifdef CONFIG_DEBUG_FS
struct dentry *dbgfs_dir;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 11150bddd872..24de4033c886 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3725,6 +3725,7 @@ static void stmmac_free_irq(struct net_device *dev,
enum request_irq_err irq_err, int irq_idx)
{
struct stmmac_priv *priv = netdev_priv(dev);
+ struct stmmac_msi *msi = priv->msi;
int j;

switch (irq_err) {
@@ -3733,27 +3734,27 @@ static void stmmac_free_irq(struct net_device *dev,
fallthrough;
case REQ_IRQ_ERR_TX:
for (j = irq_idx - 1; j >= 0; j--) {
- if (priv->tx_irq[j] > 0) {
- irq_set_affinity_hint(priv->tx_irq[j], NULL);
- free_irq(priv->tx_irq[j], &priv->dma_conf.tx_queue[j]);
+ if (msi->tx_irq[j] > 0) {
+ irq_set_affinity_hint(msi->tx_irq[j], NULL);
+ free_irq(msi->tx_irq[j], &priv->dma_conf.tx_queue[j]);
}
}
irq_idx = priv->plat->rx_queues_to_use;
fallthrough;
case REQ_IRQ_ERR_RX:
for (j = irq_idx - 1; j >= 0; j--) {
- if (priv->rx_irq[j] > 0) {
- irq_set_affinity_hint(priv->rx_irq[j], NULL);
- free_irq(priv->rx_irq[j], &priv->dma_conf.rx_queue[j]);
+ if (msi->rx_irq[j] > 0) {
+ irq_set_affinity_hint(msi->rx_irq[j], NULL);
+ free_irq(msi->rx_irq[j], &priv->dma_conf.rx_queue[j]);
}
}

- if (priv->sfty_ue_irq > 0 && priv->sfty_ue_irq != dev->irq)
- free_irq(priv->sfty_ue_irq, dev);
+ if (msi->sfty_ue_irq > 0 && msi->sfty_ue_irq != dev->irq)
+ free_irq(msi->sfty_ue_irq, dev);
fallthrough;
case REQ_IRQ_ERR_SFTY_UE:
- if (priv->sfty_ce_irq > 0 && priv->sfty_ce_irq != dev->irq)
- free_irq(priv->sfty_ce_irq, dev);
+ if (msi->sfty_ce_irq > 0 && msi->sfty_ce_irq != dev->irq)
+ free_irq(msi->sfty_ce_irq, dev);
fallthrough;
case REQ_IRQ_ERR_SFTY_CE:
if (priv->wol_irq > 0 && priv->wol_irq != dev->irq)
@@ -3773,9 +3774,30 @@ static void stmmac_free_irq(struct net_device *dev,
}
}

+static int stmmac_msi_init(struct stmmac_priv *priv,
+ struct stmmac_resources *res)
+{
+ int i;
+
+ priv->msi = devm_kmalloc(priv->device, sizeof(*priv->msi), GFP_KERNEL);
+ if (!priv->msi)
+ return -ENOMEM;
+
+ priv->msi->sfty_ce_irq = res->sfty_ce_irq;
+ priv->msi->sfty_ue_irq = res->sfty_ue_irq;
+
+ for (i = 0; i < MTL_MAX_RX_QUEUES; i++)
+ priv->msi->rx_irq[i] = res->rx_irq[i];
+ for (i = 0; i < MTL_MAX_TX_QUEUES; i++)
+ priv->msi->tx_irq[i] = res->tx_irq[i];
+
+ return 0;
+}
+
static int stmmac_request_irq_multi_msi(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
+ struct stmmac_msi *msi = priv->msi;
enum request_irq_err irq_err;
int irq_idx = 0;
char *int_name;
@@ -3783,7 +3805,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
int i;

/* For common interrupt */
- int_name = priv->int_name_mac;
+ int_name = msi->int_name_mac;
sprintf(int_name, "%s:%s", dev->name, "mac");
ret = request_irq(dev->irq, stmmac_mac_interrupt,
0, int_name, dev);
@@ -3799,7 +3821,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
* is used for WoL
*/
if (priv->wol_irq > 0 && priv->wol_irq != dev->irq) {
- int_name = priv->int_name_wol;
+ int_name = msi->int_name_wol;
sprintf(int_name, "%s:%s", dev->name, "wol");
ret = request_irq(priv->wol_irq,
stmmac_mac_interrupt,
@@ -3817,7 +3839,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
* Error line in case of another line is used
*/
if (priv->sfty_irq > 0 && priv->sfty_irq != dev->irq) {
- int_name = priv->int_name_sfty;
+ int_name = msi->int_name_sfty;
sprintf(int_name, "%s:%s", dev->name, "safety");
ret = request_irq(priv->sfty_irq, stmmac_safety_interrupt,
0, int_name, dev);
@@ -3833,16 +3855,16 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
/* Request the Safety Feature Correctible Error line in
* case of another line is used
*/
- if (priv->sfty_ce_irq > 0 && priv->sfty_ce_irq != dev->irq) {
- int_name = priv->int_name_sfty_ce;
+ if (msi->sfty_ce_irq > 0 && msi->sfty_ce_irq != dev->irq) {
+ int_name = msi->int_name_sfty_ce;
sprintf(int_name, "%s:%s", dev->name, "safety-ce");
- ret = request_irq(priv->sfty_ce_irq,
+ ret = request_irq(msi->sfty_ce_irq,
stmmac_safety_interrupt,
0, int_name, dev);
if (unlikely(ret < 0)) {
netdev_err(priv->dev,
"%s: alloc sfty ce MSI %d (error: %d)\n",
- __func__, priv->sfty_ce_irq, ret);
+ __func__, msi->sfty_ce_irq, ret);
irq_err = REQ_IRQ_ERR_SFTY_CE;
goto irq_error;
}
@@ -3851,16 +3873,16 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
/* Request the Safety Feature Uncorrectible Error line in
* case of another line is used
*/
- if (priv->sfty_ue_irq > 0 && priv->sfty_ue_irq != dev->irq) {
- int_name = priv->int_name_sfty_ue;
+ if (msi->sfty_ue_irq > 0 && msi->sfty_ue_irq != dev->irq) {
+ int_name = msi->int_name_sfty_ue;
sprintf(int_name, "%s:%s", dev->name, "safety-ue");
- ret = request_irq(priv->sfty_ue_irq,
+ ret = request_irq(msi->sfty_ue_irq,
stmmac_safety_interrupt,
0, int_name, dev);
if (unlikely(ret < 0)) {
netdev_err(priv->dev,
"%s: alloc sfty ue MSI %d (error: %d)\n",
- __func__, priv->sfty_ue_irq, ret);
+ __func__, msi->sfty_ue_irq, ret);
irq_err = REQ_IRQ_ERR_SFTY_UE;
goto irq_error;
}
@@ -3870,23 +3892,23 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
for (i = 0; i < priv->plat->rx_queues_to_use; i++) {
if (i >= MTL_MAX_RX_QUEUES)
break;
- if (priv->rx_irq[i] == 0)
+ if (msi->rx_irq[i] == 0)
continue;

- int_name = priv->int_name_rx_irq[i];
+ int_name = msi->int_name_rx_irq[i];
sprintf(int_name, "%s:%s-%d", dev->name, "rx", i);
- ret = request_irq(priv->rx_irq[i],
+ ret = request_irq(msi->rx_irq[i],
stmmac_msi_intr_rx,
0, int_name, &priv->dma_conf.rx_queue[i]);
if (unlikely(ret < 0)) {
netdev_err(priv->dev,
"%s: alloc rx-%d MSI %d (error: %d)\n",
- __func__, i, priv->rx_irq[i], ret);
+ __func__, i, msi->rx_irq[i], ret);
irq_err = REQ_IRQ_ERR_RX;
irq_idx = i;
goto irq_error;
}
- irq_set_affinity_hint(priv->rx_irq[i],
+ irq_set_affinity_hint(msi->rx_irq[i],
cpumask_of(i % num_online_cpus()));
}

@@ -3894,23 +3916,23 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
for (i = 0; i < priv->plat->tx_queues_to_use; i++) {
if (i >= MTL_MAX_TX_QUEUES)
break;
- if (priv->tx_irq[i] == 0)
+ if (msi->tx_irq[i] == 0)
continue;

- int_name = priv->int_name_tx_irq[i];
+ int_name = msi->int_name_tx_irq[i];
sprintf(int_name, "%s:%s-%d", dev->name, "tx", i);
- ret = request_irq(priv->tx_irq[i],
+ ret = request_irq(msi->tx_irq[i],
stmmac_msi_intr_tx,
0, int_name, &priv->dma_conf.tx_queue[i]);
if (unlikely(ret < 0)) {
netdev_err(priv->dev,
"%s: alloc tx-%d MSI %d (error: %d)\n",
- __func__, i, priv->tx_irq[i], ret);
+ __func__, i, msi->tx_irq[i], ret);
irq_err = REQ_IRQ_ERR_TX;
irq_idx = i;
goto irq_error;
}
- irq_set_affinity_hint(priv->tx_irq[i],
+ irq_set_affinity_hint(msi->tx_irq[i],
cpumask_of(i % num_online_cpus()));
}

@@ -7806,12 +7828,12 @@ static int __stmmac_dvr_probe(struct device *device,
priv->dev->irq = res->irq;
priv->wol_irq = res->wol_irq;
priv->sfty_irq = res->sfty_irq;
- priv->sfty_ce_irq = res->sfty_ce_irq;
- priv->sfty_ue_irq = res->sfty_ue_irq;
- for (i = 0; i < MTL_MAX_RX_QUEUES; i++)
- priv->rx_irq[i] = res->rx_irq[i];
- for (i = 0; i < MTL_MAX_TX_QUEUES; i++)
- priv->tx_irq[i] = res->tx_irq[i];
+
+ if (priv->plat->flags & STMMAC_FLAG_MULTI_MSI_EN) {
+ ret = stmmac_msi_init(priv, res);
+ if (ret)
+ return ret;
+ }

if (!is_zero_ether_addr(res->mac))
eth_hw_addr_set(priv->dev, res->mac);
--
2.47.3

--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!