summaryrefslogtreecommitdiffstats
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
parent4ebb78cffda897c4175f6659e98e6722ea60703f (diff)
downloadblackbird-skiboot-8a43bf86b7d4346521bd4ebc15eb3809d3d27adb.tar.gz
blackbird-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>
-rw-r--r--asm/head.S20
-rw-r--r--core/cpu.c35
-rw-r--r--core/exceptions.c24
-rw-r--r--include/processor.h4
-rw-r--r--include/skiboot.h5
5 files changed, 77 insertions, 11 deletions
diff --git a/asm/head.S b/asm/head.S
index 29560c38..27f104dc 100644
--- a/asm/head.S
+++ b/asm/head.S
@@ -107,6 +107,7 @@ hir_trigger:
* used for recovering from rvw or nap mode
*/
. = 0x100
+sreset_vector:
/* BML entry, load up r3 with device tree location */
li %r3, 0
oris %r3, %r3, 0xa
@@ -668,8 +669,25 @@ enter_p9_pm_state:
*/
.global reset_patch_start
reset_patch_start:
+ mtsprg0 %r3
+ mtsprg1 %r4
+ mfspr %r3,SPR_SRR1
+ mfcr %r4
+ rldicl. %r3,%r3,48,62
+ bne 1f /* powersave wakeup (CFAR not required) */
+ mtcr %r4
+ mfspr %r3,SPR_CFAR
+ li %r4,0x100
+ b _exception + (reset_patch_start - sreset_vector)
+1:
LOAD_IMM64(%r30, SKIBOOT_BASE)
+ cmpdi %r3,0x1
+ bne 2f /* state loss */
+ LOAD_IMM32(%r3, reset_resume - __head)
+ b 3f
+2:
LOAD_IMM32(%r3, reset_wakeup - __head)
+3:
add %r3,%r30,%r3
mtctr %r3
bctr
@@ -715,7 +733,7 @@ reset_wakeup:
REST_GPR(29,%r1)
REST_GPR(30,%r1)
REST_GPR(31,%r1)
-
+reset_resume:
/* Get LR back, pop stack and return */
addi %r1,%r1,STACK_FRAMESIZE
ld %r0,16(%r1)
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)
diff --git a/include/processor.h b/include/processor.h
index f6b227d3..0a934300 100644
--- a/include/processor.h
+++ b/include/processor.h
@@ -88,6 +88,10 @@
#define SPR_HID5 0x3f6
#define SPR_PIR 0x3ff /* RO: Processor Identification */
+/* Bits in SRR1 */
+
+#define SPR_SRR1_PM_WAKE_MASK 0x3c0000 /* PM wake reason for P8/9 */
+#define SPR_SRR1_PM_WAKE_SRESET 0x100000
/* Bits in LPCR */
diff --git a/include/skiboot.h b/include/skiboot.h
index 96caa271..0f6a8552 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -285,6 +285,11 @@ extern void fast_sleep_exit(void);
/* Fallback fake RTC */
extern void fake_rtc_init(void);
+/* Exceptions */
+struct stack_frame;
+extern void __noreturn exception_entry(struct stack_frame *stack);
+extern void __noreturn exception_entry_pm_sreset(void);
+
/* Assembly in head.S */
extern void disable_machine_check(void);
extern void enable_machine_check(void);
OpenPOWER on IntegriCloud