summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2019-01-08 00:04:26 +1000
committerStewart Smith <stewart@linux.ibm.com>2019-02-13 14:36:44 +1100
commit8a43bf86b7d4346521bd4ebc15eb3809d3d27adb (patch)
treed17ac162d4037ecff73d27477ffc61945a37ac4e /core
parent4ebb78cffda897c4175f6659e98e6722ea60703f (diff)
downloadtalos-skiboot-8a43bf86b7d4346521bd4ebc15eb3809d3d27adb.tar.gz
talos-skiboot-8a43bf86b7d4346521bd4ebc15eb3809d3d27adb.zip
core/exceptions: implement an exception handler for non-powersave sresets
Detect non-powersave sresets and send them to the normal exception handler which prints registers and stack. 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.c35
-rw-r--r--core/exceptions.c24
2 files changed, 49 insertions, 10 deletions
diff --git a/core/cpu.c b/core/cpu.c
index ad64b6e6..50f399c2 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -380,14 +380,15 @@ enum cpu_wake_cause {
cpu_wake_on_dec,
};
-static void cpu_idle_p8(enum cpu_wake_cause wake_on)
+static unsigned int cpu_idle_p8(enum cpu_wake_cause wake_on)
{
uint64_t lpcr = mfspr(SPR_LPCR) & ~SPR_LPCR_P8_PECE;
struct cpu_thread *cpu = this_cpu();
+ unsigned int vec = 0;
if (!pm_enabled) {
prlog_once(PR_DEBUG, "cpu_idle_p8 called pm disabled\n");
- return;
+ return vec;
}
/* Clean up ICP, be ready for IPIs */
@@ -426,6 +427,7 @@ static void cpu_idle_p8(enum cpu_wake_cause wake_on)
/* Enter nap */
enter_p8_pm_state(false);
+ vec = 0x100;
skip_sleep:
/* Restore */
@@ -433,17 +435,20 @@ skip_sleep:
cpu->in_idle = false;
cpu->in_sleep = false;
reset_cpu_icp();
+
+ return vec;
}
-static void cpu_idle_p9(enum cpu_wake_cause wake_on)
+static unsigned int cpu_idle_p9(enum cpu_wake_cause wake_on)
{
uint64_t lpcr = mfspr(SPR_LPCR) & ~SPR_LPCR_P9_PECE;
uint64_t psscr;
struct cpu_thread *cpu = this_cpu();
+ unsigned int vec = 0;
if (!pm_enabled) {
prlog_once(PR_DEBUG, "cpu_idle_p9 called pm disabled\n");
- return;
+ return vec;
}
/* Synchronize with wakers */
@@ -482,6 +487,7 @@ static void cpu_idle_p9(enum cpu_wake_cause wake_on)
psscr = PPC_BIT(42) | PPC_BIT(43) |
PPC_BITMASK(54, 55) | PPC_BIT(63);
enter_p9_pm_state(psscr);
+ vec = 0x100;
} 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 */
@@ -497,21 +503,38 @@ static void cpu_idle_p9(enum cpu_wake_cause wake_on)
sync();
cpu->in_idle = false;
cpu->in_sleep = false;
+
+ return vec;
}
static void cpu_idle_pm(enum cpu_wake_cause wake_on)
{
+ unsigned int vec;
+
switch(proc_gen) {
case proc_gen_p8:
- cpu_idle_p8(wake_on);
+ vec = cpu_idle_p8(wake_on);
break;
case proc_gen_p9:
- cpu_idle_p9(wake_on);
+ vec = cpu_idle_p9(wake_on);
break;
default:
+ vec = 0;
prlog_once(PR_DEBUG, "cpu_idle_pm called with bad processor type\n");
break;
}
+
+ if (vec == 0x100) {
+ unsigned long srr1 = mfspr(SPR_SRR1);
+
+ switch (srr1 & SPR_SRR1_PM_WAKE_MASK) {
+ case SPR_SRR1_PM_WAKE_SRESET:
+ exception_entry_pm_sreset();
+ break;
+ default:
+ break;
+ }
+ }
}
void cpu_idle_job(void)
diff --git a/core/exceptions.c b/core/exceptions.c
index f05bcfb9..1c291735 100644
--- a/core/exceptions.c
+++ b/core/exceptions.c
@@ -39,9 +39,6 @@ static void dump_regs(struct stack_frame *stack)
i, stack->gpr[i], i + 16, stack->gpr[i + 16]);
}
-/* Called from head.S, thus no prototype */
-void __noreturn exception_entry(struct stack_frame *stack);
-
void __noreturn exception_entry(struct stack_frame *stack)
{
uint64_t nip;
@@ -71,7 +68,10 @@ void __noreturn exception_entry(struct stack_frame *stack)
prerror("***********************************************\n");
l = 0;
- if (stack->type == 0x200) {
+ if (stack->type == 0x100) {
+ l += snprintf(buf + l, max - l,
+ "Fatal System Reset at "REG" ", nip);
+ } else if (stack->type == 0x200) {
l += snprintf(buf + l, max - l,
"Fatal MCE at "REG" ", nip);
} else {
@@ -86,6 +86,22 @@ void __noreturn exception_entry(struct stack_frame *stack)
abort();
}
+void __noreturn exception_entry_pm_sreset(void)
+{
+ const size_t max = 320;
+ char buf[max];
+ size_t l;
+
+ prerror("***********************************************\n");
+ l = 0;
+ l += snprintf(buf + l, max - l,
+ "Fatal System Reset in sleep");
+ prerror("%s\n", buf);
+
+ abort();
+}
+
+
static int64_t opal_register_exc_handler(uint64_t opal_exception __unused,
uint64_t handler_address __unused,
uint64_t glue_cache_line __unused)
OpenPOWER on IntegriCloud