From 25f6b929c7e379cbea7cb8caa67b49b2d1efae17 Mon Sep 17 00:00:00 2001 From: Feng Liu Date: Tue, 30 Jun 2026 14:51:49 +0300 Subject: [PATCH 1/3] net/mlx5e: Fix HV VHCA stats zero-sized buffer allocation mlx5e_hv_vhca_stats_create() is called from mlx5e_nic_enable(), before mlx5e_open(). At that point priv->stats_nch is still zero, because it is only ever incremented in mlx5e_channel_stats_alloc(), which is reached only from mlx5e_open_channel(). mlx5e_hv_vhca_stats_buf_size() therefore returns 0, and kvzalloc(0, GFP_KERNEL) returns ZERO_SIZE_PTR ((void *)16) rather than NULL. The "if (!buf)" guard does not catch this, and mlx5e_hv_vhca_stats_create() completes "successfully" with priv->stats_agent.buf set to ZERO_SIZE_PTR. Once channels are opened (priv->stats_nch > 0) and the hypervisor enables stats reporting, mlx5e_hv_vhca_stats_work() recomputes buf_len using the new non-zero stats_nch and calls memset(buf, 0, buf_len) on ZERO_SIZE_PTR, faulting at address 0x10. Allocate the buffer based on priv->max_nch, which is set in mlx5e_priv_init() and is the upper bound on stats_nch: - Add a separate helper mlx5e_hv_vhca_stats_buf_max_size() that returns sizeof(per_ring_stats) * max(max_nch, stats_nch), and use it for the kvzalloc() in mlx5e_hv_vhca_stats_create(). - Keep mlx5e_hv_vhca_stats_buf_size() (which returns based on stats_nch) for the worker's active payload size, so the wire format (block->rings = stats_nch) and the amount of data filled by mlx5e_hv_vhca_fill_stats() are unchanged. The max(max_nch, stats_nch) guard handles the rare case where mlx5e_attach_netdev() recomputes max_nch downward across a detach/resume cycle while priv->stats_nch persists (mlx5e_detach_netdev does not call mlx5e_priv_cleanup, so stats_nch is only reset when the netdev is destroyed). Without the guard, the worker could compute buf_len from stats_nch and overrun the smaller buffer allocated based on the reduced max_nch. Allocating a non-zero buffer also makes the kvzalloc() failure path in mlx5e_hv_vhca_stats_create() reachable for the first time: it returns early without (re)creating the agent. Clear priv->stats_agent.{agent,buf} in mlx5e_hv_vhca_stats_destroy() after freeing them, so that if a later create() bails out on this path, a subsequent teardown does not double-free the stale agent/buffer left from a previous enable/disable cycle. This mirrors the existing mlx5e pattern of preallocating arrays of size max_nch (e.g. priv->channel_stats) and lazily populating entries up to stats_nch on demand. Fixes: fa691d0c9c08 ("net/mlx5e: Allocate per-channel stats dynamically at first usage") Signed-off-by: Feng Liu Reviewed-by: Eran Ben Elisha Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/20260630115151.729219-2-tariqt@nvidia.com Signed-off-by: Paolo Abeni --- .../net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c index 195863b2c013..72f3ca4dd076 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c @@ -54,6 +54,12 @@ static int mlx5e_hv_vhca_stats_buf_size(struct mlx5e_priv *priv) priv->stats_nch); } +static int mlx5e_hv_vhca_stats_buf_max_size(struct mlx5e_priv *priv) +{ + return (sizeof(struct mlx5e_hv_vhca_per_ring_stats) * + max(priv->max_nch, priv->stats_nch)); +} + static void mlx5e_hv_vhca_stats_work(struct work_struct *work) { struct mlx5e_hv_vhca_stats_agent *sagent; @@ -122,7 +128,7 @@ static void mlx5e_hv_vhca_stats_cleanup(struct mlx5_hv_vhca_agent *agent) void mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv) { - int buf_len = mlx5e_hv_vhca_stats_buf_size(priv); + int buf_len = mlx5e_hv_vhca_stats_buf_max_size(priv); struct mlx5_hv_vhca_agent *agent; priv->stats_agent.buf = kvzalloc(buf_len, GFP_KERNEL); @@ -155,5 +161,7 @@ void mlx5e_hv_vhca_stats_destroy(struct mlx5e_priv *priv) return; mlx5_hv_vhca_agent_destroy(priv->stats_agent.agent); + priv->stats_agent.agent = NULL; kvfree(priv->stats_agent.buf); + priv->stats_agent.buf = NULL; } From 89b25b5f46f488ea3b29b3444864c76944c9075b Mon Sep 17 00:00:00 2001 From: Feng Liu Date: Tue, 30 Jun 2026 14:51:50 +0300 Subject: [PATCH 2/3] net/mlx5e: Fix HV VHCA stats agent registration race mlx5e_hv_vhca_stats_create() registers the stats agent through mlx5_hv_vhca_agent_create(). The helper publishes the agent in hv_vhca->agents[type] under agents_lock and immediately schedules an asynchronous control invalidation on the HV VHCA workqueue before returning to mlx5e. The asynchronous invalidation invokes the control agent's invalidate callback, which reads the hypervisor control block and forwards the command to mlx5e_hv_vhca_stats_control(). That callback may either: - call cancel_delayed_work_sync(&priv->stats_agent.work), or - call queue_delayed_work(priv->wq, &sagent->work, sagent->delay). However, the delayed_work and priv->stats_agent.agent are only initialized after mlx5_hv_vhca_agent_create() returns to mlx5e: agent = mlx5_hv_vhca_agent_create(...); /* publish + invalidate */ ... priv->stats_agent.agent = agent; /* too late */ INIT_DELAYED_WORK(&priv->stats_agent.work, ...); /* too late */ If the asynchronous control path runs before the two assignments above, it can: - Operate on an uninitialized delayed_work whose timer.function is NULL. queue_delayed_work() calls add_timer() unconditionally, so when the timer expires the timer softirq invokes a NULL function pointer. - Re-initialize the timer later through INIT_DELAYED_WORK() while the timer is already enqueued in the timer wheel, corrupting the hlist (entry.pprev cleared while the previous bucket node still points at this entry). - When the worker eventually runs, mlx5e_hv_vhca_stats_work() reads sagent->agent (NULL) and dereferences it inside mlx5_hv_vhca_agent_write(). Fix this by: - Initializing priv->stats_agent.work before invoking mlx5_hv_vhca_agent_create(), so the work is always in a valid state when the control callback observes it. - Adding a struct mlx5_hv_vhca_agent **ctx_update out-parameter to mlx5_hv_vhca_agent_create(). The helper writes the agent pointer to *ctx_update before publishing into hv_vhca->agents[] and triggering the agents_update flow, so any callback subsequently invoked from that flow already sees a valid priv->stats_agent.agent. This avoids having the control callback participate in agent initialization. While at it, access priv->stats_agent.agent with READ_ONCE()/WRITE_ONCE() for the cross-CPU access with the worker, and clear priv->stats_agent.buf on the agent_create() failure path. Fixes: cef35af34d6d ("net/mlx5e: Add mlx5e HV VHCA stats agent") Signed-off-by: Feng Liu Reviewed-by: Eran Ben Elisha Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/20260630115151.729219-3-tariqt@nvidia.com Signed-off-by: Paolo Abeni --- .../mellanox/mlx5/core/en/hv_vhca_stats.c | 21 +++++++++++-------- .../ethernet/mellanox/mlx5/core/lib/hv_vhca.c | 8 +++++-- .../ethernet/mellanox/mlx5/core/lib/hv_vhca.h | 6 ++++-- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c index 72f3ca4dd076..cdaf77650164 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c @@ -73,7 +73,7 @@ static void mlx5e_hv_vhca_stats_work(struct work_struct *work) sagent = container_of(dwork, struct mlx5e_hv_vhca_stats_agent, work); priv = container_of(sagent, struct mlx5e_priv, stats_agent); buf_len = mlx5e_hv_vhca_stats_buf_size(priv); - agent = sagent->agent; + agent = READ_ONCE(sagent->agent); buf = sagent->buf; memset(buf, 0, buf_len); @@ -135,11 +135,14 @@ void mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv) if (!priv->stats_agent.buf) return; + INIT_DELAYED_WORK(&priv->stats_agent.work, mlx5e_hv_vhca_stats_work); + agent = mlx5_hv_vhca_agent_create(priv->mdev->hv_vhca, MLX5_HV_VHCA_AGENT_STATS, mlx5e_hv_vhca_stats_control, NULL, mlx5e_hv_vhca_stats_cleanup, - priv); + priv, + &priv->stats_agent.agent); if (IS_ERR_OR_NULL(agent)) { if (IS_ERR(agent)) @@ -148,20 +151,20 @@ void mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv) agent); kvfree(priv->stats_agent.buf); - return; + priv->stats_agent.buf = NULL; } - - priv->stats_agent.agent = agent; - INIT_DELAYED_WORK(&priv->stats_agent.work, mlx5e_hv_vhca_stats_work); } void mlx5e_hv_vhca_stats_destroy(struct mlx5e_priv *priv) { - if (IS_ERR_OR_NULL(priv->stats_agent.agent)) + struct mlx5_hv_vhca_agent *agent; + + agent = READ_ONCE(priv->stats_agent.agent); + if (IS_ERR_OR_NULL(agent)) return; - mlx5_hv_vhca_agent_destroy(priv->stats_agent.agent); - priv->stats_agent.agent = NULL; + mlx5_hv_vhca_agent_destroy(agent); + WRITE_ONCE(priv->stats_agent.agent, NULL); kvfree(priv->stats_agent.buf); priv->stats_agent.buf = NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c index d6dc7bce855e..305752dab7bd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c @@ -190,7 +190,7 @@ mlx5_hv_vhca_control_agent_create(struct mlx5_hv_vhca *hv_vhca) return mlx5_hv_vhca_agent_create(hv_vhca, MLX5_HV_VHCA_AGENT_CONTROL, NULL, mlx5_hv_vhca_control_agent_invalidate, - NULL, NULL); + NULL, NULL, NULL); } static void mlx5_hv_vhca_control_agent_destroy(struct mlx5_hv_vhca_agent *agent) @@ -256,7 +256,8 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca, void (*invalidate)(struct mlx5_hv_vhca_agent*, u64 block_mask), void (*cleaup)(struct mlx5_hv_vhca_agent *agent), - void *priv) + void *priv, + struct mlx5_hv_vhca_agent **ctx_update) { struct mlx5_hv_vhca_agent *agent; @@ -284,6 +285,9 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca, agent->invalidate = invalidate; agent->cleanup = cleaup; + if (ctx_update) + WRITE_ONCE(*ctx_update, agent); + mutex_lock(&hv_vhca->agents_lock); hv_vhca->agents[type] = agent; mutex_unlock(&hv_vhca->agents_lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.h index f240ffe5116c..8b3974cf0ee4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.h @@ -43,7 +43,8 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca, void (*invalidate)(struct mlx5_hv_vhca_agent*, u64 block_mask), void (*cleanup)(struct mlx5_hv_vhca_agent *agent), - void *context); + void *context, + struct mlx5_hv_vhca_agent **ctx_update); void mlx5_hv_vhca_agent_destroy(struct mlx5_hv_vhca_agent *agent); int mlx5_hv_vhca_agent_write(struct mlx5_hv_vhca_agent *agent, @@ -84,7 +85,8 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca, void (*invalidate)(struct mlx5_hv_vhca_agent*, u64 block_mask), void (*cleanup)(struct mlx5_hv_vhca_agent *agent), - void *context) + void *context, + struct mlx5_hv_vhca_agent **ctx_update) { return NULL; } From 5a799714e8ca0bce9ea40694f49914cf1adbbaa9 Mon Sep 17 00:00:00 2001 From: Feng Liu Date: Tue, 30 Jun 2026 14:51:51 +0300 Subject: [PATCH 3/3] net/mlx5e: Fix publication race for priv->channel_stats[] mlx5e_channel_stats_alloc() publishes a new entry to priv->channel_stats[] and then increments priv->stats_nch as a publication token, but neither store carries any memory barrier: priv->channel_stats[ix] = kvzalloc_node(...); if (!priv->channel_stats[ix]) return -ENOMEM; priv->stats_nch++; Concurrent readers compute the loop bound from priv->stats_nch and then dereference priv->channel_stats[i] using plain accesses, e.g. for (i = 0; i < priv->stats_nch; i++) { struct mlx5e_channel_stats *cs = priv->channel_stats[i]; ... cs->rq.packets ... } On weakly-ordered architectures (ARM, PowerPC, RISC-V) the writes to channel_stats[ix] and stats_nch may become visible to other CPUs out of program order. A reader can observe stats_nch == N while still seeing channel_stats[N-1] == NULL, leading to a NULL pointer dereference in the channel_stats loop. This has been observed in production on BlueField-3 DPUs (arm64), where ovs-vswitchd queries netdev statistics over netlink during NIC bringup, racing mlx5e_open_channel() -> mlx5e_channel_stats_alloc() on another CPU: Unable to handle kernel NULL pointer dereference at virtual address 0x840 Hardware name: BlueField-3 DPU pc : mlx5e_fold_sw_stats64+0x30/0x180 [mlx5_core] Call trace: mlx5e_fold_sw_stats64+0x30/0x180 [mlx5_core] dev_get_stats+0x50/0xc0 ovs_vport_get_stats+0x38/0xac [openvswitch] ovs_vport_cmd_fill_info+0x194/0x290 [openvswitch] ovs_vport_cmd_get+0xbc/0x10c [openvswitch] genl_family_rcv_msg_doit+0xd0/0x160 genl_rcv_msg+0xec/0x1f0 netlink_rcv_skb+0x64/0x130 genl_rcv+0x40/0x60 netlink_unicast+0x2fc/0x370 netlink_sendmsg+0x1dc/0x454 ... __arm64_sys_sendmsg+0x2c/0x40 Add mlx5e_stats_nch_write() and mlx5e_stats_nch_read() helpers in en.h that wrap the smp_store_release()/smp_load_acquire() pair on stats_nch. The release/acquire pair establishes the contract: stats_nch == N => channel_stats[0..N-1] are visible and non-NULL. Publish the stats_nch increment via mlx5e_stats_nch_write() in the writer (mlx5e_channel_stats_alloc()), and read stats_nch via mlx5e_stats_nch_read() in all readers: mlx5e RX/TX queue stats, mlx5e_get_base_stats(), ethtool channels stats, IPoIB stats, the sw_stats fold and the HV VHCA stats agent. Fixes: fa691d0c9c08 ("net/mlx5e: Allocate per-channel stats dynamically at first usage") Signed-off-by: Feng Liu Reviewed-by: Eran Ben Elisha Reviewed-by: Cosmin Ratiu Reviewed-by: Nimrod Oren Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/20260630115151.729219-4-tariqt@nvidia.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 12 ++++++++++++ .../ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c | 10 ++++++---- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 14 ++++++++------ drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 9 +++++---- .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 3 ++- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 2270e2e550dd..d507289096c2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -987,6 +987,18 @@ struct mlx5e_priv { struct ethtool_fec_hist_range *fec_ranges; }; +static inline u16 mlx5e_stats_nch_read(const struct mlx5e_priv *priv) +{ + /* Pairs with smp_store_release in mlx5e_stats_nch_write(). */ + return smp_load_acquire(&priv->stats_nch); +} + +static inline void mlx5e_stats_nch_write(struct mlx5e_priv *priv, u16 n) +{ + /* Pairs with smp_load_acquire in mlx5e_stats_nch_read(). */ + smp_store_release(&priv->stats_nch, n); +} + struct mlx5e_dev { struct net_device *netdev; struct devlink_port dl_port; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c index cdaf77650164..631f802105d5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c @@ -33,9 +33,10 @@ mlx5e_hv_vhca_fill_ring_stats(struct mlx5e_priv *priv, int ch, static void mlx5e_hv_vhca_fill_stats(struct mlx5e_priv *priv, void *data, int buf_len) { + u16 nch = mlx5e_stats_nch_read(priv); int ch, i = 0; - for (ch = 0; ch < priv->stats_nch; ch++) { + for (ch = 0; ch < nch; ch++) { void *buf = data + i; if (WARN_ON_ONCE(buf + @@ -50,8 +51,9 @@ static void mlx5e_hv_vhca_fill_stats(struct mlx5e_priv *priv, void *data, static int mlx5e_hv_vhca_stats_buf_size(struct mlx5e_priv *priv) { - return (sizeof(struct mlx5e_hv_vhca_per_ring_stats) * - priv->stats_nch); + u16 nch = mlx5e_stats_nch_read(priv); + + return sizeof(struct mlx5e_hv_vhca_per_ring_stats) * nch; } static int mlx5e_hv_vhca_stats_buf_max_size(struct mlx5e_priv *priv) @@ -106,7 +108,7 @@ static void mlx5e_hv_vhca_stats_control(struct mlx5_hv_vhca_agent *agent, sagent = &priv->stats_agent; block->version = MLX5_HV_VHCA_STATS_VERSION; - block->rings = priv->stats_nch; + block->rings = mlx5e_stats_nch_read(priv); if (!block->command) { cancel_delayed_work_sync(&priv->stats_agent.work); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 775f0c6e55c9..aa8610cedaa8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2773,7 +2773,7 @@ static int mlx5e_channel_stats_alloc(struct mlx5e_priv *priv, int ix, int cpu) GFP_KERNEL, cpu_to_node(cpu)); if (!priv->channel_stats[ix]) return -ENOMEM; - priv->stats_nch++; + mlx5e_stats_nch_write(priv, priv->stats_nch + 1); return 0; } @@ -4040,9 +4040,10 @@ static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type, void mlx5e_fold_sw_stats64(struct mlx5e_priv *priv, struct rtnl_link_stats64 *s) { + u16 nch = mlx5e_stats_nch_read(priv); int i; - for (i = 0; i < priv->stats_nch; i++) { + for (i = 0; i < nch; i++) { struct mlx5e_channel_stats *channel_stats = priv->channel_stats[i]; struct mlx5e_rq_stats *xskrq_stats = &channel_stats->xskrq; struct mlx5e_rq_stats *rq_stats = &channel_stats->rq; @@ -5488,7 +5489,7 @@ static void mlx5e_get_queue_stats_rx(struct net_device *dev, int i, struct mlx5e_rq_stats *xskrq_stats; struct mlx5e_rq_stats *rq_stats; - if (mlx5e_is_uplink_rep(priv) || !priv->stats_nch) + if (mlx5e_is_uplink_rep(priv) || !mlx5e_stats_nch_read(priv)) return; channel_stats = priv->channel_stats[i]; @@ -5512,7 +5513,7 @@ static void mlx5e_get_queue_stats_tx(struct net_device *dev, int i, struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5e_sq_stats *sq_stats; - if (!priv->stats_nch) + if (!mlx5e_stats_nch_read(priv)) return; /* no special case needed for ptp htb etc since txq2sq_stats is kept up @@ -5538,6 +5539,7 @@ static void mlx5e_get_base_stats(struct net_device *dev, struct netdev_queue_stats_tx *tx) { struct mlx5e_priv *priv = netdev_priv(dev); + u16 nch = mlx5e_stats_nch_read(priv); struct mlx5e_ptp *ptp_channel; int i, tc; @@ -5549,7 +5551,7 @@ static void mlx5e_get_base_stats(struct net_device *dev, rx->hw_gro_wire_packets = 0; rx->hw_gro_wire_bytes = 0; - for (i = priv->channels.params.num_channels; i < priv->stats_nch; i++) { + for (i = priv->channels.params.num_channels; i < nch; i++) { struct netdev_queue_stats_rx rx_i = {0}; mlx5e_get_queue_stats_rx(dev, i, &rx_i); @@ -5585,7 +5587,7 @@ static void mlx5e_get_base_stats(struct net_device *dev, tx->stop = 0; tx->wake = 0; - for (i = 0; i < priv->stats_nch; i++) { + for (i = 0; i < nch; i++) { struct mlx5e_channel_stats *channel_stats = priv->channel_stats[i]; /* handle two cases: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index 7f33261ba655..de38b60806c2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -515,6 +515,7 @@ static void mlx5e_stats_update_stats_rq_page_pool(struct mlx5e_channel *c) static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw) { struct mlx5e_sw_stats *s = &priv->stats.sw; + u16 nch = mlx5e_stats_nch_read(priv); int i; memset(s, 0, sizeof(*s)); @@ -522,7 +523,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw) for (i = 0; i < priv->channels.num; i++) /* for active channels only */ mlx5e_stats_update_stats_rq_page_pool(priv->channels.c[i]); - for (i = 0; i < priv->stats_nch; i++) { + for (i = 0; i < nch; i++) { struct mlx5e_channel_stats *channel_stats = priv->channel_stats[i]; @@ -2614,7 +2615,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(ptp) { return; } static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(channels) { - int max_nch = priv->stats_nch; + int max_nch = mlx5e_stats_nch_read(priv); return (NUM_RQ_STATS * max_nch) + (NUM_CH_STATS * max_nch) + @@ -2627,8 +2628,8 @@ static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(channels) static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(channels) { + int max_nch = mlx5e_stats_nch_read(priv); bool is_xsk = priv->xsk.ever_used; - int max_nch = priv->stats_nch; int i, j, tc; for (i = 0; i < max_nch; i++) @@ -2660,8 +2661,8 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(channels) static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(channels) { + int max_nch = mlx5e_stats_nch_read(priv); bool is_xsk = priv->xsk.ever_used; - int max_nch = priv->stats_nch; int i, j, tc; for (i = 0; i < max_nch; i++) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 0a6003fe60e9..674bed721e63 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -135,10 +135,11 @@ void mlx5i_cleanup(struct mlx5e_priv *priv) static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv) { + u16 nch = mlx5e_stats_nch_read(priv); struct rtnl_link_stats64 s = {}; int i, j; - for (i = 0; i < priv->stats_nch; i++) { + for (i = 0; i < nch; i++) { struct mlx5e_channel_stats *channel_stats; struct mlx5e_rq_stats *rq_stats;