diff options
author | Nicholas Piggin <npiggin@gmail.com> | 2019-01-08 00:04:26 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.ibm.com> | 2019-02-13 14:36:44 +1100 |
commit | 8a43bf86b7d4346521bd4ebc15eb3809d3d27adb (patch) | |
tree | d17ac162d4037ecff73d27477ffc61945a37ac4e | |
parent | 4ebb78cffda897c4175f6659e98e6722ea60703f (diff) | |
download | skiboot-8a43bf86b7d4346521bd4ebc15eb3809d3d27adb.zip skiboot-8a43bf86b7d4346521bd4ebc15eb3809d3d27adb.tar.gz skiboot-8a43bf86b7d4346521bd4ebc15eb3809d3d27adb.tar.bz2 |
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.S | 20 | ||||
-rw-r--r-- | core/cpu.c | 35 | ||||
-rw-r--r-- | core/exceptions.c | 24 | ||||
-rw-r--r-- | include/processor.h | 4 | ||||
-rw-r--r-- | include/skiboot.h | 5 |
5 files changed, 77 insertions, 11 deletions
@@ -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) @@ -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 f05bcfb..1c29173 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 f6b227d..0a93430 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 96caa27..0f6a855 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); |