On Mon, Jan 28, 2019 at 10:46:16AM +0100, Cédric Le Goater wrote: > From: Benjamin Herrenschmidt > > STOP must act differently based on PSSCR:EC on POWER9. When set, it > acts like the P7/P8 power management instructions and wake up at 0x100 > based on the wakeup conditions in LPCR. > > When PSSCR:EC is clear however it will wakeup at the next instruction > after STOP (if EE is clear) or take the corresponding interrupts (if > EE is set). > > Signed-off-by: Benjamin Herrenschmidt > Signed-off-by: Cédric Le Goater Reviewed-by: David Gibson > --- > target/ppc/cpu-qom.h | 1 + > target/ppc/cpu.h | 12 +++++++++--- > target/ppc/excp_helper.c | 8 ++++++-- > target/ppc/translate.c | 13 ++++++++++++- > target/ppc/translate_init.inc.c | 7 +++++++ > 5 files changed, 35 insertions(+), 6 deletions(-) > > diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h > index 4ea67692e2a6..7c54093a7122 100644 > --- a/target/ppc/cpu-qom.h > +++ b/target/ppc/cpu-qom.h > @@ -122,6 +122,7 @@ typedef enum { > PPC_PM_NAP, > PPC_PM_SLEEP, > PPC_PM_RVWINKLE, > + PPC_PM_STOP, > } powerpc_pm_insn_t; > > /*****************************************************************************/ > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h > index 2c22292e7f41..7ff65c804b57 100644 > --- a/target/ppc/cpu.h > +++ b/target/ppc/cpu.h > @@ -413,6 +413,10 @@ struct ppc_slb_t { > #define LPCR_HVICE PPC_BIT(62) /* HV Virtualisation Int Enable */ > #define LPCR_HDICE PPC_BIT(63) > > +/* PSSCR bits */ > +#define PSSCR_ESL PPC_BIT(42) /* Enable State Loss */ > +#define PSSCR_EC PPC_BIT(43) /* Exit Criterion */ > + > #define msr_sf ((env->msr >> MSR_SF) & 1) > #define msr_isf ((env->msr >> MSR_ISF) & 1) > #define msr_shv ((env->msr >> MSR_SHV) & 1) > @@ -1109,9 +1113,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. > + > + /* > + * On P7/P8/P9, 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 > diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c > index 7c7c8d1b9dc6..97503193ef43 100644 > --- a/target/ppc/excp_helper.c > +++ b/target/ppc/excp_helper.c > @@ -97,7 +97,10 @@ 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 */ > + /* > + * check for special resume at 0x100 from doze/nap/sleep/winkle on > + * P7/P8/P9 > + */ > if (env->in_pm_state) { > env->in_pm_state = false; > > @@ -960,7 +963,8 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) > env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); > > /* Condition for waking up at 0x100 */ > - env->in_pm_state = true; > + env->in_pm_state = (insn != PPC_PM_STOP) || > + (env->spr[SPR_PSSCR] & PSSCR_EC); > } > #endif /* defined(TARGET_PPC64) */ > > diff --git a/target/ppc/translate.c b/target/ppc/translate.c > index 55281a8975e0..07bedbb8f1ce 100644 > --- a/target/ppc/translate.c > +++ b/target/ppc/translate.c > @@ -3594,7 +3594,18 @@ static void gen_nap(DisasContext *ctx) > > static void gen_stop(DisasContext *ctx) > { > - gen_nap(ctx); > +#if defined(CONFIG_USER_ONLY) > + GEN_PRIV; > +#else > + TCGv_i32 t; > + > + CHK_HV; > + t = tcg_const_i32(PPC_PM_STOP); > + gen_helper_pminsn(cpu_env, t); > + tcg_temp_free_i32(t); > + /* Stop translation, as the CPU is supposed to sleep from now */ > + gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); > +#endif /* defined(CONFIG_USER_ONLY) */ > } > > static void gen_sleep(DisasContext *ctx) > diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c > index 59e0b8676236..076d94f45755 100644 > --- a/target/ppc/translate_init.inc.c > +++ b/target/ppc/translate_init.inc.c > @@ -8801,9 +8801,16 @@ static bool cpu_has_work_POWER9(CPUState *cs) > CPUPPCState *env = &cpu->env; > > if (cs->halted) { > + uint64_t psscr = env->spr[SPR_PSSCR]; > + > if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { > return false; > } > + > + /* If EC is clear, just return true on any pending interrupt */ > + if (!(psscr & PSSCR_EC)) { > + return true; > + } > /* External Exception */ > if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && > (env->spr[SPR_LPCR] & LPCR_EEE)) { -- 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