summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--asm/head.S47
-rw-r--r--core/cpu.c11
-rw-r--r--core/exceptions.c17
-rw-r--r--include/processor.h1
-rw-r--r--include/skiboot.h5
5 files changed, 65 insertions, 16 deletions
diff --git a/asm/head.S b/asm/head.S
index 2157e544..5e7dc896 100644
--- a/asm/head.S
+++ b/asm/head.S
@@ -119,6 +119,31 @@ hdat_entry:
li %r27,0
b boot_entry
+ .= 0x200
+ 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,0x200
+ b _exception
+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
+ li %r3,0x200
+ bctr
+
#define EXCEPTION(nr) \
.= nr ;\
mtsprg0 %r3 ;\
@@ -128,7 +153,6 @@ hdat_entry:
b _exception
/* More exception stubs */
- EXCEPTION(0x200)
EXCEPTION(0x300)
EXCEPTION(0x380)
EXCEPTION(0x400)
@@ -669,7 +693,8 @@ enter_p9_pm_state:
b .
/* This is a little piece of code that is copied down to
- * 0x100 for handling power management wakeups
+ * 0x100 for handling sresets and power management wakeups.
+ * This matches the 0x200 handler closely.
*/
.global reset_patch_start
reset_patch_start:
@@ -694,10 +719,12 @@ reset_patch_start:
3:
add %r3,%r30,%r3
mtctr %r3
+ li %r3,0x100
bctr
.global reset_patch_end
reset_patch_end:
+/* Wakeup vector in r3 */
reset_wakeup:
/* Get PIR */
mfspr %r31,SPR_PIR
@@ -710,14 +737,14 @@ reset_wakeup:
ld %r1,CPUTHREAD_SAVE_R1(%r13)
/* Restore more stuff */
- lwz %r3,STACK_CR(%r1)
- lwz %r4,STACK_XER(%r1)
- ld %r5,STACK_GPR0(%r1)
- ld %r6,STACK_GPR1(%r1)
- mtcr %r3
- mtxer %r4
- mtspr SPR_HSPRG0,%r5
- mtspr SPR_HSPRG1,%r6
+ lwz %r4,STACK_CR(%r1)
+ lwz %r5,STACK_XER(%r1)
+ ld %r6,STACK_GPR0(%r1)
+ ld %r7,STACK_GPR1(%r1)
+ mtcr %r4
+ mtxer %r5
+ mtspr SPR_HSPRG0,%r6
+ mtspr SPR_HSPRG1,%r7
REST_GPR(2,%r1)
REST_GPR(14,%r1)
REST_GPR(15,%r1)
diff --git a/core/cpu.c b/core/cpu.c
index 85a14783..d9d47133 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 779cd620..e15848ad 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,
diff --git a/include/processor.h b/include/processor.h
index 0a934300..edcc2106 100644
--- a/include/processor.h
+++ b/include/processor.h
@@ -92,6 +92,7 @@
#define SPR_SRR1_PM_WAKE_MASK 0x3c0000 /* PM wake reason for P8/9 */
#define SPR_SRR1_PM_WAKE_SRESET 0x100000
+#define SPR_SRR1_PM_WAKE_MCE 0x3c0000 /* Use reserved value for MCE */
/* Bits in LPCR */
diff --git a/include/skiboot.h b/include/skiboot.h
index c06146d0..6da62233 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -289,12 +289,13 @@ extern void fake_rtc_init(void);
struct stack_frame;
extern void exception_entry(struct stack_frame *stack);
extern void exception_entry_pm_sreset(void);
+extern void exception_entry_pm_mce(void);
/* Assembly in head.S */
extern void disable_machine_check(void);
extern void enable_machine_check(void);
-extern void enter_p8_pm_state(bool winkle);
-extern void enter_p9_pm_state(uint64_t psscr);
+extern unsigned int enter_p8_pm_state(bool winkle);
+extern unsigned int enter_p9_pm_state(uint64_t psscr);
extern void enter_p9_pm_lite_state(uint64_t psscr);
extern uint32_t reset_patch_start;
extern uint32_t reset_patch_end;
OpenPOWER on IntegriCloud