diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c index 236e8e66e9..d245663158 100644 --- a/target/ppc/power8-pmu.c +++ b/target/ppc/power8-pmu.c @@ -222,6 +222,20 @@ static void pmu_update_overflow_timers(CPUPPCState *env) } } +static void pmu_delete_timers(CPUPPCState *env) +{ + QEMUTimer *pmc_overflow_timer; + int sprn; + + for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) { + pmc_overflow_timer = get_cyc_overflow_timer(env, sprn); + + if (pmc_overflow_timer) { + timer_del(pmc_overflow_timer); + } + } +} + void helper_store_mmcr0(CPUPPCState *env, target_ulong value) { bool hflags_pmcc0 = (value & MMCR0_PMCC0) != 0; @@ -271,8 +285,26 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; - if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_EBE)) { - return; + pmu_update_cycles(env); + + if (env->spr[SPR_POWER_MMCR0] & MMCR0_FCECE) { + 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); + + /* + * Delete all pending timers if we need to freeze + * the PMC. We'll restart them when the PMC starts + * running again. + */ + pmu_delete_timers(env); + } + + if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE) { + env->spr[SPR_POWER_MMCR0] &= ~MMCR0_PMAE; + env->spr[SPR_POWER_MMCR0] |= MMCR0_PMAO; } /* PMC interrupt not implemented yet */