Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'pm-5.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull power management fixes from Rafael Wysocki:
"These fix three issues in the system-wide suspend and hibernation area
related to PCI device PM handling by suspend-to-idle, device wakeup
optimizations and arbitrary differences between suspend and
hiberantion.

Specifics:

- Modify the PCI bus type's PM code to avoid putting devices left by
their drivers in D0 on purpose during suspend to idle into
low-power states as doing that may confuse the system resume
callbacks of the drivers in question (Rafael Wysocki).

- Avoid checking ACPI wakeup configuration during system-wide suspend
for suspended devices that do not use ACPI-based wakeup to allow
them to stay in suspend more often (Rafael Wysocki).

- The last phase of hibernation is analogous to system-wide suspend
also because on platforms with ACPI it passes control to the
platform firmware to complete the transision, so make it indicate
that by calling pm_set_suspend_via_firmware() to allow the drivers
that care about this to do the right thing (Rafael Wysocki)"

* tag 'pm-5.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
PCI: PM: Avoid possible suspend-to-idle issue
ACPI: PM: Call pm_set_suspend_via_firmware() during hibernation
ACPI/PCI: PM: Add missing wakeup.flags.valid checks

+48 -22
+2 -2
drivers/acpi/device_pm.c
··· 944 944 u32 sys_target = acpi_target_system_state(); 945 945 int ret, state; 946 946 947 - if (!pm_runtime_suspended(dev) || !adev || 948 - device_may_wakeup(dev) != !!adev->wakeup.prepare_count) 947 + if (!pm_runtime_suspended(dev) || !adev || (adev->wakeup.flags.valid && 948 + device_may_wakeup(dev) != !!adev->wakeup.prepare_count)) 949 949 return true; 950 950 951 951 if (sys_target == ACPI_STATE_S0)
+24 -15
drivers/acpi/sleep.c
··· 1132 1132 nosigcheck = true; 1133 1133 } 1134 1134 1135 - static int acpi_hibernation_begin(void) 1135 + static int acpi_hibernation_begin(pm_message_t stage) 1136 1136 { 1137 - int error; 1137 + if (!nvs_nosave) { 1138 + int error = suspend_nvs_alloc(); 1139 + if (error) 1140 + return error; 1141 + } 1138 1142 1139 - error = nvs_nosave ? 0 : suspend_nvs_alloc(); 1140 - if (!error) 1141 - acpi_pm_start(ACPI_STATE_S4); 1143 + if (stage.event == PM_EVENT_HIBERNATE) 1144 + pm_set_suspend_via_firmware(); 1142 1145 1143 - return error; 1146 + acpi_pm_start(ACPI_STATE_S4); 1147 + return 0; 1144 1148 } 1145 1149 1146 1150 static int acpi_hibernation_enter(void) ··· 1204 1200 * function is used if the pre-ACPI 2.0 suspend ordering has been 1205 1201 * requested. 1206 1202 */ 1207 - static int acpi_hibernation_begin_old(void) 1203 + static int acpi_hibernation_begin_old(pm_message_t stage) 1208 1204 { 1209 1205 int error; 1210 1206 /* ··· 1215 1211 acpi_sleep_tts_switch(ACPI_STATE_S4); 1216 1212 1217 1213 error = acpi_sleep_prepare(ACPI_STATE_S4); 1214 + if (error) 1215 + return error; 1218 1216 1219 - if (!error) { 1220 - if (!nvs_nosave) 1221 - error = suspend_nvs_alloc(); 1222 - if (!error) { 1223 - acpi_target_sleep_state = ACPI_STATE_S4; 1224 - acpi_scan_lock_acquire(); 1225 - } 1217 + if (!nvs_nosave) { 1218 + error = suspend_nvs_alloc(); 1219 + if (error) 1220 + return error; 1226 1221 } 1227 - return error; 1222 + 1223 + if (stage.event == PM_EVENT_HIBERNATE) 1224 + pm_set_suspend_via_firmware(); 1225 + 1226 + acpi_target_sleep_state = ACPI_STATE_S4; 1227 + acpi_scan_lock_acquire(); 1228 + return 0; 1228 1229 } 1229 1230 1230 1231 /*
+2 -1
drivers/pci/pci-acpi.c
··· 733 733 if (!adev || !acpi_device_power_manageable(adev)) 734 734 return false; 735 735 736 - if (device_may_wakeup(&dev->dev) != !!adev->wakeup.prepare_count) 736 + if (adev->wakeup.flags.valid && 737 + device_may_wakeup(&dev->dev) != !!adev->wakeup.prepare_count) 737 738 return true; 738 739 739 740 if (acpi_target_system_state() == ACPI_STATE_S0)
+16 -1
drivers/pci/pci-driver.c
··· 734 734 struct pci_dev *pci_dev = to_pci_dev(dev); 735 735 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 736 736 737 + pci_dev->skip_bus_pm = false; 738 + 737 739 if (pci_has_legacy_pm_support(pci_dev)) 738 740 return pci_legacy_suspend(dev, PMSG_SUSPEND); 739 741 ··· 829 827 } 830 828 } 831 829 832 - if (!pci_dev->state_saved) { 830 + if (pci_dev->skip_bus_pm) { 831 + /* 832 + * The function is running for the second time in a row without 833 + * going through full resume, which is possible only during 834 + * suspend-to-idle in a spurious wakeup case. Moreover, the 835 + * device was originally left in D0, so its power state should 836 + * not be changed here and the device register values saved 837 + * originally should be restored on resume again. 838 + */ 839 + pci_dev->state_saved = true; 840 + } else if (pci_dev->state_saved) { 841 + if (pci_dev->current_state == PCI_D0) 842 + pci_dev->skip_bus_pm = true; 843 + } else { 833 844 pci_save_state(pci_dev); 834 845 if (pci_power_manageable(pci_dev)) 835 846 pci_prepare_to_sleep(pci_dev);
+1
include/linux/pci.h
··· 344 344 D3cold, not set for devices 345 345 powered on/off by the 346 346 corresponding bridge */ 347 + unsigned int skip_bus_pm:1; /* Internal: Skip bus-level PM */ 347 348 unsigned int ignore_hotplug:1; /* Ignore hotplug events */ 348 349 unsigned int hotplug_user_indicators:1; /* SlotCtl indicators 349 350 controlled exclusively by
+1 -1
include/linux/suspend.h
··· 359 359 * platforms which require special recovery actions in that situation. 360 360 */ 361 361 struct platform_hibernation_ops { 362 - int (*begin)(void); 362 + int (*begin)(pm_message_t stage); 363 363 void (*end)(void); 364 364 int (*pre_snapshot)(void); 365 365 void (*finish)(void);
+2 -2
kernel/power/hibernate.c
··· 129 129 static int platform_begin(int platform_mode) 130 130 { 131 131 return (platform_mode && hibernation_ops) ? 132 - hibernation_ops->begin() : 0; 132 + hibernation_ops->begin(PMSG_FREEZE) : 0; 133 133 } 134 134 135 135 /** ··· 542 542 * hibernation_ops->finish() before saving the image, so we should let 543 543 * the firmware know that we're going to enter the sleep state after all 544 544 */ 545 - error = hibernation_ops->begin(); 545 + error = hibernation_ops->begin(PMSG_HIBERNATE); 546 546 if (error) 547 547 goto Close; 548 548