History

PM: sleep: Pause cpuidle later and resume it earlier during system transitions

Commit 8651f97bd951 ("PM / cpuidle: System resume hang fix with cpuidle") that introduced cpuidle pausing during system suspend did that to work around a platform firmware issue causing systems to hang during resume if CPUs were allowed to enter idle states in the system suspend and resume code paths. However, pausing cpuidle before the last phase of suspending devices is the source of an otherwise arbitrary difference between the suspend-to-idle path and other system suspend variants, so it is cleaner to do that later, before taking secondary CPUs offline (it is still safer to take secondary CPUs offline with cpuidle paused, though). Modify the code accordingly, but in order to avoid code duplication, introduce new wrapper functions, pm_sleep_disable_secondary_cpus() and pm_sleep_enable_secondary_cpus(), to combine cpuidle_pause() and cpuidle_resume(), respectively, with the handling of secondary CPUs during system-wide transitions to sleep states.

Rafael J. Wysocki committed 5 years ago

Commit 23f62d71 parent 8d898354 files · +24 −20Browse files

Showing the changes to kernel (3 of 4 files). Show all

Unified · Split

3 files
  1. kernel/power/hibernate.c +7 −5
  2. kernel/power/power.h +14 −0
  3. kernel/power/suspend.c +2 −8
kernel/power/hibernate.c+7−5
@@ -300,7 +300,7 @@ static int create_image(int platform_mode) · 299 unmodified lines
300300 if (error || hibernation_test(TEST_PLATFORM))
301301 goto Platform_finish;
302302
303− error = suspend_disable_secondary_cpus();
303+ error = pm_sleep_disable_secondary_cpus();
304304 if (error || hibernation_test(TEST_CPUS))
305305 goto Enable_cpus;
306306
@@ -342,7 +342,7 @@ static int create_image(int platform_mode) · 35 unmodified lines
342342 local_irq_enable();
343343
344344 Enable_cpus:
345− suspend_enable_secondary_cpus();
345+ pm_sleep_enable_secondary_cpus();
346346
347347 /* Allow architectures to do nosmt-specific post-resume dances */
348348 if (!in_suspend)
@@ -466,6 +466,8 @@ static int resume_target_kernel(bool platform_mode) · 117 unmodified lines
466466 if (error)
467467 goto Cleanup;
468468
469+ cpuidle_pause();
470+
469471 error = hibernate_resume_nonboot_cpu_disable();
470472 if (error)
471473 goto Enable_cpus;
@@ -509,7 +511,7 @@ static int resume_target_kernel(bool platform_mode) · 37 unmodified lines
509511 local_irq_enable();
510512
511513 Enable_cpus:
512− suspend_enable_secondary_cpus();
514+ pm_sleep_enable_secondary_cpus();
513515
514516 Cleanup:
515517 platform_restore_cleanup(platform_mode);
@@ -587,7 +589,7 @@ int hibernation_platform_enter(void) · 71 unmodified lines
587589 if (error)
588590 goto Platform_finish;
589591
590− error = suspend_disable_secondary_cpus();
592+ error = pm_sleep_disable_secondary_cpus();
591593 if (error)
592594 goto Enable_cpus;
593595
@@ -609,7 +611,7 @@ int hibernation_platform_enter(void) · 15 unmodified lines
609611 local_irq_enable();
610612
611613 Enable_cpus:
612− suspend_enable_secondary_cpus();
614+ pm_sleep_enable_secondary_cpus();
613615
614616 Platform_finish:
615617 hibernation_ops->finish();
kernel/power/power.h+14−0
@@ -4,6 +4,8 @@ · 3 unmodified lines
44 #include <linux/utsname.h>
55 #include <linux/freezer.h>
66 #include <linux/compiler.h>
7+#include <linux/cpu.h>
8+#include <linux/cpuidle.h>
79
810 struct swsusp_info {
911 struct new_utsname uts;
@@ -310,3 +312,15 @@ extern int pm_wake_lock(const char *buf); · 300 unmodified lines
310312 extern int pm_wake_unlock(const char *buf);
311313
312314 #endif /* !CONFIG_PM_WAKELOCKS */
315+
316+static inline int pm_sleep_disable_secondary_cpus(void)
317+{
318+ cpuidle_pause();
319+ return suspend_disable_secondary_cpus();
320+}
321+
322+static inline void pm_sleep_enable_secondary_cpus(void)
323+{
324+ suspend_enable_secondary_cpus();
325+ cpuidle_resume();
326+}
kernel/power/suspend.c+2−8
@@ -403,9 +403,6 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) · 402 unmodified lines
403403 if (error)
404404 goto Devices_early_resume;
405405
406− if (state != PM_SUSPEND_TO_IDLE)
407− cpuidle_pause();
408−
409406 error = dpm_suspend_noirq(PMSG_SUSPEND);
410407 if (error) {
411408 pr_err("noirq suspend of devices failed\n");
@@ -423,7 +420,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) · 11 unmodified lines
423420 goto Platform_wake;
424421 }
425422
426− error = suspend_disable_secondary_cpus();
423+ error = pm_sleep_disable_secondary_cpus();
427424 if (error || suspend_test(TEST_CPUS))
428425 goto Enable_cpus;
429426
@@ -453,16 +450,13 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) · 23 unmodified lines
453450 BUG_ON(irqs_disabled());
454451
455452 Enable_cpus:
456− suspend_enable_secondary_cpus();
453+ pm_sleep_enable_secondary_cpus();
457454
458455 Platform_wake:
459456 platform_resume_noirq(state);
460457 dpm_resume_noirq(PMSG_RESUME);
461458
462459 Platform_early_resume:
463− if (state != PM_SUSPEND_TO_IDLE)
464− cpuidle_resume();
465−
466460 platform_resume_early(state);
467461
468462 Devices_early_resume: