aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2017-06-27 17:30:01 -0500
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-06-30 14:43:29 +1000
commitd98c46b55801015a887fa27752db421280a48f7b (patch)
tree115ec6a266fbe3c731ea250d84bcde678e089a23 /core
parentbdf6c2a69eae55536aa2e0cff937387e5e151c00 (diff)
downloadskiboot-d98c46b55801015a887fa27752db421280a48f7b.zip
skiboot-d98c46b55801015a887fa27752db421280a48f7b.tar.gz
skiboot-d98c46b55801015a887fa27752db421280a48f7b.tar.bz2
cpu: Cleanup AMR and IAMR when re-initializing CPUs
There's a bug in current Linux kernels leaving crap in those registers accross kexec and not sanitizing them on boot. This breaks kexec under some circumstances (such as booting a hash kernel from a radix one on P9 DD2.0). The long term fix is in Linux, but this workaround is a reasonable way of "sanitizing" those SPRs when Linux calls opal_reinit_cpus() and shouldn't have adverse effects. We could also use that same mechanism to cleanup other things as well such as restoring some other SPRs to their default value in the future. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'core')
-rw-r--r--core/cpu.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/core/cpu.c b/core/cpu.c
index 75c7008..a0c395f 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -1077,6 +1077,27 @@ void cpu_set_radix_mode(void)
cpu_change_all_hid0(&req);
}
+static void cpu_cleanup_one(void *param __unused)
+{
+ mtspr(SPR_AMR, 0);
+ mtspr(SPR_IAMR, 0);
+}
+
+static int64_t cpu_cleanup_all(void)
+{
+ struct cpu_thread *cpu;
+
+ for_each_available_cpu(cpu) {
+ if (cpu == this_cpu()) {
+ cpu_cleanup_one(NULL);
+ continue;
+ }
+ cpu_wait_job(cpu_queue_job(cpu, "cpu_cleanup",
+ cpu_cleanup_one, NULL), true);
+ }
+ return OPAL_SUCCESS;
+}
+
void cpu_fast_reboot_complete(void)
{
/* Fast reboot will have cleared HID0:HILE */
@@ -1132,6 +1153,14 @@ static int64_t opal_reinit_cpus(uint64_t flags)
this_cpu()->in_reinit = true;
unlock(&reinit_lock);
+ /*
+ * This cleans up a few things left over by Linux
+ * that can cause problems in cases such as radix->hash
+ * transitions. Ideally Linux should do it but doing it
+ * here works around existing broken kernels.
+ */
+ cpu_cleanup_all();
+
/* If HILE change via HID0 is supported ... */
if (hile_supported &&
(flags & (OPAL_REINIT_CPUS_HILE_BE |