From af8bb9f89838249872240f258e67774ccbcc5970 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 17 Apr 2018 10:58:09 -0500 Subject: PCI/ACPI: Request LTR control from platform before using it Per the PCI Firmware spec r3.2, sec 4.5, an ACPI-based OS should use _OSC to request control of Latency Tolerance Reporting (LTR) before using it. Request control of LTR, and if the platform does not grant control, don't use it. N.B. If the hardware supports LTR and the ASPM L1.2 substate but the BIOS doesn't support LTR in _OSC, we previously would enable ASPM L1.2. This patch will prevent us from enabling ASPM L1.2 in that case. It does not prevent us from enabling PCI-PM L1.2, since that doesn't depend on LTR. See PCIe r40, sec 5.5.1, for the L1 PM substate entry conditions. Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 6 ++++++ drivers/pci/probe.c | 5 +++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0da18bd..2ff0d67 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -153,6 +153,7 @@ static struct pci_osc_bit_struct pci_osc_control_bit[] = { { OSC_PCI_EXPRESS_PME_CONTROL, "PME" }, { OSC_PCI_EXPRESS_AER_CONTROL, "AER" }, { OSC_PCI_EXPRESS_CAPABILITY_CONTROL, "PCIeCapability" }, + { OSC_PCI_EXPRESS_LTR_CONTROL, "LTR" }, }; static void decode_osc_bits(struct acpi_pci_root *root, char *msg, u32 word, @@ -475,6 +476,9 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | OSC_PCI_EXPRESS_PME_CONTROL; + if (IS_ENABLED(CONFIG_PCIEASPM)) + control |= OSC_PCI_EXPRESS_LTR_CONTROL; + if (pci_aer_available()) { if (aer_acpi_firmware_first()) dev_info(&device->dev, @@ -905,6 +909,8 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, host_bridge->native_aer = 0; if (!(root->osc_control_set & OSC_PCI_EXPRESS_PME_CONTROL)) host_bridge->native_pme = 0; + if (!(root->osc_control_set & OSC_PCI_EXPRESS_LTR_CONTROL)) + host_bridge->native_ltr = 0; pci_scan_child_bus(bus); pci_set_host_bridge_release(host_bridge, acpi_pci_root_release_info, diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ac91b6f..cc1688d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -554,6 +554,7 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) bridge->native_aer = 1; bridge->native_hotplug = 1; bridge->native_pme = 1; + bridge->native_ltr = 1; return bridge; } @@ -1954,9 +1955,13 @@ static void pci_configure_relaxed_ordering(struct pci_dev *dev) static void pci_configure_ltr(struct pci_dev *dev) { #ifdef CONFIG_PCIEASPM + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); u32 cap; struct pci_dev *bridge; + if (!host->native_ltr) + return; + if (!pci_is_pcie(dev)) return; -- cgit v1.1