ACPI: Disable ASPM if the platform won't provide _OSC control for PCIe
authorMatthew Garrett <mjg@redhat.com>
Tue, 22 Jun 2010 15:25:43 +0000 (11:25 -0400)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Fri, 30 Jul 2010 16:29:17 +0000 (09:29 -0700)
The PCI SIG documentation for the _OSC OS/firmware handshaking interface
states:

"If the _OSC control method is absent from the scope of a host bridge
device, then the operating system must not enable or attempt to use any
features defined in this section for the hierarchy originated by the host
bridge."

The obvious interpretation of this is that the OS should not attempt to use
PCIe hotplug, PME or AER - however, the specification also notes that an
_OSC method is *required* for PCIe hierarchies, and experimental validation
with An Alternative OS indicates that it doesn't use any PCIe functionality
if the _OSC method is missing. That arguably means we shouldn't be using
MSI or extended config space, but right now our problems seem to be limited
to vendors being surprised when ASPM gets enabled on machines when other
OSs refuse to do so. So, for now, let's just disable ASPM if the _OSC
method doesn't exist or refuses to hand over PCIe capability control.

Acked-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
drivers/acpi/pci_root.c

index 4eac59393edc5b13e3c25283f08e6cf899fb61d7..1f67057af2a571991481bb761d157320b9d3f329 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pci.h>
 #include <linux/pci-acpi.h>
+#include <linux/pci-aspm.h>
 #include <linux/acpi.h>
 #include <linux/slab.h>
 #include <acpi/acpi_bus.h>
@@ -543,6 +544,14 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        if (flags != base_flags)
                acpi_pci_osc_support(root, flags);
 
+       status = acpi_pci_osc_control_set(root->device->handle,
+                                         OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n");
+               pcie_no_aspm();
+       }
+
        pci_acpi_add_bus_pm_notifier(device, root->bus);
        if (device->wakeup.flags.run_wake)
                device_set_run_wake(root->bus->bridge, true);