Re: [PATCH RFC 3/3] net: stmmac: Migrate IRQ balancing to cpumask_local_spread()

From: Yury Norov

Date: Wed Aug 19 2026 - 14:49:41 EST


On Wed, Aug 19, 2026 at 04:30:32PM +0200, Florian Bezdeka wrote:
> The previous balancing mechanism was based on num_online_cpus(), which
> is a problem for systems cpu-isolating workloads. IRQs were targeting
> CPUs that were isolated for those sensitive workloads.
>
> With a migration to cpumask_local_spread() we
> - get NUMA locality
> - honor the default SMP affinity mask, which avoids targeting
> isolated CPUs.
>
> This also aligns with the pattern used by most network drivers dealing
> with IRQ affinities / affinity hints.
>
> Signed-off-by: Florian Bezdeka <florian.bezdeka@xxxxxxxxxxx>
> ---
> drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 21 +++++++++++++++++----
> 1 file changed, 17 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index a71f0df263785dd8badc45292ca3067ab33bda05..949ced7e46d2814b57c6bd86b4886ac3bf33996c 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -3826,11 +3826,16 @@ 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;
> + cpumask_var_t affinity;
> int irq_idx = 0;
> char *int_name;
> + int node;
> int ret;
> int i;
>
> + if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
> + return -ENOMEM;
> +
> /* For common interrupt */
> int_name = msi->int_name_mac;
> sprintf(int_name, "%s:%s", dev->name, "mac");
> @@ -3916,6 +3921,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
> }
>
> /* Request Rx MSI irq */
> + node = dev_to_node(&priv->dev->dev);
> for (i = 0; i < priv->plat->rx_queues_to_use; i++) {
> if (i >= MTL_MAX_RX_QUEUES)
> break;
> @@ -3935,8 +3941,10 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
> irq_idx = i;
> goto irq_error;
> }
> - irq_set_affinity_hint(msi->rx_irq[i],
> - cpumask_of(i % num_online_cpus()));
> +
> + cpumask_clear(affinity);
> + cpumask_set_cpu(cpumask_local_spread(i, node), affinity);
> + irq_set_affinity_and_hint(msi->rx_irq[i], affinity);

If you want to spread more than one IRQ, you'd better convert your
loop into for_each_numa_hop_mask(). That way you don't need to
introduce new function. See the comment on top of
cpumask_local_spread():

* For those who wants to enumerate all CPUs based on their NUMA distances,
* i.e. call this function in a loop, like:
*
* for (i = 0; i < num_online_cpus(); i++) {
* cpu = cpumask_local_spread(i, node);
* do_something(cpu);
* }
*
* There's a better alternative based on for_each()-like iterators:
*
* for_each_numa_hop_mask(mask, node) {
* for_each_cpu_andnot(cpu, mask, prev)
* do_something(cpu);
* prev = mask;
* }

Thanks,
Yury

> }
>
> /* Request Tx MSI irq */
> @@ -3959,13 +3967,18 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
> irq_idx = i;
> goto irq_error;
> }
> - irq_set_affinity_hint(msi->tx_irq[i],
> - cpumask_of(i % num_online_cpus()));
> +
> + cpumask_clear(affinity);
> + cpumask_set_cpu(cpumask_local_spread(i, node), affinity);
> + irq_set_affinity_and_hint(msi->tx_irq[i], affinity);
> }
>
> + free_cpumask_var(affinity);
> +
> return 0;
>
> irq_error:
> + free_cpumask_var(affinity);
> stmmac_free_irq(dev, irq_err, irq_idx);
> return ret;
> }
>
> --
> 2.55.0