On Thu, Jul 17, 2025 at 2:40 AM David E. Box <david.e.box@xxxxxxxxxxxxxxx> wrote: > > 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 This doesn't seem to match the code - the name of the new flag is different there. > 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. I'm guessing that VMD is supposed to set PCI_BUS_FLAGS_NO_ASPM_DEFAULT, but that doesn't happen in patch [2/2] AFAICS. And I would just merge the two patches, IMV there's no reason to keep them separate. > 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; Could you avoid using the new flag by assuming that if parent->bus->aspm_bus_link_state was zero, link->aspm_enabled would take effect? So the check would be something like if (parent->bus->aspm_bus_link_state) 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 */ > --