git: 52fbff965499 - main - e1000: Configure PCH low-power link modes for suspend
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 31 Aug 2026 13:18:49 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=52fbff96549904933898908644f3a99e5cd4cdca
commit 52fbff96549904933898908644f3a99e5cd4cdca
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-30 08:25:09 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-31 13:18:43 +0000
e1000: Configure PCH low-power link modes for suspend
The PCH suspend path kept a wake link fully powered and did not restore
the negotiated EEE modes after its stop-time reset. Intel provides the
ULP entry and exit machinery in the shared code, but FreeBSD did not
invoke its Sx policy.
Enter ULP on LPT and newer PCH controllers when wake is armed without
directed-unicast, multicast, or broadcast filters, which ULP cannot
preserve. For a link retained by host wake or management, restore the
100BASE-TX and 1000BASE-T LPI controls selected by the local
advertisement and the cached link-partner ability.
Keep these power reductions best-effort: wake filters and PME are
already configured independently, and a ULP or EEE failure is logged
without converting an optional power optimization into a suspend
failure. The existing PCH resume workaround forcibly exits ULP and
clears automatic Sx LPI state before normal initialization.
Validated on a ThinkPad T440p with an I217-LM. FBT confirmed that the
helper received the magic-wake mask during device suspend. The shared
ULP helper returned its documented no-op for the initial I217 device ID.
A full S3 cycle resumed cleanly.
On a ThinkPad P51 with an I219, full S3 waited for a magic packet and
then resumed with the 1-Gbps link and traffic restored.
MFC after: 2 weeks
Sponsored by: BBOX.io
---
share/man/man4/em.4 | 5 ++++-
sys/dev/e1000/if_em.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/share/man/man4/em.4 b/share/man/man4/em.4
index 512f0dc11dc9..c652dbbb285e 100644
--- a/share/man/man4/em.4
+++ b/share/man/man4/em.4
@@ -32,7 +32,7 @@
.\"
.\" * Other names and brands may be claimed as the property of others.
.\"
-.Dd August 29, 2026
+.Dd August 30, 2026
.Dt EM 4
.Os
.Sh NAME
@@ -116,6 +116,9 @@ The
.Xr ifconfig 8
wake capabilities select the controller packet filters; they do not enable
the ACPI wake source.
+On supported PCH controllers, suspend uses the PHY ultra-low-power mode when
+the selected wake filters permit it and preserves negotiated Energy Efficient
+Ethernet operation while the wake link remains active.
.Pp
Furthermore it supports TCP segmentation offload (TSO) on all adapters but
those based on the 82542, 82543, 82544 and 82547 controller chips.
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 19717d9e5371..e27b804a3cb4 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -509,6 +509,7 @@ static void em_release_hw_control(struct e1000_softc *);
static void em_get_wakeup(if_ctx_t);
static void em_fill_wakeup_mta(struct e1000_hw *);
static int em_enable_wakeup(if_ctx_t);
+static void em_configure_sx_low_power(struct e1000_softc *, u32);
static int em_enable_phy_wakeup(struct e1000_softc *, u32);
static int em_disable_phy_wakeup(struct e1000_softc *, u16 *);
static void em_power_up_wakeup_link(struct e1000_softc *);
@@ -6825,6 +6826,7 @@ em_enable_wakeup(if_ctx_t ctx)
if (manage) {
if (sc->suspend_link_powered_down)
em_power_up_wakeup_link(sc);
+ em_configure_sx_low_power(sc, 0);
pci_enable_pme(dev);
} else {
em_power_down_wakeup_link(sc);
@@ -6888,6 +6890,7 @@ em_enable_wakeup(if_ctx_t ctx)
if (sc->hw.mac.type < igb_mac_min &&
sc->hw.phy.type == e1000_phy_igp_3)
e1000_igp3_phy_powerdown_workaround_ich8lan(&sc->hw);
+ em_configure_sx_low_power(sc, wufc);
pme:
if (!error)
@@ -6913,6 +6916,63 @@ master_disable:
return (error == E1000_SUCCESS ? 0 : EIO);
}
+/* Configure the PCH low-power link modes used while the system sleeps. */
+static void
+em_configure_sx_low_power(struct e1000_softc *sc, u32 wufc)
+{
+ struct e1000_hw *hw = &sc->hw;
+ struct e1000_dev_spec_ich8lan *dev_spec;
+ s32 error;
+ u16 eee_advert, lpi_ctrl;
+
+ if (hw->mac.type < e1000_pch_lpt || hw->mac.type >= igb_mac_min ||
+ sc->suspend_link_powered_down)
+ return;
+
+ if (wufc != 0 &&
+ (wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC)) == 0) {
+ /* ULP cannot preserve directed or broad multicast wake. */
+ error = e1000_enable_ulp_lpt_lp(hw, true);
+ if (error != E1000_SUCCESS) {
+ device_printf(sc->dev,
+ "Could not enter PHY ultra-low-power mode: %d\n",
+ error);
+ return;
+ }
+ }
+
+ dev_spec = &hw->dev_spec.ich8lan;
+ if (hw->phy.type != e1000_phy_i217 || dev_spec->eee_disable ||
+ dev_spec->eee_lp_ability == 0)
+ return;
+
+ error = hw->phy.ops.acquire(hw);
+ if (error != E1000_SUCCESS)
+ goto out;
+ error = hw->phy.ops.read_reg_locked(hw, I82579_LPI_CTRL, &lpi_ctrl);
+ if (error != E1000_SUCCESS)
+ goto release;
+ error = e1000_read_emi_reg_locked(hw, I217_EEE_ADVERTISEMENT,
+ &eee_advert);
+ if (error != E1000_SUCCESS)
+ goto release;
+
+ if ((eee_advert & dev_spec->eee_lp_ability &
+ I82579_EEE_100_SUPPORTED) != 0)
+ lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
+ if ((eee_advert & dev_spec->eee_lp_ability &
+ I82579_EEE_1000_SUPPORTED) != 0)
+ lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
+ error = hw->phy.ops.write_reg_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
+release:
+ hw->phy.ops.release(hw);
+out:
+ if (error != E1000_SUCCESS)
+ device_printf(sc->dev,
+ "Could not configure Energy Efficient Ethernet for sleep: %d\n",
+ error);
+}
+
static void
em_power_up_wakeup_link(struct e1000_softc *sc)
{