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
Unified · Split
| @@ -944,8 +944,8 @@ static bool acpi_dev_needs_resume(struct device *dev, struct acpi_device *adev) · 943 unmodified lines | ||
| 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) |
| @@ -1132,15 +1132,19 @@ void __init acpi_no_s4_hw_signature(void) · 1131 unmodified lines | ||
| 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) |
| @@ -1200,7 +1204,7 @@ static const struct platform_hibernation_ops acpi_hibernation_ops = { · 53 unmodified lines | ||
| 1200 | 1204 | * function is used if the pre-ACPI 2.0 suspend ordering has been |
| 1201 | 1205 | * requested. |
| 1202 | 1206 | */ |
| 1203 | −static int acpi_hibernation_begin_old(void) | |
| 1207 | +static int acpi_hibernation_begin_old(pm_message_t stage) | |
| 1204 | 1208 | { |
| 1205 | 1209 | int error; |
| 1206 | 1210 | /* |
| @@ -1211,16 +1215,21 @@ static int acpi_hibernation_begin_old(void) · 4 unmodified lines | ||
| 1211 | 1215 | acpi_sleep_tts_switch(ACPI_STATE_S4); |
| 1212 | 1216 | |
| 1213 | 1217 | error = acpi_sleep_prepare(ACPI_STATE_S4); |
| 1218 | + if (error) | |
| 1219 | + return error; | |
| 1214 | 1220 | |
| 1215 | − if (!error) { | |
| 1216 | − if (!nvs_nosave) | |
| 1217 | − error = suspend_nvs_alloc(); | |
| 1218 | − if (!error) { | |
| 1219 | − acpi_target_sleep_state = ACPI_STATE_S4; | |
| 1220 | − acpi_scan_lock_acquire(); | |
| 1221 | − } | |
| 1221 | + if (!nvs_nosave) { | |
| 1222 | + error = suspend_nvs_alloc(); | |
| 1223 | + if (error) | |
| 1224 | + return error; | |
| 1222 | 1225 | } |
| 1223 | − return error; | |
| 1226 | + | |
| 1227 | + if (stage.event == PM_EVENT_HIBERNATE) | |
| 1228 | + pm_set_suspend_via_firmware(); | |
| 1229 | + | |
| 1230 | + acpi_target_sleep_state = ACPI_STATE_S4; | |
| 1231 | + acpi_scan_lock_acquire(); | |
| 1232 | + return 0; | |
| 1224 | 1233 | } |
| 1225 | 1234 | |
| 1226 | 1235 | /* |
| @@ -733,7 +733,8 @@ static bool acpi_pci_need_resume(struct pci_dev *dev) · 732 unmodified lines | ||
| 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) |
| @@ -734,6 +734,8 @@ static int pci_pm_suspend(struct device *dev) · 733 unmodified lines | ||
| 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 | |
| @@ -827,7 +829,20 @@ static int pci_pm_suspend_noirq(struct device *dev) · 87 unmodified lines | ||
| 827 | 829 | } |
| 828 | 830 | } |
| 829 | 831 | |
| 830 | − if (!pci_dev->state_saved) { | |
| 832 | + if (pci_dev->skip_bus_pm) { | |
| 833 | + /* | |
| 834 | + * The function is running for the second time in a row without | |
| 835 | + * going through full resume, which is possible only during | |
| 836 | + * suspend-to-idle in a spurious wakeup case. Moreover, the | |
| 837 | + * device was originally left in D0, so its power state should | |
| 838 | + * not be changed here and the device register values saved | |
| 839 | + * originally should be restored on resume again. | |
| 840 | + */ | |
| 841 | + pci_dev->state_saved = true; | |
| 842 | + } else if (pci_dev->state_saved) { | |
| 843 | + if (pci_dev->current_state == PCI_D0) | |
| 844 | + pci_dev->skip_bus_pm = true; | |
| 845 | + } else { | |
| 831 | 846 | pci_save_state(pci_dev); |
| 832 | 847 | if (pci_power_manageable(pci_dev)) |
| 833 | 848 | pci_prepare_to_sleep(pci_dev); |
| @@ -344,6 +344,7 @@ struct pci_dev { · 343 unmodified lines | ||
| 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 |
| @@ -359,7 +359,7 @@ extern void mark_free_pages(struct zone *zone); · 358 unmodified lines | ||
| 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); |
| @@ -129,7 +129,7 @@ static int hibernation_test(int level) { return 0; } · 128 unmodified lines | ||
| 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,7 +542,7 @@ int hibernation_platform_enter(void) · 406 unmodified lines | ||
| 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 | |