Merge tag 'pci-v5.15-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[linux-2.6-microblaze.git] / drivers / pci / pci.c
index 292dadd..ce2ab62 100644 (file)
@@ -1916,11 +1916,7 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
         * so that things like MSI message writing will behave as expected
         * (e.g. if the device really is in D0 at enable time).
         */
-       if (dev->pm_cap) {
-               u16 pmcsr;
-               pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
-               dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
-       }
+       pci_update_current_state(dev, dev->current_state);
 
        if (atomic_inc_return(&dev->enable_cnt) > 1)
                return 0;               /* already enabled */
@@ -2505,7 +2501,14 @@ static int __pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable
        if (enable) {
                int error;
 
-               if (pci_pme_capable(dev, state))
+               /*
+                * Enable PME signaling if the device can signal PME from
+                * D3cold regardless of whether or not it can signal PME from
+                * the current target state, because that will allow it to
+                * signal PME when the hierarchy above it goes into D3cold and
+                * the device itself ends up in D3cold as a result of that.
+                */
+               if (pci_pme_capable(dev, state) || pci_pme_capable(dev, PCI_D3cold))
                        pci_pme_active(dev, true);
                else
                        ret = 1;
@@ -2609,16 +2612,20 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
        if (dev->current_state == PCI_D3cold)
                target_state = PCI_D3cold;
 
-       if (wakeup) {
+       if (wakeup && dev->pme_support) {
+               pci_power_t state = target_state;
+
                /*
                 * Find the deepest state from which the device can generate
                 * PME#.
                 */
-               if (dev->pme_support) {
-                       while (target_state
-                             && !(dev->pme_support & (1 << target_state)))
-                               target_state--;
-               }
+               while (state && !(dev->pme_support & (1 << state)))
+                       state--;
+
+               if (state)
+                       return state;
+               else if (dev->pme_support & 1)
+                       return PCI_D0;
        }
 
        return target_state;