]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/pci/pci.c
PCI / PM: Simplify device wakeup settings code
[mirror_ubuntu-artful-kernel.git] / drivers / pci / pci.c
index b01bd5bba8e604709c3b51f14f9fbdb796a2c4fb..d378262d30e392f3a4b14b568a3947f15926c191 100644 (file)
@@ -574,8 +574,7 @@ static const struct pci_platform_pm_ops *pci_platform_pm;
 int pci_set_platform_pm(const struct pci_platform_pm_ops *ops)
 {
        if (!ops->is_manageable || !ops->set_state  || !ops->get_state ||
-           !ops->choose_state  || !ops->sleep_wake || !ops->run_wake  ||
-           !ops->need_resume)
+           !ops->choose_state  || !ops->set_wakeup || !ops->need_resume)
                return -EINVAL;
        pci_platform_pm = ops;
        return 0;
@@ -603,16 +602,10 @@ static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
                        pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
 }
 
-static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
+static inline int platform_pci_set_wakeup(struct pci_dev *dev, bool enable)
 {
        return pci_platform_pm ?
-                       pci_platform_pm->sleep_wake(dev, enable) : -ENODEV;
-}
-
-static inline int platform_pci_run_wake(struct pci_dev *dev, bool enable)
-{
-       return pci_platform_pm ?
-                       pci_platform_pm->run_wake(dev, enable) : -ENODEV;
+                       pci_platform_pm->set_wakeup(dev, enable) : -ENODEV;
 }
 
 static inline bool platform_pci_need_resume(struct pci_dev *dev)
@@ -1805,6 +1798,23 @@ static void __pci_pme_active(struct pci_dev *dev, bool enable)
        pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
 }
 
+static void pci_pme_restore(struct pci_dev *dev)
+{
+       u16 pmcsr;
+
+       if (!dev->pme_support)
+               return;
+
+       pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+       if (dev->wakeup_prepared) {
+               pmcsr |= PCI_PM_CTRL_PME_ENABLE;
+       } else {
+               pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
+               pmcsr |= PCI_PM_CTRL_PME_STATUS;
+       }
+       pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
+}
+
 /**
  * pci_pme_active - enable or disable PCI device's PME# function
  * @dev: PCI device to handle.
@@ -1872,10 +1882,9 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
 EXPORT_SYMBOL(pci_pme_active);
 
 /**
- * __pci_enable_wake - enable PCI device as wakeup event source
+ * pci_enable_wake - enable PCI device as wakeup event source
  * @dev: PCI device affected
  * @state: PCI state from which device will issue wakeup events
- * @runtime: True if the events are to be generated at run time
  * @enable: True to enable event generation; false to disable
  *
  * This enables the device as a wakeup event source, or disables it.
@@ -1891,17 +1900,18 @@ EXPORT_SYMBOL(pci_pme_active);
  * Error code depending on the platform is returned if both the platform and
  * the native mechanism fail to enable the generation of wake-up events
  */
-int __pci_enable_wake(struct pci_dev *dev, pci_power_t state,
-                     bool runtime, bool enable)
+int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
 {
        int ret = 0;
 
-       if (enable && !runtime && !device_may_wakeup(&dev->dev))
-               return -EINVAL;
-
-       /* Don't do the same thing twice in a row for one device. */
-       if (!!enable == !!dev->wakeup_prepared)
+       /*
+        * Don't do the same thing twice in a row for one device, but restore
+        * PME Enable in case it has been updated by config space restoration.
+        */
+       if (!!enable == !!dev->wakeup_prepared) {
+               pci_pme_restore(dev);
                return 0;
+       }
 
        /*
         * According to "PCI System Architecture" 4th ed. by Tom Shanley & Don
@@ -1916,24 +1926,20 @@ int __pci_enable_wake(struct pci_dev *dev, pci_power_t state,
                        pci_pme_active(dev, true);
                else
                        ret = 1;
-               error = runtime ? platform_pci_run_wake(dev, true) :
-                                       platform_pci_sleep_wake(dev, true);
+               error = platform_pci_set_wakeup(dev, true);
                if (ret)
                        ret = error;
                if (!ret)
                        dev->wakeup_prepared = true;
        } else {
-               if (runtime)
-                       platform_pci_run_wake(dev, false);
-               else
-                       platform_pci_sleep_wake(dev, false);
+               platform_pci_set_wakeup(dev, false);
                pci_pme_active(dev, false);
                dev->wakeup_prepared = false;
        }
 
        return ret;
 }
-EXPORT_SYMBOL(__pci_enable_wake);
+EXPORT_SYMBOL(pci_enable_wake);
 
 /**
  * pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold
@@ -2075,12 +2081,12 @@ int pci_finish_runtime_suspend(struct pci_dev *dev)
 
        dev->runtime_d3cold = target_state == PCI_D3cold;
 
-       __pci_enable_wake(dev, target_state, true, pci_dev_run_wake(dev));
+       pci_enable_wake(dev, target_state, pci_dev_run_wake(dev));
 
        error = pci_set_power_state(dev, target_state);
 
        if (error) {
-               __pci_enable_wake(dev, target_state, true, false);
+               pci_enable_wake(dev, target_state, false);
                dev->runtime_d3cold = false;
        }
 
@@ -2144,7 +2150,8 @@ bool pci_dev_keep_suspended(struct pci_dev *pci_dev)
 
        if (!pm_runtime_suspended(dev)
            || pci_target_state(pci_dev) != pci_dev->current_state
-           || platform_pci_need_resume(pci_dev))
+           || platform_pci_need_resume(pci_dev)
+           || (pci_dev->dev_flags & PCI_DEV_FLAGS_NEEDS_RESUME))
                return false;
 
        /*