Synthetic PCIe hierarchies such as those created by Intel VMD are not enumerated or configured by firmware, and therefore do not receive BIOS-provided ASPM defaults. This leaves devices behind such domains with ASPM effectively disabled, despite platform intent. Introduce a mechanism to allow the bus owner (e.g. a controller driver) to supply a default ASPM policy via a new aspm_bus_link_state field in pci_bus. A new bus flag, PCI_BUS_FLAGS_ASPM_DEFAULT_OVERRIDE, indicates that the core should use this value instead of the BIOS default when initializing link state. This avoids the need for controller-specific logic in ASPM core and allows for proper power savings in these otherwise unsupported hierarchies. Suggested-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> Signed-off-by: David E. Box <david.e.box@xxxxxxxxxxxxxxx> --- drivers/pci/pcie/aspm.c | 5 ++++- include/linux/pci.h | 12 ++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 29fcb0689a91..2ad1852ac9b2 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -866,7 +866,10 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) } /* Save default state */ - link->aspm_default = link->aspm_enabled; + if (parent->bus->bus_flags & PCI_BUS_FLAGS_NO_ASPM_DEFAULT) + link->aspm_default = parent->bus->aspm_bus_link_state; + else + link->aspm_default = link->aspm_enabled; /* Setup initial capable state. Will be updated later */ link->aspm_capable = link->aspm_support; diff --git a/include/linux/pci.h b/include/linux/pci.h index 05e68f35f392..7e1c305c419c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -256,10 +256,11 @@ enum pci_irq_reroute_variant { typedef unsigned short __bitwise pci_bus_flags_t; enum pci_bus_flags { - PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, - PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2, - PCI_BUS_FLAGS_NO_AERSID = (__force pci_bus_flags_t) 4, - PCI_BUS_FLAGS_NO_EXTCFG = (__force pci_bus_flags_t) 8, + PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, + PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2, + PCI_BUS_FLAGS_NO_AERSID = (__force pci_bus_flags_t) 4, + PCI_BUS_FLAGS_NO_EXTCFG = (__force pci_bus_flags_t) 8, + PCI_BUS_FLAGS_NO_ASPM_DEFAULT = (__force pci_bus_flags_t) 16, }; /* Values from Link Status register, PCIe r3.1, sec 7.8.8 */ @@ -665,6 +666,9 @@ struct pci_bus { void *sysdata; /* Hook for sys-specific extension */ struct proc_dir_entry *procdir; /* Directory entry in /proc/bus/pci */ +#ifdef CONFIG_PCIEASPM + unsigned int aspm_bus_link_state; /* Bus owner provided link state */ +#endif unsigned char number; /* Bus number */ unsigned char primary; /* Number of primary bridge */ unsigned char max_bus_speed; /* enum pci_bus_speed */ -- 2.43.0