During a normal successful hibernate sequence devices will go through
the freeze() callbacks create an image, go through the thaw() callbacks,
and poweroff() callbacks.

During a successful hibernate sequence some device drivers may want to
skip the thaw() callbacks.  This confuses the PM core though because it
thinks the device is no longer suspended.

To accommodate drivers that want to do this, introduce a new is_frozen
bit that the driver can set and manage.  From the driver perspective
any thaw() or restore() callbacks that are being skipped should set
is_frozen and return an error code.  The PM core will then put the
device back into the list of devices to resume for any aborted hibernate.

Tested-by: Muhammad Usama Anjum <[email protected]>
Signed-off-by: Mario Limonciello (AMD) <[email protected]>
---
v2:
 * add tag
 * fix lkp robot issue
 * rebase on linux-pm/bleeding-edge
---
 Documentation/driver-api/pm/devices.rst | 8 ++++++++
 drivers/base/power/main.c               | 7 +++++++
 include/linux/pm.h                      | 3 +++
 3 files changed, 18 insertions(+)

diff --git a/Documentation/driver-api/pm/devices.rst 
b/Documentation/driver-api/pm/devices.rst
index 36d5c9c9fd113..55c6337271086 100644
--- a/Documentation/driver-api/pm/devices.rst
+++ b/Documentation/driver-api/pm/devices.rst
@@ -578,6 +578,14 @@ should already have been stored during the ``freeze``, 
``freeze_late`` or
 the entire system, so it is not necessary for the callback to put the device in
 a low-power state.
 
+Skipping thaw phase
+-------------------
+In some rare situations, it may be desirable to skip the thaw phases
+(``thaw_noirq``, ``thaw_early``, ``thaw``) of a device entirely.  This can be
+achieved by a device driver returning an error code from any of it's thaw
+callbacks but also setting dev->power.is_frozen to true.  This indicates to the
+PM core that the device is still in the frozen state.  The PM core will 
consider
+this when resuming the device in later phases such as `restore` or `poweroff`.
 
 Leaving Hibernation
 -------------------
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 7a8807ec9a5d0..c5a192fc04344 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1110,6 +1110,13 @@ static void device_resume(struct device *dev, 
pm_message_t state, bool async)
 
  End:
        error = dpm_run_callback(callback, dev, state, info);
+#ifdef CONFIG_HIBERNATE_CALLBACKS
+       /* device manages frozen state */
+       if (error && dev->power.is_frozen) {
+               dev->power.is_suspended = true;
+               error = 0;
+       }
+#endif
 
        device_unlock(dev);
        dpm_watchdog_clear(&wd);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index a72e42eec1303..852902fc72158 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -689,6 +689,9 @@ struct dev_pm_info {
 #else
        bool                    should_wakeup:1;
 #endif
+#ifdef CONFIG_HIBERNATE_CALLBACKS
+       bool                    is_frozen:1;    /* Owned by the driver */
+#endif
 #ifdef CONFIG_PM
        struct hrtimer          suspend_timer;
        u64                     timer_expires;
-- 
2.43.0

Reply via email to