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/cpu.c | |
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>
Diffstat (limited to 'core/cpu.c')
-rw-r--r-- | core/cpu.c | 35 |
1 files changed, 29 insertions, 6 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) |