PCI/ACPI: Request LTR control from platform before using it
authorBjorn Helgaas <bhelgaas@google.com>
Tue, 17 Apr 2018 15:58:09 +0000 (10:58 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Mon, 23 Apr 2018 13:18:44 +0000 (08:18 -0500)
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 <bhelgaas@google.com>
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/pci_root.c
drivers/pci/probe.c
include/linux/acpi.h
include/linux/pci.h

index 0da18bde6a165cd5d02dad6855850adfd1bde604..2ff0d6702a2e239b2f40c9c08b247013383a9d54 100644 (file)
@@ -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,
index ac91b6fd0bcd5ac33cb69a02ea4382b50f559f40..cc1688d75664242c5547f58d94c544bdff9d63e3 100644 (file)
@@ -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;
 
index 15bfb15c2fa5e1c369184c3839aa2131a416b0bd..49f63c67a9d140e1dbc2b1b1be60b25982cc8958 100644 (file)
@@ -506,7 +506,8 @@ extern bool osc_pc_lpi_support_confirmed;
 #define OSC_PCI_EXPRESS_PME_CONTROL            0x00000004
 #define OSC_PCI_EXPRESS_AER_CONTROL            0x00000008
 #define OSC_PCI_EXPRESS_CAPABILITY_CONTROL     0x00000010
-#define OSC_PCI_CONTROL_MASKS                  0x0000001f
+#define OSC_PCI_EXPRESS_LTR_CONTROL            0x00000020
+#define OSC_PCI_CONTROL_MASKS                  0x0000003f
 
 #define ACPI_GSB_ACCESS_ATTRIB_QUICK           0x00000002
 #define ACPI_GSB_ACCESS_ATTRIB_SEND_RCV         0x00000004
index 73178a2fcee09b10b0e5a78a838213d9fe204b65..d0149c01996d1e68f0598c32d601a3221d414d06 100644 (file)
@@ -473,6 +473,7 @@ struct pci_host_bridge {
        unsigned int    native_aer:1;           /* OS may use PCIe AER */
        unsigned int    native_hotplug:1;       /* OS may use PCIe hotplug */
        unsigned int    native_pme:1;           /* OS may use PCIe PME */
+       unsigned int    native_ltr:1;           /* OS may use PCIe LTR */
        /* Resource alignment requirements */
        resource_size_t (*align_resource)(struct pci_dev *dev,
                        const struct resource *res,