git: 4a28d390f5fb - main - igc: Disable PCIe L1.2 on I225
Kevin Bowling <[email protected]> Mon, 03 Aug 2026 10:00:08 +0000
| Newsgroups | gmane.os.freebsd.devel.cvs.src |
|---|---|
| Message-ID | <6a7066a8.409e7.3c078c31__20210.6421392941$1785751234$gmane$org@gitrepo.freebsd.org> |
The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=4a28d390f5fbae2483e88805559881b04ccf9a80 commit 4a28d390f5fbae2483e88805559881b04ccf9a80 Author: Kevin Bowling <[email protected]> AuthorDate: 2026-08-03 09:55:15 +0000 Commit: Kevin Bowling <[email protected]> CommitDate: 2026-08-03 10:00:00 +0000 igc: Disable PCIe L1.2 on I225 I225 devices can incorrectly enter L1 substates while CLKREQ# is asserted, both while idle and in D3. Disable ASPM and PCI-PM L1.2 on I225 to prevent the resulting packet loss. Keep the I226 workaround ASPM-only because it addresses a separate traffic exit latency observation. PR: 265714 MFC after: 4 days --- sys/dev/igc/if_igc.c | 42 ++++++++++++++++++++++-------------------- sys/dev/igc/igc_base.c | 29 +++++++++++++++++++++++++++++ sys/dev/igc/igc_base.h | 1 + 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/sys/dev/igc/if_igc.c b/sys/dev/igc/if_igc.c index f8de961afeca..4a54d8ca7a6c 100644 --- a/sys/dev/igc/if_igc.c +++ b/sys/dev/igc/if_igc.c @@ -114,7 +114,7 @@ static bool igc_if_needs_restart(if_ctx_t, enum iflib_restart_event); static void igc_identify_hardware(if_ctx_t); static int igc_allocate_pci_resources(if_ctx_t); static void igc_free_pci_resources(if_ctx_t); -static void igc_disable_broken_aspm_l1_2(if_ctx_t); +static void igc_disable_broken_l1_2(if_ctx_t); static void igc_reset(if_ctx_t); static int igc_setup_interface(if_ctx_t); static int igc_setup_msix(if_ctx_t); @@ -555,13 +555,8 @@ igc_if_attach_pre(if_ctx_t ctx) /* Determine hardware and mac info */ igc_identify_hardware(ctx); - /* - * I226 parts have an erratum where the PCIe ASPM L1.2 exit - * latency can exceed what the packet buffer can absorb under - * load, stalling the inbound packet stream. Disable ASPM L1.2 - * on the device to work around it. - */ - igc_disable_broken_aspm_l1_2(ctx); + /* Apply device-specific PCIe L1.2 errata workarounds. */ + igc_disable_broken_l1_2(ctx); scctx->isc_tx_nsegments = IGC_MAX_SCATTER; scctx->isc_nrxqsets_max = @@ -806,10 +801,10 @@ static int igc_if_resume(if_ctx_t ctx) { /* - * PCIe config space, and with it ASPM L1.2, may have been reset + * PCIe config space, and with it L1.2, may have been reset * across the suspend/resume cycle. */ - igc_disable_broken_aspm_l1_2(ctx); + igc_disable_broken_l1_2(ctx); igc_if_init(ctx); @@ -1514,30 +1509,37 @@ igc_identify_hardware(if_ctx_t ctx) /********************************************************************* * - * I226 devices advertise support for the PCIe L1.2 link substate, but - * due to a hardware erratum the exit latency from that low-power state - * can exceed what the packet buffer can tolerate under load, which - * stalls the inbound packet stream. Disabling ASPM L1.2 on the device - * itself (as opposed to disabling ASPM/power management in the BIOS or - * at the OS level) works around the issue. + * Intel's I225/I226 Specification Update, erratum 2, states that I225 + * devices can incorrectly enter L1 substates while CLKREQ# is asserted, + * causing repeated L1-substate entry and exit. Disable both ASPM and + * PCI-PM L1.2, as the erratum can occur while idle or in D3. + * + * I226 devices have a separate erratum where ASPM L1.2 exit latency can + * exceed what the packet buffer can tolerate under load. Disabling ASPM + * L1.2 on the device itself works around the issue. * **********************************************************************/ static void -igc_disable_broken_aspm_l1_2(if_ctx_t ctx) +igc_disable_broken_l1_2(if_ctx_t ctx) { device_t dev = iflib_get_dev(ctx); struct igc_softc *sc = iflib_get_softc(ctx); int cap; - uint32_t ctl1; + uint32_t ctl1, mask; - if (!igc_is_device_id_i226(&sc->hw)) + if (igc_is_device_id_i225(&sc->hw)) + mask = PCIM_L1PM_CTL1_ASPM_L1_2 | + PCIM_L1PM_CTL1_PCIPM_L1_2; + else if (igc_is_device_id_i226(&sc->hw)) + mask = PCIM_L1PM_CTL1_ASPM_L1_2; + else return; if (pci_find_extcap(dev, PCIZ_L1PM, &cap) != 0) return; ctl1 = pci_read_config(dev, cap + PCIR_L1PM_CTL1, 4); - ctl1 &= ~PCIM_L1PM_CTL1_ASPM_L1_2; + ctl1 &= ~mask; pci_write_config(dev, cap + PCIR_L1PM_CTL1, ctl1, 4); } diff --git a/sys/dev/igc/igc_base.c b/sys/dev/igc/igc_base.c index e3ab9733009f..510f4c132b9a 100644 --- a/sys/dev/igc/igc_base.c +++ b/sys/dev/igc/igc_base.c @@ -185,6 +185,35 @@ void igc_rx_fifo_flush_base(struct igc_hw *hw) IGC_READ_REG(hw, IGC_MPC); } +/** + * igc_is_device_id_i225 - Check whether the device is I225 silicon + * @hw: pointer to the HW structure + * + * I225 and I226 share the same mac.type, so this checks the PCI + * device ID directly to distinguish I225 parts, e.g. for erratum + * workarounds that apply only to that silicon. + * + * I225_BLANK_NVM is absent from the equivalent Linux helper. I220 is + * kept separate because Intel's I225 specification update does not + * identify it as affected. + **/ +bool igc_is_device_id_i225(struct igc_hw *hw) +{ + switch (hw->device_id) { + case IGC_DEV_ID_I225_LM: + case IGC_DEV_ID_I225_V: + case IGC_DEV_ID_I225_K: + case IGC_DEV_ID_I225_I: + case IGC_DEV_ID_I225_K2: + case IGC_DEV_ID_I225_LMVP: + case IGC_DEV_ID_I225_IT: + case IGC_DEV_ID_I225_BLANK_NVM: + return true; + default: + return false; + } +} + /** * igc_is_device_id_i226 - Check whether the device is I226 silicon * @hw: pointer to the HW structure diff --git a/sys/dev/igc/igc_base.h b/sys/dev/igc/igc_base.h index 91cb602f809d..26344330ffed 100644 --- a/sys/dev/igc/igc_base.h +++ b/sys/dev/igc/igc_base.h @@ -13,6 +13,7 @@ void igc_power_down_phy_copper_base(struct igc_hw *hw); extern void igc_rx_fifo_flush_base(struct igc_hw *hw); s32 igc_acquire_phy_base(struct igc_hw *hw); void igc_release_phy_base(struct igc_hw *hw); +bool igc_is_device_id_i225(struct igc_hw *hw); bool igc_is_device_id_i226(struct igc_hw *hw); /* Transmit Descriptor - Advanced */