diff options
-rw-r--r-- | asm/head.S | 47 | ||||
-rw-r--r-- | core/cpu.c | 11 | ||||
-rw-r--r-- | core/exceptions.c | 17 | ||||
-rw-r--r-- | include/processor.h | 1 | ||||
-rw-r--r-- | include/skiboot.h | 5 |
5 files changed, 65 insertions, 16 deletions
@@ -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) @@ -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, diff --git a/include/processor.h b/include/processor.h index 0a93430..edcc210 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 c06146d..6da6223 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; |