Skip to contentSkip to conversation

Fixes for hybrid sleep

PATCH In review Mario Limonciello (AMD) 2 participants 5 messages Sep 25, 2025

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

v3 cover Fixes for hybrid sleep

From: Mario Limonciello <[email protected]>

Ionut Nechita reported recently a hibernate failure, but in debugging the issue it's actually not a hibernate failure; but a hybrid sleep failure.

Multiple changes related to the change of when swap is disabled in the suspend sequence contribute to the failure. See the individual patches for details.

As it touches two subsystems it either needs to go through linux-pm or drm. Patch 3 has an Ack from Alex, this should merge through linux-pm.
---
v3:
* Push all calls for gfp mask changes into power_down()
Mario Limonciello (AMD) (3):
PM: hibernate: Fix hybrid-sleep
PM: hibernate: Add pm_hibernation_mode_is_suspend() drm/amd: Fix hybrid sleep

 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c |  2 +-
 include/linux/suspend.h                 |  2 ++
 kernel/power/hibernate.c                | 14 ++++++++++++++
 3 files changed, 17 insertions(+), 1 deletion(-)
Signature · 1 line
2.51.0
#1 lore raw

PATCH v3 1/3 PM: hibernate: Fix hybrid-sleep

Hybrid sleep will hibernate the system followed by running through the suspend routine. Since both the hibernate and the suspend routine will call pm_restrict_gfp_mask(), pm_restore_gfp_mask() must be called before starting the suspend sequence.

Add an explicit call to pm_restore_gfp_mask() to power_down() before the suspend sequence starts. Add an extra call for pm_restrict_gfp_mask() when exiting suspend so that the pm_restore_gfp_mask() call in hibernate() is balanced.

---
 kernel/power/hibernate.c | 3 +++
 1 file changed, 3 insertions(+)
kernel/power/hibernate.c +3 -0
index 2f66ab453823..3c6b110ee9b0 100644
@@ -695,12 +695,15 @@ static void power_down(void)
 
 #ifdef CONFIG_SUSPEND
 	if (hibernation_mode == HIBERNATION_SUSPEND) {
+		pm_restore_gfp_mask();
 		error = suspend_devices_and_enter(mem_sleep_current);
 		if (error) {
 			hibernation_mode = hibernation_ops ?
 						HIBERNATION_PLATFORM :
 						HIBERNATION_SHUTDOWN;
 		} else {
+			pm_restrict_gfp_mask();
+
 			/* Restore swap signature. */
 			error = swsusp_unmark();
 			if (error)
Signature · 1 line
2.51.0
#2 lore raw

PATCH v3 2/3 PM: hibernate: Add pm_hibernation_mode_is_suspend()

In reply to Mario Limonciello (AMD)

Some drivers have different flows for hibernation and suspend. If the driver opportunistically will skip thaw() then it needs a hint to know what is happening after the hibernate.

Introduce a new symbol pm_hibernation_mode_is_suspend() that drivers can call to determine if suspending the system for this purpose.

---
 include/linux/suspend.h  |  2 ++
 kernel/power/hibernate.c | 11 +++++++++++
 2 files changed, 13 insertions(+)
include/linux/suspend.h +2 -0
index 317ae31e89b3..0664c685f0b2 100644
@@ -276,6 +276,7 @@ extern void arch_suspend_enable_irqs(void);
 
 extern int pm_suspend(suspend_state_t state);
 extern bool sync_on_suspend_enabled;
+bool pm_hibernation_mode_is_suspend(void);
 #else /* !CONFIG_SUSPEND */
 #define suspend_valid_only_mem	NULL
 
@@ -288,6 +289,7 @@ static inline bool pm_suspend_via_firmware(void) { return false; }
 static inline bool pm_resume_via_firmware(void) { return false; }
 static inline bool pm_suspend_no_platform(void) { return false; }
 static inline bool pm_suspend_default_s2idle(void) { return false; }
+static inline bool pm_hibernation_mode_is_suspend(void) { return false; }
 
 static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}
 static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
kernel/power/hibernate.c +11 -0
index 3c6b110ee9b0..989d76a911de 100644
@@ -80,6 +80,17 @@ static const struct platform_hibernation_ops *hibernation_ops;
 
 static atomic_t hibernate_atomic = ATOMIC_INIT(1);
 
+#ifdef CONFIG_SUSPEND
+/**
+ * pm_hibernation_mode_is_suspend - Check if hibernation has been set to suspend
+ */
+bool pm_hibernation_mode_is_suspend(void)
+{
+	return hibernation_mode == HIBERNATION_SUSPEND;
+}
+EXPORT_SYMBOL_GPL(pm_hibernation_mode_is_suspend);
+#endif
+
 bool hibernate_acquire(void)
 {
 	return atomic_add_unless(&hibernate_atomic, -1, 0);
Signature · 1 line
2.51.0
#3 lore raw

PATCH v3 3/3 drm/amd: Fix hybrid sleep

In reply to Mario Limonciello (AMD)

[Why]
commit 530694f54dd5e ("drm/amdgpu: do not resume device in thaw for normal hibernation") optimized the flow for systems that are going into S4 where the power would be turned off. Basically the thaw() callback wouldn't resume the device if the hibernation image was successfully created since the system would be powered off.

This however isn't the correct flow for a system entering into s0i3 after the hibernation image is created. Some of the amdgpu callbacks have different behavior depending upon the intended state of the suspend.

[How]
Use pm_hibernation_mode_is_suspend() as an input to decide whether to run resume during thaw() callback.

---
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +1 -1
index 395c6be901ce..dcea66aadfa3 100644
@@ -2665,7 +2665,7 @@ static int amdgpu_pmops_thaw(struct device *dev)
 	struct drm_device *drm_dev = dev_get_drvdata(dev);
 
 	/* do not resume device if it's normal hibernation */
-	if (!pm_hibernate_is_recovering())
+	if (!pm_hibernate_is_recovering() && !pm_hibernation_mode_is_suspend())
 		return 0;
 
 	return amdgpu_device_resume(drm_dev, true);
Signature · 1 line
2.51.0
#4 lore raw
In reply to Mario Limonciello (AMD)
Quoted 24 lines · Mario Limonciello (AMD)

From: Mario Limonciello <[email protected]>

Ionut Nechita reported recently a hibernate failure, but in debugging the issue it's actually not a hibernate failure; but a hybrid sleep failure.

Multiple changes related to the change of when swap is disabled in the suspend sequence contribute to the failure. See the individual patches for details.

As it touches two subsystems it either needs to go through linux-pm or drm. Patch 3 has an Ack from Alex, this should merge through linux-pm.
---
v3:
* Push all calls for gfp mask changes into power_down()
Mario Limonciello (AMD) (3):
PM: hibernate: Fix hybrid-sleep
PM: hibernate: Add pm_hibernation_mode_is_suspend() drm/amd: Fix hybrid sleep

Quoted 6 lines
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c |  2 +-
 include/linux/suspend.h                 |  2 ++
 kernel/power/hibernate.c                | 14 ++++++++++++++
 3 files changed, 17 insertions(+), 1 deletion(-)

--

All applied as 6.18 material, thanks!