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
300 if (error || hibernation_test(TEST_PLATFORM))300 if (error || hibernation_test(TEST_PLATFORM))
301 goto Platform_finish;301 goto Platform_finish;
302 302
303 error = suspend_disable_secondary_cpus();303 error = pm_sleep_disable_secondary_cpus();
304 if (error || hibernation_test(TEST_CPUS))304 if (error || hibernation_test(TEST_CPUS))
305 goto Enable_cpus;305 goto Enable_cpus;
306 306
@@ -342,7 +342,7 @@ static int create_image(int platform_mode) · 35 unmodified lines
342 local_irq_enable();342 local_irq_enable();
343 343
344 Enable_cpus:344 Enable_cpus:
345 suspend_enable_secondary_cpus();345 pm_sleep_enable_secondary_cpus();
346 346
347 /* Allow architectures to do nosmt-specific post-resume dances */347 /* Allow architectures to do nosmt-specific post-resume dances */
348 if (!in_suspend)348 if (!in_suspend)
@@ -466,6 +466,8 @@ static int resume_target_kernel(bool platform_mode) · 117 unmodified lines
466 if (error)466 if (error)
467 goto Cleanup;467 goto Cleanup;
468 468
469 cpuidle_pause();
470
469 error = hibernate_resume_nonboot_cpu_disable();471 error = hibernate_resume_nonboot_cpu_disable();
470 if (error)472 if (error)
471 goto Enable_cpus;473 goto Enable_cpus;
@@ -509,7 +511,7 @@ static int resume_target_kernel(bool platform_mode) · 37 unmodified lines
509 local_irq_enable();511 local_irq_enable();
510 512
511 Enable_cpus:513 Enable_cpus:
512 suspend_enable_secondary_cpus();514 pm_sleep_enable_secondary_cpus();
513 515
514 Cleanup:516 Cleanup:
515 platform_restore_cleanup(platform_mode);517 platform_restore_cleanup(platform_mode);
@@ -587,7 +589,7 @@ int hibernation_platform_enter(void) · 71 unmodified lines
587 if (error)589 if (error)
588 goto Platform_finish;590 goto Platform_finish;
589 591
590 error = suspend_disable_secondary_cpus();592 error = pm_sleep_disable_secondary_cpus();
591 if (error)593 if (error)
592 goto Enable_cpus;594 goto Enable_cpus;
593 595
@@ -609,7 +611,7 @@ int hibernation_platform_enter(void) · 15 unmodified lines
609 local_irq_enable();611 local_irq_enable();
610 612
611 Enable_cpus:613 Enable_cpus:
612 suspend_enable_secondary_cpus();614 pm_sleep_enable_secondary_cpus();
613 615
614 Platform_finish:616 Platform_finish:
615 hibernation_ops->finish();617 hibernation_ops->finish();
kernel/power/power.h+14−0
@@ -4,6 +4,8 @@ · 3 unmodified lines
4#include <linux/utsname.h>4#include <linux/utsname.h>
5#include <linux/freezer.h>5#include <linux/freezer.h>
6#include <linux/compiler.h>6#include <linux/compiler.h>
7#include <linux/cpu.h>
8#include <linux/cpuidle.h>
7 9
8struct swsusp_info {10struct swsusp_info {
9 struct new_utsname uts;11 struct new_utsname uts;
@@ -310,3 +312,15 @@ extern int pm_wake_lock(const char *buf); · 300 unmodified lines
310extern int pm_wake_unlock(const char *buf);312extern int pm_wake_unlock(const char *buf);
311 313
312#endif /* !CONFIG_PM_WAKELOCKS */314#endif /* !CONFIG_PM_WAKELOCKS */
315
316static inline int pm_sleep_disable_secondary_cpus(void)
317{
318 cpuidle_pause();
319 return suspend_disable_secondary_cpus();
320}
321
322static 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
403 if (error)403 if (error)
404 goto Devices_early_resume;404 goto Devices_early_resume;
405 405
406 if (state != PM_SUSPEND_TO_IDLE)
407 cpuidle_pause();
408
409 error = dpm_suspend_noirq(PMSG_SUSPEND);406 error = dpm_suspend_noirq(PMSG_SUSPEND);
410 if (error) {407 if (error) {
411 pr_err("noirq suspend of devices failed\n");408 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
423 goto Platform_wake;420 goto Platform_wake;
424 }421 }
425 422
426 error = suspend_disable_secondary_cpus();423 error = pm_sleep_disable_secondary_cpus();
427 if (error || suspend_test(TEST_CPUS))424 if (error || suspend_test(TEST_CPUS))
428 goto Enable_cpus;425 goto Enable_cpus;
429 426
@@ -453,16 +450,13 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) · 23 unmodified lines
453 BUG_ON(irqs_disabled());450 BUG_ON(irqs_disabled());
454 451
455 Enable_cpus:452 Enable_cpus:
456 suspend_enable_secondary_cpus();453 pm_sleep_enable_secondary_cpus();
457 454
458 Platform_wake:455 Platform_wake:
459 platform_resume_noirq(state);456 platform_resume_noirq(state);
460 dpm_resume_noirq(PMSG_RESUME);457 dpm_resume_noirq(PMSG_RESUME);
461 458
462 Platform_early_resume:459 Platform_early_resume:
463 if (state != PM_SUSPEND_TO_IDLE)
464 cpuidle_resume();
465
466 platform_resume_early(state);460 platform_resume_early(state);
467 461
468 Devices_early_resume:462 Devices_early_resume: