We're missing two counter freeze bits that are used to further control how the PMCs behaves: MMCR0_FC14 and MMCR0_FC56. These bits can frozen PMCs separately: MMCR0_FC14 freezes PMCs 1 to 4 and MMCR0_FC56 freezes PMCs 5 and 6.
The EBB powerpc kernel test 'pmc56_overflow' exercises this logic. Let's add it in the PMU logic to make this test pass. Signed-off-by: Daniel Henrique Barboza <danielhb...@gmail.com> --- target/ppc/cpu.h | 2 ++ target/ppc/pmu_book3s_helper.c | 23 +++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 1aa1fd42af..204f0d58ee 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -352,6 +352,8 @@ typedef struct ppc_v3_pate_t { #define MMCR0_PMCC PPC_BITMASK(44, 45) /* PMC Control */ #define MMCR0_PMC1CE PPC_BIT(48) #define MMCR0_PMCjCE PPC_BIT(49) +#define MMCR0_FC14 PPC_BIT(58) +#define MMCR0_FC56 PPC_BIT(59) #define MMCR1_PMC1SEL_SHIFT (63 - 39) #define MMCR1_PMC1SEL PPC_BITMASK(32, 39) diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c index 388263688b..ae7050cd62 100644 --- a/target/ppc/pmu_book3s_helper.c +++ b/target/ppc/pmu_book3s_helper.c @@ -115,14 +115,20 @@ static void update_programmable_PMC_reg(CPUPPCState *env, int sprn, */ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta) { + bool PMC14_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC14); + bool PMC56_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC56); int sprn; - for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) { - update_programmable_PMC_reg(env, sprn, icount_delta); + if (PMC14_running) { + for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) { + update_programmable_PMC_reg(env, sprn, icount_delta); + } } - update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, icount_delta); - update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta); + if (PMC56_running) { + update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, icount_delta); + update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta); + } } static int64_t get_INST_CMPL_timeout(CPUPPCState *env, int sprn) @@ -159,16 +165,21 @@ static int64_t get_CYC_timeout(CPUPPCState *env, int sprn) static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn) { + bool PMC14_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC14); + bool PMC56_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC56); + switch (sprn) { case SPR_POWER_PMC1: - return env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE; + return env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE && PMC14_running; case SPR_POWER_PMC2: case SPR_POWER_PMC3: case SPR_POWER_PMC4: + return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE && PMC14_running; + case SPR_POWER_PMC5: case SPR_POWER_PMC6: - return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE; + return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE && PMC56_running; default: break; -- 2.31.1