Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 Jul 2026 05:09:05 +0000
From:      Kevin Bowling <kbowling@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 5ce6c94f9859 - main - igb: Update only changed IOV VLAN filters
Message-ID:  <6a6adc71.320ea.35d6e2a5@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=5ce6c94f98599e5ae0595ff5178a224145b6225f

commit 5ce6c94f98599e5ae0595ff5178a224145b6225f
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-07-29 09:09:24 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-07-30 05:08:24 +0000

    igb: Update only changed IOV VLAN filters
    
    Keep the full VFTA/VLVF software recomputation and clear-map-set
    ordering, but compare each phase against the authoritative old value.
    Write only VFTA words and VLVF slots whose effective contents change.
    
    I350 uses its software VFTA shadow because erratum 20 makes live reads
    unreliable; an invalid shadow forces a complete clear before sparse
    restoration. 82576 continues to diff against live VFTA reads.
    
    Add SDT probes for every logical write phase and the final software
    images so hardware tests can verify exact elision counts. On my I350
    DUT, the old full table path averaged 819 us across 31 VLAN removals
    versus about 79 us for the PF statistics sweep.
    
    Sponsored by:   BBOX.io
---
 sys/dev/e1000/if_igb_iov.c | 98 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 83 insertions(+), 15 deletions(-)

diff --git a/sys/dev/e1000/if_igb_iov.c b/sys/dev/e1000/if_igb_iov.c
index 8b8dfcd0a8f6..9b2c77a92eb7 100644
--- a/sys/dev/e1000/if_igb_iov.c
+++ b/sys/dev/e1000/if_igb_iov.c
@@ -11,6 +11,7 @@
 #ifdef PCI_IOV
 
 #include <sys/iov.h>
+#include <sys/sdt.h>
 #include <sys/time.h>
 
 #define	IGB_IOV_RAH_POOLSEL_SHIFT	18
@@ -78,6 +79,23 @@ struct igb_vf_mac_filter {
 
 MALLOC_DEFINE(M_IGB_IOV, "igb_iov", "igb SR-IOV allocations");
 
+/*
+ * These logical-write probes let hardware tests verify the elision policy.
+ * e1000_write_vfta_i350() expands one VFTA call into ten physical writes, so
+ * the probes intentionally count calls made by the rebuild rather than MMIO
+ * transactions.  The state probe exposes the final software images while the
+ * stack arrays are still live.
+ */
+SDT_PROVIDER_DEFINE(igb_iov);
+SDT_PROBE_DEFINE3(igb_iov, vlan, rebuild, vfta_clear,
+    "struct e1000_softc *", "u_int", "uint32_t");
+SDT_PROBE_DEFINE3(igb_iov, vlan, rebuild, vlvf_write,
+    "struct e1000_softc *", "u_int", "uint32_t");
+SDT_PROBE_DEFINE3(igb_iov, vlan, rebuild, vfta_set,
+    "struct e1000_softc *", "u_int", "uint32_t");
+SDT_PROBE_DEFINE3(igb_iov, vlan, rebuild, state,
+    "struct e1000_softc *", "uint32_t *", "uint32_t *");
+
 static const struct timeval igb_iov_nack_interval = { 2, 0 };
 static const struct timeval igb_iov_mbx_log_interval = { 2, 0 };
 static const struct timeval igb_iov_spoof_log_interval = { 2, 0 };
@@ -470,6 +488,29 @@ igb_iov_intr_mask(const struct e1000_softc *sc)
 	return (E1000_IMS_VMMB | E1000_IMS_MDDET);
 }
 
+static void
+igb_iov_vfta_shadow_invalidate(struct e1000_softc *sc)
+{
+
+	/*
+	 * I350 erratum 20 makes VFTA reads unreliable while VMDq loopback or
+	 * anti-spoofing is active.  The shadow is therefore authoritative
+	 * until a reset or another independent hardware writer invalidates
+	 * it.  Readback cannot reliably audit a stale-but-valid shadow on
+	 * this part, so keep all shadow mutation in these two helpers.
+	 */
+	memset(sc->iov_vfta, 0, sizeof(sc->iov_vfta));
+	sc->iov_vfta_valid = false;
+}
+
+static void
+igb_iov_vfta_shadow_store(struct e1000_softc *sc, const u32 *vfta)
+{
+
+	memcpy(sc->iov_vfta, vfta, sizeof(sc->iov_vfta));
+	sc->iov_vfta_valid = true;
+}
+
 static void
 igb_iov_notify_vfs_reset(struct e1000_softc *sc)
 {
@@ -558,7 +599,7 @@ igb_iov_reset_prepare(struct e1000_softc *sc)
 	if (sc->iov_mbx_retry_initialized)
 		callout_stop(&sc->iov_mbx_retry);
 	sc->iov_mta_valid = false;
-	sc->iov_vfta_valid = false;
+	igb_iov_vfta_shadow_invalidate(sc);
 	atomic_readandclear_32(&sc->iov_mdd_cause);
 	atomic_readandclear_32(&sc->iov_pending);
 	atomic_readandclear_32(&sc->iov_spoof_pending);
@@ -657,9 +698,11 @@ igb_iov_rebuild_vlan(struct e1000_softc *sc)
 	struct e1000_hw *hw;
 	struct igb_vf *vf;
 	u32 old_vlvf[E1000_VLVF_ARRAY_SIZE];
-	u32 vfta[EM_VFTA_SIZE], vlvf[E1000_VLVF_ARRAY_SIZE];
+	u32 effective_vfta[EM_VFTA_SIZE], vfta[EM_VFTA_SIZE];
+	u32 vlvf[E1000_VLVF_ARRAY_SIZE];
 	u32 old_vfta, rctl, vmolr;
-	bool pf_overflow, pf_vlan_promisc, preserve_pf;
+	bool force_vfta, pf_overflow, pf_vlan_promisc, preserve_pf;
+	bool vfta_changed, vlvf_changed;
 	int i, vid;
 
 	if (!igb_iov_enabled(sc))
@@ -769,28 +812,54 @@ igb_iov_rebuild_vlan(struct e1000_softc *sc)
 	 * transition to a PF-only VLAN deliberately retains VFTA membership
 	 * and falls through to the default PF pool.
 	 */
+	force_vfta = hw->mac.type == e1000_i350 &&
+	    !sc->iov_vfta_valid;
+	vfta_changed = false;
 	for (i = 0; i < EM_VFTA_SIZE; i++) {
 		/*
 		 * I350 erratum 20 makes VFTA reads unreliable while VMDq
 		 * loopback or anti-spoofing is active.  Its ten-write
-		 * workaround is already in e1000_write_vfta_i350(); keep a
-		 * software shadow for the read side of this transition.
+		 * workaround is already in e1000_write_vfta_i350().  Force a
+		 * complete clear when the authoritative shadow is invalid;
+		 * 82576 can safely diff against its live register contents.
 		 */
 		if (hw->mac.type == e1000_i350)
-			old_vfta = sc->iov_vfta_valid ? sc->iov_vfta[i] : 0;
+			old_vfta = force_vfta ? 0 : sc->iov_vfta[i];
 		else
 			old_vfta =
 			    E1000_READ_REG_ARRAY(hw, E1000_VFTA, i);
-		e1000_write_vfta(hw, i, old_vfta & vfta[i]);
+		effective_vfta[i] = old_vfta & vfta[i];
+		if (force_vfta || effective_vfta[i] != old_vfta) {
+			SDT_PROBE3(igb_iov, vlan, rebuild, vfta_clear,
+			    sc, i, effective_vfta[i]);
+			e1000_write_vfta(hw, i, effective_vfta[i]);
+			vfta_changed = true;
+		}
 	}
-	E1000_WRITE_FLUSH(hw);
+	if (vfta_changed)
+		E1000_WRITE_FLUSH(hw);
+	vlvf_changed = false;
 	for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++)
-		E1000_WRITE_REG(hw, E1000_VLVF(i), vlvf[i]);
-	E1000_WRITE_FLUSH(hw);
+		if (vlvf[i] != old_vlvf[i]) {
+			SDT_PROBE3(igb_iov, vlan, rebuild, vlvf_write,
+			    sc, i, vlvf[i]);
+			E1000_WRITE_REG(hw, E1000_VLVF(i), vlvf[i]);
+			vlvf_changed = true;
+		}
+	if (vlvf_changed)
+		E1000_WRITE_FLUSH(hw);
+	vfta_changed = false;
 	for (i = 0; i < EM_VFTA_SIZE; i++)
-		e1000_write_vfta(hw, i, vfta[i]);
-	memcpy(sc->iov_vfta, vfta, sizeof(sc->iov_vfta));
-	sc->iov_vfta_valid = true;
+		if (vfta[i] != effective_vfta[i]) {
+			SDT_PROBE3(igb_iov, vlan, rebuild, vfta_set,
+			    sc, i, vfta[i]);
+			e1000_write_vfta(hw, i, vfta[i]);
+			vfta_changed = true;
+		}
+	if (vfta_changed)
+		E1000_WRITE_FLUSH(hw);
+	SDT_PROBE3(igb_iov, vlan, rebuild, state, sc, vfta, vlvf);
+	igb_iov_vfta_shadow_store(sc, vfta);
 }
 
 static bool
@@ -1740,8 +1809,7 @@ igb_if_iov_uninit(if_ctx_t ctx)
 	sc->iov_mta_valid = false;
 	sc->iov_pf_mdd_blocked = false;
 	sc->iov_pf_vlan_promisc = false;
-	sc->iov_vfta_valid = false;
-	memset(sc->iov_vfta, 0, sizeof(sc->iov_vfta));
+	igb_iov_vfta_shadow_invalidate(sc);
 	sc->tx_queues[0].txr.me = 0;
 	sc->rx_queues[0].rxr.me = 0;
 	atomic_readandclear_32(&sc->iov_mdd_cause);


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a6adc71.320ea.35d6e2a5>