git: cb85c4397bb3 - main - ixv: Preserve statistics across resets
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 16 Aug 2026 01:25:31 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=cb85c4397bb3f57e60ab20c239b9339c4b752412
commit cb85c4397bb3f57e60ab20c239b9339c4b752412
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-10 15:12:24 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-16 01:23:22 +0000
ixv: Preserve statistics across resets
The VF statistics registers are free running and are not cleared on
read. The existing code records attach time bases and pre-reset totals,
but never uses either when publishing counters. It instead replaces
the low hardware bits directly, so counters can inherit pre-attach
traffic or jump backward after a reset.
Accumulate modular 32- and 36-bit deltas, following DPDK, while keeping
the software totals across planned resets. Establish a fresh hardware
baseline after each successful reset and invalidate the sampling epoch
when mailbox state is lost. Detect unsolicited PF resets explicitly so
a reset while link is down cannot be mistaken for counter wrap.
Remove the unused base and saved-reset bookkeeping.
On E610, packet and octet counters remained monotonic across a VF FLR
and a PF down/up cycle. Traffic after each reset advanced both RX and
TX counters.
MFC after: 2 weeks
Sponsored by: BBOX.io
---
sys/dev/ixgbe/if_ixv.c | 115 ++++++++++++++++++++---------------------------
sys/dev/ixgbe/ixgbe_vf.h | 13 +-----
2 files changed, 50 insertions(+), 78 deletions(-)
diff --git a/sys/dev/ixgbe/if_ixv.c b/sys/dev/ixgbe/if_ixv.c
index 99d1169254c5..c88c334ee94f 100644
--- a/sys/dev/ixgbe/if_ixv.c
+++ b/sys/dev/ixgbe/if_ixv.c
@@ -149,7 +149,6 @@ static void ixv_if_unregister_vlan(if_ctx_t, u16);
static uint64_t ixv_if_get_counter(if_ctx_t, ift_counter);
static bool ixv_if_needs_restart(if_ctx_t, enum iflib_restart_event);
-static void ixv_save_stats(struct ixgbe_softc *);
static void ixv_init_stats(struct ixgbe_softc *);
static void ixv_update_stats(struct ixgbe_softc *);
static void ixv_add_stats_sysctls(struct ixgbe_softc *);
@@ -568,8 +567,8 @@ ixv_if_attach_post(if_ctx_t ctx)
}
/* Do the stats setup */
- ixv_save_stats(sc);
- ixv_init_stats(sc);
+ if (atomic_load_acq_32(&sc->vf_mbx_ready) != 0)
+ ixv_init_stats(sc);
ixv_add_stats_sysctls(sc);
end:
@@ -674,12 +673,14 @@ ixv_if_init(if_ctx_t ctx)
/* Reset VF and renegotiate mailbox API version. */
error = hw->mac.ops.reset_hw(hw);
if (error != IXGBE_SUCCESS) {
+ sc->stats.vf.initialized = false;
ixv_log_reset_failure(sc, error, false);
hw->mac.ops.stop_adapter(hw);
ixv_mbx_retry_failed(ctx);
return;
}
hw->mac.ops.start_hw(hw);
+ ixv_init_stats(sc);
error = ixv_negotiate_api(sc);
if (error) {
/*
@@ -725,9 +726,6 @@ ixv_if_init(if_ctx_t ctx)
/* Set moderation on the Link interrupt */
IXGBE_WRITE_REG(hw, IXGBE_VTEITR(sc->vector), IXGBE_LINK_ITR);
- /* Stats init */
- ixv_init_stats(sc);
-
/* Config/Enable Link */
error = hw->mac.ops.get_link_state(hw, &sc->link_enabled);
if (error) {
@@ -1294,7 +1292,7 @@ ixv_if_update_admin_status(if_ctx_t ctx)
struct ixgbe_softc *sc = iflib_get_softc(ctx);
device_t dev = iflib_get_dev(ctx);
if_t ifp = iflib_get_ifp(ctx);
- bool check_link;
+ bool check_link, reset_seen;
s32 status;
uint64_t baudrate;
@@ -1311,13 +1309,13 @@ ixv_if_update_admin_status(if_ctx_t ctx)
if (sc->hw.mac.type != ixgbe_mac_E610_vf ||
sc->hw.api_version != ixgbe_mbox_api_16)
check_link = true;
+ reset_seen = ixgbe_check_for_rst(&sc->hw, 0) == IXGBE_SUCCESS;
+ if (reset_seen)
+ sc->hw.mac.get_link_status = true;
if (check_link) {
sc->hw.mac.get_link_status = true;
status = ixgbe_check_link(&sc->hw, &sc->link_speed,
&sc->link_up, false);
- } else if (ixgbe_check_for_rst(&sc->hw, 0) == IXGBE_SUCCESS) {
- /* Process an unsolicited PF reset without issuing another query. */
- status = IXGBE_ERR_MBX;
} else
status = IXGBE_SUCCESS;
if (sc->hw.mac.type == ixgbe_mac_E610_vf &&
@@ -1335,6 +1333,9 @@ ixv_if_update_admin_status(if_ctx_t ctx)
status = IXGBE_SUCCESS;
} else if (status == IXGBE_SUCCESS)
sc->vf_link_mbx_failures = 0;
+ /* Reinitialize after an unsolicited reset, even while link is down. */
+ if (reset_seen)
+ status = IXGBE_ERR_MBX;
if (status != IXGBE_SUCCESS && sc->hw.adapter_stopped == false) {
/* Mailbox's Clear To Send status is lost or timeout occurred.
@@ -1370,8 +1371,11 @@ ixv_if_update_admin_status(if_ctx_t ctx)
atomic_readandclear_32(&sc->vf_vlan_retry_tick) != 0)
ixv_vlan_retry_tick(sc);
- /* Stats Update */
- ixv_update_stats(sc);
+ /* Do not treat a PF reset as a hardware-counter wrap. */
+ if (status == IXGBE_SUCCESS)
+ ixv_update_stats(sc);
+ else
+ sc->stats.vf.initialized = false;
} /* ixv_if_update_admin_status */
@@ -1387,7 +1391,7 @@ ixv_if_stop(if_ctx_t ctx)
struct ixgbe_softc *sc = iflib_get_softc(ctx);
struct ixgbe_hw *hw = &sc->hw;
if_t ifp = iflib_get_ifp(ctx);
- bool mailbox_ready;
+ bool mailbox_ready, reset_seen;
INIT_DEBUGOUT("ixv_stop: begin\n");
@@ -1395,8 +1399,18 @@ ixv_if_stop(if_ctx_t ctx)
ixv_if_disable_intr(ctx);
mailbox_ready = atomic_load_acq_32(&sc->vf_mbx_ready) != 0;
- if (mailbox_ready && (if_getflags(ifp) & IFF_UP) == 0)
- hw->mac.ops.reset_hw(hw);
+ reset_seen = mailbox_ready &&
+ ixgbe_check_for_rst(hw, 0) == IXGBE_SUCCESS;
+ if (reset_seen)
+ sc->stats.vf.initialized = false;
+ else if (mailbox_ready && sc->stats.vf.initialized)
+ ixv_update_stats(sc);
+ if (mailbox_ready && (if_getflags(ifp) & IFF_UP) == 0) {
+ if (hw->mac.ops.reset_hw(hw) == IXGBE_SUCCESS)
+ ixv_init_stats(sc);
+ else
+ sc->stats.vf.initialized = false;
+ }
atomic_store_rel_32(&sc->vf_mbx_ready, 0);
sc->vf_link_mbx_failures = 0;
sc->hw.adapter_stopped = false;
@@ -2290,34 +2304,11 @@ ixv_configure_ivars(struct ixgbe_softc *sc)
ixv_set_ivar(sc, 1, sc->vector, -1);
} /* ixv_configure_ivars */
-/************************************************************************
- * ixv_save_stats
- *
- * The VF stats registers never have a truly virgin
- * starting point, so this routine tries to make an
- * artificial one, marking ground zero on attach as
- * it were.
- ************************************************************************/
-static void
-ixv_save_stats(struct ixgbe_softc *sc)
-{
- if (sc->stats.vf.vfgprc || sc->stats.vf.vfgptc) {
- sc->stats.vf.saved_reset_vfgprc +=
- sc->stats.vf.vfgprc - sc->stats.vf.base_vfgprc;
- sc->stats.vf.saved_reset_vfgptc +=
- sc->stats.vf.vfgptc - sc->stats.vf.base_vfgptc;
- sc->stats.vf.saved_reset_vfgorc +=
- sc->stats.vf.vfgorc - sc->stats.vf.base_vfgorc;
- sc->stats.vf.saved_reset_vfgotc +=
- sc->stats.vf.vfgotc - sc->stats.vf.base_vfgotc;
- sc->stats.vf.saved_reset_vfmprc +=
- sc->stats.vf.vfmprc - sc->stats.vf.base_vfmprc;
- }
-} /* ixv_save_stats */
-
/************************************************************************
* ixv_init_stats
************************************************************************/
+#define IXV_STAT_36_MASK 0xFFFFFFFFFULL
+
static void
ixv_init_stats(struct ixgbe_softc *sc)
{
@@ -2327,42 +2318,31 @@ ixv_init_stats(struct ixgbe_softc *sc)
sc->stats.vf.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB);
sc->stats.vf.last_vfgorc |=
(((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32);
+ sc->stats.vf.last_vfgorc &= IXV_STAT_36_MASK;
sc->stats.vf.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC);
sc->stats.vf.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB);
sc->stats.vf.last_vfgotc |=
(((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32);
+ sc->stats.vf.last_vfgotc &= IXV_STAT_36_MASK;
sc->stats.vf.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC);
-
- sc->stats.vf.base_vfgprc = sc->stats.vf.last_vfgprc;
- sc->stats.vf.base_vfgorc = sc->stats.vf.last_vfgorc;
- sc->stats.vf.base_vfgptc = sc->stats.vf.last_vfgptc;
- sc->stats.vf.base_vfgotc = sc->stats.vf.last_vfgotc;
- sc->stats.vf.base_vfmprc = sc->stats.vf.last_vfmprc;
+ sc->stats.vf.initialized = true;
} /* ixv_init_stats */
-#define UPDATE_STAT_32(reg, last, count) \
-{ \
- u32 current = IXGBE_READ_REG(hw, reg); \
- if (current < last) \
- count += 0x100000000LL; \
- last = current; \
- count &= 0xFFFFFFFF00000000LL; \
- count |= current; \
-}
+#define UPDATE_STAT_32(reg, last, count) do { \
+ u32 current = IXGBE_READ_REG(hw, reg); \
+ count += (u32)(current - (u32)last); \
+ last = current; \
+} while (0)
-#define UPDATE_STAT_36(lsb, msb, last, count) \
-{ \
- u64 cur_lsb = IXGBE_READ_REG(hw, lsb); \
- u64 cur_msb = IXGBE_READ_REG(hw, msb); \
- u64 current = ((cur_msb << 32) | cur_lsb); \
- if (current < last) \
- count += 0x1000000000LL; \
- last = current; \
- count &= 0xFFFFFFF000000000LL; \
- count |= current; \
-}
+#define UPDATE_STAT_36(lsb, msb, last, count) do { \
+ u64 current = IXGBE_READ_REG(hw, lsb); \
+ current |= (u64)IXGBE_READ_REG(hw, msb) << 32; \
+ current &= IXV_STAT_36_MASK; \
+ count += (current - last) & IXV_STAT_36_MASK; \
+ last = current; \
+} while (0)
/************************************************************************
* ixv_update_stats - Update the board statistics counters.
@@ -2373,6 +2353,9 @@ ixv_update_stats(struct ixgbe_softc *sc)
struct ixgbe_hw *hw = &sc->hw;
struct ixgbevf_hw_stats *stats = &sc->stats.vf;
+ if (!stats->initialized)
+ return;
+
UPDATE_STAT_32(IXGBE_VFGPRC, sc->stats.vf.last_vfgprc,
sc->stats.vf.vfgprc);
UPDATE_STAT_32(IXGBE_VFGPTC, sc->stats.vf.last_vfgptc,
diff --git a/sys/dev/ixgbe/ixgbe_vf.h b/sys/dev/ixgbe/ixgbe_vf.h
index 7f5a8c2e85cf..b55bb745aa95 100644
--- a/sys/dev/ixgbe/ixgbe_vf.h
+++ b/sys/dev/ixgbe/ixgbe_vf.h
@@ -90,12 +90,6 @@
struct ixgbevf_hw_stats {
- u64 base_vfgprc;
- u64 base_vfgptc;
- u64 base_vfgorc;
- u64 base_vfgotc;
- u64 base_vfmprc;
-
u64 last_vfgprc;
u64 last_vfgptc;
u64 last_vfgorc;
@@ -107,12 +101,7 @@ struct ixgbevf_hw_stats {
u64 vfgorc;
u64 vfgotc;
u64 vfmprc;
-
- u64 saved_reset_vfgprc;
- u64 saved_reset_vfgptc;
- u64 saved_reset_vfgorc;
- u64 saved_reset_vfgotc;
- u64 saved_reset_vfmprc;
+ bool initialized;
};
s32 ixgbe_init_ops_vf(struct ixgbe_hw *hw);