aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2019-01-08 00:04:28 +1000
committerStewart Smith <stewart@linux.ibm.com>2019-02-13 14:36:44 +1100
commit5d86cebd53683d055f039dbecf3f74fb0084ea83 (patch)
treec9c4c9e9844643ca4f73ca686d1c4ec05d2287ee /core
parent22524e9017445a08d63733ae5a8c75d9126bdb28 (diff)
downloadskiboot-5d86cebd53683d055f039dbecf3f74fb0084ea83.zip
skiboot-5d86cebd53683d055f039dbecf3f74fb0084ea83.tar.gz
skiboot-5d86cebd53683d055f039dbecf3f74fb0084ea83.tar.bz2
core/exceptions: implement support for MCE interrupts in powersave
The ISA specifies that MCE interrupts in power saving modes will enter at 0x200 with powersave bits in SRR1 set. This is not currently supported properly, the MCE will just happen like a normal interrupt, but GPRs could be lost, which would lead to crashes (e.g., r1, r2, r13 etc). So check the power save bits similarly to the sreset vector, and handle this properly. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
Diffstat (limited to 'core')
-rw-r--r--core/cpu.c11
-rw-r--r--core/exceptions.c17
2 files changed, 24 insertions, 4 deletions
diff --git a/core/cpu.c b/core/cpu.c
index 85a1478..d9d4713 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -426,8 +426,7 @@ static unsigned int cpu_idle_p8(enum cpu_wake_cause wake_on)
isync();
/* Enter nap */
- enter_p8_pm_state(false);
- vec = 0x100;
+ vec = enter_p8_pm_state(false);
skip_sleep:
/* Restore */
@@ -486,8 +485,7 @@ static unsigned int cpu_idle_p9(enum cpu_wake_cause wake_on)
/* PSSCR SD=0 ESL=1 EC=1 PSSL=0 TR=3 MTL=0 RL=1 */
psscr = PPC_BIT(42) | PPC_BIT(43) |
PPC_BITMASK(54, 55) | PPC_BIT(63);
- enter_p9_pm_state(psscr);
- vec = 0x100;
+ vec = enter_p9_pm_state(psscr);
} else {
/* stop with EC=0 (resumes) which does not require sreset. */
/* PSSCR SD=0 ESL=0 EC=0 PSSL=0 TR=3 MTL=0 RL=1 */
@@ -535,6 +533,11 @@ static void cpu_idle_pm(enum cpu_wake_cause wake_on)
break;
}
mtmsrd(MSR_RI, 1);
+
+ } else if (vec == 0x200) {
+ exception_entry_pm_mce();
+ enable_machine_check();
+ mtmsrd(MSR_RI, 1);
}
}
diff --git a/core/exceptions.c b/core/exceptions.c
index 779cd62..e15848a 100644
--- a/core/exceptions.c
+++ b/core/exceptions.c
@@ -127,6 +127,23 @@ void exception_entry_pm_sreset(void)
backtrace();
}
+void __noreturn exception_entry_pm_mce(void)
+{
+ const size_t max = 320;
+ char buf[max];
+ size_t l;
+
+ prerror("***********************************************\n");
+ l = 0;
+ l += snprintf(buf + l, max - l,
+ "Fatal MCE in sleep");
+ prerror("%s\n", buf);
+ prerror("SRR0 : "REG" SRR1 : "REG"\n",
+ (uint64_t)mfspr(SPR_SRR0), (uint64_t)mfspr(SPR_SRR1));
+ prerror("DSISR: "REG32" DAR : "REG"\n",
+ (uint32_t)mfspr(SPR_DSISR), (uint64_t)mfspr(SPR_DAR));
+ abort();
+}
static int64_t opal_register_exc_handler(uint64_t opal_exception __unused,
uint64_t handler_address __unused,