aboutsummaryrefslogtreecommitdiff
path: root/target/ppc/power8-pmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/ppc/power8-pmu.c')
-rw-r--r--target/ppc/power8-pmu.c39
1 files changed, 35 insertions, 4 deletions
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index 236e8e66e9..beeab5c494 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,12 +285,29 @@ 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 */
- return;
+ raise_ebb_perfm_exception(env);
}
/* This helper assumes that the PMC is running. */