Message ID | 20190128094625.4428-11-clg@kaod.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | ppc: support for the baremetal XIVE interrupt controller (POWER9) | expand |
On Mon, Jan 28, 2019 at 10:46:16AM +0100, Cédric Le Goater wrote: > From: Benjamin Herrenschmidt <benh@kernel.crashing.org> > > 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 <benh@kernel.crashing.org> > Signed-off-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: David Gibson <david@gibson.dropbear.id.au> > --- > 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)) {
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)) {