* [Intel-wired-lan] [PATCH iwl-next v4 0/6] ice: properly use u64_stats API for all ring stats
@ 2025-11-20 20:20 Jacob Keller
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 1/6] ice: initialize ring_stats->syncp Jacob Keller
` (5 more replies)
0 siblings, 6 replies; 19+ messages in thread
From: Jacob Keller @ 2025-11-20 20:20 UTC (permalink / raw)
To: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel
Cc: Simon Horman, intel-wired-lan, netdev, Jacob Keller,
Aleksandr Loktionov
The ice driver has multiple u64 values stored in the ring structures for
each queue used for statistics. These are accumulated in
ice_update_vsi_stats(). The packet and byte values are read using the
u64_stats API from <linux/u64_stats_sync.h>.
Several non-standard counters are also accumulated in the same function,
but do not use the u64_stats API. This could result in load/store tears on
32-bit architectures. Further, since commit 316580b69d0a ("u64_stats:
provide u64_stats_t type"), the u64 stats API has had u64_stats_t and
access functions which convert to local64_t on 64-bit architectures.
The ice driver doesn't use u64_stats_t and these access functions. Thus
even on 64-bit architectures it could read inconsistent values. This series
refactors the ice driver to use the updated API. Along the way I noticed
several other issues and inconsistencies which I have cleaned up,
summarized below.
*) The driver never called u64_stats_init, leaving the syncp improperly
initialized. Since the field is part of a kzalloc block, this only
impacts 32-bit systems with CONFIG_LOCKDEP enabled.
*) A few locations accessed the packets and byte counts directly without
using the u64 stats API.
*) The ice_fetch_u64_stats_per_ring() function took the ice_q_stats by
value, defeating the point of using the u64_stats API entirely.
To keep the stats increments short, I introduced ice_stats_inc, as
otherwise each stat increment has to be quite verbose. Similarly a few
places read only one stat, so I added ice_stats_read for those.
This version uses struct ice_vsi_(tx|rx)_stats structures defined in
ice_main.c for the accumulator. I haven't come up with a better solution
that allows accumulating nicely without this structure. Its a bit
frustrating as it copies the entries in the ring stats structures but with
u64 instead of u64_stats_t.
I am also still not entirely certain how the ice_update_vsi_ring_stats()
function is synchronized in the ice driver. It is called from multiple
places without an obvious synchronization mechanism. It is ultimately
called from the service task and from ethtool, and I think it may also be
called from one of the netdev stats callbacks.
I'm open to suggestions on ways to improve this, as I think the result
still has some ugly logic and a fair amount of near duplicate code.
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
Changes in v4:
- Drop the cacheline_group changes. Olek and I plan to work on a full
solution in a separate series.
- Drop moving prev_pkt out of the stats. This might still be a good idea,
but it should wait for the cacheline group changes.
- Link to v3: https://patch.msgid.link/20251107-jk-refactor-queue-stats-v3-0-771ae1414b2e@intel.com
Changes in v3:
- Use SMP_CACHE_BYTES in assertions to avoid issues on ARM v7 with 128-byte
cache (due to xdp_rxq_info changing size)
- Only check the tx_lock cache group size for non-debug kernels, rather
than keeping logic to check its size when DEBUG_LOCK_ALLOC is enabled.
- Link to v2: https://patch.msgid.link/20251105-jk-refactor-queue-stats-v2-0-8652557f9572@intel.com
Changes in v2:
- Fix minor typos.
- Link to v1: https://patch.msgid.link/20251103-jk-refactor-queue-stats-v1-0-164d2ed859b6@intel.com
---
Jacob Keller (6):
ice: initialize ring_stats->syncp
ice: pass pointer to ice_fetch_u64_stats_per_ring
ice: remove ice_q_stats struct and use struct_group
ice: use u64_stats API to access pkts/bytes in dim sample
ice: shorten ring stat names and add accessors
ice: convert all ring stats to u64_stats_t
drivers/net/ethernet/intel/ice/ice.h | 3 -
drivers/net/ethernet/intel/ice/ice_lib.h | 6 +
drivers/net/ethernet/intel/ice/ice_txrx.h | 77 +++++++---
drivers/net/ethernet/intel/ice/ice_txrx_lib.h | 2 +-
drivers/net/ethernet/intel/ice/ice_base.c | 4 +-
drivers/net/ethernet/intel/ice/ice_ethtool.c | 30 ++--
drivers/net/ethernet/intel/ice/ice_lib.c | 61 +++++---
drivers/net/ethernet/intel/ice/ice_main.c | 196 +++++++++++++++++---------
drivers/net/ethernet/intel/ice/ice_txrx.c | 45 +++---
drivers/net/ethernet/intel/ice/ice_txrx_lib.c | 2 +-
drivers/net/ethernet/intel/ice/ice_xsk.c | 4 +-
11 files changed, 280 insertions(+), 150 deletions(-)
---
base-commit: 2fcc88754f4c49e3d9aef226fdfaa1634aa24c66
change-id: 20251016-jk-refactor-queue-stats-9e721b34ce01
Best regards,
--
Jacob Keller <jacob.e.keller@intel.com>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [Intel-wired-lan] [PATCH iwl-next v4 1/6] ice: initialize ring_stats->syncp
2025-11-20 20:20 [Intel-wired-lan] [PATCH iwl-next v4 0/6] ice: properly use u64_stats API for all ring stats Jacob Keller
@ 2025-11-20 20:20 ` Jacob Keller
2025-11-25 10:15 ` Simon Horman
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 2/6] ice: pass pointer to ice_fetch_u64_stats_per_ring Jacob Keller
` (4 subsequent siblings)
5 siblings, 1 reply; 19+ messages in thread
From: Jacob Keller @ 2025-11-20 20:20 UTC (permalink / raw)
To: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel
Cc: Simon Horman, intel-wired-lan, netdev, Jacob Keller,
Aleksandr Loktionov
The u64_stats_sync structure is empty on 64-bit systems. However, on 32-bit
systems it contains a seqcount_t which needs to be initialized. While the
memory is zero-initialized, a lack of u64_stats_init means that lockdep
won't get initialized properly. Fix this by adding u64_stats_init() calls
to the rings just after allocation.
Fixes: 2b245cb29421 ("ice: Implement transmit and NAPI support")
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
drivers/net/ethernet/intel/ice/ice_lib.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 44f3c2bab308..116a4f4ef91d 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -400,7 +400,10 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
if (!ring_stats)
goto err_out;
+ u64_stats_init(&ring_stats->syncp);
+
WRITE_ONCE(tx_ring_stats[i], ring_stats);
+
}
ring->ring_stats = ring_stats;
@@ -419,6 +422,8 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
if (!ring_stats)
goto err_out;
+ u64_stats_init(&ring_stats->syncp);
+
WRITE_ONCE(rx_ring_stats[i], ring_stats);
}
--
2.51.0.rc1.197.g6d975e95c9d7
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Intel-wired-lan] [PATCH iwl-next v4 2/6] ice: pass pointer to ice_fetch_u64_stats_per_ring
2025-11-20 20:20 [Intel-wired-lan] [PATCH iwl-next v4 0/6] ice: properly use u64_stats API for all ring stats Jacob Keller
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 1/6] ice: initialize ring_stats->syncp Jacob Keller
@ 2025-11-20 20:20 ` Jacob Keller
2025-11-25 10:16 ` Simon Horman
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 3/6] ice: remove ice_q_stats struct and use struct_group Jacob Keller
` (3 subsequent siblings)
5 siblings, 1 reply; 19+ messages in thread
From: Jacob Keller @ 2025-11-20 20:20 UTC (permalink / raw)
To: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel
Cc: Simon Horman, intel-wired-lan, netdev, Jacob Keller,
Aleksandr Loktionov
The ice_fetch_u64_stats_per_ring function takes a pointer to the syncp from
the ring stats to synchronize reading of the packet stats. It also takes a
*copy* of the ice_q_stats fields instead of a pointer to the stats. This
completely defeats the point of using the u64_stats API. We pass the stats
by value, so they are static at the point of reading within the
u64_stats_fetch_retry loop.
Simplify the function to take a pointer to the ice_ring_stats instead of
two separate parameters. Additionally, since we never call this outside of
ice_main.c, make it a static function.
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
drivers/net/ethernet/intel/ice/ice.h | 3 ---
drivers/net/ethernet/intel/ice/ice_main.c | 24 +++++++++---------------
2 files changed, 9 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 147aaee192a7..5c01e886e83e 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -957,9 +957,6 @@ u16 ice_get_avail_rxq_count(struct ice_pf *pf);
int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked);
void ice_update_vsi_stats(struct ice_vsi *vsi);
void ice_update_pf_stats(struct ice_pf *pf);
-void
-ice_fetch_u64_stats_per_ring(struct u64_stats_sync *syncp,
- struct ice_q_stats stats, u64 *pkts, u64 *bytes);
int ice_up(struct ice_vsi *vsi);
int ice_down(struct ice_vsi *vsi);
int ice_down_up(struct ice_vsi *vsi);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 0b6175ade40d..4133d297dda2 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -6811,25 +6811,23 @@ int ice_up(struct ice_vsi *vsi)
/**
* ice_fetch_u64_stats_per_ring - get packets and bytes stats per ring
- * @syncp: pointer to u64_stats_sync
- * @stats: stats that pkts and bytes count will be taken from
+ * @stats: pointer to ring stats structure
* @pkts: packets stats counter
* @bytes: bytes stats counter
*
* This function fetches stats from the ring considering the atomic operations
* that needs to be performed to read u64 values in 32 bit machine.
*/
-void
-ice_fetch_u64_stats_per_ring(struct u64_stats_sync *syncp,
- struct ice_q_stats stats, u64 *pkts, u64 *bytes)
+static void ice_fetch_u64_stats_per_ring(struct ice_ring_stats *stats,
+ u64 *pkts, u64 *bytes)
{
unsigned int start;
do {
- start = u64_stats_fetch_begin(syncp);
- *pkts = stats.pkts;
- *bytes = stats.bytes;
- } while (u64_stats_fetch_retry(syncp, start));
+ start = u64_stats_fetch_begin(&stats->syncp);
+ *pkts = stats->stats.pkts;
+ *bytes = stats->stats.bytes;
+ } while (u64_stats_fetch_retry(&stats->syncp, start));
}
/**
@@ -6853,9 +6851,7 @@ ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi,
ring = READ_ONCE(rings[i]);
if (!ring || !ring->ring_stats)
continue;
- ice_fetch_u64_stats_per_ring(&ring->ring_stats->syncp,
- ring->ring_stats->stats, &pkts,
- &bytes);
+ ice_fetch_u64_stats_per_ring(ring->ring_stats, &pkts, &bytes);
vsi_stats->tx_packets += pkts;
vsi_stats->tx_bytes += bytes;
vsi->tx_restart += ring->ring_stats->tx_stats.restart_q;
@@ -6899,9 +6895,7 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
struct ice_ring_stats *ring_stats;
ring_stats = ring->ring_stats;
- ice_fetch_u64_stats_per_ring(&ring_stats->syncp,
- ring_stats->stats, &pkts,
- &bytes);
+ ice_fetch_u64_stats_per_ring(ring_stats, &pkts, &bytes);
vsi_stats->rx_packets += pkts;
vsi_stats->rx_bytes += bytes;
vsi->rx_buf_failed += ring_stats->rx_stats.alloc_buf_failed;
--
2.51.0.rc1.197.g6d975e95c9d7
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Intel-wired-lan] [PATCH iwl-next v4 3/6] ice: remove ice_q_stats struct and use struct_group
2025-11-20 20:20 [Intel-wired-lan] [PATCH iwl-next v4 0/6] ice: properly use u64_stats API for all ring stats Jacob Keller
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 1/6] ice: initialize ring_stats->syncp Jacob Keller
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 2/6] ice: pass pointer to ice_fetch_u64_stats_per_ring Jacob Keller
@ 2025-11-20 20:20 ` Jacob Keller
2025-11-25 10:16 ` Simon Horman
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 4/6] ice: use u64_stats API to access pkts/bytes in dim sample Jacob Keller
` (2 subsequent siblings)
5 siblings, 1 reply; 19+ messages in thread
From: Jacob Keller @ 2025-11-20 20:20 UTC (permalink / raw)
To: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel
Cc: Simon Horman, intel-wired-lan, netdev, Jacob Keller,
Aleksandr Loktionov
The ice_qp_reset_stats function resets the stats for all rings on a VSI. It
currently behaves differently for Tx and Rx rings. For Rx rings, it only
clears the rx_stats which do not include the pkt and byte counts. For Tx
rings and XDP rings, it clears only the pkt and byte counts.
We could add extra memset calls to cover both the stats and relevant
tx/rx stats fields. Instead, lets convert stats into a struct_group which
contains both the pkts and bytes fields as well as the Tx or Rx stats, and
remove the ice_q_stats structure entirely.
The only remaining user of ice_q_stats is the ice_q_stats_len function in
ice_ethtool.c, which just counts the number of fields. Replace this with a
simple multiplication by 2. I find this to be simpler to reason about than
relying on knowing the layout of the ice_q_stats structure.
Now that the stats field of the ice_ring_stats covers all of the statistic
values, the ice_qp_reset_stats function will properly zero out all of the
fields.
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
drivers/net/ethernet/intel/ice/ice_txrx.h | 18 ++++++++----------
drivers/net/ethernet/intel/ice/ice_base.c | 4 ++--
drivers/net/ethernet/intel/ice/ice_ethtool.c | 4 ++--
drivers/net/ethernet/intel/ice/ice_lib.c | 7 ++++---
4 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index e440c55d9e9f..d5ad76b25f16 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -129,11 +129,6 @@ struct ice_tx_offload_params {
u8 header_len;
};
-struct ice_q_stats {
- u64 pkts;
- u64 bytes;
-};
-
struct ice_txq_stats {
u64 restart_q;
u64 tx_busy;
@@ -149,12 +144,15 @@ struct ice_rxq_stats {
struct ice_ring_stats {
struct rcu_head rcu; /* to avoid race on free */
- struct ice_q_stats stats;
struct u64_stats_sync syncp;
- union {
- struct ice_txq_stats tx_stats;
- struct ice_rxq_stats rx_stats;
- };
+ struct_group(stats,
+ u64 pkts;
+ u64 bytes;
+ union {
+ struct ice_txq_stats tx_stats;
+ struct ice_rxq_stats rx_stats;
+ };
+ );
};
enum ice_ring_state_t {
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index eadb1e3d12b3..afbff8aa9ceb 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -1414,8 +1414,8 @@ static void ice_qp_reset_stats(struct ice_vsi *vsi, u16 q_idx)
if (!vsi_stat)
return;
- memset(&vsi_stat->rx_ring_stats[q_idx]->rx_stats, 0,
- sizeof(vsi_stat->rx_ring_stats[q_idx]->rx_stats));
+ memset(&vsi_stat->rx_ring_stats[q_idx]->stats, 0,
+ sizeof(vsi_stat->rx_ring_stats[q_idx]->stats));
memset(&vsi_stat->tx_ring_stats[q_idx]->stats, 0,
sizeof(vsi_stat->tx_ring_stats[q_idx]->stats));
if (vsi->xdp_rings)
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index a1d9abee97e5..0bc6f31a2b06 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -33,8 +33,8 @@ static int ice_q_stats_len(struct net_device *netdev)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
- return ((np->vsi->alloc_txq + np->vsi->alloc_rxq) *
- (sizeof(struct ice_q_stats) / sizeof(u64)));
+ /* One packets and one bytes count per queue */
+ return ((np->vsi->alloc_txq + np->vsi->alloc_rxq) * 2);
}
#define ICE_PF_STATS_LEN ARRAY_SIZE(ice_gstrings_pf_stats)
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 116a4f4ef91d..85bc18600c17 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -3441,7 +3441,8 @@ int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc)
*
* This function assumes that caller has acquired a u64_stats_sync lock.
*/
-static void ice_update_ring_stats(struct ice_q_stats *stats, u64 pkts, u64 bytes)
+static void ice_update_ring_stats(struct ice_ring_stats *stats,
+ u64 pkts, u64 bytes)
{
stats->bytes += bytes;
stats->pkts += pkts;
@@ -3456,7 +3457,7 @@ static void ice_update_ring_stats(struct ice_q_stats *stats, u64 pkts, u64 bytes
void ice_update_tx_ring_stats(struct ice_tx_ring *tx_ring, u64 pkts, u64 bytes)
{
u64_stats_update_begin(&tx_ring->ring_stats->syncp);
- ice_update_ring_stats(&tx_ring->ring_stats->stats, pkts, bytes);
+ ice_update_ring_stats(tx_ring->ring_stats, pkts, bytes);
u64_stats_update_end(&tx_ring->ring_stats->syncp);
}
@@ -3469,7 +3470,7 @@ void ice_update_tx_ring_stats(struct ice_tx_ring *tx_ring, u64 pkts, u64 bytes)
void ice_update_rx_ring_stats(struct ice_rx_ring *rx_ring, u64 pkts, u64 bytes)
{
u64_stats_update_begin(&rx_ring->ring_stats->syncp);
- ice_update_ring_stats(&rx_ring->ring_stats->stats, pkts, bytes);
+ ice_update_ring_stats(rx_ring->ring_stats, pkts, bytes);
u64_stats_update_end(&rx_ring->ring_stats->syncp);
}
--
2.51.0.rc1.197.g6d975e95c9d7
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Intel-wired-lan] [PATCH iwl-next v4 4/6] ice: use u64_stats API to access pkts/bytes in dim sample
2025-11-20 20:20 [Intel-wired-lan] [PATCH iwl-next v4 0/6] ice: properly use u64_stats API for all ring stats Jacob Keller
` (2 preceding siblings ...)
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 3/6] ice: remove ice_q_stats struct and use struct_group Jacob Keller
@ 2025-11-20 20:20 ` Jacob Keller
2025-11-25 10:17 ` Simon Horman
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 5/6] ice: shorten ring stat names and add accessors Jacob Keller
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 6/6] ice: convert all ring stats to u64_stats_t Jacob Keller
5 siblings, 1 reply; 19+ messages in thread
From: Jacob Keller @ 2025-11-20 20:20 UTC (permalink / raw)
To: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel
Cc: Simon Horman, intel-wired-lan, netdev, Jacob Keller,
Aleksandr Loktionov
The __ice_update_sample and __ice_get_ethtool_stats functions directly
accesses the pkts and bytes counters from the ring stats. A following
change is going to update the fields to be u64_stats_t type, and will need
to be accessed appropriately. This will ensure that the accesses do not
cause load/store tearing.
Add helper functions similar to the ones used for updating the stats
values, and use them. This ensures use of the syncp pointer on 32-bit
architectures. Once the fields are updated to u64_stats_t, it will then
properly avoid tears on all architectures.
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
drivers/net/ethernet/intel/ice/ice_lib.h | 6 +++++
drivers/net/ethernet/intel/ice/ice_ethtool.c | 26 +++++++++++++-------
drivers/net/ethernet/intel/ice/ice_lib.c | 36 ++++++++++++++++++++++++++++
drivers/net/ethernet/intel/ice/ice_txrx.c | 29 +++++++++++-----------
4 files changed, 75 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
index 2cb1eb98b9da..49454d98dcfe 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -92,6 +92,12 @@ void ice_update_tx_ring_stats(struct ice_tx_ring *ring, u64 pkts, u64 bytes);
void ice_update_rx_ring_stats(struct ice_rx_ring *ring, u64 pkts, u64 bytes);
+void ice_fetch_tx_ring_stats(const struct ice_tx_ring *ring,
+ u64 *pkts, u64 *bytes);
+
+void ice_fetch_rx_ring_stats(const struct ice_rx_ring *ring,
+ u64 *pkts, u64 *bytes);
+
void ice_write_intrl(struct ice_q_vector *q_vector, u8 intrl);
void ice_write_itr(struct ice_ring_container *rc, u16 itr);
void ice_set_q_vector_intrl(struct ice_q_vector *q_vector);
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 0bc6f31a2b06..6c93e0e91ef5 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -1942,25 +1942,35 @@ __ice_get_ethtool_stats(struct net_device *netdev,
rcu_read_lock();
ice_for_each_alloc_txq(vsi, j) {
+ u64 pkts, bytes;
+
tx_ring = READ_ONCE(vsi->tx_rings[j]);
- if (tx_ring && tx_ring->ring_stats) {
- data[i++] = tx_ring->ring_stats->stats.pkts;
- data[i++] = tx_ring->ring_stats->stats.bytes;
- } else {
+ if (!tx_ring || !tx_ring->ring_stats) {
data[i++] = 0;
data[i++] = 0;
+ continue;
}
+
+ ice_fetch_tx_ring_stats(tx_ring, &pkts, &bytes);
+
+ data[i++] = pkts;
+ data[i++] = bytes;
}
ice_for_each_alloc_rxq(vsi, j) {
+ u64 pkts, bytes;
+
rx_ring = READ_ONCE(vsi->rx_rings[j]);
- if (rx_ring && rx_ring->ring_stats) {
- data[i++] = rx_ring->ring_stats->stats.pkts;
- data[i++] = rx_ring->ring_stats->stats.bytes;
- } else {
+ if (!rx_ring || !rx_ring->ring_stats) {
data[i++] = 0;
data[i++] = 0;
+ continue;
}
+
+ ice_fetch_rx_ring_stats(rx_ring, &pkts, &bytes);
+
+ data[i++] = pkts;
+ data[i++] = bytes;
}
rcu_read_unlock();
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 85bc18600c17..1e3946a1dd36 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -3474,6 +3474,42 @@ void ice_update_rx_ring_stats(struct ice_rx_ring *rx_ring, u64 pkts, u64 bytes)
u64_stats_update_end(&rx_ring->ring_stats->syncp);
}
+/**
+ * ice_fetch_tx_ring_stats - Fetch Tx ring packet and byte counters
+ * @ring: ring to update
+ * @pkts: number of processed packets
+ * @bytes: number of processed bytes
+ */
+void ice_fetch_tx_ring_stats(const struct ice_tx_ring *ring,
+ u64 *pkts, u64 *bytes)
+{
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin(&ring->ring_stats->syncp);
+ *pkts = ring->ring_stats->pkts;
+ *bytes = ring->ring_stats->bytes;
+ } while (u64_stats_fetch_retry(&ring->ring_stats->syncp, start));
+}
+
+/**
+ * ice_fetch_rx_ring_stats - Fetch Rx ring packet and byte counters
+ * @ring: ring to read
+ * @pkts: number of processed packets
+ * @bytes: number of processed bytes
+ */
+void ice_fetch_rx_ring_stats(const struct ice_rx_ring *ring,
+ u64 *pkts, u64 *bytes)
+{
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin(&ring->ring_stats->syncp);
+ *pkts = ring->ring_stats->pkts;
+ *bytes = ring->ring_stats->bytes;
+ } while (u64_stats_fetch_retry(&ring->ring_stats->syncp, start));
+}
+
/**
* ice_is_dflt_vsi_in_use - check if the default forwarding VSI is being used
* @pi: port info of the switch with default VSI
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index ad76768a4232..f4196347b23a 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -1087,35 +1087,36 @@ static void __ice_update_sample(struct ice_q_vector *q_vector,
struct dim_sample *sample,
bool is_tx)
{
- u64 packets = 0, bytes = 0;
+ u64 total_packets = 0, total_bytes = 0, pkts, bytes;
if (is_tx) {
struct ice_tx_ring *tx_ring;
ice_for_each_tx_ring(tx_ring, *rc) {
- struct ice_ring_stats *ring_stats;
-
- ring_stats = tx_ring->ring_stats;
- if (!ring_stats)
+ if (!tx_ring->ring_stats)
continue;
- packets += ring_stats->stats.pkts;
- bytes += ring_stats->stats.bytes;
+
+ ice_fetch_tx_ring_stats(tx_ring, &pkts, &bytes);
+
+ total_packets += pkts;
+ total_bytes += bytes;
}
} else {
struct ice_rx_ring *rx_ring;
ice_for_each_rx_ring(rx_ring, *rc) {
- struct ice_ring_stats *ring_stats;
-
- ring_stats = rx_ring->ring_stats;
- if (!ring_stats)
+ if (!rx_ring->ring_stats)
continue;
- packets += ring_stats->stats.pkts;
- bytes += ring_stats->stats.bytes;
+
+ ice_fetch_rx_ring_stats(rx_ring, &pkts, &bytes);
+
+ total_packets += pkts;
+ total_bytes += bytes;
}
}
- dim_update_sample(q_vector->total_events, packets, bytes, sample);
+ dim_update_sample(q_vector->total_events,
+ total_packets, total_bytes, sample);
sample->comp_ctr = 0;
/* if dim settings get stale, like when not updated for 1
--
2.51.0.rc1.197.g6d975e95c9d7
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Intel-wired-lan] [PATCH iwl-next v4 5/6] ice: shorten ring stat names and add accessors
2025-11-20 20:20 [Intel-wired-lan] [PATCH iwl-next v4 0/6] ice: properly use u64_stats API for all ring stats Jacob Keller
` (3 preceding siblings ...)
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 4/6] ice: use u64_stats API to access pkts/bytes in dim sample Jacob Keller
@ 2025-11-20 20:20 ` Jacob Keller
2025-11-25 10:17 ` Simon Horman
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 6/6] ice: convert all ring stats to u64_stats_t Jacob Keller
5 siblings, 1 reply; 19+ messages in thread
From: Jacob Keller @ 2025-11-20 20:20 UTC (permalink / raw)
To: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel
Cc: Simon Horman, intel-wired-lan, netdev, Jacob Keller,
Aleksandr Loktionov
The ice Tx/Rx hotpath has a few statistics counters for tracking unexpected
events. These values are stored as u64 but are not accumulated using the
u64_stats API. This could result in load/tear stores on some architectures.
Even some 64-bit architectures could have issues since the fields are not
read or written using ACCESS_ONCE or READ_ONCE.
A following change is going to refactor the stats accumulator code to use
the u64_stats API for all of these stats, and to use u64_stats_read and
u64_stats_inc properly to prevent load/store tears on all architectures.
Using u64_stats_inc and the syncp pointer is slightly verbose and would be
duplicated in a number of places in the Tx and Rx hot path. Add accessor
macros for the cases where only a single stat value is touched at once. To
keep lines short, also shorten the stats names and convert ice_txq_stats
and ice_rxq_stats to struct_group.
This will ease the transition to properly using the u64_stats API in the
following change.
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
drivers/net/ethernet/intel/ice/ice_txrx.h | 55 +++++++++++++++++++--------
drivers/net/ethernet/intel/ice/ice_txrx_lib.h | 2 +-
drivers/net/ethernet/intel/ice/ice_main.c | 16 ++++----
drivers/net/ethernet/intel/ice/ice_txrx.c | 16 ++++----
drivers/net/ethernet/intel/ice/ice_txrx_lib.c | 2 +-
drivers/net/ethernet/intel/ice/ice_xsk.c | 4 +-
6 files changed, 60 insertions(+), 35 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index d5ad76b25f16..e7e4991c0934 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -129,19 +129,6 @@ struct ice_tx_offload_params {
u8 header_len;
};
-struct ice_txq_stats {
- u64 restart_q;
- u64 tx_busy;
- u64 tx_linearize;
- int prev_pkt; /* negative if no pending Tx descriptors */
-};
-
-struct ice_rxq_stats {
- u64 non_eop_descs;
- u64 alloc_page_failed;
- u64 alloc_buf_failed;
-};
-
struct ice_ring_stats {
struct rcu_head rcu; /* to avoid race on free */
struct u64_stats_sync syncp;
@@ -149,12 +136,50 @@ struct ice_ring_stats {
u64 pkts;
u64 bytes;
union {
- struct ice_txq_stats tx_stats;
- struct ice_rxq_stats rx_stats;
+ struct_group(tx,
+ u64 tx_restart_q;
+ u64 tx_busy;
+ u64 tx_linearize;
+ /* negative if no pending Tx descriptors */
+ int prev_pkt;
+ );
+ struct_group(rx,
+ u64 rx_non_eop_descs;
+ u64 rx_page_failed;
+ u64 rx_buf_failed;
+ );
};
);
};
+/**
+ * ice_stats_read - Read a single ring stat value
+ * @stats: pointer to ring_stats structure for a queue
+ * @member: the ice_ring_stats member to read
+ *
+ * Shorthand for reading a single 64-bit stat value from struct
+ * ice_ring_stats.
+ *
+ * Return: the value of the requested stat.
+ */
+#define ice_stats_read(stats, member) ({ \
+ struct ice_ring_stats *__stats = (stats); \
+ __stats->member; \
+})
+
+/**
+ * ice_stats_inc - Increment a single ring stat value
+ * @stats: pointer to the ring_stats structure for a queue
+ * @member: the ice_ring_stats member to increment
+ *
+ * Shorthand for incrementing a single 64-bit stat value in struct
+ * ice_ring_stats.
+ */
+#define ice_stats_inc(stats, member) do { \
+ struct ice_ring_stats *__stats = (stats); \
+ __stats->member++; \
+} while (0)
+
enum ice_ring_state_t {
ICE_TX_XPS_INIT_DONE,
ICE_TX_NBITS,
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
index 6a3f10f7a53f..f17990b68b62 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
@@ -38,7 +38,7 @@ ice_is_non_eop(const struct ice_rx_ring *rx_ring,
if (likely(ice_test_staterr(rx_desc->wb.status_error0, ICE_RXD_EOF)))
return false;
- rx_ring->ring_stats->rx_stats.non_eop_descs++;
+ ice_stats_inc(rx_ring->ring_stats, rx_non_eop_descs);
return true;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 4133d297dda2..740596e5d384 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -159,8 +159,8 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf)
* prev_pkt would be negative if there was no
* pending work.
*/
- packets = ring_stats->stats.pkts & INT_MAX;
- if (ring_stats->tx_stats.prev_pkt == packets) {
+ packets = ice_stats_read(ring_stats, pkts) & INT_MAX;
+ if (ring_stats->tx.prev_pkt == packets) {
/* Trigger sw interrupt to revive the queue */
ice_trigger_sw_intr(hw, tx_ring->q_vector);
continue;
@@ -170,7 +170,7 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf)
* to ice_get_tx_pending()
*/
smp_rmb();
- ring_stats->tx_stats.prev_pkt =
+ ring_stats->tx.prev_pkt =
ice_get_tx_pending(tx_ring) ? packets : -1;
}
}
@@ -6854,9 +6854,9 @@ ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi,
ice_fetch_u64_stats_per_ring(ring->ring_stats, &pkts, &bytes);
vsi_stats->tx_packets += pkts;
vsi_stats->tx_bytes += bytes;
- vsi->tx_restart += ring->ring_stats->tx_stats.restart_q;
- vsi->tx_busy += ring->ring_stats->tx_stats.tx_busy;
- vsi->tx_linearize += ring->ring_stats->tx_stats.tx_linearize;
+ vsi->tx_restart += ring->ring_stats->tx_restart_q;
+ vsi->tx_busy += ring->ring_stats->tx_busy;
+ vsi->tx_linearize += ring->ring_stats->tx_linearize;
}
}
@@ -6898,8 +6898,8 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
ice_fetch_u64_stats_per_ring(ring_stats, &pkts, &bytes);
vsi_stats->rx_packets += pkts;
vsi_stats->rx_bytes += bytes;
- vsi->rx_buf_failed += ring_stats->rx_stats.alloc_buf_failed;
- vsi->rx_page_failed += ring_stats->rx_stats.alloc_page_failed;
+ vsi->rx_buf_failed += ring_stats->rx_buf_failed;
+ vsi->rx_page_failed += ring_stats->rx_page_failed;
}
/* update XDP Tx rings counters */
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index f4196347b23a..eea83b26b094 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -379,7 +379,7 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
if (netif_tx_queue_stopped(txring_txq(tx_ring)) &&
!test_bit(ICE_VSI_DOWN, vsi->state)) {
netif_tx_wake_queue(txring_txq(tx_ring));
- ++tx_ring->ring_stats->tx_stats.restart_q;
+ ice_stats_inc(tx_ring->ring_stats, tx_restart_q);
}
}
@@ -499,7 +499,7 @@ int ice_setup_tx_ring(struct ice_tx_ring *tx_ring)
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
- tx_ring->ring_stats->tx_stats.prev_pkt = -1;
+ tx_ring->ring_stats->tx.prev_pkt = -1;
return 0;
err:
@@ -849,7 +849,7 @@ bool ice_alloc_rx_bufs(struct ice_rx_ring *rx_ring, unsigned int cleaned_count)
addr = libeth_rx_alloc(&fq, ntu);
if (addr == DMA_MAPPING_ERROR) {
- rx_ring->ring_stats->rx_stats.alloc_page_failed++;
+ ice_stats_inc(rx_ring->ring_stats, rx_page_failed);
break;
}
@@ -863,7 +863,7 @@ bool ice_alloc_rx_bufs(struct ice_rx_ring *rx_ring, unsigned int cleaned_count)
addr = libeth_rx_alloc(&hdr_fq, ntu);
if (addr == DMA_MAPPING_ERROR) {
- rx_ring->ring_stats->rx_stats.alloc_page_failed++;
+ ice_stats_inc(rx_ring->ring_stats, rx_page_failed);
libeth_rx_recycle_slow(fq.fqes[ntu].netmem);
break;
@@ -1045,7 +1045,7 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
/* exit if we failed to retrieve a buffer */
if (!skb) {
libeth_xdp_return_buff_slow(xdp);
- rx_ring->ring_stats->rx_stats.alloc_buf_failed++;
+ ice_stats_inc(rx_ring->ring_stats, rx_buf_failed);
continue;
}
@@ -1363,7 +1363,7 @@ static int __ice_maybe_stop_tx(struct ice_tx_ring *tx_ring, unsigned int size)
/* A reprieve! - use start_queue because it doesn't call schedule */
netif_tx_start_queue(txring_txq(tx_ring));
- ++tx_ring->ring_stats->tx_stats.restart_q;
+ ice_stats_inc(tx_ring->ring_stats, tx_restart_q);
return 0;
}
@@ -2165,7 +2165,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
if (__skb_linearize(skb))
goto out_drop;
count = ice_txd_use_count(skb->len);
- tx_ring->ring_stats->tx_stats.tx_linearize++;
+ ice_stats_inc(tx_ring->ring_stats, tx_linearize);
}
/* need: 1 descriptor per page * PAGE_SIZE/ICE_MAX_DATA_PER_TXD,
@@ -2176,7 +2176,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
*/
if (ice_maybe_stop_tx(tx_ring, count + ICE_DESCS_PER_CACHE_LINE +
ICE_DESCS_FOR_CTX_DESC)) {
- tx_ring->ring_stats->tx_stats.tx_busy++;
+ ice_stats_inc(tx_ring->ring_stats, tx_busy);
return NETDEV_TX_BUSY;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
index 956da38d63b0..e68f3e5d35b4 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
@@ -480,7 +480,7 @@ int __ice_xmit_xdp_ring(struct xdp_buff *xdp, struct ice_tx_ring *xdp_ring,
return ICE_XDP_CONSUMED;
busy:
- xdp_ring->ring_stats->tx_stats.tx_busy++;
+ ice_stats_inc(xdp_ring->ring_stats, tx_busy);
return ICE_XDP_CONSUMED;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c
index 989ff1fd9110..953e68ed0f9a 100644
--- a/drivers/net/ethernet/intel/ice/ice_xsk.c
+++ b/drivers/net/ethernet/intel/ice/ice_xsk.c
@@ -497,7 +497,7 @@ static int ice_xmit_xdp_tx_zc(struct xdp_buff *xdp,
return ICE_XDP_TX;
busy:
- xdp_ring->ring_stats->tx_stats.tx_busy++;
+ ice_stats_inc(xdp_ring->ring_stats, tx_busy);
return ICE_XDP_CONSUMED;
}
@@ -659,7 +659,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring,
xsk_buff_free(first);
first = NULL;
- rx_ring->ring_stats->rx_stats.alloc_buf_failed++;
+ ice_stats_inc(rx_ring->ring_stats, rx_buf_failed);
continue;
}
--
2.51.0.rc1.197.g6d975e95c9d7
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Intel-wired-lan] [PATCH iwl-next v4 6/6] ice: convert all ring stats to u64_stats_t
2025-11-20 20:20 [Intel-wired-lan] [PATCH iwl-next v4 0/6] ice: properly use u64_stats API for all ring stats Jacob Keller
` (4 preceding siblings ...)
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 5/6] ice: shorten ring stat names and add accessors Jacob Keller
@ 2025-11-20 20:20 ` Jacob Keller
2025-11-25 10:17 ` Simon Horman
5 siblings, 1 reply; 19+ messages in thread
From: Jacob Keller @ 2025-11-20 20:20 UTC (permalink / raw)
To: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel
Cc: Simon Horman, intel-wired-lan, netdev, Jacob Keller,
Aleksandr Loktionov
After several cleanups, the ice driver is now finally ready to convert all
Tx and Rx ring stats to the u64_stats_t and proper use of the u64 stats
APIs.
The final remaining part to cleanup is the VSI stats accumulation logic in
ice_update_vsi_ring_stats().
Refactor the function and its helpers so that all stat values (and not
just pkts and bytes) use the u64_stats APIs. The
ice_fetch_u64_(tx|rx)_stats functions read the stat values using
u64_stats_read and then copy them into local ice_vsi_(tx|rx)_stats
structures. This does require making a new struct with the stat fields as
u64.
The ice_update_vsi_(tx|rx)_ring_stats functions call the fetch functions
per ring and accumulate the result into one copy of the struct. This
accumulated total is then used to update the relevant VSI fields.
Since these are relatively small, the contents are all stored on the stack
rather than allocating and freeing memory.
Once the accumulator side is updated, the helper ice_stats_read and
ice_stats_inc and other related helper functions all easily translate to
use of u64_stats_read and u64_stats_inc. This completes the refactor and
ensures that all stats accesses now make proper use of the API.
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
drivers/net/ethernet/intel/ice/ice_txrx.h | 28 +++--
drivers/net/ethernet/intel/ice/ice_lib.c | 29 ++---
drivers/net/ethernet/intel/ice/ice_main.c | 180 ++++++++++++++++++++----------
3 files changed, 147 insertions(+), 90 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index e7e4991c0934..c51b1e60f717 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -133,20 +133,20 @@ struct ice_ring_stats {
struct rcu_head rcu; /* to avoid race on free */
struct u64_stats_sync syncp;
struct_group(stats,
- u64 pkts;
- u64 bytes;
+ u64_stats_t pkts;
+ u64_stats_t bytes;
union {
struct_group(tx,
- u64 tx_restart_q;
- u64 tx_busy;
- u64 tx_linearize;
+ u64_stats_t tx_restart_q;
+ u64_stats_t tx_busy;
+ u64_stats_t tx_linearize;
/* negative if no pending Tx descriptors */
int prev_pkt;
);
struct_group(rx,
- u64 rx_non_eop_descs;
- u64 rx_page_failed;
- u64 rx_buf_failed;
+ u64_stats_t rx_non_eop_descs;
+ u64_stats_t rx_page_failed;
+ u64_stats_t rx_buf_failed;
);
};
);
@@ -164,7 +164,13 @@ struct ice_ring_stats {
*/
#define ice_stats_read(stats, member) ({ \
struct ice_ring_stats *__stats = (stats); \
- __stats->member; \
+ unsigned int start; \
+ u64 val; \
+ do { \
+ start = u64_stats_fetch_begin(&__stats->syncp); \
+ val = u64_stats_read(&__stats->member); \
+ } while (u64_stats_fetch_retry(&__stats->syncp, start)); \
+ val; \
})
/**
@@ -177,7 +183,9 @@ struct ice_ring_stats {
*/
#define ice_stats_inc(stats, member) do { \
struct ice_ring_stats *__stats = (stats); \
- __stats->member++; \
+ u64_stats_update_begin(&__stats->syncp); \
+ u64_stats_inc(&__stats->member); \
+ u64_stats_update_end(&__stats->syncp); \
} while (0)
enum ice_ring_state_t {
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 1e3946a1dd36..1d77e993ceb5 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -3433,21 +3433,6 @@ int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc)
return ret;
}
-/**
- * ice_update_ring_stats - Update ring statistics
- * @stats: stats to be updated
- * @pkts: number of processed packets
- * @bytes: number of processed bytes
- *
- * This function assumes that caller has acquired a u64_stats_sync lock.
- */
-static void ice_update_ring_stats(struct ice_ring_stats *stats,
- u64 pkts, u64 bytes)
-{
- stats->bytes += bytes;
- stats->pkts += pkts;
-}
-
/**
* ice_update_tx_ring_stats - Update Tx ring specific counters
* @tx_ring: ring to update
@@ -3457,7 +3442,8 @@ static void ice_update_ring_stats(struct ice_ring_stats *stats,
void ice_update_tx_ring_stats(struct ice_tx_ring *tx_ring, u64 pkts, u64 bytes)
{
u64_stats_update_begin(&tx_ring->ring_stats->syncp);
- ice_update_ring_stats(tx_ring->ring_stats, pkts, bytes);
+ u64_stats_add(&tx_ring->ring_stats->pkts, pkts);
+ u64_stats_add(&tx_ring->ring_stats->bytes, bytes);
u64_stats_update_end(&tx_ring->ring_stats->syncp);
}
@@ -3470,7 +3456,8 @@ void ice_update_tx_ring_stats(struct ice_tx_ring *tx_ring, u64 pkts, u64 bytes)
void ice_update_rx_ring_stats(struct ice_rx_ring *rx_ring, u64 pkts, u64 bytes)
{
u64_stats_update_begin(&rx_ring->ring_stats->syncp);
- ice_update_ring_stats(rx_ring->ring_stats, pkts, bytes);
+ u64_stats_add(&rx_ring->ring_stats->pkts, pkts);
+ u64_stats_add(&rx_ring->ring_stats->bytes, bytes);
u64_stats_update_end(&rx_ring->ring_stats->syncp);
}
@@ -3487,8 +3474,8 @@ void ice_fetch_tx_ring_stats(const struct ice_tx_ring *ring,
do {
start = u64_stats_fetch_begin(&ring->ring_stats->syncp);
- *pkts = ring->ring_stats->pkts;
- *bytes = ring->ring_stats->bytes;
+ *pkts = u64_stats_read(&ring->ring_stats->pkts);
+ *bytes = u64_stats_read(&ring->ring_stats->bytes);
} while (u64_stats_fetch_retry(&ring->ring_stats->syncp, start));
}
@@ -3505,8 +3492,8 @@ void ice_fetch_rx_ring_stats(const struct ice_rx_ring *ring,
do {
start = u64_stats_fetch_begin(&ring->ring_stats->syncp);
- *pkts = ring->ring_stats->pkts;
- *bytes = ring->ring_stats->bytes;
+ *pkts = u64_stats_read(&ring->ring_stats->pkts);
+ *bytes = u64_stats_read(&ring->ring_stats->bytes);
} while (u64_stats_fetch_retry(&ring->ring_stats->syncp, start));
}
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 740596e5d384..557b108a334a 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -6809,54 +6809,132 @@ int ice_up(struct ice_vsi *vsi)
return err;
}
+struct ice_vsi_tx_stats {
+ u64 pkts;
+ u64 bytes;
+ u64 tx_restart_q;
+ u64 tx_busy;
+ u64 tx_linearize;
+};
+
+struct ice_vsi_rx_stats {
+ u64 pkts;
+ u64 bytes;
+ u64 rx_non_eop_descs;
+ u64 rx_page_failed;
+ u64 rx_buf_failed;
+};
+
/**
- * ice_fetch_u64_stats_per_ring - get packets and bytes stats per ring
- * @stats: pointer to ring stats structure
- * @pkts: packets stats counter
- * @bytes: bytes stats counter
+ * ice_fetch_u64_tx_stats - get Tx stats from a ring
+ * @ring: the Tx ring to copy stats from
+ * @copy: temporary storage for the ring statistics
*
- * This function fetches stats from the ring considering the atomic operations
- * that needs to be performed to read u64 values in 32 bit machine.
+ * Fetch the u64 stats from the ring using u64_stats_fetch. This ensures each
+ * stat value is self-consistent, though not necessarily consistent w.r.t
+ * other stats.
*/
-static void ice_fetch_u64_stats_per_ring(struct ice_ring_stats *stats,
- u64 *pkts, u64 *bytes)
+static void ice_fetch_u64_tx_stats(struct ice_tx_ring *ring,
+ struct ice_vsi_tx_stats *copy)
{
+ struct ice_ring_stats *stats = ring->ring_stats;
unsigned int start;
do {
start = u64_stats_fetch_begin(&stats->syncp);
- *pkts = stats->stats.pkts;
- *bytes = stats->stats.bytes;
+ copy->pkts = u64_stats_read(&stats->pkts);
+ copy->bytes = u64_stats_read(&stats->bytes);
+ copy->tx_restart_q = u64_stats_read(&stats->tx_restart_q);
+ copy->tx_busy = u64_stats_read(&stats->tx_busy);
+ copy->tx_linearize = u64_stats_read(&stats->tx_linearize);
+ } while (u64_stats_fetch_retry(&stats->syncp, start));
+}
+
+/**
+ * ice_fetch_u64_rx_stats - get Rx stats from a ring
+ * @ring: the Rx ring to copy stats from
+ * @copy: temporary storage for the ring statistics
+ *
+ * Fetch the u64 stats from the ring using u64_stats_fetch. This ensures each
+ * stat value is self-consistent, though not necessarily consistent w.r.t
+ * other stats.
+ */
+static void ice_fetch_u64_rx_stats(struct ice_rx_ring *ring,
+ struct ice_vsi_rx_stats *copy)
+{
+ struct ice_ring_stats *stats = ring->ring_stats;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin(&stats->syncp);
+ copy->pkts = u64_stats_read(&stats->pkts);
+ copy->bytes = u64_stats_read(&stats->bytes);
+ copy->rx_non_eop_descs =
+ u64_stats_read(&stats->rx_non_eop_descs);
+ copy->rx_page_failed = u64_stats_read(&stats->rx_page_failed);
+ copy->rx_buf_failed = u64_stats_read(&stats->rx_buf_failed);
} while (u64_stats_fetch_retry(&stats->syncp, start));
}
/**
* ice_update_vsi_tx_ring_stats - Update VSI Tx ring stats counters
* @vsi: the VSI to be updated
- * @vsi_stats: the stats struct to be updated
+ * @vsi_stats: accumulated stats for this VSI
* @rings: rings to work on
* @count: number of rings
*/
-static void
-ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi,
- struct rtnl_link_stats64 *vsi_stats,
- struct ice_tx_ring **rings, u16 count)
+static void ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi,
+ struct ice_vsi_tx_stats *vsi_stats,
+ struct ice_tx_ring **rings, u16 count)
{
+ struct ice_vsi_tx_stats copy = {};
u16 i;
for (i = 0; i < count; i++) {
struct ice_tx_ring *ring;
- u64 pkts = 0, bytes = 0;
ring = READ_ONCE(rings[i]);
if (!ring || !ring->ring_stats)
continue;
- ice_fetch_u64_stats_per_ring(ring->ring_stats, &pkts, &bytes);
- vsi_stats->tx_packets += pkts;
- vsi_stats->tx_bytes += bytes;
- vsi->tx_restart += ring->ring_stats->tx_restart_q;
- vsi->tx_busy += ring->ring_stats->tx_busy;
- vsi->tx_linearize += ring->ring_stats->tx_linearize;
+
+ ice_fetch_u64_tx_stats(ring, ©);
+
+ vsi_stats->pkts += copy.pkts;
+ vsi_stats->bytes += copy.bytes;
+ vsi_stats->tx_restart_q += copy.tx_restart_q;
+ vsi_stats->tx_busy += copy.tx_busy;
+ vsi_stats->tx_linearize += copy.tx_linearize;
+ }
+}
+
+/**
+ * ice_update_vsi_rx_ring_stats - Update VSI Rx ring stats counters
+ * @vsi: the VSI to be updated
+ * @vsi_stats: accumulated stats for this VSI
+ * @rings: rings to work on
+ * @count: number of rings
+ */
+static void ice_update_vsi_rx_ring_stats(struct ice_vsi *vsi,
+ struct ice_vsi_rx_stats *vsi_stats,
+ struct ice_rx_ring **rings, u16 count)
+{
+ struct ice_vsi_rx_stats copy = {};
+ u16 i;
+
+ for (i = 0; i < count; i++) {
+ struct ice_rx_ring *ring;
+
+ ring = READ_ONCE(rings[i]);
+ if (!ring || !ring->ring_stats)
+ continue;
+
+ ice_fetch_u64_rx_stats(ring, ©);
+
+ vsi_stats->pkts += copy.pkts;
+ vsi_stats->bytes += copy.bytes;
+ vsi_stats->rx_non_eop_descs += copy.rx_non_eop_descs;
+ vsi_stats->rx_page_failed += copy.rx_page_failed;
+ vsi_stats->rx_buf_failed += copy.rx_buf_failed;
}
}
@@ -6867,48 +6945,34 @@ ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi,
static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
{
struct rtnl_link_stats64 *net_stats, *stats_prev;
- struct rtnl_link_stats64 *vsi_stats;
+ struct ice_vsi_tx_stats tx_stats = {};
+ struct ice_vsi_rx_stats rx_stats = {};
struct ice_pf *pf = vsi->back;
- u64 pkts, bytes;
- int i;
-
- vsi_stats = kzalloc(sizeof(*vsi_stats), GFP_ATOMIC);
- if (!vsi_stats)
- return;
-
- /* reset non-netdev (extended) stats */
- vsi->tx_restart = 0;
- vsi->tx_busy = 0;
- vsi->tx_linearize = 0;
- vsi->rx_buf_failed = 0;
- vsi->rx_page_failed = 0;
rcu_read_lock();
/* update Tx rings counters */
- ice_update_vsi_tx_ring_stats(vsi, vsi_stats, vsi->tx_rings,
+ ice_update_vsi_tx_ring_stats(vsi, &tx_stats, vsi->tx_rings,
vsi->num_txq);
/* update Rx rings counters */
- ice_for_each_rxq(vsi, i) {
- struct ice_rx_ring *ring = READ_ONCE(vsi->rx_rings[i]);
- struct ice_ring_stats *ring_stats;
-
- ring_stats = ring->ring_stats;
- ice_fetch_u64_stats_per_ring(ring_stats, &pkts, &bytes);
- vsi_stats->rx_packets += pkts;
- vsi_stats->rx_bytes += bytes;
- vsi->rx_buf_failed += ring_stats->rx_buf_failed;
- vsi->rx_page_failed += ring_stats->rx_page_failed;
- }
+ ice_update_vsi_rx_ring_stats(vsi, &rx_stats, vsi->rx_rings,
+ vsi->num_rxq);
/* update XDP Tx rings counters */
if (ice_is_xdp_ena_vsi(vsi))
- ice_update_vsi_tx_ring_stats(vsi, vsi_stats, vsi->xdp_rings,
+ ice_update_vsi_tx_ring_stats(vsi, &tx_stats, vsi->xdp_rings,
vsi->num_xdp_txq);
rcu_read_unlock();
+ /* Save non-netdev (extended) stats */
+ vsi->tx_restart = tx_stats.tx_restart_q;
+ vsi->tx_busy = tx_stats.tx_busy;
+ vsi->tx_linearize = tx_stats.tx_linearize;
+ vsi->rx_buf_failed = rx_stats.rx_buf_failed;
+ vsi->rx_page_failed = rx_stats.rx_page_failed;
+
net_stats = &vsi->net_stats;
stats_prev = &vsi->net_stats_prev;
@@ -6918,18 +6982,16 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
* let's skip this round.
*/
if (likely(pf->stat_prev_loaded)) {
- net_stats->tx_packets += vsi_stats->tx_packets - stats_prev->tx_packets;
- net_stats->tx_bytes += vsi_stats->tx_bytes - stats_prev->tx_bytes;
- net_stats->rx_packets += vsi_stats->rx_packets - stats_prev->rx_packets;
- net_stats->rx_bytes += vsi_stats->rx_bytes - stats_prev->rx_bytes;
+ net_stats->tx_packets += tx_stats.pkts - stats_prev->tx_packets;
+ net_stats->tx_bytes += tx_stats.bytes - stats_prev->tx_bytes;
+ net_stats->rx_packets += rx_stats.pkts - stats_prev->rx_packets;
+ net_stats->rx_bytes += rx_stats.bytes - stats_prev->rx_bytes;
}
- stats_prev->tx_packets = vsi_stats->tx_packets;
- stats_prev->tx_bytes = vsi_stats->tx_bytes;
- stats_prev->rx_packets = vsi_stats->rx_packets;
- stats_prev->rx_bytes = vsi_stats->rx_bytes;
-
- kfree(vsi_stats);
+ stats_prev->tx_packets = tx_stats.pkts;
+ stats_prev->tx_bytes = tx_stats.bytes;
+ stats_prev->rx_packets = rx_stats.pkts;
+ stats_prev->rx_bytes = rx_stats.bytes;
}
/**
--
2.51.0.rc1.197.g6d975e95c9d7
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 1/6] ice: initialize ring_stats->syncp
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 1/6] ice: initialize ring_stats->syncp Jacob Keller
@ 2025-11-25 10:15 ` Simon Horman
2025-12-03 22:23 ` Jacob Keller
0 siblings, 1 reply; 19+ messages in thread
From: Simon Horman @ 2025-11-25 10:15 UTC (permalink / raw)
To: Jacob Keller
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
On Thu, Nov 20, 2025 at 12:20:41PM -0800, Jacob Keller wrote:
> The u64_stats_sync structure is empty on 64-bit systems. However, on 32-bit
> systems it contains a seqcount_t which needs to be initialized. While the
> memory is zero-initialized, a lack of u64_stats_init means that lockdep
> won't get initialized properly. Fix this by adding u64_stats_init() calls
> to the rings just after allocation.
>
> Fixes: 2b245cb29421 ("ice: Implement transmit and NAPI support")
I think that either this patch should be routed via net. Or the Fixes tag
should be removed, and optionally something about commit 2b245cb29421
("ice: Implement transmit and NAPI support") included in the commit message
above the tags.
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
> ---
> drivers/net/ethernet/intel/ice/ice_lib.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
> index 44f3c2bab308..116a4f4ef91d 100644
> --- a/drivers/net/ethernet/intel/ice/ice_lib.c
> +++ b/drivers/net/ethernet/intel/ice/ice_lib.c
> @@ -400,7 +400,10 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
> if (!ring_stats)
> goto err_out;
>
> + u64_stats_init(&ring_stats->syncp);
> +
> WRITE_ONCE(tx_ring_stats[i], ring_stats);
> +
nit: perhaps adding this blank line is unintentional.
> }
>
> ring->ring_stats = ring_stats;
> @@ -419,6 +422,8 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
> if (!ring_stats)
> goto err_out;
>
> + u64_stats_init(&ring_stats->syncp);
> +
> WRITE_ONCE(rx_ring_stats[i], ring_stats);
> }
The above comments not withstanding, this looks good to me.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 2/6] ice: pass pointer to ice_fetch_u64_stats_per_ring
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 2/6] ice: pass pointer to ice_fetch_u64_stats_per_ring Jacob Keller
@ 2025-11-25 10:16 ` Simon Horman
2025-12-03 22:12 ` Jacob Keller
0 siblings, 1 reply; 19+ messages in thread
From: Simon Horman @ 2025-11-25 10:16 UTC (permalink / raw)
To: Jacob Keller
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
On Thu, Nov 20, 2025 at 12:20:42PM -0800, Jacob Keller wrote:
> The ice_fetch_u64_stats_per_ring function takes a pointer to the syncp from
> the ring stats to synchronize reading of the packet stats. It also takes a
> *copy* of the ice_q_stats fields instead of a pointer to the stats. This
> completely defeats the point of using the u64_stats API. We pass the stats
> by value, so they are static at the point of reading within the
> u64_stats_fetch_retry loop.
>
> Simplify the function to take a pointer to the ice_ring_stats instead of
> two separate parameters. Additionally, since we never call this outside of
> ice_main.c, make it a static function.
>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
The *copy* was certainly working against us here.
But TBH, C syntax led me to read the code more than
once before seeing it.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 3/6] ice: remove ice_q_stats struct and use struct_group
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 3/6] ice: remove ice_q_stats struct and use struct_group Jacob Keller
@ 2025-11-25 10:16 ` Simon Horman
2025-12-03 22:14 ` Jacob Keller
0 siblings, 1 reply; 19+ messages in thread
From: Simon Horman @ 2025-11-25 10:16 UTC (permalink / raw)
To: Jacob Keller
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
On Thu, Nov 20, 2025 at 12:20:43PM -0800, Jacob Keller wrote:
> The ice_qp_reset_stats function resets the stats for all rings on a VSI. It
> currently behaves differently for Tx and Rx rings. For Rx rings, it only
> clears the rx_stats which do not include the pkt and byte counts. For Tx
> rings and XDP rings, it clears only the pkt and byte counts.
>
> We could add extra memset calls to cover both the stats and relevant
> tx/rx stats fields. Instead, lets convert stats into a struct_group which
> contains both the pkts and bytes fields as well as the Tx or Rx stats, and
> remove the ice_q_stats structure entirely.
>
> The only remaining user of ice_q_stats is the ice_q_stats_len function in
> ice_ethtool.c, which just counts the number of fields. Replace this with a
> simple multiplication by 2. I find this to be simpler to reason about than
> relying on knowing the layout of the ice_q_stats structure.
>
> Now that the stats field of the ice_ring_stats covers all of the statistic
> values, the ice_qp_reset_stats function will properly zero out all of the
> fields.
>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
I agree this is both more consistent and cleaner.
I do feel there might be a yet cleaner way to handle things
in place of multiplication by 2. But I can't think of such
a way at this time.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 4/6] ice: use u64_stats API to access pkts/bytes in dim sample
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 4/6] ice: use u64_stats API to access pkts/bytes in dim sample Jacob Keller
@ 2025-11-25 10:17 ` Simon Horman
0 siblings, 0 replies; 19+ messages in thread
From: Simon Horman @ 2025-11-25 10:17 UTC (permalink / raw)
To: Jacob Keller
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
On Thu, Nov 20, 2025 at 12:20:44PM -0800, Jacob Keller wrote:
> The __ice_update_sample and __ice_get_ethtool_stats functions directly
> accesses the pkts and bytes counters from the ring stats. A following
> change is going to update the fields to be u64_stats_t type, and will need
> to be accessed appropriately. This will ensure that the accesses do not
> cause load/store tearing.
>
> Add helper functions similar to the ones used for updating the stats
> values, and use them. This ensures use of the syncp pointer on 32-bit
> architectures. Once the fields are updated to u64_stats_t, it will then
> properly avoid tears on all architectures.
>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
This seems like a nice clean up to me. And I think it makes sense in the
context of where this patch set is going.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 5/6] ice: shorten ring stat names and add accessors
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 5/6] ice: shorten ring stat names and add accessors Jacob Keller
@ 2025-11-25 10:17 ` Simon Horman
2025-12-03 22:17 ` Jacob Keller
0 siblings, 1 reply; 19+ messages in thread
From: Simon Horman @ 2025-11-25 10:17 UTC (permalink / raw)
To: Jacob Keller
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
On Thu, Nov 20, 2025 at 12:20:45PM -0800, Jacob Keller wrote:
> The ice Tx/Rx hotpath has a few statistics counters for tracking unexpected
> events. These values are stored as u64 but are not accumulated using the
> u64_stats API. This could result in load/tear stores on some architectures.
> Even some 64-bit architectures could have issues since the fields are not
> read or written using ACCESS_ONCE or READ_ONCE.
>
> A following change is going to refactor the stats accumulator code to use
> the u64_stats API for all of these stats, and to use u64_stats_read and
> u64_stats_inc properly to prevent load/store tears on all architectures.
>
> Using u64_stats_inc and the syncp pointer is slightly verbose and would be
> duplicated in a number of places in the Tx and Rx hot path. Add accessor
> macros for the cases where only a single stat value is touched at once. To
> keep lines short, also shorten the stats names and convert ice_txq_stats
> and ice_rxq_stats to struct_group.
>
> This will ease the transition to properly using the u64_stats API in the
> following change.
>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
I had to read this and the next patch a few times to understand what was
going on. In the end, the key for me understanding this patch is "...
accessor macros for the cases where only a single stat value is touched at
once.". Especially the "once" bit.
In the context of the following patch I think this change makes sense.
And I appreciate that keeping lines short also makes sense. So no
objections to the direction you've taken here. But I might not have
thought to use struct_group for this myself.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 6/6] ice: convert all ring stats to u64_stats_t
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 6/6] ice: convert all ring stats to u64_stats_t Jacob Keller
@ 2025-11-25 10:17 ` Simon Horman
2025-12-03 22:21 ` Jacob Keller
0 siblings, 1 reply; 19+ messages in thread
From: Simon Horman @ 2025-11-25 10:17 UTC (permalink / raw)
To: Jacob Keller
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
On Thu, Nov 20, 2025 at 12:20:46PM -0800, Jacob Keller wrote:
> After several cleanups, the ice driver is now finally ready to convert all
> Tx and Rx ring stats to the u64_stats_t and proper use of the u64 stats
> APIs.
>
> The final remaining part to cleanup is the VSI stats accumulation logic in
> ice_update_vsi_ring_stats().
>
> Refactor the function and its helpers so that all stat values (and not
> just pkts and bytes) use the u64_stats APIs. The
> ice_fetch_u64_(tx|rx)_stats functions read the stat values using
> u64_stats_read and then copy them into local ice_vsi_(tx|rx)_stats
> structures. This does require making a new struct with the stat fields as
> u64.
>
> The ice_update_vsi_(tx|rx)_ring_stats functions call the fetch functions
> per ring and accumulate the result into one copy of the struct. This
> accumulated total is then used to update the relevant VSI fields.
>
> Since these are relatively small, the contents are all stored on the stack
> rather than allocating and freeing memory.
>
> Once the accumulator side is updated, the helper ice_stats_read and
> ice_stats_inc and other related helper functions all easily translate to
> use of u64_stats_read and u64_stats_inc. This completes the refactor and
> ensures that all stats accesses now make proper use of the API.
>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Thanks.
I do notice in the cover that you solicit alternate approaches to
lead to a yet cleaner solution. But I think that the approach you have
taken does significantly improve both the cleanliness and correctness
of the code. So even if we think of something better later, I think
this is a good step to take now.
Thanks for breaking out the series into bite-sized chunks, especially
the last few patches. It really helped me in my review.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 2/6] ice: pass pointer to ice_fetch_u64_stats_per_ring
2025-11-25 10:16 ` Simon Horman
@ 2025-12-03 22:12 ` Jacob Keller
0 siblings, 0 replies; 19+ messages in thread
From: Jacob Keller @ 2025-12-03 22:12 UTC (permalink / raw)
To: Simon Horman
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
[-- Attachment #1.1: Type: text/plain, Size: 1164 bytes --]
On 11/25/2025 2:16 AM, Simon Horman wrote:
> On Thu, Nov 20, 2025 at 12:20:42PM -0800, Jacob Keller wrote:
>> The ice_fetch_u64_stats_per_ring function takes a pointer to the syncp from
>> the ring stats to synchronize reading of the packet stats. It also takes a
>> *copy* of the ice_q_stats fields instead of a pointer to the stats. This
>> completely defeats the point of using the u64_stats API. We pass the stats
>> by value, so they are static at the point of reading within the
>> u64_stats_fetch_retry loop.
>>
>> Simplify the function to take a pointer to the ice_ring_stats instead of
>> two separate parameters. Additionally, since we never call this outside of
>> ice_main.c, make it a static function.
>>
>> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
>
> The *copy* was certainly working against us here.
> But TBH, C syntax led me to read the code more than
> once before seeing it.
>
Yes, I had the exact same issue. It took me a while while refactoring to
notice this particular bug...
> Reviewed-by: Simon Horman <horms@kernel.org>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 3/6] ice: remove ice_q_stats struct and use struct_group
2025-11-25 10:16 ` Simon Horman
@ 2025-12-03 22:14 ` Jacob Keller
0 siblings, 0 replies; 19+ messages in thread
From: Jacob Keller @ 2025-12-03 22:14 UTC (permalink / raw)
To: Simon Horman
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
[-- Attachment #1.1: Type: text/plain, Size: 1963 bytes --]
On 11/25/2025 2:16 AM, Simon Horman wrote:
> On Thu, Nov 20, 2025 at 12:20:43PM -0800, Jacob Keller wrote:
>> The ice_qp_reset_stats function resets the stats for all rings on a VSI. It
>> currently behaves differently for Tx and Rx rings. For Rx rings, it only
>> clears the rx_stats which do not include the pkt and byte counts. For Tx
>> rings and XDP rings, it clears only the pkt and byte counts.
>>
>> We could add extra memset calls to cover both the stats and relevant
>> tx/rx stats fields. Instead, lets convert stats into a struct_group which
>> contains both the pkts and bytes fields as well as the Tx or Rx stats, and
>> remove the ice_q_stats structure entirely.
>>
>> The only remaining user of ice_q_stats is the ice_q_stats_len function in
>> ice_ethtool.c, which just counts the number of fields. Replace this with a
>> simple multiplication by 2. I find this to be simpler to reason about than
>> relying on knowing the layout of the ice_q_stats structure.
>>
>> Now that the stats field of the ice_ring_stats covers all of the statistic
>> values, the ice_qp_reset_stats function will properly zero out all of the
>> fields.
>>
>> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
>
> I agree this is both more consistent and cleaner.
>
> I do feel there might be a yet cleaner way to handle things
> in place of multiplication by 2. But I can't think of such
> a way at this time.
>
I agree as well. Potentially some structure layouts would allow us to
get the total amount of stats, or we could count the number of Tx and Rx
queues separately.. The driver has some effort to allow varying number
of Tx/Rx queues in some places, but then lacks proper support for that
in others. In particular, the maximum number of both is always the same,
hence the multiply by 2 here.
> Reviewed-by: Simon Horman <horms@kernel.org>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 5/6] ice: shorten ring stat names and add accessors
2025-11-25 10:17 ` Simon Horman
@ 2025-12-03 22:17 ` Jacob Keller
0 siblings, 0 replies; 19+ messages in thread
From: Jacob Keller @ 2025-12-03 22:17 UTC (permalink / raw)
To: Simon Horman
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
[-- Attachment #1.1: Type: text/plain, Size: 2440 bytes --]
On 11/25/2025 2:17 AM, Simon Horman wrote:
> On Thu, Nov 20, 2025 at 12:20:45PM -0800, Jacob Keller wrote:
>> The ice Tx/Rx hotpath has a few statistics counters for tracking unexpected
>> events. These values are stored as u64 but are not accumulated using the
>> u64_stats API. This could result in load/tear stores on some architectures.
>> Even some 64-bit architectures could have issues since the fields are not
>> read or written using ACCESS_ONCE or READ_ONCE.
>>
>> A following change is going to refactor the stats accumulator code to use
>> the u64_stats API for all of these stats, and to use u64_stats_read and
>> u64_stats_inc properly to prevent load/store tears on all architectures.
>>
>> Using u64_stats_inc and the syncp pointer is slightly verbose and would be
>> duplicated in a number of places in the Tx and Rx hot path. Add accessor
>> macros for the cases where only a single stat value is touched at once. To
>> keep lines short, also shorten the stats names and convert ice_txq_stats
>> and ice_rxq_stats to struct_group.
>>
>> This will ease the transition to properly using the u64_stats API in the
>> following change.
>>
>> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
>
> I had to read this and the next patch a few times to understand what was
> going on. In the end, the key for me understanding this patch is "...
> accessor macros for the cases where only a single stat value is touched at
> once.". Especially the "once" bit.
>
I'm a little unhappy with needing access macros like this because its
yet another "driver specific wrapper".. but I couldn't come up with
something better..
> In the context of the following patch I think this change makes sense.
> And I appreciate that keeping lines short also makes sense. So no
> objections to the direction you've taken here. But I might not have
> thought to use struct_group for this myself.
>
Right. The main issue I had was all the places where we increment one
stat we'd end up needing *at least* 3 lines. And trying to split or
refactor all of those updates seemed like it would be problematic.
I liked the use of struct_group since it lets us keep size information
and logical separation without needing to add the extra layer of
indirection in the accesses.
> Reviewed-by: Simon Horman <horms@kernel.org>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 6/6] ice: convert all ring stats to u64_stats_t
2025-11-25 10:17 ` Simon Horman
@ 2025-12-03 22:21 ` Jacob Keller
0 siblings, 0 replies; 19+ messages in thread
From: Jacob Keller @ 2025-12-03 22:21 UTC (permalink / raw)
To: Simon Horman
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
[-- Attachment #1.1: Type: text/plain, Size: 2767 bytes --]
On 11/25/2025 2:17 AM, Simon Horman wrote:
> On Thu, Nov 20, 2025 at 12:20:46PM -0800, Jacob Keller wrote:
>> After several cleanups, the ice driver is now finally ready to convert all
>> Tx and Rx ring stats to the u64_stats_t and proper use of the u64 stats
>> APIs.
>>
>> The final remaining part to cleanup is the VSI stats accumulation logic in
>> ice_update_vsi_ring_stats().
>>
>> Refactor the function and its helpers so that all stat values (and not
>> just pkts and bytes) use the u64_stats APIs. The
>> ice_fetch_u64_(tx|rx)_stats functions read the stat values using
>> u64_stats_read and then copy them into local ice_vsi_(tx|rx)_stats
>> structures. This does require making a new struct with the stat fields as
>> u64.
>>
>> The ice_update_vsi_(tx|rx)_ring_stats functions call the fetch functions
>> per ring and accumulate the result into one copy of the struct. This
>> accumulated total is then used to update the relevant VSI fields.
>>
>> Since these are relatively small, the contents are all stored on the stack
>> rather than allocating and freeing memory.
>>
>> Once the accumulator side is updated, the helper ice_stats_read and
>> ice_stats_inc and other related helper functions all easily translate to
>> use of u64_stats_read and u64_stats_inc. This completes the refactor and
>> ensures that all stats accesses now make proper use of the API.
>>
>> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
>
> Thanks.
>
> I do notice in the cover that you solicit alternate approaches to
> lead to a yet cleaner solution. But I think that the approach you have
> taken does significantly improve both the cleanliness and correctness
> of the code. So even if we think of something better later, I think
> this is a good step to take now.
>
Thanks. In particular, I was wondering if there is a way to help improve
or extend the overall u64_stats API to make some of this non-driver
specific.
It does seem like quite a lot of boilerplate code is needed to make
correct use of the APIs, especially with the u64_stat_t type existing
now which is necessary even on some 64-bit arch.
Perhaps some of the macro wrappers could migrate into u64_stats.h header
somehow. Though I'm not sure we can keep them quite as short without
being in the driver.
> Thanks for breaking out the series into bite-sized chunks, especially
> the last few patches. It really helped me in my review.
>
Yep. I originally had this all munged together but it became impossible
to follow the logic of how I got to this point, and also obscured
several of the outright fixes.
> Reviewed-by: Simon Horman <horms@kernel.org>
>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 1/6] ice: initialize ring_stats->syncp
2025-11-25 10:15 ` Simon Horman
@ 2025-12-03 22:23 ` Jacob Keller
2025-12-04 12:13 ` Simon Horman
0 siblings, 1 reply; 19+ messages in thread
From: Jacob Keller @ 2025-12-03 22:23 UTC (permalink / raw)
To: Simon Horman
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
[-- Attachment #1.1: Type: text/plain, Size: 2482 bytes --]
On 11/25/2025 2:15 AM, Simon Horman wrote:
> On Thu, Nov 20, 2025 at 12:20:41PM -0800, Jacob Keller wrote:
>> The u64_stats_sync structure is empty on 64-bit systems. However, on 32-bit
>> systems it contains a seqcount_t which needs to be initialized. While the
>> memory is zero-initialized, a lack of u64_stats_init means that lockdep
>> won't get initialized properly. Fix this by adding u64_stats_init() calls
>> to the rings just after allocation.
>>
>> Fixes: 2b245cb29421 ("ice: Implement transmit and NAPI support")
>
> I think that either this patch should be routed via net. Or the Fixes tag
> should be removed, and optionally something about commit 2b245cb29421
> ("ice: Implement transmit and NAPI support") included in the commit message
> above the tags.
>
>> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
>> ---
>> drivers/net/ethernet/intel/ice/ice_lib.c | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
>> index 44f3c2bab308..116a4f4ef91d 100644
>> --- a/drivers/net/ethernet/intel/ice/ice_lib.c
>> +++ b/drivers/net/ethernet/intel/ice/ice_lib.c
>> @@ -400,7 +400,10 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
>> if (!ring_stats)
>> goto err_out;
>>
>> + u64_stats_init(&ring_stats->syncp);
>> +
>> WRITE_ONCE(tx_ring_stats[i], ring_stats);
>> +
>
> nit: perhaps adding this blank line is unintentional.
>
Indeed it was. I believe its a result of the rebasing I did to split the
changes into separate patches, and this mistake slipped through.
>> }
>>
>> ring->ring_stats = ring_stats;
>> @@ -419,6 +422,8 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
>> if (!ring_stats)
>> goto err_out;
>>
>> + u64_stats_init(&ring_stats->syncp);
>> +
>> WRITE_ONCE(rx_ring_stats[i], ring_stats);
>> }
>
> The above comments not withstanding, this looks good to me.
>
> Reviewed-by: Simon Horman <horms@kernel.org>
>
Tony is going to help work with me to separate this lone patch from the
series and prepare it for submission through net separate from the rest
of the series. Unless there's other review that requires it, I likely
won't post a v5 to Intel Wired LAN, but wanted to confirm that we'll
submit this fix through net.
Thanks,
Jake
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 1/6] ice: initialize ring_stats->syncp
2025-12-03 22:23 ` Jacob Keller
@ 2025-12-04 12:13 ` Simon Horman
0 siblings, 0 replies; 19+ messages in thread
From: Simon Horman @ 2025-12-04 12:13 UTC (permalink / raw)
To: Jacob Keller
Cc: Aleksandr Loktionov, Alexander Lobakin, Tony Nguyen,
Przemek Kitszel, intel-wired-lan, netdev
On Wed, Dec 03, 2025 at 02:23:06PM -0800, Jacob Keller wrote:
...
> Tony is going to help work with me to separate this lone patch from the
> series and prepare it for submission through net separate from the rest
> of the series. Unless there's other review that requires it, I likely
> won't post a v5 to Intel Wired LAN, but wanted to confirm that we'll
> submit this fix through net.
Ack. No objections from my side.
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2025-12-04 12:13 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-20 20:20 [Intel-wired-lan] [PATCH iwl-next v4 0/6] ice: properly use u64_stats API for all ring stats Jacob Keller
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 1/6] ice: initialize ring_stats->syncp Jacob Keller
2025-11-25 10:15 ` Simon Horman
2025-12-03 22:23 ` Jacob Keller
2025-12-04 12:13 ` Simon Horman
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 2/6] ice: pass pointer to ice_fetch_u64_stats_per_ring Jacob Keller
2025-11-25 10:16 ` Simon Horman
2025-12-03 22:12 ` Jacob Keller
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 3/6] ice: remove ice_q_stats struct and use struct_group Jacob Keller
2025-11-25 10:16 ` Simon Horman
2025-12-03 22:14 ` Jacob Keller
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 4/6] ice: use u64_stats API to access pkts/bytes in dim sample Jacob Keller
2025-11-25 10:17 ` Simon Horman
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 5/6] ice: shorten ring stat names and add accessors Jacob Keller
2025-11-25 10:17 ` Simon Horman
2025-12-03 22:17 ` Jacob Keller
2025-11-20 20:20 ` [Intel-wired-lan] [PATCH iwl-next v4 6/6] ice: convert all ring stats to u64_stats_t Jacob Keller
2025-11-25 10:17 ` Simon Horman
2025-12-03 22:21 ` Jacob Keller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).