]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/pci/pci.c
Merge tag 'pci-v4.13-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[karo-tx-linux.git] / drivers / pci / pci.c
index 34b5fe025dd4357ef314bbaca9d013baa26a95d7..d88edf5c563b6f07a709c917204b0a77f54ab1f3 100644 (file)
@@ -575,8 +575,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;
@@ -604,16 +603,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)
@@ -1808,6 +1801,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.
@@ -1875,10 +1885,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.
@@ -1894,17 +1903,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
@@ -1919,24 +1929,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
@@ -2081,12 +2087,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;
        }
 
@@ -2105,7 +2111,7 @@ bool pci_dev_run_wake(struct pci_dev *dev)
 {
        struct pci_bus *bus = dev->bus;
 
-       if (device_run_wake(&dev->dev))
+       if (device_can_wakeup(&dev->dev))
                return true;
 
        if (!dev->pme_support)
@@ -2118,7 +2124,7 @@ bool pci_dev_run_wake(struct pci_dev *dev)
        while (bus->parent) {
                struct pci_dev *bridge = bus->self;
 
-               if (device_run_wake(&bridge->dev))
+               if (device_can_wakeup(&bridge->dev))
                        return true;
 
                bus = bus->parent;
@@ -2126,7 +2132,7 @@ bool pci_dev_run_wake(struct pci_dev *dev)
 
        /* We have reached the root bus. */
        if (bus->bridge)
-               return device_run_wake(bus->bridge);
+               return device_can_wakeup(bus->bridge);
 
        return false;
 }