aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/excp_helper.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2016-06-21 23:48:55 +0200
committerDavid Gibson <david@gibson.dropbear.id.au>2016-06-23 12:43:54 +1000
commit7778a575c7055276afdd01737e9d1029a65f923d (patch)
tree5e9323df82c440327f9f21d5c1c54cc041f34213 /target-ppc/excp_helper.c
parentb9971cc53e31d0c6139dd74acd879d8a902577ef (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.c59
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));