From: Anshumali Gaur <hidden> Date: 2026-05-11 09:42:21
Currently netdev driver is not retaining ethtool stats during
interface up and down, as per kernel driver standard netdev driver
must keep stats constant to avoid race conditions with user space
trying to read them. Stats must persist across routine
operations like bringing the interface down and up.
Signed-off-by: Anshumali Gaur <redacted>
---
v2:
- Fix subject prefix to target net-next
.../marvell/octeontx2/nic/otx2_common.c | 20 ++++++++++---------
.../marvell/octeontx2/nic/otx2_common.h | 1 +
.../ethernet/marvell/octeontx2/nic/otx2_pf.c | 18 +++++++++++++++++
3 files changed, 30 insertions(+), 9 deletions(-)
@@ -2158,10 +2158,28 @@ int otx2_stop(struct net_device *netdev)structotx2_qset*qset=&pf->qset;intqidx,vec,wrk;+structotx2_dev_stats*dev=&pf->hw.dev_stats;+structotx2_dev_stats*old_stats=&pf->hw.old_stats;+/* If the DOWN flag is set resources are already freed */if(pf->flags&OTX2_FLAG_INTF_DOWN)return0;+/* Accumulate old stats */+old_stats->rx_bytes+=dev->rx_bytes;+old_stats->rx_drops+=dev->rx_drops;+old_stats->rx_bcast_frames+=dev->rx_bcast_frames;+old_stats->rx_mcast_frames+=dev->rx_mcast_frames;+old_stats->rx_ucast_frames+=dev->rx_ucast_frames;+old_stats->rx_frames+=dev->rx_frames;++old_stats->tx_bytes+=dev->tx_bytes;+old_stats->tx_drops+=dev->tx_drops;+old_stats->tx_bcast_frames+=dev->tx_bcast_frames;+old_stats->tx_mcast_frames+=dev->tx_mcast_frames;+old_stats->tx_ucast_frames+=dev->tx_ucast_frames;+old_stats->tx_frames+=dev->tx_frames;+netif_carrier_off(netdev);netif_tx_stop_all_queues(netdev);
Currently netdev driver is not retaining ethtool stats during
interface up and down, as per kernel driver standard netdev driver
must keep stats constant to avoid race conditions with user space
trying to read them. Stats must persist across routine
operations like bringing the interface down and up.
Signed-off-by: Anshumali Gaur <redacted>
---
v2:
- Fix subject prefix to target net-next
.../marvell/octeontx2/nic/otx2_common.c | 20 ++++++++++---------
.../marvell/octeontx2/nic/otx2_common.h | 1 +
.../ethernet/marvell/octeontx2/nic/otx2_pf.c | 18 +++++++++++++++++
3 files changed, 30 insertions(+), 9 deletions(-)
I don't quite understand why the additional old_stats is required.
Why not accumulate dev_stats in place? Either directly in
otx2_get_dev_stats() or pass a local struct otx2_dev_stats var
and then accumulate that into dev_stats?
Thanks,
Dragos
From: Jakub Kicinski <kuba@kernel.org> Date: 2026-05-12 00:12:47
On Mon, 11 May 2026 15:12:05 +0530 Anshumali Gaur wrote:
Currently netdev driver is not retaining ethtool stats during
interface up and down, as per kernel driver standard netdev driver
must keep stats constant to avoid race conditions with user space
trying to read them. Stats must persist across routine
operations like bringing the interface down and up.
I think you're confusing the value of the stats with the list of stats.
Retaining values thru down/up is probably the most common behavior but
that's not what the doc is likely talking about.
From: Anshumali Gaur <hidden> Date: 2026-05-14 06:35:48
On Mon, May 11, 2026 at 12:03:32PM +0200, Dragos Tatulea wrote:
On 11.05.26 11:42, Anshumali Gaur wrote:
quoted
Currently netdev driver is not retaining ethtool stats during
interface up and down, as per kernel driver standard netdev driver
must keep stats constant to avoid race conditions with user space
trying to read them. Stats must persist across routine
operations like bringing the interface down and up.
Signed-off-by: Anshumali Gaur <redacted>
---
v2:
- Fix subject prefix to target net-next
.../marvell/octeontx2/nic/otx2_common.c | 20 ++++++++++---------
.../marvell/octeontx2/nic/otx2_common.h | 1 +
.../ethernet/marvell/octeontx2/nic/otx2_pf.c | 18 +++++++++++++++++
3 files changed, 30 insertions(+), 9 deletions(-)
I don't quite understand why the additional old_stats is required.
Why not accumulate dev_stats in place? Either directly in
otx2_get_dev_stats() or pass a local struct otx2_dev_stats var
and then accumulate that into dev_stats?
Thanks,
Dragos
Hi Dragos,
Thanks for the review.
otx2_get_dev_stats() reads absolute HW counter values from
NIX LF stats registers and does direct assignment to dev_stats
(e.g., dev_stats->rx_bytes = OTX2_GET_RX_STATS(RX_OCTS)).
These HW counters reset to zero when the interface goes down.
Since they report absolute values, not deltas,
accumulating in-place with += would double-count on every stats query.
Thanks,
Anshu
On Mon, May 11, 2026 at 12:03:32PM +0200, Dragos Tatulea wrote:
quoted
[...]
I don't quite understand why the additional old_stats is required.
Why not accumulate dev_stats in place? Either directly in
otx2_get_dev_stats() or pass a local struct otx2_dev_stats var
and then accumulate that into dev_stats?
Thanks,
Dragos
Hi Dragos,
Thanks for the review.
otx2_get_dev_stats() reads absolute HW counter values from
NIX LF stats registers and does direct assignment to dev_stats
(e.g., dev_stats->rx_bytes = OTX2_GET_RX_STATS(RX_OCTS)).
These HW counters reset to zero when the interface goes down.
Since they report absolute values, not deltas,
accumulating in-place with += would double-count on every stats query.
@@ -2158,10 +2158,28 @@ int otx2_stop(struct net_device *netdev)structotx2_qset*qset=&pf->qset;intqidx,vec,wrk;+structotx2_dev_stats*dev=&pf->hw.dev_stats;+structotx2_dev_stats*old_stats=&pf->hw.old_stats;+/* If the DOWN flag is set resources are already freed */if(pf->flags&OTX2_FLAG_INTF_DOWN)return0;+/* Accumulate old stats */+old_stats->rx_bytes+=dev->rx_bytes;+old_stats->rx_drops+=dev->rx_drops;+old_stats->rx_bcast_frames+=dev->rx_bcast_frames;+old_stats->rx_mcast_frames+=dev->rx_mcast_frames;+old_stats->rx_ucast_frames+=dev->rx_ucast_frames;+old_stats->rx_frames+=dev->rx_frames;++old_stats->tx_bytes+=dev->tx_bytes;+old_stats->tx_drops+=dev->tx_drops;+old_stats->tx_bcast_frames+=dev->tx_bcast_frames;+old_stats->tx_mcast_frames+=dev->tx_mcast_frames;+old_stats->tx_ucast_frames+=dev->tx_ucast_frames;+old_stats->tx_frames+=dev->tx_frames;+netif_carrier_off(netdev);netif_tx_stop_all_queues(netdev);