+++ /dev/null
-From 8984dcf2ede2f48df34cd584ae0ac04b3c66d7f9 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 17 May 2019 11:08:50 +0200
-Subject: PCI: PM: Avoid possible suspend-to-idle issue
-
-From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-
-[ Upstream commit d491f2b75237ef37d8867830ab7fad8d9659e853 ]
-
-If a PCI driver leaves the device handled by it in D0 and calls
-pci_save_state() on the device in its ->suspend() or ->suspend_late()
-callback, it can expect the device to stay in D0 over the whole
-s2idle cycle. However, that may not be the case if there is a
-spurious wakeup while the system is suspended, because in that case
-pci_pm_suspend_noirq() will run again after pci_pm_resume_noirq()
-which calls pci_restore_state(), via pci_pm_default_resume_early(),
-so state_saved is cleared and the second iteration of
-pci_pm_suspend_noirq() will invoke pci_prepare_to_sleep() which
-may change the power state of the device.
-
-To avoid that, add a new internal flag, skip_bus_pm, that will be set
-by pci_pm_suspend_noirq() when it runs for the first time during the
-given system suspend-resume cycle if the state of the device has
-been saved already and the device is still in D0. Setting that flag
-will cause the next iterations of pci_pm_suspend_noirq() to set
-state_saved for pci_pm_resume_noirq(), so that it always restores the
-device state from the originally saved data, and avoid calling
-pci_prepare_to_sleep() for the device.
-
-Fixes: 33e4f80ee69b ("ACPI / PM: Ignore spurious SCI wakeups from suspend-to-idle")
-Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-Reviewed-by: Keith Busch <keith.busch@intel.com>
-Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/pci/pci-driver.c | 17 ++++++++++++++++-
- include/linux/pci.h | 1 +
- 2 files changed, 17 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
-index 522e59274b5d0..1589a147c5364 100644
---- a/drivers/pci/pci-driver.c
-+++ b/drivers/pci/pci-driver.c
-@@ -728,6 +728,8 @@ static int pci_pm_suspend(struct device *dev)
- struct pci_dev *pci_dev = to_pci_dev(dev);
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-+ pci_dev->skip_bus_pm = false;
-+
- if (pci_has_legacy_pm_support(pci_dev))
- return pci_legacy_suspend(dev, PMSG_SUSPEND);
-
-@@ -801,7 +803,20 @@ static int pci_pm_suspend_noirq(struct device *dev)
- }
- }
-
-- if (!pci_dev->state_saved) {
-+ if (pci_dev->skip_bus_pm) {
-+ /*
-+ * The function is running for the second time in a row without
-+ * going through full resume, which is possible only during
-+ * suspend-to-idle in a spurious wakeup case. Moreover, the
-+ * device was originally left in D0, so its power state should
-+ * not be changed here and the device register values saved
-+ * originally should be restored on resume again.
-+ */
-+ pci_dev->state_saved = true;
-+ } else if (pci_dev->state_saved) {
-+ if (pci_dev->current_state == PCI_D0)
-+ pci_dev->skip_bus_pm = true;
-+ } else {
- pci_save_state(pci_dev);
- if (pci_power_manageable(pci_dev))
- pci_prepare_to_sleep(pci_dev);
-diff --git a/include/linux/pci.h b/include/linux/pci.h
-index 59f4d10568c65..430f3c335446e 100644
---- a/include/linux/pci.h
-+++ b/include/linux/pci.h
-@@ -346,6 +346,7 @@ struct pci_dev {
- D3cold, not set for devices
- powered on/off by the
- corresponding bridge */
-+ unsigned int skip_bus_pm:1; /* Internal: Skip bus-level PM */
- unsigned int ignore_hotplug:1; /* Ignore hotplug events */
- unsigned int hotplug_user_indicators:1; /* SlotCtl indicators
- controlled exclusively by
---
-2.20.1
-
+++ /dev/null
-From 3e26c5feed2add218046ecf91bab3cfa9bf762a6 Mon Sep 17 00:00:00 2001
-From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
-Date: Thu, 13 Jun 2019 23:59:45 +0200
-Subject: PCI: PM: Skip devices in D0 for suspend-to-idle
-
-From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-
-commit 3e26c5feed2add218046ecf91bab3cfa9bf762a6 upstream.
-
-Commit d491f2b75237 ("PCI: PM: Avoid possible suspend-to-idle issue")
-attempted to avoid a problem with devices whose drivers want them to
-stay in D0 over suspend-to-idle and resume, but it did not go as far
-as it should with that.
-
-Namely, first of all, the power state of a PCI bridge with a
-downstream device in D0 must be D0 (based on the PCI PM spec r1.2,
-sec 6, table 6-1, if the bridge is not in D0, there can be no PCI
-transactions on its secondary bus), but that is not actively enforced
-during system-wide PM transitions, so use the skip_bus_pm flag
-introduced by commit d491f2b75237 for that.
-
-Second, the configuration of devices left in D0 (whatever the reason)
-during suspend-to-idle need not be changed and attempting to put them
-into D0 again by force is pointless, so explicitly avoid doing that.
-
-Fixes: d491f2b75237 ("PCI: PM: Avoid possible suspend-to-idle issue")
-Reported-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
-Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- drivers/pci/pci-driver.c | 47 +++++++++++++++++++++++++++++++++++------------
- 1 file changed, 35 insertions(+), 12 deletions(-)
-
---- a/drivers/pci/pci-driver.c
-+++ b/drivers/pci/pci-driver.c
-@@ -526,7 +526,6 @@ static void pci_pm_default_resume_early(
- pci_power_up(pci_dev);
- pci_restore_state(pci_dev);
- pci_pme_restore(pci_dev);
-- pci_fixup_device(pci_fixup_resume_early, pci_dev);
- }
-
- /*
-@@ -805,23 +804,37 @@ static int pci_pm_suspend_noirq(struct d
-
- if (pci_dev->skip_bus_pm) {
- /*
-- * The function is running for the second time in a row without
-+ * Either the device is a bridge with a child in D0 below it, or
-+ * the function is running for the second time in a row without
- * going through full resume, which is possible only during
-- * suspend-to-idle in a spurious wakeup case. Moreover, the
-- * device was originally left in D0, so its power state should
-- * not be changed here and the device register values saved
-- * originally should be restored on resume again.
-+ * suspend-to-idle in a spurious wakeup case. The device should
-+ * be in D0 at this point, but if it is a bridge, it may be
-+ * necessary to save its state.
- */
-- pci_dev->state_saved = true;
-- } else if (pci_dev->state_saved) {
-- if (pci_dev->current_state == PCI_D0)
-- pci_dev->skip_bus_pm = true;
-- } else {
-+ if (!pci_dev->state_saved)
-+ pci_save_state(pci_dev);
-+ } else if (!pci_dev->state_saved) {
- pci_save_state(pci_dev);
- if (pci_power_manageable(pci_dev))
- pci_prepare_to_sleep(pci_dev);
- }
-
-+ if (pci_dev->current_state == PCI_D0) {
-+ pci_dev->skip_bus_pm = true;
-+ /*
-+ * Per PCI PM r1.2, table 6-1, a bridge must be in D0 if any
-+ * downstream device is in D0, so avoid changing the power state
-+ * of the parent bridge by setting the skip_bus_pm flag for it.
-+ */
-+ if (pci_dev->bus->self)
-+ pci_dev->bus->self->skip_bus_pm = true;
-+ }
-+
-+ if (pci_dev->skip_bus_pm && !pm_suspend_via_firmware()) {
-+ dev_dbg(dev, "PCI PM: Skipped\n");
-+ goto Fixup;
-+ }
-+
- pci_pm_set_unknown_state(pci_dev);
-
- /*
-@@ -848,7 +861,16 @@ static int pci_pm_resume_noirq(struct de
- struct device_driver *drv = dev->driver;
- int error = 0;
-
-- pci_pm_default_resume_early(pci_dev);
-+ /*
-+ * In the suspend-to-idle case, devices left in D0 during suspend will
-+ * stay in D0, so it is not necessary to restore or update their
-+ * configuration here and attempting to put them into D0 again may
-+ * confuse some firmware, so avoid doing that.
-+ */
-+ if (!pci_dev->skip_bus_pm || pm_suspend_via_firmware())
-+ pci_pm_default_resume_early(pci_dev);
-+
-+ pci_fixup_device(pci_fixup_resume_early, pci_dev);
-
- if (pci_has_legacy_pm_support(pci_dev))
- return pci_legacy_resume_early(dev);
-@@ -1119,6 +1141,7 @@ static int pci_pm_restore_noirq(struct d
- }
-
- pci_pm_default_resume_early(pci_dev);
-+ pci_fixup_device(pci_fixup_resume_early, pci_dev);
-
- if (pci_has_legacy_pm_support(pci_dev))
- return pci_legacy_resume_early(dev);
+++ /dev/null
-From e614522dbdc622afcfbb24432f5b2836675196aa Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 17 May 2019 11:08:50 +0200
-Subject: PCI: PM: Avoid possible suspend-to-idle issue
-
-From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-
-[ Upstream commit d491f2b75237ef37d8867830ab7fad8d9659e853 ]
-
-If a PCI driver leaves the device handled by it in D0 and calls
-pci_save_state() on the device in its ->suspend() or ->suspend_late()
-callback, it can expect the device to stay in D0 over the whole
-s2idle cycle. However, that may not be the case if there is a
-spurious wakeup while the system is suspended, because in that case
-pci_pm_suspend_noirq() will run again after pci_pm_resume_noirq()
-which calls pci_restore_state(), via pci_pm_default_resume_early(),
-so state_saved is cleared and the second iteration of
-pci_pm_suspend_noirq() will invoke pci_prepare_to_sleep() which
-may change the power state of the device.
-
-To avoid that, add a new internal flag, skip_bus_pm, that will be set
-by pci_pm_suspend_noirq() when it runs for the first time during the
-given system suspend-resume cycle if the state of the device has
-been saved already and the device is still in D0. Setting that flag
-will cause the next iterations of pci_pm_suspend_noirq() to set
-state_saved for pci_pm_resume_noirq(), so that it always restores the
-device state from the originally saved data, and avoid calling
-pci_prepare_to_sleep() for the device.
-
-Fixes: 33e4f80ee69b ("ACPI / PM: Ignore spurious SCI wakeups from suspend-to-idle")
-Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-Reviewed-by: Keith Busch <keith.busch@intel.com>
-Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/pci/pci-driver.c | 17 ++++++++++++++++-
- include/linux/pci.h | 1 +
- 2 files changed, 17 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
-index bc1ff41ce3d35..5c9873fcbd08b 100644
---- a/drivers/pci/pci-driver.c
-+++ b/drivers/pci/pci-driver.c
-@@ -736,6 +736,8 @@ static int pci_pm_suspend(struct device *dev)
- struct pci_dev *pci_dev = to_pci_dev(dev);
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-+ pci_dev->skip_bus_pm = false;
-+
- if (pci_has_legacy_pm_support(pci_dev))
- return pci_legacy_suspend(dev, PMSG_SUSPEND);
-
-@@ -829,7 +831,20 @@ static int pci_pm_suspend_noirq(struct device *dev)
- }
- }
-
-- if (!pci_dev->state_saved) {
-+ if (pci_dev->skip_bus_pm) {
-+ /*
-+ * The function is running for the second time in a row without
-+ * going through full resume, which is possible only during
-+ * suspend-to-idle in a spurious wakeup case. Moreover, the
-+ * device was originally left in D0, so its power state should
-+ * not be changed here and the device register values saved
-+ * originally should be restored on resume again.
-+ */
-+ pci_dev->state_saved = true;
-+ } else if (pci_dev->state_saved) {
-+ if (pci_dev->current_state == PCI_D0)
-+ pci_dev->skip_bus_pm = true;
-+ } else {
- pci_save_state(pci_dev);
- if (pci_power_manageable(pci_dev))
- pci_prepare_to_sleep(pci_dev);
-diff --git a/include/linux/pci.h b/include/linux/pci.h
-index b1f297f4b7b0b..94853094b6ef4 100644
---- a/include/linux/pci.h
-+++ b/include/linux/pci.h
-@@ -342,6 +342,7 @@ struct pci_dev {
- D3cold, not set for devices
- powered on/off by the
- corresponding bridge */
-+ unsigned int skip_bus_pm:1; /* Internal: Skip bus-level PM */
- unsigned int ignore_hotplug:1; /* Ignore hotplug events */
- unsigned int hotplug_user_indicators:1; /* SlotCtl indicators
- controlled exclusively by
---
-2.20.1
-
+++ /dev/null
-From 917fbb79016d9e16438b608e3d18d1512bae5ac6 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Jun 2019 23:59:45 +0200
-Subject: PCI: PM: Skip devices in D0 for suspend-to-idle
-
-From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-
-[ Upstream commit 3e26c5feed2add218046ecf91bab3cfa9bf762a6 ]
-
-Commit d491f2b75237 ("PCI: PM: Avoid possible suspend-to-idle issue")
-attempted to avoid a problem with devices whose drivers want them to
-stay in D0 over suspend-to-idle and resume, but it did not go as far
-as it should with that.
-
-Namely, first of all, the power state of a PCI bridge with a
-downstream device in D0 must be D0 (based on the PCI PM spec r1.2,
-sec 6, table 6-1, if the bridge is not in D0, there can be no PCI
-transactions on its secondary bus), but that is not actively enforced
-during system-wide PM transitions, so use the skip_bus_pm flag
-introduced by commit d491f2b75237 for that.
-
-Second, the configuration of devices left in D0 (whatever the reason)
-during suspend-to-idle need not be changed and attempting to put them
-into D0 again by force is pointless, so explicitly avoid doing that.
-
-Fixes: d491f2b75237 ("PCI: PM: Avoid possible suspend-to-idle issue")
-Reported-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
-Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/pci/pci-driver.c | 47 ++++++++++++++++++++++++++++++----------
- 1 file changed, 35 insertions(+), 12 deletions(-)
-
-diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
-index 5c9873fcbd08b..e69af9b8361dc 100644
---- a/drivers/pci/pci-driver.c
-+++ b/drivers/pci/pci-driver.c
-@@ -526,7 +526,6 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
- pci_power_up(pci_dev);
- pci_restore_state(pci_dev);
- pci_pme_restore(pci_dev);
-- pci_fixup_device(pci_fixup_resume_early, pci_dev);
- }
-
- /*
-@@ -833,18 +832,16 @@ static int pci_pm_suspend_noirq(struct device *dev)
-
- if (pci_dev->skip_bus_pm) {
- /*
-- * The function is running for the second time in a row without
-+ * Either the device is a bridge with a child in D0 below it, or
-+ * the function is running for the second time in a row without
- * going through full resume, which is possible only during
-- * suspend-to-idle in a spurious wakeup case. Moreover, the
-- * device was originally left in D0, so its power state should
-- * not be changed here and the device register values saved
-- * originally should be restored on resume again.
-+ * suspend-to-idle in a spurious wakeup case. The device should
-+ * be in D0 at this point, but if it is a bridge, it may be
-+ * necessary to save its state.
- */
-- pci_dev->state_saved = true;
-- } else if (pci_dev->state_saved) {
-- if (pci_dev->current_state == PCI_D0)
-- pci_dev->skip_bus_pm = true;
-- } else {
-+ if (!pci_dev->state_saved)
-+ pci_save_state(pci_dev);
-+ } else if (!pci_dev->state_saved) {
- pci_save_state(pci_dev);
- if (pci_power_manageable(pci_dev))
- pci_prepare_to_sleep(pci_dev);
-@@ -853,6 +850,22 @@ static int pci_pm_suspend_noirq(struct device *dev)
- dev_dbg(dev, "PCI PM: Suspend power state: %s\n",
- pci_power_name(pci_dev->current_state));
-
-+ if (pci_dev->current_state == PCI_D0) {
-+ pci_dev->skip_bus_pm = true;
-+ /*
-+ * Per PCI PM r1.2, table 6-1, a bridge must be in D0 if any
-+ * downstream device is in D0, so avoid changing the power state
-+ * of the parent bridge by setting the skip_bus_pm flag for it.
-+ */
-+ if (pci_dev->bus->self)
-+ pci_dev->bus->self->skip_bus_pm = true;
-+ }
-+
-+ if (pci_dev->skip_bus_pm && !pm_suspend_via_firmware()) {
-+ dev_dbg(dev, "PCI PM: Skipped\n");
-+ goto Fixup;
-+ }
-+
- pci_pm_set_unknown_state(pci_dev);
-
- /*
-@@ -900,7 +913,16 @@ static int pci_pm_resume_noirq(struct device *dev)
- if (dev_pm_smart_suspend_and_suspended(dev))
- pm_runtime_set_active(dev);
-
-- pci_pm_default_resume_early(pci_dev);
-+ /*
-+ * In the suspend-to-idle case, devices left in D0 during suspend will
-+ * stay in D0, so it is not necessary to restore or update their
-+ * configuration here and attempting to put them into D0 again may
-+ * confuse some firmware, so avoid doing that.
-+ */
-+ if (!pci_dev->skip_bus_pm || pm_suspend_via_firmware())
-+ pci_pm_default_resume_early(pci_dev);
-+
-+ pci_fixup_device(pci_fixup_resume_early, pci_dev);
-
- if (pci_has_legacy_pm_support(pci_dev))
- return pci_legacy_resume_early(dev);
-@@ -1201,6 +1223,7 @@ static int pci_pm_restore_noirq(struct device *dev)
- }
-
- pci_pm_default_resume_early(pci_dev);
-+ pci_fixup_device(pci_fixup_resume_early, pci_dev);
-
- if (pci_has_legacy_pm_support(pci_dev))
- return pci_legacy_resume_early(dev);
---
-2.20.1
-