From: Mario Limonciello <mario.limoncie...@amd.com> Suspend and hibernate notifications are available specifically when the sequence starts and finishes. However there are no notifications during the process when tasks have been frozen.
Introduce two new events `PM_SUSPEND_POST_FREEZE` and `PM_HIBERNATE_POST_FREEZE` that drivers can subscribe to and take different actions specifically knowing userspace is frozen. Suggested-by: Alex Deucher <alexander.deuc...@amd.com> Signed-off-by: Mario Limonciello <mario.limoncie...@amd.com> --- Documentation/driver-api/pm/notifiers.rst | 19 ++++++++++++++++--- include/linux/suspend.h | 14 ++++++++------ kernel/power/hibernate.c | 9 +++++++-- kernel/power/suspend.c | 13 +++++++++---- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/Documentation/driver-api/pm/notifiers.rst b/Documentation/driver-api/pm/notifiers.rst index 186435c43b77e..6a1912fbee214 100644 --- a/Documentation/driver-api/pm/notifiers.rst +++ b/Documentation/driver-api/pm/notifiers.rst @@ -32,6 +32,18 @@ will be called upon the following events by the PM core: additional work is done between the notifiers and the invocation of PM callbacks for the "freeze" transition. +``PM_HIBERNATION_POST_FREEZE`` + The system is going to hibernate and tasks have just been frozen. + +``PM_SUSPEND_PREPARE`` + The system is going to suspend, tasks will be frozen immediately. This + is different from ``PM_HIBERNATION_PREPARE`` above, because in this case + additional work is done between the notifiers and the invocation of PM + callbacks for the "freeze" transition. + +``PM_SUSPEND_POST_FREEZE`` + The system is going to suspend and tasks have just been frozen. + ``PM_POST_HIBERNATION`` The system memory state has been restored from a hibernation image or an error occurred during hibernation. Device restore callbacks have been @@ -54,9 +66,10 @@ will be called upon the following events by the PM core: resume callbacks have been executed and tasks have been thawed. It is generally assumed that whatever the notifiers do for -``PM_HIBERNATION_PREPARE``, should be undone for ``PM_POST_HIBERNATION``. -Analogously, operations carried out for ``PM_SUSPEND_PREPARE`` should be -reversed for ``PM_POST_SUSPEND``. +``PM_HIBERNATION_PREPARE`` and ``PM_HIBERNATION_POST_FREEZE``, should be undone +for ``PM_POST_HIBERNATION``. +Analogously, operations carried out for ``PM_SUSPEND_PREPARE`` and ``PM_SUSPEND_POST_FREEZE`` +should be reversed for ``PM_POST_SUSPEND``. Moreover, if one of the notifiers fails for the ``PM_HIBERNATION_PREPARE`` or ``PM_SUSPEND_PREPARE`` event, the notifiers that have already succeeded for that diff --git a/include/linux/suspend.h b/include/linux/suspend.h index da6ebca3ff774..704e6579b0df6 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -422,12 +422,14 @@ static inline int is_hibernate_resume_dev(dev_t dev) { return 0; } #endif /* Hibernation and suspend events */ -#define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */ -#define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */ -#define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */ -#define PM_POST_SUSPEND 0x0004 /* Suspend finished */ -#define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */ -#define PM_POST_RESTORE 0x0006 /* Restore failed */ +#define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */ +#define PM_HIBERNATION_POST_FREEZE 0x0002 /* Prepared for hibernation and tasks have been frozen */ +#define PM_POST_HIBERNATION 0x0003 /* Hibernation finished */ +#define PM_SUSPEND_PREPARE 0x0004 /* Going to suspend the system */ +#define PM_SUSPEND_POST_FREEZE 0x0005 /* Prepared and tasks have been frozen */ +#define PM_POST_SUSPEND 0x0006 /* Suspend finished */ +#define PM_RESTORE_PREPARE 0x0007 /* Going to restore a saved image */ +#define PM_POST_RESTORE 0x0008 /* Restore failed */ extern struct mutex system_transition_mutex; diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index f0db9d1896e80..f896056ad2e5d 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -783,11 +783,15 @@ int hibernate(void) if (error) goto Exit; + error = pm_notifier_call_chain_robust(PM_HIBERNATION_POST_FREEZE, PM_POST_HIBERNATION); + if (error) + goto Thaw; + lock_device_hotplug(); /* Allocate memory management structures */ error = create_basic_memory_bitmaps(); if (error) - goto Thaw; + goto Unlock_hotplug; error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); if (error || freezer_test_done) @@ -833,8 +837,9 @@ int hibernate(void) Free_bitmaps: free_basic_memory_bitmaps(); - Thaw: + Unlock_hotplug: unlock_device_hotplug(); + Thaw: if (snapshot_test) { pm_pr_dbg("Checking hibernation image\n"); error = swsusp_check(false); diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 8eaec4ab121d4..bc6654e8cdc80 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -377,13 +377,18 @@ static int suspend_prepare(suspend_state_t state) trace_suspend_resume(TPS("freeze_processes"), 0, true); error = suspend_freeze_processes(); trace_suspend_resume(TPS("freeze_processes"), 0, false); - if (!error) - return 0; + if (error) + goto Restore; + error = pm_notifier_call_chain_robust(PM_SUSPEND_POST_FREEZE, PM_POST_SUSPEND); + if (error) + goto Thaw; - dpm_save_failed_step(SUSPEND_FREEZE); - pm_notifier_call_chain(PM_POST_SUSPEND); + return 0; + Thaw: + suspend_thaw_processes(); Restore: pm_restore_console(); + dpm_save_failed_step(SUSPEND_FREEZE); return error; } -- 2.43.0