[PATCH] PM: Restrict swap use to later in the suspend sequence

Mario Limonciello superm1 at kernel.org
Sun Jun 22 18:29:58 PDT 2025



On 6/13/25 4:43 PM, Mario Limonciello wrote:
> From: Mario Limonciello <mario.limonciello at amd.com>
> 
> Currently swap is restricted before drivers have had a chance to do their
> prepare() PM callbacks. Restricting swap this early means that if a driver
> needs to evict some content from memory into sawp in it's prepare callback
> it won't be able to.
> 
> On AMD dGPUs this can lead to failed suspends under memory pressure
> situations as all VRAM must be evicted to system memory or swap.
> 
> Move the swap restriction to right after all devices have had a chance to
> do the prepare() callback.  If there is any problem with the sequence,
> restore swap in the appropriate dpm resume callbacks or error handling
> paths.
> 
> Closes: https://github.com/ROCm/ROCK-Kernel-Driver/issues/174
> Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/2362
> Signed-off-by: Mario Limonciello <mario.limonciello at amd.com>

Besides my testing for this, on the bugs two people have tested it helps 
this issue.  One of them had a hard time replying to the lore post, so 
I'll proxy the tag for them.

Tested-by: Nat Wittstock <nat at fardog.io>

> ---
>   drivers/base/power/main.c | 5 ++++-
>   include/linux/suspend.h   | 5 +++++
>   kernel/kexec_core.c       | 1 +
>   kernel/power/hibernate.c  | 3 ---
>   kernel/power/power.h      | 5 -----
>   kernel/power/suspend.c    | 3 +--
>   6 files changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> index 0215b20c5e2c8..4970a804afb6d 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -1241,6 +1241,7 @@ void dpm_complete(pm_message_t state)
>    */
>   void dpm_resume_end(pm_message_t state)
>   {
> +	pm_restore_gfp_mask();
>   	dpm_resume(state);
>   	dpm_complete(state);
>   }
> @@ -2183,8 +2184,10 @@ int dpm_suspend_start(pm_message_t state)
>   	error = dpm_prepare(state);
>   	if (error)
>   		dpm_save_failed_step(SUSPEND_PREPARE);
> -	else
> +	else {
> +		pm_restrict_gfp_mask();
>   		error = dpm_suspend(state);
> +	}
>   
>   	dpm_show_time(starttime, state, error, "start");
>   	return error;
> diff --git a/include/linux/suspend.h b/include/linux/suspend.h
> index b1c76c8f2c822..6a3f920988720 100644
> --- a/include/linux/suspend.h
> +++ b/include/linux/suspend.h
> @@ -446,6 +446,8 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
>   extern void ksys_sync_helper(void);
>   extern void pm_report_hw_sleep_time(u64 t);
>   extern void pm_report_max_hw_sleep(u64 t);
> +void pm_restrict_gfp_mask(void);
> +void pm_restore_gfp_mask(void);
>   
>   #define pm_notifier(fn, pri) {				\
>   	static struct notifier_block fn##_nb =			\
> @@ -492,6 +494,9 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
>   static inline void pm_report_hw_sleep_time(u64 t) {};
>   static inline void pm_report_max_hw_sleep(u64 t) {};
>   
> +static inline void pm_restrict_gfp_mask(void) {}
> +static inline void pm_restore_gfp_mask(void) {}
> +
>   static inline void ksys_sync_helper(void) {}
>   
>   #define pm_notifier(fn, pri)	do { (void)(fn); } while (0)
> diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
> index 9c59fa480b0b6..3a9a9f240dbc9 100644
> --- a/kernel/kexec_core.c
> +++ b/kernel/kexec_core.c
> @@ -1136,6 +1136,7 @@ int kernel_kexec(void)
>    Resume_devices:
>   		dpm_resume_end(PMSG_RESTORE);
>    Resume_console:
> +		pm_restore_gfp_mask();
>   		console_resume_all();
>   		thaw_processes();
>    Restore_console:
> diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
> index 519fb09de5e0c..9216e3b91d3b3 100644
> --- a/kernel/power/hibernate.c
> +++ b/kernel/power/hibernate.c
> @@ -423,7 +423,6 @@ int hibernation_snapshot(int platform_mode)
>   	}
>   
>   	console_suspend_all();
> -	pm_restrict_gfp_mask();
>   
>   	error = dpm_suspend(PMSG_FREEZE);
>   
> @@ -559,7 +558,6 @@ int hibernation_restore(int platform_mode)
>   
>   	pm_prepare_console();
>   	console_suspend_all();
> -	pm_restrict_gfp_mask();
>   	error = dpm_suspend_start(PMSG_QUIESCE);
>   	if (!error) {
>   		error = resume_target_kernel(platform_mode);
> @@ -571,7 +569,6 @@ int hibernation_restore(int platform_mode)
>   		BUG_ON(!error);
>   	}
>   	dpm_resume_end(PMSG_RECOVER);
> -	pm_restore_gfp_mask();
>   	console_resume_all();
>   	pm_restore_console();
>   	return error;
> diff --git a/kernel/power/power.h b/kernel/power/power.h
> index cb1d715620020..7ccd709af93f5 100644
> --- a/kernel/power/power.h
> +++ b/kernel/power/power.h
> @@ -239,11 +239,6 @@ static inline void suspend_test_finish(const char *label) {}
>   /* kernel/power/main.c */
>   extern int pm_notifier_call_chain_robust(unsigned long val_up, unsigned long val_down);
>   extern int pm_notifier_call_chain(unsigned long val);
> -void pm_restrict_gfp_mask(void);
> -void pm_restore_gfp_mask(void);
> -#else
> -static inline void pm_restrict_gfp_mask(void) {}
> -static inline void pm_restore_gfp_mask(void) {}
>   #endif
>   
>   #ifdef CONFIG_HIGHMEM
> diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
> index 76b141b9aac01..bb608b68fb301 100644
> --- a/kernel/power/suspend.c
> +++ b/kernel/power/suspend.c
> @@ -540,6 +540,7 @@ int suspend_devices_and_enter(suspend_state_t state)
>   	return error;
>   
>    Recover_platform:
> +	pm_restore_gfp_mask();
>   	platform_recover(state);
>   	goto Resume_devices;
>   }
> @@ -606,9 +607,7 @@ static int enter_state(suspend_state_t state)
>   
>   	trace_suspend_resume(TPS("suspend_enter"), state, false);
>   	pm_pr_dbg("Suspending system (%s)\n", mem_sleep_labels[state]);
> -	pm_restrict_gfp_mask();
>   	error = suspend_devices_and_enter(state);
> -	pm_restore_gfp_mask();
>   
>    Finish:
>   	events_check_enabled = false;




More information about the kexec mailing list