diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2016-06-21 23:48:55 +0200 |
---|---|---|
committer | David Gibson <david@gibson.dropbear.id.au> | 2016-06-23 12:43:54 +1000 |
commit | 7778a575c7055276afdd01737e9d1029a65f923d (patch) | |
tree | 5e9323df82c440327f9f21d5c1c54cc041f34213 /target-ppc/excp_helper.c | |
parent | b9971cc53e31d0c6139dd74acd879d8a902577ef (diff) |
ppc: Add P7/P8 Power Management instructions
This adds the ISA 2.06 and later power management instructions
(doze, nap, sleep and rvwinkle) and associated wakeup cause testing
in LPCR
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[clg: fixed checkpatch.pl errors ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'target-ppc/excp_helper.c')
-rw-r--r-- | target-ppc/excp_helper.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 054c12de3b..533866b87b 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -101,6 +101,44 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) asrr0 = -1; asrr1 = -1; + /* check for special resume at 0x100 from doze/nap/sleep/winkle on P7/P8 */ + if (env->in_pm_state) { + env->in_pm_state = false; + + /* Pretend to be returning from doze always as we don't lose state */ + msr |= (0x1ull << (63 - 47)); + + /* Non-machine check are routed to 0x100 with a wakeup cause + * encoded in SRR1 + */ + if (excp != POWERPC_EXCP_MCHECK) { + switch (excp) { + case POWERPC_EXCP_RESET: + msr |= 0x4ull << (63 - 45); + break; + case POWERPC_EXCP_EXTERNAL: + msr |= 0x8ull << (63 - 45); + break; + case POWERPC_EXCP_DECR: + msr |= 0x6ull << (63 - 45); + break; + case POWERPC_EXCP_SDOOR: + msr |= 0x5ull << (63 - 45); + break; + case POWERPC_EXCP_SDOOR_HV: + msr |= 0x3ull << (63 - 45); + break; + case POWERPC_EXCP_HV_MAINT: + msr |= 0xaull << (63 - 45); + break; + default: + cpu_abort(cs, "Unsupported exception %d in Power Save mode\n", + excp); + } + excp = POWERPC_EXCP_RESET; + } + } + /* Exception targetting modifiers * * LPES0 is supported on POWER7/8 @@ -897,6 +935,27 @@ void helper_store_msr(CPUPPCState *env, target_ulong val) } } +#if defined(TARGET_PPC64) +void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) +{ + CPUState *cs; + + cs = CPU(ppc_env_get_cpu(env)); + cs->halted = 1; + env->in_pm_state = true; + + /* Technically, nap doesn't set EE, but if we don't set it + * then ppc_hw_interrupt() won't deliver. We could add some + * other tests there based on LPCR but it's simpler to just + * whack EE in. It will be cleared by the 0x100 at wakeup + * anyway. It will still be observable by the guest in SRR1 + * but this doesn't seem to be a problem. + */ + env->msr |= (1ull << MSR_EE); + helper_raise_exception(env, EXCP_HLT); +} +#endif /* defined(TARGET_PPC64) */ + static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) { CPUState *cs = CPU(ppc_env_get_cpu(env)); |