From: Daniel Henrique Barboza <danielhb413@gmail.com>
To: Nicholas Piggin <npiggin@gmail.com>, qemu-ppc@nongnu.org
Cc: qemu-devel@nongnu.org,
Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Subject: Re: [PATCH v4] target/ppc: Fix PMU hflags calculation
Date: Thu, 1 Jun 2023 17:30:58 -0300 [thread overview]
Message-ID: <749b68b2-20fa-8a8d-2473-daac5f092151@gmail.com> (raw)
In-Reply-To: <20230530130447.372617-1-npiggin@gmail.com>
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
and queued. Thanks,
Daniel
On 5/30/23 10:04, Nicholas Piggin wrote:
> Some of the PMU hflags bits can go out of synch, for example a store to
> MMCR0 with PMCjCE=1 fails to update hflags correctly and results in
> hflags mismatch:
>
> qemu: fatal: TCG hflags mismatch (current:0x2408003d rebuilt:0x240a003d)
>
> This can be reproduced by running perf on a recent machine.
>
> Some of the fragility here is the duplication of PMU hflags calculations.
> This change consolidates that in a single place to update pmu-related
> hflags, to be called after a well defined state changes.
>
> The post-load PMU update is pulled out of the MSR update because it does
> not depend on the MSR value.
>
> Fixes: 8b3d1c49a9f0 ("target/ppc: Add new PMC HFLAGS")
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
> This is a significant rework from v3, which missed a couple of hflags.
> I think it's more robust.
>
> Question came up whether we should rearm overflow timers in something
> like cpu post load, but that's for a later patch.
>
> This is probably a stable candidate but I will wait for upstream
> before ccing.
>
> Thanks,
> Nick
> ---
>
> target/ppc/cpu_init.c | 2 +-
> target/ppc/helper_regs.c | 73 ++++++++++++++++++++++++++++++----------
> target/ppc/helper_regs.h | 1 +
> target/ppc/machine.c | 8 ++---
> target/ppc/power8-pmu.c | 38 ++++++++++++---------
> target/ppc/power8-pmu.h | 4 +--
> 6 files changed, 85 insertions(+), 41 deletions(-)
>
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index 05bf73296b..398f2d9966 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -7083,7 +7083,7 @@ static void ppc_cpu_reset_hold(Object *obj)
> if (env->mmu_model != POWERPC_MMU_REAL) {
> ppc_tlb_invalidate_all(env);
> }
> - pmu_update_summaries(env);
> + pmu_mmcr01_updated(env);
> }
>
> /* clean any pending stop state */
> diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
> index fb351c303f..bc7e9d7eda 100644
> --- a/target/ppc/helper_regs.c
> +++ b/target/ppc/helper_regs.c
> @@ -47,6 +47,48 @@ void hreg_swap_gpr_tgpr(CPUPPCState *env)
> env->tgpr[3] = tmp;
> }
>
> +static uint32_t hreg_compute_pmu_hflags_value(CPUPPCState *env)
> +{
> + uint32_t hflags = 0;
> +
> +#if defined(TARGET_PPC64)
> + if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC0) {
> + hflags |= 1 << HFLAGS_PMCC0;
> + }
> + if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) {
> + hflags |= 1 << HFLAGS_PMCC1;
> + }
> + if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE) {
> + hflags |= 1 << HFLAGS_PMCJCE;
> + }
> +
> +#ifndef CONFIG_USER_ONLY
> + if (env->pmc_ins_cnt) {
> + hflags |= 1 << HFLAGS_INSN_CNT;
> + }
> + if (env->pmc_ins_cnt & 0x1e) {
> + hflags |= 1 << HFLAGS_PMC_OTHER;
> + }
> +#endif
> +#endif
> +
> + return hflags;
> +}
> +
> +/* Mask of all PMU hflags */
> +static uint32_t hreg_compute_pmu_hflags_mask(CPUPPCState *env)
> +{
> + uint32_t hflags_mask = 0;
> +#if defined(TARGET_PPC64)
> + hflags_mask |= 1 << HFLAGS_PMCC0;
> + hflags_mask |= 1 << HFLAGS_PMCC1;
> + hflags_mask |= 1 << HFLAGS_PMCJCE;
> + hflags_mask |= 1 << HFLAGS_INSN_CNT;
> + hflags_mask |= 1 << HFLAGS_PMC_OTHER;
> +#endif
> + return hflags_mask;
> +}
> +
> static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
> {
> target_ulong msr = env->msr;
> @@ -104,30 +146,12 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
> if (env->spr[SPR_LPCR] & LPCR_HR) {
> hflags |= 1 << HFLAGS_HR;
> }
> - if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC0) {
> - hflags |= 1 << HFLAGS_PMCC0;
> - }
> - if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) {
> - hflags |= 1 << HFLAGS_PMCC1;
> - }
> - if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE) {
> - hflags |= 1 << HFLAGS_PMCJCE;
> - }
>
> #ifndef CONFIG_USER_ONLY
> if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
> hflags |= 1 << HFLAGS_HV;
> }
>
> -#if defined(TARGET_PPC64)
> - if (env->pmc_ins_cnt) {
> - hflags |= 1 << HFLAGS_INSN_CNT;
> - }
> - if (env->pmc_ins_cnt & 0x1e) {
> - hflags |= 1 << HFLAGS_PMC_OTHER;
> - }
> -#endif
> -
> /*
> * This is our encoding for server processors. The architecture
> * specifies that there is no such thing as userspace with
> @@ -172,6 +196,8 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
> hflags |= dmmu_idx << HFLAGS_DMMU_IDX;
> #endif
>
> + hflags |= hreg_compute_pmu_hflags_value(env);
> +
> return hflags | (msr & msr_mask);
> }
>
> @@ -180,6 +206,17 @@ void hreg_compute_hflags(CPUPPCState *env)
> env->hflags = hreg_compute_hflags_value(env);
> }
>
> +/*
> + * This can be used as a lighter-weight alternative to hreg_compute_hflags
> + * when PMU MMCR0 or pmc_ins_cnt changes. pmc_ins_cnt is changed by
> + * pmu_update_summaries.
> + */
> +void hreg_update_pmu_hflags(CPUPPCState *env)
> +{
> + env->hflags &= ~hreg_compute_pmu_hflags_mask(env);
> + env->hflags |= hreg_compute_pmu_hflags_value(env);
> +}
> +
> #ifdef CONFIG_DEBUG_TCG
> void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
> target_ulong *cs_base, uint32_t *flags)
> diff --git a/target/ppc/helper_regs.h b/target/ppc/helper_regs.h
> index 42f26870b9..8196c1346d 100644
> --- a/target/ppc/helper_regs.h
> +++ b/target/ppc/helper_regs.h
> @@ -22,6 +22,7 @@
>
> void hreg_swap_gpr_tgpr(CPUPPCState *env);
> void hreg_compute_hflags(CPUPPCState *env);
> +void hreg_update_pmu_hflags(CPUPPCState *env);
> void cpu_interrupt_exittb(CPUState *cs);
> int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv);
>
> diff --git a/target/ppc/machine.c b/target/ppc/machine.c
> index be6eb3d968..134b16c625 100644
> --- a/target/ppc/machine.c
> +++ b/target/ppc/machine.c
> @@ -21,10 +21,6 @@ static void post_load_update_msr(CPUPPCState *env)
> */
> env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB);
> ppc_store_msr(env, msr);
> -
> - if (tcg_enabled()) {
> - pmu_update_summaries(env);
> - }
> }
>
> static int get_avr(QEMUFile *f, void *pv, size_t size,
> @@ -317,6 +313,10 @@ static int cpu_post_load(void *opaque, int version_id)
>
> post_load_update_msr(env);
>
> + if (tcg_enabled()) {
> + pmu_mmcr01_updated(env);
> + }
> +
> return 0;
> }
>
> diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
> index 64a64865d7..c4c331c6b5 100644
> --- a/target/ppc/power8-pmu.c
> +++ b/target/ppc/power8-pmu.c
> @@ -31,7 +31,11 @@ static bool pmc_has_overflow_enabled(CPUPPCState *env, int sprn)
> return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
> }
>
> -void pmu_update_summaries(CPUPPCState *env)
> +/*
> + * Called after MMCR0 or MMCR1 changes to update pmc_ins_cnt and pmc_cyc_cnt.
> + * hflags must subsequently be updated.
> + */
> +static void pmu_update_summaries(CPUPPCState *env)
> {
> target_ulong mmcr0 = env->spr[SPR_POWER_MMCR0];
> target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1];
> @@ -39,7 +43,7 @@ void pmu_update_summaries(CPUPPCState *env)
> int cyc_cnt = 0;
>
> if (mmcr0 & MMCR0_FC) {
> - goto hflags_calc;
> + goto out;
> }
>
> if (!(mmcr0 & MMCR0_FC14) && mmcr1 != 0) {
> @@ -73,10 +77,19 @@ void pmu_update_summaries(CPUPPCState *env)
> ins_cnt |= !(mmcr0 & MMCR0_FC56) << 5;
> cyc_cnt |= !(mmcr0 & MMCR0_FC56) << 6;
>
> - hflags_calc:
> + out:
> env->pmc_ins_cnt = ins_cnt;
> env->pmc_cyc_cnt = cyc_cnt;
> - env->hflags = deposit32(env->hflags, HFLAGS_INSN_CNT, 1, ins_cnt != 0);
> +}
> +
> +void pmu_mmcr01_updated(CPUPPCState *env)
> +{
> + pmu_update_summaries(env);
> + hreg_update_pmu_hflags(env);
> + /*
> + * Should this update overflow timers (if mmcr0 is updated) so they
> + * get set in cpu_post_load?
> + */
> }
>
> static bool pmu_increment_insns(CPUPPCState *env, uint32_t num_insns)
> @@ -234,18 +247,11 @@ static void pmu_delete_timers(CPUPPCState *env)
>
> void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
> {
> - bool hflags_pmcc0 = (value & MMCR0_PMCC0) != 0;
> - bool hflags_pmcc1 = (value & MMCR0_PMCC1) != 0;
> -
> pmu_update_cycles(env);
>
> env->spr[SPR_POWER_MMCR0] = value;
>
> - /* MMCR0 writes can change HFLAGS_PMCC[01] and HFLAGS_INSN_CNT */
> - env->hflags = deposit32(env->hflags, HFLAGS_PMCC0, 1, hflags_pmcc0);
> - env->hflags = deposit32(env->hflags, HFLAGS_PMCC1, 1, hflags_pmcc1);
> -
> - pmu_update_summaries(env);
> + pmu_mmcr01_updated(env);
>
> /* Update cycle overflow timers with the current MMCR0 state */
> pmu_update_overflow_timers(env);
> @@ -257,8 +263,7 @@ void helper_store_mmcr1(CPUPPCState *env, uint64_t value)
>
> env->spr[SPR_POWER_MMCR1] = value;
>
> - /* MMCR1 writes can change HFLAGS_INSN_CNT */
> - pmu_update_summaries(env);
> + pmu_mmcr01_updated(env);
> }
>
> target_ulong helper_read_pmc(CPUPPCState *env, uint32_t sprn)
> @@ -287,8 +292,8 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu)
> env->spr[SPR_POWER_MMCR0] &= ~MMCR0_FCECE;
> env->spr[SPR_POWER_MMCR0] |= MMCR0_FC;
>
> - /* Changing MMCR0_FC requires a new HFLAGS_INSN_CNT calc */
> - pmu_update_summaries(env);
> + /* Changing MMCR0_FC requires summaries and hflags update */
> + pmu_mmcr01_updated(env);
>
> /*
> * Delete all pending timers if we need to freeze
> @@ -299,6 +304,7 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu)
> }
>
> if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE) {
> + /* These MMCR0 bits do not require summaries or hflags update. */
> env->spr[SPR_POWER_MMCR0] &= ~MMCR0_PMAE;
> env->spr[SPR_POWER_MMCR0] |= MMCR0_PMAO;
> }
> diff --git a/target/ppc/power8-pmu.h b/target/ppc/power8-pmu.h
> index c0093e2219..775e640053 100644
> --- a/target/ppc/power8-pmu.h
> +++ b/target/ppc/power8-pmu.h
> @@ -18,10 +18,10 @@
> #define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL
>
> void cpu_ppc_pmu_init(CPUPPCState *env);
> -void pmu_update_summaries(CPUPPCState *env);
> +void pmu_mmcr01_updated(CPUPPCState *env);
> #else
> static inline void cpu_ppc_pmu_init(CPUPPCState *env) { }
> -static inline void pmu_update_summaries(CPUPPCState *env) { }
> +static inline void pmu_mmcr01_updated(CPUPPCState *env) { }
> #endif
>
> #endif
prev parent reply other threads:[~2023-06-01 20:32 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-30 13:04 [PATCH v4] target/ppc: Fix PMU hflags calculation Nicholas Piggin
2023-06-01 20:30 ` Daniel Henrique Barboza [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=749b68b2-20fa-8a8d-2473-daac5f092151@gmail.com \
--to=danielhb413@gmail.com \
--cc=dbarboza@ventanamicro.com \
--cc=npiggin@gmail.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).