aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Bowling <kbowling@FreeBSD.org>2026-08-16 07:02:25 +0000
committerKevin Bowling <kbowling@FreeBSD.org>2026-08-16 10:23:51 +0000
commit81d5356799a1db1701cb3f91146131c34dede413 (patch)
tree50a0a9336ba1dc6a2334900f90893e31c29761e4
parentc82a015ede8d49aabc8bb253b7597b8db0f42524 (diff)
e1000: Recover from the 82574 PHY hang
The shared code provides e1000_check_phy_82574() to recognize a PHY hang from saturated receive error and idle error counters, but em(4) never calls it. Run the check from timer driven admin work. Match Intel e1000e by requiring two consecutive positive samples before requesting a full iflib reset. MFC after: 2 weeks Sponsored by: BBOX.io
-rw-r--r--sys/dev/e1000/if_em.c25
-rw-r--r--sys/dev/e1000/if_em.h1
2 files changed, 25 insertions, 1 deletions
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 6574b2d0e7d7..f07f75100650 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -3447,8 +3447,30 @@ em_if_update_admin_status(if_ctx_t ctx)
* message. Exported counters can consequently trail hardware by the
* timer interval (normally 500 ms).
*/
- if (atomic_readandclear_32(&sc->stats_pending) != 0)
+ if (atomic_readandclear_32(&sc->stats_pending) != 0) {
em_update_stats_counters(sc);
+ /*
+ * The 82574 PHY can enter a state in which both its receive
+ * error and idle error counters saturate. Require two
+ * consecutive timer samples before resetting, matching Intel's
+ * e1000e recovery policy and avoiding a reset on a transient
+ * register sample.
+ */
+ if (hw->mac.type == e1000_82574) {
+ if (e1000_check_phy_82574(hw))
+ sc->phy_hang_count++;
+ else
+ sc->phy_hang_count = 0;
+ if (sc->phy_hang_count > 1) {
+ sc->phy_hang_count = 0;
+ device_printf(dev,
+ "PHY appears hung; requesting reset\n");
+ iflib_request_reset(ctx);
+ iflib_admin_intr_deferred(ctx);
+ return;
+ }
+ }
+ }
/* Reset LAA into RAR[0] on 82571 */
if (hw->mac.type == e1000_82571 && e1000_get_laa_state_82571(hw))
@@ -4511,6 +4533,7 @@ em_reset(if_ctx_t ctx)
E1000_WRITE_REG(hw, E1000_VET, ETHERTYPE_VLAN);
e1000_get_phy_info(hw);
e1000_check_for_link(hw);
+ sc->phy_hang_count = 0;
return (E1000_SUCCESS);
}
diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h
index 9c441edd320b..e5b0fec8b087 100644
--- a/sys/dev/e1000/if_em.h
+++ b/sys/dev/e1000/if_em.h
@@ -622,6 +622,7 @@ struct e1000_softc {
u32 pba;
int link_mask;
int tso_automasked;
+ u32 phy_hang_count;
u32 promisc_pending;
u32 stats_pending;
u32 fatal_error_state;