summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-06-29 07:29:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-06-29 07:29:45 -0400
commit2407e486066b8ce00dabd7e2b3a2cbcc59ea6186 (patch)
tree5e4fcdb178bcb824f8b3af6742b4221c3a889935
parent01305db842e1e637944090a3de7e4259c4a3a029 (diff)
parent471a739a47aa7d582f0cdf9d392957d04632bae2 (diff)
Merge tag 'pm-5.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management fix from Rafael Wysocki: "Avoid skipping bus-level PCI power management during system resume for PCIe ports left in D0 during the preceding suspend transition on platforms where the power states of those ports can change out of the PCI layer's control" * tag 'pm-5.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: PCI: PM: Avoid skipping bus-level PM on platforms without ACPI
-rw-r--r--drivers/pci/pci-driver.c8
-rw-r--r--include/linux/suspend.h26
-rw-r--r--kernel/power/suspend.c3
3 files changed, 31 insertions, 6 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 98af9ecd4a90..ca3793002e2f 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -859,7 +859,7 @@ static int pci_pm_suspend_noirq(struct device *dev)
859 pci_dev->bus->self->skip_bus_pm = true; 859 pci_dev->bus->self->skip_bus_pm = true;
860 } 860 }
861 861
862 if (pci_dev->skip_bus_pm && !pm_suspend_via_firmware()) { 862 if (pci_dev->skip_bus_pm && pm_suspend_no_platform()) {
863 dev_dbg(dev, "PCI PM: Skipped\n"); 863 dev_dbg(dev, "PCI PM: Skipped\n");
864 goto Fixup; 864 goto Fixup;
865 } 865 }
@@ -914,10 +914,10 @@ static int pci_pm_resume_noirq(struct device *dev)
914 /* 914 /*
915 * In the suspend-to-idle case, devices left in D0 during suspend will 915 * In the suspend-to-idle case, devices left in D0 during suspend will
916 * stay in D0, so it is not necessary to restore or update their 916 * stay in D0, so it is not necessary to restore or update their
917 * configuration here and attempting to put them into D0 again may 917 * configuration here and attempting to put them into D0 again is
918 * confuse some firmware, so avoid doing that. 918 * pointless, so avoid doing that.
919 */ 919 */
920 if (!pci_dev->skip_bus_pm || pm_suspend_via_firmware()) 920 if (!(pci_dev->skip_bus_pm && pm_suspend_no_platform()))
921 pci_pm_default_resume_early(pci_dev); 921 pci_pm_default_resume_early(pci_dev);
922 922
923 pci_fixup_device(pci_fixup_resume_early, pci_dev); 923 pci_fixup_device(pci_fixup_resume_early, pci_dev);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 8594001e8be8..f0d262ad7b78 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -209,8 +209,9 @@ extern int suspend_valid_only_mem(suspend_state_t state);
209 209
210extern unsigned int pm_suspend_global_flags; 210extern unsigned int pm_suspend_global_flags;
211 211
212#define PM_SUSPEND_FLAG_FW_SUSPEND (1 << 0) 212#define PM_SUSPEND_FLAG_FW_SUSPEND BIT(0)
213#define PM_SUSPEND_FLAG_FW_RESUME (1 << 1) 213#define PM_SUSPEND_FLAG_FW_RESUME BIT(1)
214#define PM_SUSPEND_FLAG_NO_PLATFORM BIT(2)
214 215
215static inline void pm_suspend_clear_flags(void) 216static inline void pm_suspend_clear_flags(void)
216{ 217{
@@ -227,6 +228,11 @@ static inline void pm_set_resume_via_firmware(void)
227 pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME; 228 pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME;
228} 229}
229 230
231static inline void pm_set_suspend_no_platform(void)
232{
233 pm_suspend_global_flags |= PM_SUSPEND_FLAG_NO_PLATFORM;
234}
235
230/** 236/**
231 * pm_suspend_via_firmware - Check if platform firmware will suspend the system. 237 * pm_suspend_via_firmware - Check if platform firmware will suspend the system.
232 * 238 *
@@ -268,6 +274,22 @@ static inline bool pm_resume_via_firmware(void)
268 return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME); 274 return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME);
269} 275}
270 276
277/**
278 * pm_suspend_no_platform - Check if platform may change device power states.
279 *
280 * To be called during system-wide power management transitions to sleep states
281 * or during the subsequent system-wide transitions back to the working state.
282 *
283 * Return 'true' if the power states of devices remain under full control of the
284 * kernel throughout the system-wide suspend and resume cycle in progress (that
285 * is, if a device is put into a certain power state during suspend, it can be
286 * expected to remain in that state during resume).
287 */
288static inline bool pm_suspend_no_platform(void)
289{
290 return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_NO_PLATFORM);
291}
292
271/* Suspend-to-idle state machnine. */ 293/* Suspend-to-idle state machnine. */
272enum s2idle_states { 294enum s2idle_states {
273 S2IDLE_STATE_NONE, /* Not suspended/suspending. */ 295 S2IDLE_STATE_NONE, /* Not suspended/suspending. */
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 9505101ed2bc..096211299c07 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -493,6 +493,9 @@ int suspend_devices_and_enter(suspend_state_t state)
493 493
494 pm_suspend_target_state = state; 494 pm_suspend_target_state = state;
495 495
496 if (state == PM_SUSPEND_TO_IDLE)
497 pm_set_suspend_no_platform();
498
496 error = platform_suspend_begin(state); 499 error = platform_suspend_begin(state);
497 if (error) 500 if (error)
498 goto Close; 501 goto Close;