From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37348) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Zzi00-0000jJ-Uh for qemu-devel@nongnu.org; Fri, 20 Nov 2015 04:28:59 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Zzhzy-0002g1-Ev for qemu-devel@nongnu.org; Fri, 20 Nov 2015 04:28:56 -0500 Date: Fri, 20 Nov 2015 19:06:49 +1100 From: David Gibson Message-ID: <20151120080649.GF7118@voom.redhat.com> References: <1447201710-10229-1-git-send-email-benh@kernel.crashing.org> <1447201710-10229-26-git-send-email-benh@kernel.crashing.org> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="s5/bjXLgkIwAv6Hi" Content-Disposition: inline In-Reply-To: <1447201710-10229-26-git-send-email-benh@kernel.crashing.org> Subject: Re: [Qemu-devel] [Qemu-ppc] [PATCH 25/77] ppc: Add P7/P8 Power Management instructions List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Benjamin Herrenschmidt Cc: qemu-ppc@nongnu.org, qemu-devel@nongnu.org --s5/bjXLgkIwAv6Hi Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Wed, Nov 11, 2015 at 11:27:38AM +1100, Benjamin Herrenschmidt wrote: > This adds the ISA 2.06 and later power management instructions > (doze, nap, sleep and rvwinkle) and associated wakeup cause testing > in LPCR >=20 > Signed-off-by: Benjamin Herrenschmidt Looks fine, though I haven't checked against the ISA in detail. > --- > target-ppc/cpu.h | 26 ++++++++++++- > target-ppc/excp_helper.c | 59 +++++++++++++++++++++++++++++ > target-ppc/helper.h | 1 + > target-ppc/translate.c | 66 ++++++++++++++++++++++++++++++++ > target-ppc/translate_init.c | 92 +++++++++++++++++++++++++++++++++++++++= +++++- > 5 files changed, 241 insertions(+), 3 deletions(-) >=20 > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h > index 3d22a4f..a7236cf 100644 > --- a/target-ppc/cpu.h > +++ b/target-ppc/cpu.h > @@ -300,6 +300,15 @@ enum { > }; > =20 > /***********************************************************************= ******/ > +/* PM instructions */ > +typedef enum { > + PPC_PM_DOZE, > + PPC_PM_NAP, > + PPC_PM_SLEEP, > + PPC_PM_RVWINKLE, > +} powerpc_pm_insn_t; > + > +/***********************************************************************= ******/ > /* Input pins model = */ > typedef enum powerpc_input_t powerpc_input_t; > enum powerpc_input_t { > @@ -490,6 +499,14 @@ struct ppc_slb_t { > #define LPCR_LPES1 (1ull << (63-61)) > #define LPCR_AIL_SHIFT (63-40) /* Alternate interrupt location */ > #define LPCR_AIL (3ull << LPCR_AIL_SHIFT) > +#define LPCR_P7_PECE0 (1ull << (63-49)) > +#define LPCR_P7_PECE1 (1ull << (63-50)) > +#define LPCR_P7_PECE2 (1ull << (63-51)) > +#define LPCR_P8_PECE0 (1ull << (63-47)) > +#define LPCR_P8_PECE1 (1ull << (63-48)) > +#define LPCR_P8_PECE2 (1ull << (63-49)) > +#define LPCR_P8_PECE3 (1ull << (63-50)) > +#define LPCR_P8_PECE4 (1ull << (63-51)) > =20 > #define msr_sf ((env->msr >> MSR_SF) & 1) > #define msr_isf ((env->msr >> MSR_ISF) & 1) > @@ -1126,6 +1143,11 @@ struct CPUPPCState { > * instructions and SPRs are diallowed if MSR:HV is 0 > */ > bool has_hv_mode; > + /* On P7/P8, set when in PM state, we need to handle resume > + * in a special way (such as routing some resume causes to > + * 0x100), so flag this here. > + */ > + bool in_pm_state; > #endif > =20 > /* Those resources are used only during code translation */ > @@ -2069,6 +2091,8 @@ enum { > PPC2_FP_CVT_S64 =3D 0x0000000000010000ULL, > /* Transactional Memory (ISA 2.07, Book II) = */ > PPC2_TM =3D 0x0000000000020000ULL, > + /* Server PM instructgions (ISA 2.06, Book III) = */ > + PPC2_PM_ISA206 =3D 0x0000000000040000ULL, > =20 > #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DB= RX | \ > PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ > @@ -2076,7 +2100,7 @@ enum { > PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \ > PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \ > PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \ > - PPC2_FP_CVT_S64 | PPC2_TM) > + PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206) > }; > =20 > /***********************************************************************= ******/ > diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c > index 80a70f4..3f77df7 100644 > --- a/target-ppc/excp_helper.c > +++ b/target-ppc/excp_helper.c > @@ -100,6 +100,44 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int= excp_model, int excp) > asrr0 =3D -1; > asrr1 =3D -1; > =20 > + /* check for special resume at 0x100 from doze/nap/sleep/winkle on P= 7/P8 */ > + if (env->in_pm_state) { > + env->in_pm_state =3D false; > + > + /* Pretend to be returning from doze always as we don't lose sta= te */ > + msr |=3D (0x1ull << (63 - 47)); > + > + /* Non-machine check are routed to 0x100 with a wakeup cause > + * encoded in SRR1 > + */ > + if (excp !=3D POWERPC_EXCP_MCHECK) { > + switch(excp) { > + case POWERPC_EXCP_RESET: > + msr |=3D 0x4ull << (63-45); > + break; > + case POWERPC_EXCP_EXTERNAL: > + msr |=3D 0x8ull << (63-45); > + break; > + case POWERPC_EXCP_DECR: > + msr |=3D 0x6ull << (63-45); > + break; > + case POWERPC_EXCP_SDOOR: > + msr |=3D 0x5ull << (63-45); > + break; > + case POWERPC_EXCP_SDOOR_HV: > + msr |=3D 0x3ull << (63-45); > + break; > + case POWERPC_EXCP_HV_MAINT: > + msr |=3D 0xaull << (63-45); > + break; > + default: > + cpu_abort(cs, "Unsupported exception %d in Power Save mo= de\n", > + excp); > + } > + excp =3D POWERPC_EXCP_RESET; > + } > + } > + > /* Exception targetting modifiers > * > * LPES0 is supported on POWER7/8 > @@ -898,6 +936,27 @@ void helper_store_msr(CPUPPCState *env, target_ulong= val) > } > } > =20 > +#if defined(TARGET_PPC64) > +void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) > +{ > + CPUState *cs; > + > + cs =3D CPU(ppc_env_get_cpu(env)); > + cs->halted =3D 1; > + env->in_pm_state =3D 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 |=3D (1ull << MSR_EE); > + helper_raise_exception(env, EXCP_HLT); > +} > +#endif /* defined(TARGET_PPC64) */ > + > static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulo= ng msr, > target_ulong msrm, int keep_msrh) > { > diff --git a/target-ppc/helper.h b/target-ppc/helper.h > index ff2d50b..8292dd8 100644 > --- a/target-ppc/helper.h > +++ b/target-ppc/helper.h > @@ -13,6 +13,7 @@ DEF_HELPER_1(rfci, void, env) > DEF_HELPER_1(rfdi, void, env) > DEF_HELPER_1(rfmci, void, env) > #if defined(TARGET_PPC64) > +DEF_HELPER_2(pminsn, void, env, i32) > DEF_HELPER_1(rfid, void, env) > DEF_HELPER_1(hrfid, void, env) > #endif > diff --git a/target-ppc/translate.c b/target-ppc/translate.c > index ac62942..f76a0c3 100644 > --- a/target-ppc/translate.c > +++ b/target-ppc/translate.c > @@ -3567,6 +3567,68 @@ static void gen_wait(DisasContext *ctx) > gen_exception_err(ctx, EXCP_HLT, 1); > } > =20 > +#if defined(TARGET_PPC64) > +static void gen_doze(DisasContext *ctx) > +{ > +#if defined(CONFIG_USER_ONLY) > + GEN_PRIV; > +#else > + TCGv_i32 t; > + > + CHK_HV; > + t =3D tcg_const_i32(PPC_PM_DOZE); > + gen_helper_pminsn(cpu_env, t); > + tcg_temp_free_i32(t); > + gen_stop_exception(ctx); > +#endif /* defined(CONFIG_USER_ONLY) */ > +} > + > +static void gen_nap(DisasContext *ctx) > +{ > +#if defined(CONFIG_USER_ONLY) > + GEN_PRIV; > +#else > + TCGv_i32 t; > + > + CHK_HV; > + t =3D tcg_const_i32(PPC_PM_NAP); > + gen_helper_pminsn(cpu_env, t); > + tcg_temp_free_i32(t); > + gen_stop_exception(ctx); > +#endif /* defined(CONFIG_USER_ONLY) */ > +} > + > +static void gen_sleep(DisasContext *ctx) > +{ > +#if defined(CONFIG_USER_ONLY) > + GEN_PRIV; > +#else > + TCGv_i32 t; > + > + CHK_HV; > + t =3D tcg_const_i32(PPC_PM_SLEEP); > + gen_helper_pminsn(cpu_env, t); > + tcg_temp_free_i32(t); > + gen_stop_exception(ctx); > +#endif /* defined(CONFIG_USER_ONLY) */ > +} > + > +static void gen_rvwinkle(DisasContext *ctx) > +{ > +#if defined(CONFIG_USER_ONLY) > + GEN_PRIV; > +#else > + TCGv_i32 t; > + > + CHK_HV; > + t =3D tcg_const_i32(PPC_PM_RVWINKLE); > + gen_helper_pminsn(cpu_env, t); > + tcg_temp_free_i32(t); > + gen_stop_exception(ctx); > +#endif /* defined(CONFIG_USER_ONLY) */ > +} > +#endif /* #if defined(TARGET_PPC64) */ > + > /*** Floating-point load = ***/ > #define GEN_LDF(name, ldop, opc, type) = \ > static void glue(gen_, name)(DisasContext *ctx) = \ > @@ -9828,6 +9890,10 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PP= C_INTEGER), > GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW), > #if defined(TARGET_PPC64) > GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B), > +GEN_HANDLER_E(doze, 0x13, 0x12, 0x0c, 0x03FFF801, PPC_NONE, PPC2_PM_ISA2= 06), > +GEN_HANDLER_E(nap, 0x13, 0x12, 0x0d, 0x03FFF801, PPC_NONE, PPC2_PM_ISA20= 6), > +GEN_HANDLER_E(sleep, 0x13, 0x12, 0x0e, 0x03FFF801, PPC_NONE, PPC2_PM_ISA= 206), > +GEN_HANDLER_E(rvwinkle, 0x13, 0x12, 0x0f, 0x03FFF801, PPC_NONE, PPC2_PM_= ISA206), > GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H), > #endif > GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW), > diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c > index 8d82bc8..8a1ce85 100644 > --- a/target-ppc/translate_init.c > +++ b/target-ppc/translate_init.c > @@ -8297,10 +8297,45 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass = *pcc, uint32_t pvr) > return false; > } > =20 > +static bool cpu_has_work_POWER7(CPUState *cs) > +{ > + PowerPCCPU *cpu =3D POWERPC_CPU(cs); > + CPUPPCState *env =3D &cpu->env; > + > + if (cs->halted) { > + if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { > + return false; > + } > + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && > + (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { > + return true; > + } > + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && > + (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) { > + return true; > + } > + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK)) && > + (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { > + return true; > + } > + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HMI)) && > + (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { > + return true; > + } > + if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { > + return true; > + } > + return false; > + } else { > + return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); > + } > +} > + > POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) > { > DeviceClass *dc =3D DEVICE_CLASS(oc); > PowerPCCPUClass *pcc =3D POWERPC_CPU_CLASS(oc); > + CPUClass *cc =3D CPU_CLASS(oc); > =20 > dc->fw_name =3D "PowerPC,POWER7"; > dc->desc =3D "POWER7"; > @@ -8309,6 +8344,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) > pcc->pcr_mask =3D PCR_COMPAT_2_05 | PCR_COMPAT_2_06; > pcc->init_proc =3D init_proc_POWER7; > pcc->check_pow =3D check_pow_nocheck; > + cc->has_work =3D cpu_has_work_POWER7; > pcc->insns_flags =3D PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MF= TB | > PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | > PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | > @@ -8325,7 +8361,8 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) > pcc->insns_flags2 =3D PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 | > PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | > PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | > - PPC2_FP_TST_ISA206 | PPC2_FP_CVT_S64; > + PPC2_FP_TST_ISA206 | PPC2_FP_CVT_S64 | > + PPC2_PM_ISA206; > pcc->msr_mask =3D (1ull << MSR_SF) | > (1ull << MSR_VR) | > (1ull << MSR_VSX) | > @@ -8375,10 +8412,53 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass = *pcc, uint32_t pvr) > return false; > } > =20 > +static bool cpu_has_work_POWER8(CPUState *cs) > +{ > + PowerPCCPU *cpu =3D POWERPC_CPU(cs); > + CPUPPCState *env =3D &cpu->env; > + > + if (cs->halted) { > + if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { > + return false; > + } > + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && > + (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { > + return true; > + } > + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && > + (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) { > + return true; > + } > + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK)) && > + (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { > + return true; > + } > + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HMI)) && > + (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { > + return true; > + } > + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) && > + (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) { > + return true; > + } > + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) = && > + (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) { > + return true; > + } > + if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { > + return true; > + } > + return false; > + } else { > + return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); > + } > +} > + > POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) > { > DeviceClass *dc =3D DEVICE_CLASS(oc); > PowerPCCPUClass *pcc =3D POWERPC_CPU_CLASS(oc); > + CPUClass *cc =3D CPU_CLASS(oc); > =20 > dc->fw_name =3D "PowerPC,POWER8"; > dc->desc =3D "POWER8"; > @@ -8387,6 +8467,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) > pcc->pcr_mask =3D PCR_COMPAT_2_05 | PCR_COMPAT_2_06; > pcc->init_proc =3D init_proc_POWER8; > pcc->check_pow =3D check_pow_nocheck; > + cc->has_work =3D cpu_has_work_POWER8; > pcc->insns_flags =3D PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MF= TB | > PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | > PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | > @@ -8406,7 +8487,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) > PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | > PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | > PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | > - PPC2_TM; > + PPC2_TM | PPC2_PM_ISA206; > pcc->msr_mask =3D (1ull << MSR_SF) | > (1ull << MSR_SHV) | > (1ull << MSR_TM) | > @@ -8464,6 +8545,13 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu) > lpcr->default_value &=3D ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_K= BV); > lpcr->default_value |=3D LPCR_LPES0 | LPCR_LPES1; > =20 > + /* P7 and P8 has slightly different PECE bits, mostly because P8 adds > + * bit 47 and 48 which are reserved on P7. Here we set them all, whi= ch > + * will work as expected for both implementations > + */ > + lpcr->default_value |=3D LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PEC= E2 | > + LPCR_P8_PECE3 | LPCR_P8_PECE4; > + > /* We should be followed by a CPU reset but update the active value > * just in case... > */ --=20 David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson --s5/bjXLgkIwAv6Hi Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAEBAgAGBQJWTtSZAAoJEGw4ysog2bOSCggP/0/iEvbv6dVn9gwCv52D/mDi K5kJwFeecExYaBwGfgMlPm1Ms6RtqlbgBrEiHwe+H4owiUwK+Uj3h0ybcBhcm5LM l4XCEqQqJTMQNDM3fzb3jeeLfhLP0ip6C0/8xM89GGNZVSwbIaMx7I3ifppfFOdx huiDM8/kdKvwTaQdXKr95V+e4ocZmU2k6VfQOOTCxqpkuN8Rd6NZdWlslPDZtSLT Ei8i8C3abMt5j2LIJKJ9QmsyKbaT4rRGYUgW5nKgLm59wTsRpli0kSEegKn1aLVV Q9fzyr3Z54cqM5uRu/3a7d2h9pup9KC7Hpvvgs30O8r/6lcar5ZY5ocmdGJlbcib oBgWXcmAOZJIXeOf6SFYJJDRzU8HnCfoqVYiKYMdAkpJVOhlOKHaqMH4xg6AzwXQ LIzpwZHKU0KQ6NI580kFXIzoV7WTLaFsKScPATAMOeO9tPnbwLOv2+s4JMIxeuEm x1kGxNP79Up53I0uXfin/nnIt7T8aT6xLG5gxKzRx/Bz4PN3kMtBg35RqW5qebY4 A1WtfU8f0cTkKyQoG6AjTYULefEt5r0QCjueMCwBd7iEd962x2HeNod3rqPHOm9L f1i/32i9vomLnzGjdZrMwBf720winbz3Zbb3s2bPrPr9ocFxmRBb70tW88g729ps c2SooMGJWuGQ/0/1/Ye8 =L2Bs -----END PGP SIGNATURE----- --s5/bjXLgkIwAv6Hi--