PCIE ASPM / POWER

PCIe ASPM on Linux: pcie_aspm=off is a hands-off order, not an off switch.

You added pcie_aspm=off, the AER spam stopped and the Wi-Fi card stopped dropping out. It feels like a fix. It might be, or it might be a clue you just muted.

THE SHORT ANSWER

PCIe ASPM (Active State Power Management) lets an idle link drop into low-power L0s or L1 states on its own. Booting with pcie_aspm=off tells Linux not to touch ASPM at all, so whatever firmware configured stays. If errors stop, a power transition was probably involved, but a marginal link or device quirk may remain.

What does PCIe ASPM do?

A PCIe link doesn't have to run flat out when nothing is moving. With Active State Power Management enabled, the two ends of a link drop into low-power states on their own, in hardware, whenever traffic stops. Software only decides which states are allowed.

Link stateWhat sleepsWake-up costControlled by
L0Nothing. The link is active.None—
L0sOne direction of the linkThe shortest exitASPM bits in Link Control
L1Both directionsA longer exitASPM bits in Link Control
L1.1 / L1.2More of the link circuitry; L1.2 powers down more than L1.1Longer stillThe L1 PM Substates capability
L2 / L3The whole link. The device is in D3cold.A full power-up and retrainDevice power management, not ASPM

The catch is the wake-up. Every exit from a low-power state means the link must get back to L0 within the latency both ends advertised. lspci prints those promises in LnkCap, for example Exit Latency L0s <1us, L1 <8us. When a device, board or firmware gets an exit wrong, the symptoms can look just like a bad link: receiver errors, replays, or a device that stops answering after it's been idle.

The aha: pcie_aspm=off means “kernel, hands off”

Most guides treat pcie_aspm=off as an off switch. Read the kernel's own parameter documentation: don't touch ASPM configuration at all, and “leave any configuration done by firmware unchanged.”

So if your firmware enabled L1 on a link, pcie_aspm=off leaves L1 enabled. A comment in aspm.c says the same thing in other words: disabling ASPM is meant to stop the kernel from modifying the hardware state, not to clear it.

Linux also goes hands-off by itself in two situations, without any boot parameter:

  • Firmware keeps control of PCIe features through ACPI _OSC. dmesg says _OSC: platform retains control of PCIe features.
  • The ACPI FADT declares ASPM unsupported. dmesg says FADT indicates ASPM is unsupported, using BIOS configuration.

In all three cases, the per-link ASPM switches under /sys/bus/pci/devices/…/link/ vanish, and the kernel refuses to change its ASPM policy.

So why does pcie_aspm=off so often make errors go away? Because it changes several things at once. Linux stops applying its own policy and its L1 substate settings. It also tells firmware, through _OSC, that the OS doesn't support ASPM, and how firmware reacts to that is up to the firmware. Any of these can change which low-power states your link really uses. You just don't know which one did it.

The boot parameter is an intention. LnkCtl is the fact. Read the Link Control register on both ends of the link before and after every ASPM change. Otherwise you're debugging a story, not a link.

How to check ASPM status on Linux with lspci

Replace 02:00.0 with your device and 00:1c.0 with the port above it. These commands only read state.

  1. Find out who controls ASPM.

    sudo dmesg | grep -iE 'aspm|_osc|fadt'

    Look for: OS supports [… ASPM ClockPM …] (Linux offered to manage ASPM), OS now controls [...], platform retains control, FADT indicates ASPM is unsupported, or PCIe ASPM is disabled (your boot parameter at work).

  2. Find both ends of the link. ASPM is a property of the link, so you need the port above the device as well as the device itself.

    lspci -PP -s 02:00.0

    Look for: a path such as 00:1c.0/02:00.0.

  3. Read what each end supports and has enabled. Run as root. Without it, lspci prints <access denied> instead of capabilities.

    sudo lspci -vv -s 00:1c.0 | grep -E 'LnkCap:|LnkCtl:|L1SubCap:|L1SubCtl1:'
    sudo lspci -vv -s 02:00.0 | grep -E 'LnkCap:|LnkCtl:|L1SubCap:|L1SubCtl1:'

    Look for: LnkCap: … ASPM L0s L1 means supported; LnkCtl: ASPM L1 Enabled means in use; ASPM Disabled means off. In L1SubCtl1, ASPM_L1.2+ means the deepest substate is enabled. The lspci -vvv guide covers the neighbouring fields.

  4. Check the kernel's policy.

    cat /sys/module/pcie_aspm/parameters/policy

    Look for: the value in brackets. default keeps firmware's choices. performance disables ASPM and clock power management on the links Linux controls. powersave allows L0s and L1, and powersupersave adds the L1 substates.

  5. List the per-link switches.

    ls /sys/bus/pci/devices/0000:02:00.0/link/
    cat /sys/bus/pci/devices/0000:02:00.0/link/l1_aspm

    Look for: files such as l0s_aspm, l1_aspm, l1_1_aspm, l1_2_aspm and clkpm. If the directory is missing or empty, Linux isn't managing ASPM on that link.

Here is how the important lines look on a link with L1 and both substates enabled. It's a synthetic excerpt in lspci's format:

# Synthetic example: sudo lspci -vv -s 02:00.0 (excerpt)
LnkCap: Port #0, Speed 5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s <2us, L1 <64us
LnkCtl: ASPM L1 Enabled; RCB 64 bytes, LnkDisable- CommClk+
L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
L1SubCtl1: PCI-PM_L1.2- PCI-PM_L1.1- ASPM_L1.2+ ASPM_L1.1+

The device supports L0s and L1 but only L1 is enabled, and both ASPM substates are on. If errors show up after idle periods on this link, L1.2 is the first suspect to test.

Does disabling ASPM fix PCIe errors? Test it properly

Treat ASPM as a suspect, not a verdict. Change one state on one link, keep the workload fixed and compare error rates. The AER triage steps include a one-minute counter loop you can reuse.

  1. Measure a baseline. Count corrected errors on both ends of the link for a fixed time, including idle periods. ASPM only engages when the link is idle, so a flat-out benchmark can hide the problem.

  2. Disable the deepest state first, on this link only. The change lasts until reboot.

    echo 0 | sudo tee /sys/bus/pci/devices/0000:02:00.0/link/l1_2_aspm

    Run the same measurement. If needed, repeat with l1_aspm.

  3. Confirm the hardware changed. Read LnkCtl and L1SubCtl1 again. A write that didn't reach the hardware proves nothing.

  4. Read the result.

    • Errors vanish with L1.2 off: the problem lives in substate entry or exit. Look for firmware or driver updates and known quirks for that device.
    • Errors vanish only with all ASPM off: transitions in and out of L1 are the trigger.
    • Errors stay with ASPM off: ASPM was never the cause. Go back to signal integrity and link speed.
  5. Choose the narrowest fix that holds, using the options below. Re-apply a sysfs change at boot only once you've proven it works.

If the per-link files don't exist, Linux isn't managing ASPM on that link. You're left with firmware settings or boot-wide options, so change one at a time and measure each.

What pcie_aspm=off hides: pci=noaer vs pcie_aspm=off

Four common moves, from bluntest to most precise:

  • Hide the reports: pci=noaer. Nothing changes on the link; Linux simply stops using AER. You lose every AER message, the counters and AER-based recovery, and the errors carry on.

  • Hands off: pcie_aspm=off. Linux stops managing ASPM and firmware's settings stay, so ASPM may still be on. You lose the per-link controls and drivers' ability to disable a broken state.

  • Performance policy: pcie_aspm.policy=performance. Linux disables ASPM and clock power management on every link it controls. AER stays visible, but you give up idle power savings everywhere, not just on the bad link.

  • One state, one link: write 0 to link/l1_2_aspm. The narrowest change. It lasts until reboot, so re-apply it at boot once you've proven it helps.

Now the irony. With pcie_aspm=off, a driver that knows its device can't handle a particular state can no longer turn that state off. The kernel logs can't disable ASPM; OS doesn't have ASPM control and moves on. The blunt fix can switch off a precise one.

There's a power cost as well, but it's hard to put a number on without measuring your own machine. It depends on the devices, the platform and how long the links sit idle. If idle power or battery life matters to you, measure before and after.

And remember that pcie_aspm=force goes the other way. It enables ASPM even on devices that claim not to support it, and the kernel documentation warns it may cause system lockups.

ASPM vs D3cold: two different kinds of sleep

ASPM saves power on the link while the device stays on, in D0. D3cold is a device power state: main power is removed, the link goes down, and the device has to power up and retrain before it can answer. Linux runtime power management decides when a device may enter D3cold. See the kernel's PCI power management guide for the full model.

That's why pcie_aspm=off does nothing for this message:

# Synthetic example
nvme 0000:02:00.0: Unable to change power state from D3cold to D0, device inaccessible

Inspect the device's power state instead:

cat /sys/bus/pci/devices/0000:02:00.0/power_state
cat /sys/bus/pci/devices/0000:02:00.0/d3cold_allowed
cat /sys/bus/pci/devices/0000:02:00.0/power/control

power_state shows the current state (D0, D3hot, D3cold and so on). Writing 0 to d3cold_allowed keeps that one device out of D3cold. Setting power/control to on turns off runtime power management for it. The bigger hammer, pcie_port_pm=off, disables power management for every PCIe port. As with ASPM, start narrow and measure.

If the device reads back as all ones (rev ff) after resume, see unknown header type 7f.

Questions

Does disabling ASPM fix PCIe errors?

Sometimes it makes them stop, which tells you a low-power transition is involved. It doesn't repair the cause. Disable one state on one link, compare error rates under the same workload, and keep the narrowest change that holds.

How do I check if ASPM is enabled on Linux?

Run sudo lspci -vv and read LnkCtl on both the device and the port above it. “ASPM Disabled” means off; “ASPM L1 Enabled” means L1 is allowed. L1SubCtl1 shows the L1.1 and L1.2 substates.

Is pcie_aspm=off safe?

It's easy to undo from the boot menu. But it doesn't guarantee ASPM is off, and it removes Linux's ability to manage ASPM or to apply per-device quirks. pcie_aspm=force is the risky one: the kernel documentation warns it may cause system lockups.

Should I use pci=noaer or pcie_aspm=off?

They solve different problems. pci=noaer hides error reports without changing the link. pcie_aspm=off changes who manages link power, which can change link behaviour. Neither is a diagnosis, so measure first.

What is the difference between ASPM and D3cold?

ASPM manages link power while the device is on. D3cold removes the device's main power and takes the link down. Problems waking from D3cold are runtime power-management issues, and ASPM settings won't fix them.

Why is the link folder missing under /sys/bus/pci/devices?

Linux exposes per-link ASPM controls only when it manages ASPM for that link. They're missing when you boot with pcie_aspm=off, when firmware keeps control through _OSC, when the FADT marks ASPM unsupported, or when the device has no PCIe link to manage.

Sources and scope

Source-based guide published by Header7F on 19 October 2026. Commands use placeholder addresses. Header7F has not reproduced every scenario on physical hardware, and no outcome is guaranteed.

KEEP READING

Message us