[Skiboot] [PATCH 14/16] core/exceptions: implement an exception handler for non-powersave sresets

Nicholas Piggin npiggin at gmail.com
Tue Jan 8 01:04:26 AEDT 2019


Detect non-powersave sresets and send them to the normal exception
handler which prints registers and stack.

Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
 asm/head.S          | 20 +++++++++++++++++++-
 core/cpu.c          | 35 +++++++++++++++++++++++++++++------
 core/exceptions.c   | 24 ++++++++++++++++++++----
 include/processor.h |  4 ++++
 include/skiboot.h   |  5 +++++
 5 files changed, 77 insertions(+), 11 deletions(-)

diff --git a/asm/head.S b/asm/head.S
index 0f2eccc39..85ca57cb7 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
@@ -666,8 +667,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
@@ -713,7 +731,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 e7ffe3003..4820beb31 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 f05bcfb9e..1c2917357 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 6b262b45e..70991dfb0 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 96caa2714..0f6a85520 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);
-- 
2.18.0



More information about the Skiboot mailing list