Let the kernel control PCIe ASPM, restoring UEFI deploy throughput - #146
Merged
Conversation
Deploys onto a Dell OptiPlex 3070 (RTL8168h rev 15) run at ~1.2 GB/min under UEFI against 6-10 GB/min on the same machine booted legacy, while captures still run at ~15 GB/min. Forums topic 18212; same chip and symptoms as Debian bug #1110193. CONFIG_PCIEASPM and CONFIG_PCI_MMCONFIG are `default y` upstream and have been off in FOS since b56b8d9 (2016). Nothing noticed for nine years because the out-of-tree Realtek vendor drivers managed ASPM themselves -- r8168 is built here with -DCONFIG_DYNAMIC_ASPM and switches ASPM off whenever traffic is flowing. bc9ee24 dropped those drivers for the in-kernel r8169 and removed the cover. r8169 does not manage ASPM itself; it asks the PCI core once at probe. With CONFIG_PCIEASPM=n, pci_disable_link_state() is an inline stub that RETURNS SUCCESS, so r8169 sets tp->aspm_manageable = true, concludes the OS disabled L1, and then enables ASPM, ClkReq and -- for exactly this chip's RTL_GIGA_MAC_VER_46 -- L1.2 triggering in the NIC. Nothing is logged. The link drops into L1.2 between the server's bursts and pays the exit latency on every wake, which is why only the receive direction is affected. CONFIG_PCI_MMCONFIG compounds it: without it pci_ext_cfg_avail() returns 0, cfg_size is capped at 256 bytes, and the L1 PM Substates extended capability where L1.1/L1.2 actually live is unreachable. That is also what r8169's "No native access to PCI extended config space, falling back to CSI" notice is reporting. Neither symbol is sufficient alone. This could not be left to a kernel argument: with CONFIG_PCIEASPM=n the __setup() registering `pcie_aspm=off` is compiled out, so the usual field workaround is a silent no-op on a FOS kernel. Policy is DEFAULT rather than PERFORMANCE, so each driver keeps making its own chip-specific call (r8169 honours rtl_aspm_is_safe() for vendor-certified boards) instead of blanket-overriding firmware on every link. The power-saving policies are rejected by the new harness -- they would enable ASPM on links whose firmware left it off, and would have made this bug appear on legacy boots too. Verified that both symbols survive `make olddefconfig` on x64 (the ADR-0010 silent-drop trap) and that the isolated post-oldconfig delta is exactly these symbols plus the def_bool CONFIG_MMCONF_FAM10H. Not yet validated on hardware -- ADR-0011 records a read-only setpci procedure that confirms or kills the diagnosis in a minute without a rebuild. Refs: #108
The recorded procedure cleared the whole Link Control register and did the root port before the endpoint. Both are wrong: - A bare CAP_EXP+10.w=0000 also clears Common Clock Configuration, Clock PM and Extended Sync. Clearing CCC on a live link without a retrain is its own problem, so the write is now masked to the ASPM Control bits (0000:0003). - PCIe r6.2 sec 7.5.3.7 requires ASPM L1 to be disabled in the Downstream component before the Upstream one; pcie_config_aspm_link() in drivers/pci/pcie/aspm.c does exactly that. Endpoint now goes first. Diagnostic-only change; no effect on the config fix itself. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d herring Validated on the reporter's OptiPlex 3070 (RTL8168h rev 15): UEFI deploy ~1.2 -> ~6.5 GB/min with EXP_20260805-123232, legacy unchanged. Two things the status now says explicitly: - The setpci Link Control comparison was never run, so the claim that Dell's UEFI firmware enables L1 where its CSM path does not is still an inference. The fix working does not prove the mechanism behind the UEFI/legacy split. - 'tx checksumming: ko' is r8169's probe-time jumbo capability note, keyed on tp->mac_version alone and printed regardless of MTU. It was never a second bug, and kernels with this fix print the same line -- worth naming so nobody reads a later 'ko' as a regression. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
master gained its own ADR-0011 (UKI feasibility) and an 0012 while this branch was out, so the PCIe ASPM ADR collided on 0011. Renumbered to 0013 and updated its references in CLAUDE.md, tests/README.md and the check harness header -- same cleanup GH-143 did for the duplicate 0009. The CLAUDE.md conflict was purely additive on both sides: both branches appended a bullet to the invariants list. Kept both, with PCIe ASPM moved after 0012. Also corrected the throughput figure from the '~10x' estimate to the ~5x actually measured on hardware (1.2 -> 6.5 GB/min). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the ~10x UEFI deploy slowdown reported on forums topic 18212 — Dell OptiPlex 3070, RTL8168h rev 15, kernel 6.18.38 / init 20260804. Deploy ran ~1.2 GB/min under UEFI vs 6–10 GB/min legacy on the same machine, while capture still ran ~15 GB/min. Same chip and symptoms as Debian bug #1110193.
Root cause
CONFIG_PCIEASPM(all arches) andCONFIG_PCI_MMCONFIG(x64 only — x86 always had it) aredefault yupstream and have been off in FOS sinceb56b8d9(2016).That was harmless for nine years because the out-of-tree Realtek vendor drivers managed ASPM themselves —
r8168is built here with-DCONFIG_DYNAMIC_ASPMand disables ASPM whenever traffic is flowing.bc9ee24(the #108 switch to in-kernelr8169) dropped those drivers and removed the cover. The reporter correctly identified that commit; it is the exposer, not the defect.The trap.
r8169does not manage ASPM itself — it asks the PCI core once at probe:With
CONFIG_PCIEASPM=nthat is an inline stub ininclude/linux/pci.hthat returns 0 — success.r8169therefore concludes the OS disabled L1, setsaspm_manageable, and inrtl_hw_start()goes on to enable ASPM, ClkReq, and — for exactly this chip'sRTL_GIGA_MAC_VER_46—/* chip can trigger L1.2 */. The driver switches ASPM on in the NIC believing the kernel has L1 off, on a kernel containing no ASPM code at all. Nothing is logged.CONFIG_PCI_MMCONFIGcompounds it: without itpci_ext_cfg_avail()returns 0, every device'scfg_sizecaps at 256 bytes, and the L1 PM Substates extended capability — where L1.1/L1.2 are actually controlled — is unreachable. That is what r8169'sNo native access to PCI extended config space, falling back to CSInotice is really reporting. Neither symbol is sufficient alone.Why UEFI only, and why download only. ASPM is programmed by platform firmware; Dell's native UEFI path enables L1/L1.2 on the root port, the CSM path does not, and the kernel could correct neither. Deploy is client-receive: the link idles between the server's bursts, drops into L1.2, and pays the exit latency on every wake. Capture is client-transmit, host-driven and keeps the link busy — hence uploads were unaffected. Legacy was never faster; the firmware just happened to leave ASPM off.
Note that
pcie_aspm=offon the kernel command line is a no-op on a FOS kernel — the__setup()registering it lives inside the#ifdef CONFIG_PCIEASPM. This could not be left to a kernel argument.Change
Enables on all three arches:
and on x64 (x86 already had it; arm64 has no such symbol and reaches extended config space through its own ECAM host controller):
Policy is
DEFAULTrather thanPERFORMANCEso each driver keeps making its own chip-specific call —r8169honoursrtl_aspm_is_safe()for boards whose vendor certified ASPM 1.2 — instead of blanket-overriding firmware on every link.PERFORMANCEis the documented escalation if other NICs turn out to have the same problem. The power-saving policies are rejected by the new harness; they would enable ASPM on links whose firmware left it off, and would have made this bug appear on legacy boots too.Adds
docs/adr/0011-pcie-aspm-and-extended-config-space.mdandtests/checks/pcie-aspm-config.sh, and registerssecureboot-config.shin the test lists (it was missing from both).Verification
tests/checks/harnesses and the golden harness pass.PCI_MMCONFIGon x86 (already set) and arm64 (not applicable).make olddefconfigon x64 — the ADR-0010 silent-drop trap.oldconfigdelta vs master is exactly these symbols plus thedef_boolCONFIG_MMCONF_FAM10H, and nothing else.Not yet validated on hardware
The throughput claim is derived from source, not measured. ADR-0011 records a read-only procedure that confirms or kills it in about a minute with no rebuild: from a FOS shell (
pciutilsships in the init), comparesetpci -s <bdf> CAP_EXP+10.won the NIC and its root port booted UEFI vs legacy. Prediction: UEFI reads back2or3, legacy reads0.Refs: #108