kernel-ark/kernel/power
Rafael J. Wysocki 406f992e4a x86 / hibernate: Use hlt_play_dead() when resuming from hibernation
On Intel hardware, native_play_dead() uses mwait_play_dead() by
default and only falls back to the other methods if that fails.
That also happens during resume from hibernation, when the restore
(boot) kernel runs disable_nonboot_cpus() to take all of the CPUs
except for the boot one offline.

However, that is problematic, because the address passed to
__monitor() in mwait_play_dead() is likely to be written to in the
last phase of hibernate image restoration and that causes the "dead"
CPU to start executing instructions again.  Unfortunately, the page
containing the address in that CPU's instruction pointer may not be
valid any more at that point.

First, that page may have been overwritten with image kernel memory
contents already, so the instructions the CPU attempts to execute may
simply be invalid.  Second, the page tables previously used by that
CPU may have been overwritten by image kernel memory contents, so the
address in its instruction pointer is impossible to resolve then.

A report from Varun Koyyalagunta and investigation carried out by
Chen Yu show that the latter sometimes happens in practice.

To prevent it from happening, temporarily change the smp_ops.play_dead
pointer during resume from hibernation so that it points to a special
"play dead" routine which uses hlt_play_dead() and avoids the
inadvertent "revivals" of "dead" CPUs this way.

A slightly unpleasant consequence of this change is that if the
system is hibernated with one or more CPUs offline, it will generally
draw more power after resume than it did before hibernation, because
the physical state entered by CPUs via hlt_play_dead() is higher-power
than the mwait_play_dead() one in the majority of cases.  It is
possible to work around this, but it is unclear how much of a problem
that's going to be in practice, so the workaround will be implemented
later if it turns out to be necessary.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=106371
Reported-by: Varun Koyyalagunta <cpudebug@centtech.com>
Original-by: Chen Yu <yu.c.chen@intel.com>
Tested-by: Chen Yu <yu.c.chen@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Ingo Molnar <mingo@kernel.org>
2016-07-15 22:42:48 +02:00
..
autosleep.c PM / Sleep: avoid 'autosleep' in shutdown progress 2013-07-15 01:31:37 +02:00
console.c PM / sleep: Make pm_prepare_console() return void 2016-06-15 01:26:04 +02:00
hibernate.c x86 / hibernate: Use hlt_play_dead() when resuming from hibernation 2016-07-15 22:42:48 +02:00
Kconfig PM: APM_EMULATION does not depend on PM 2016-01-27 23:20:14 +01:00
main.c PM / sleep: make PM notifiers called symmetrically 2016-06-28 00:38:55 +02:00
Makefile PM / Hibernate: Don't let kasan instrument snapshot.c 2016-06-14 00:38:56 +02:00
power.h x86 / hibernate: Use hlt_play_dead() when resuming from hibernation 2016-07-15 22:42:48 +02:00
poweroff.c power/sysrq: fix inconstistent help message of sysrq key 2013-04-30 17:04:10 -07:00
process.c Merge back earlier suspend/hibernation changes for v4.8. 2016-07-08 23:14:17 +02:00
qos.c PM / QoS: Add debugfs support to view the list of constraints 2015-01-23 22:16:21 +01:00
snapshot.c PM / hibernate: Image data protection during restoration 2016-07-10 02:12:10 +02:00
suspend_test.c PM / sleep: Enhance test_suspend option with repeat capability 2014-09-09 01:48:02 +02:00
suspend.c PM / sleep: make PM notifiers called symmetrically 2016-06-28 00:38:55 +02:00
swap.c PM / Hibernate: Call flush_icache_range() on pages restored in-place 2016-04-28 13:35:48 +01:00
user.c PM / sleep: make PM notifiers called symmetrically 2016-06-28 00:38:55 +02:00
wakelock.c PM / autosleep: Use workqueue for user space wakeup sources garbage collector 2015-07-14 21:04:48 +02:00