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 /core | |
parent | 4ebb78cffda897c4175f6659e98e6722ea60703f (diff) | |
download | talos-skiboot-8a43bf86b7d4346521bd4ebc15eb3809d3d27adb.tar.gz talos-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>
Diffstat (limited to 'core')
-rw-r--r-- | core/cpu.c | 35 | ||||
-rw-r--r-- | core/exceptions.c | 24 |
2 files changed, 49 insertions, 10 deletions
@@ -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) |