Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 26 Mar 2011 04:01:43 +0000 (21:01 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 26 Mar 2011 04:01:43 +0000 (21:01 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6:
  PCI: Disable ASPM when _OSC control is not granted for PCIe services
  PCI: Changing ASPM policy, via /sys, to POWERSAVE could cause NMIs
  PCI: PCIe links may not get configured for ASPM under POWERSAVE mode
  PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

drivers/acpi/pci_root.c
drivers/pci/pci.c
drivers/pci/pcie/aspm.c
drivers/pci/pcie/portdrv_core.c
include/linux/pci-aspm.h
include/linux/pci.h

index 85249395623baa32b556fbddeb77e4c71e6dfeac..f911a2f8cc346f40f7575db6eab96cf6acf2339a 100644 (file)
@@ -32,6 +32,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>
@@ -564,7 +565,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        /* Indicate support for various _OSC capabilities. */
        if (pci_ext_cfg_avail(root->bus->self))
                flags |= OSC_EXT_PCI_CONFIG_SUPPORT;
-       if (pcie_aspm_enabled())
+       if (pcie_aspm_support_enabled())
                flags |= OSC_ACTIVE_STATE_PWR_SUPPORT |
                        OSC_CLOCK_PWR_CAPABILITY_SUPPORT;
        if (pci_msi_enabled())
@@ -591,12 +592,16 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
 
                status = acpi_pci_osc_control_set(device->handle, &flags,
                                        OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-               if (ACPI_SUCCESS(status))
+               if (ACPI_SUCCESS(status)) {
                        dev_info(root->bus->bridge,
                                "ACPI _OSC control (0x%02x) granted\n", flags);
-               else
+               } else {
                        dev_dbg(root->bus->bridge,
                                "ACPI _OSC request failed (code %d)\n", status);
+                       printk(KERN_INFO "Unable to assume _OSC PCIe control. "
+                               "Disabling ASPM\n");
+                       pcie_no_aspm();
+               }
        }
 
        pci_acpi_add_bus_pm_notifier(device, root->bus);
index b714d787bdddeb8306324dada56412c6eef2ac68..2472e7177b4b5af6ddc813913fb193c47fef984d 100644 (file)
@@ -740,6 +740,12 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 
        if (!__pci_complete_power_transition(dev, state))
                error = 0;
+       /*
+        * When aspm_policy is "powersave" this call ensures
+        * that ASPM is configured.
+        */
+       if (!error && dev->bus->self)
+               pcie_aspm_powersave_config_link(dev->bus->self);
 
        return error;
 }
index 3188cd96b3386c2992d2b3df1d5a7bb0e363c266..eee09f756ec95a18832199801924aa2775da2195 100644 (file)
@@ -69,6 +69,7 @@ struct pcie_link_state {
 };
 
 static int aspm_disabled, aspm_force, aspm_clear_state;
+static bool aspm_support_enabled = true;
 static DEFINE_MUTEX(aspm_lock);
 static LIST_HEAD(link_list);
 
@@ -707,6 +708,28 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev)
        up_read(&pci_bus_sem);
 }
 
+void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
+{
+       struct pcie_link_state *link = pdev->link_state;
+
+       if (aspm_disabled || !pci_is_pcie(pdev) || !link)
+               return;
+
+       if (aspm_policy != POLICY_POWERSAVE)
+               return;
+
+       if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
+           (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
+               return;
+
+       down_read(&pci_bus_sem);
+       mutex_lock(&aspm_lock);
+       pcie_config_aspm_path(link);
+       pcie_set_clkpm(link, policy_to_clkpm_state(link));
+       mutex_unlock(&aspm_lock);
+       up_read(&pci_bus_sem);
+}
+
 /*
  * pci_disable_link_state - disable pci device's link state, so the link will
  * never enter specific states
@@ -747,6 +770,8 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
        int i;
        struct pcie_link_state *link;
 
+       if (aspm_disabled)
+               return -EPERM;
        for (i = 0; i < ARRAY_SIZE(policy_str); i++)
                if (!strncmp(val, policy_str[i], strlen(policy_str[i])))
                        break;
@@ -801,6 +826,8 @@ static ssize_t link_state_store(struct device *dev,
        struct pcie_link_state *link, *root = pdev->link_state->root;
        u32 val = buf[0] - '0', state = 0;
 
+       if (aspm_disabled)
+               return -EPERM;
        if (n < 1 || val > 3)
                return -EINVAL;
 
@@ -896,6 +923,7 @@ static int __init pcie_aspm_disable(char *str)
 {
        if (!strcmp(str, "off")) {
                aspm_disabled = 1;
+               aspm_support_enabled = false;
                printk(KERN_INFO "PCIe ASPM is disabled\n");
        } else if (!strcmp(str, "force")) {
                aspm_force = 1;
@@ -930,3 +958,8 @@ int pcie_aspm_enabled(void)
 }
 EXPORT_SYMBOL(pcie_aspm_enabled);
 
+bool pcie_aspm_support_enabled(void)
+{
+       return aspm_support_enabled;
+}
+EXPORT_SYMBOL(pcie_aspm_support_enabled);
index 5130d0d22390bba5266fdfb18a10cb7aa2dccb7d..595654a1a6a6eec86e8011f1efe667bf318bf257 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/slab.h>
 #include <linux/pcieport_if.h>
 #include <linux/aer.h>
-#include <linux/pci-aspm.h>
 
 #include "../pci.h"
 #include "portdrv.h"
@@ -356,10 +355,8 @@ int pcie_port_device_register(struct pci_dev *dev)
 
        /* Get and check PCI Express port services */
        capabilities = get_port_device_capability(dev);
-       if (!capabilities) {
-               pcie_no_aspm();
+       if (!capabilities)
                return 0;
-       }
 
        pci_set_master(dev);
        /*
index ce6810512c6629598f99a25775663dc7f8fa24c4..67cb3ae3801696f973ffc15e491513167cad99c5 100644 (file)
@@ -26,6 +26,7 @@
 extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
 extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
 extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
+extern void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
 extern void pci_disable_link_state(struct pci_dev *pdev, int state);
 extern void pcie_clear_aspm(void);
 extern void pcie_no_aspm(void);
@@ -39,6 +40,9 @@ static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev)
 static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
 {
 }
+static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
+{
+}
 static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
 {
 }
index 16c9f2e61977e6f7e3192384435e43ad6aaecf9d..96f70d7e058dd043716ae216e3918567923f28bb 100644 (file)
@@ -1002,12 +1002,11 @@ extern bool pcie_ports_auto;
 #endif
 
 #ifndef CONFIG_PCIEASPM
-static inline int pcie_aspm_enabled(void)
-{
-       return 0;
-}
+static inline int pcie_aspm_enabled(void) { return 0; }
+static inline bool pcie_aspm_support_enabled(void) { return false; }
 #else
 extern int pcie_aspm_enabled(void);
+extern bool pcie_aspm_support_enabled(void);
 #endif
 
 #ifdef CONFIG_PCIEAER