[PATCH net-next 2/2] net/mlx5e: Batch ICOSQ trigger RCU synchronization

From: Tariq Toukan

Date: Sun Oct 11 2026 - 12:39:48 EST


From: Carolina Jubran <cjubran@xxxxxxxxxx>

During channel activation, mlx5e_activate_channels() triggers the ICOSQ
once for every channel in order to kick NAPI. mlx5e_trigger_napi_icosq()
sets MLX5E_SQ_STATE_LOCK_NEEDED and waits for an RCU grace period before
serializing the trigger with ICOSQ users in NAPI context.

Mark all channel ICOSQs as requiring locking first, wait for a single
grace period, and then trigger all of them.

Keep mlx5e_trigger_napi_icosq() with its existing synchronization
semantics for standalone callers.

248 channels, rcu_normal=1, ip link set eth2 up:
Before: 3.095s
After: 1.794s (~1.7x faster)

Signed-off-by: Carolina Jubran <cjubran@xxxxxxxxxx>
Signed-off-by: Tariq Toukan <tariqt@xxxxxxxxxx>
---
.../net/ethernet/mellanox/mlx5/core/en_main.c | 28 +++++++++++++++----
1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index fe4e5d0b2e9a..58e4874b664f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -2837,14 +2837,11 @@ static int mlx5e_channel_stats_alloc(struct mlx5e_priv *priv, int ix, int cpu)
return 0;
}

-void mlx5e_trigger_napi_icosq(struct mlx5e_channel *c)
+static void mlx5e_trigger_napi_icosq_post_sync(struct mlx5e_channel *c)
{
struct mlx5e_icosq *sq = &c->icosq;
bool locked;

- set_bit(MLX5E_SQ_STATE_LOCK_NEEDED, &sq->state);
- synchronize_net();
-
locked = mlx5e_icosq_sync_lock(sq);
mlx5e_trigger_irq(sq);
mlx5e_icosq_sync_unlock(sq, locked);
@@ -2852,6 +2849,13 @@ void mlx5e_trigger_napi_icosq(struct mlx5e_channel *c)
clear_bit(MLX5E_SQ_STATE_LOCK_NEEDED, &sq->state);
}

+void mlx5e_trigger_napi_icosq(struct mlx5e_channel *c)
+{
+ set_bit(MLX5E_SQ_STATE_LOCK_NEEDED, &c->icosq.state);
+ synchronize_net();
+ mlx5e_trigger_napi_icosq_post_sync(c);
+}
+
void mlx5e_trigger_napi_async_icosq(struct mlx5e_channel *c)
{
struct mlx5e_icosq *sq = c->async_icosq;
@@ -3099,6 +3103,19 @@ int mlx5e_open_channels(struct mlx5e_priv *priv,
return err;
}

+static void mlx5e_trigger_napi_icosqs(struct mlx5e_channels *chs)
+{
+ int i;
+
+ for (i = 0; i < chs->num; i++)
+ set_bit(MLX5E_SQ_STATE_LOCK_NEEDED, &chs->c[i]->icosq.state);
+
+ synchronize_net();
+
+ for (i = 0; i < chs->num; i++)
+ mlx5e_trigger_napi_icosq_post_sync(chs->c[i]);
+}
+
static void mlx5e_activate_channels(struct mlx5e_priv *priv, struct mlx5e_channels *chs)
{
int i;
@@ -3109,8 +3126,7 @@ static void mlx5e_activate_channels(struct mlx5e_priv *priv, struct mlx5e_channe
if (priv->htb)
mlx5e_qos_activate_queues(priv);

- for (i = 0; i < chs->num; i++)
- mlx5e_trigger_napi_icosq(chs->c[i]);
+ mlx5e_trigger_napi_icosqs(chs);

if (chs->ptp)
mlx5e_ptp_activate_channel(chs->ptp);
--
2.44.0