git: 1c91c3ae1ec6 - main - igb: recover retained i350 admin interrupts

Kevin Bowling <[email protected]> Mon, 03 Aug 2026 10:20:22 +0000
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a706b66.4391f.21a7b9f9__18556.9571492792$1785752436$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=1c91c3ae1ec6c65e458f130a95d3119d83ca088e

commit 1c91c3ae1ec6c65e458f130a95d3119d83ca088e
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-08-03 08:05:49 +0000
Commit:     Kevin Bowling <[email protected]>
CommitDate: 2026-08-03 10:19:45 +0000

    igb: recover retained i350 admin interrupts
    
    I350 can retain EICR.OTHER with MDDET and LVMMC asserted while the
    admin vector and legacy cause remain enabled. The anti-spoof filter
    continues dropping packets, but no MSI-X is delivered and the spoof
    diagnostic is lost.
    
    Preserve the one-shot setup drain across iflib reset preparation,
    clear ICR before LVMMC during i350 setup, and kick the enabled admin
    vector from each admin pass. The synthetic no-cause interrupt stays
    in the filter and also releases a retained MDDET cause.
    
    Keep 82576 drain ordering and stop-time cleanup unchanged.
---
 sys/dev/e1000/if_igb_iov.c | 34 +++++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/sys/dev/e1000/if_igb_iov.c b/sys/dev/e1000/if_igb_iov.c
index 7a7348ede657..7b6c18690db5 100644
--- a/sys/dev/e1000/if_igb_iov.c
+++ b/sys/dev/e1000/if_igb_iov.c
@@ -677,7 +677,15 @@ igb_iov_reset_prepare(struct e1000_softc *sc)
 	atomic_readandclear_32(&sc->iov_pending);
 	atomic_readandclear_32(&sc->iov_spoof_pending);
 	atomic_readandclear_32(&sc->iov_blocked_pending);
-	atomic_readandclear_32(&sc->iov_intr_drain_pending);
+	/*
+	 * Normal iflib initialization prepares the reset before
+	 * igb_iov_initialize() requests this drain.  Preserve a still-pending
+	 * I350 request across a later stop or repeated preparation so the next
+	 * interrupt arm consumes it.  Other families retain the ordinary
+	 * stop-time cleanup.
+	 */
+	if (sc->hw.mac.type != e1000_i350)
+		atomic_readandclear_32(&sc->iov_intr_drain_pending);
 }
 
 void
@@ -1735,6 +1743,17 @@ igb_iov_handle_mdd(struct e1000_softc *sc)
 		if ((cleared & (1U << sc->pool)) != 0)
 			sc->iov_pf_mdd_blocked = false;
 	}
+	if (sc->hw.mac.type == e1000_i350) {
+		/*
+		 * I350 can retain EICR.OTHER without delivering the admin MSI-X
+		 * even though its EIMS and legacy IMS bits remain enabled.  Kick
+		 * the already-enabled vector on each admin pass so its filter
+		 * consumes any retained ICR/LVMMC cause.  A synthetic interrupt
+		 * with no legacy cause is handled entirely by the filter.
+		 */
+		E1000_WRITE_REG(&sc->hw, E1000_EICS, sc->link_mask);
+		E1000_WRITE_FLUSH(&sc->hw);
+	}
 }
 
 void
@@ -1928,11 +1947,20 @@ igb_iov_initialize(struct e1000_softc *sc)
 	 * active state.  Mailbox requests are also serviced by the periodic
 	 * admin pass, and ping_all_vfs() below supplies a fresh notification.
 	 */
+	/*
+	 * Clear the setup-time interrupt latch before its diagnostic state.
+	 * I350 does not reliably generate the next MDDET edge when LVMMC is
+	 * consumed while ICR.MDDET remains latched.  This differs deliberately
+	 * from the final arm-time drain, where ICR is read last so a later event
+	 * remains pending for the unmask.
+	 */
+	if (hw->mac.type == e1000_i350)
+		(void)E1000_READ_REG(hw, E1000_ICR);
 	(void)E1000_READ_REG(hw, E1000_LVMMC);
 	if (hw->mac.type == e1000_82576)
 		(void)E1000_READ_REG(hw, E1000_WVBR);
-	/* Read ICR last so a later event remains pending for the arm below. */
-	(void)E1000_READ_REG(hw, E1000_ICR);
+	if (hw->mac.type != e1000_i350)
+		(void)E1000_READ_REG(hw, E1000_ICR);
 	atomic_readandclear_32(&sc->iov_mdd_cause);
 	atomic_readandclear_32(&sc->iov_pending);
 	atomic_readandclear_32(&sc->iov_spoof_pending);