diff options
author | Daniel Henrique Barboza | 2022-03-02 06:51:36 +0100 |
---|---|---|
committer | Cédric Le Goater | 2022-03-02 06:51:36 +0100 |
commit | d3412df20a321f2c4d98f5759cef2441206d5bd8 (patch) | |
tree | b8939d6121c3a781872db9ca186f5251e2c4de48 /target/ppc | |
parent | target/ppc: add PPC_INTERRUPT_EBB and EBB exceptions (diff) | |
download | qemu-d3412df20a321f2c4d98f5759cef2441206d5bd8.tar.gz qemu-d3412df20a321f2c4d98f5759cef2441206d5bd8.tar.xz qemu-d3412df20a321f2c4d98f5759cef2441206d5bd8.zip |
target/ppc: trigger PERFM EBBs from power8-pmu.c
This patch adds the EBB exception support that are triggered by
Performance Monitor alerts. This happens when a Performance Monitor
alert occurs and MMCR0_EBE, BESCR_PME and BESCR_GE are set.
fire_PMC_interrupt() will execute the raise_ebb_perfm_exception() helper
which will check for MMCR0_EBE, BESCR_PME and BESCR_GE bits. If all bits
are set, do_ebb() will attempt to trigger a PERFM EBB event.
If the EBB facility is enabled in both FSCR and HFSCR we consider that
the EBB is valid and set BESCR_PMEO. After that, if we're running in
problem state, fire a POWERPC_EXCP_PERM_EBB immediately. Otherwise we'll
queue a PPC_INTERRUPT_EBB.
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20220225101140.1054160-5-danielhb413@gmail.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Diffstat (limited to 'target/ppc')
-rw-r--r-- | target/ppc/cpu.h | 5 | ||||
-rw-r--r-- | target/ppc/excp_helper.c | 48 | ||||
-rw-r--r-- | target/ppc/power8-pmu.c | 3 |
3 files changed, 54 insertions, 2 deletions
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 79375e8df4..1b687521c7 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -2502,6 +2502,11 @@ void QEMU_NORETURN raise_exception_err(CPUPPCState *env, uint32_t exception, void QEMU_NORETURN raise_exception_err_ra(CPUPPCState *env, uint32_t exception, uint32_t error_code, uintptr_t raddr); +/* PERFM EBB helper*/ +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) +void raise_ebb_perfm_exception(CPUPPCState *env); +#endif + #if !defined(CONFIG_USER_ONLY) static inline int booke206_tlbm_id(CPUPPCState *env, ppcmas_tlb_t *tlbm) { diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 5e7d29ae00..d3e2cfcd71 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2066,6 +2066,54 @@ void helper_rfebb(CPUPPCState *env, target_ulong s) env->spr[SPR_BESCR] &= ~BESCR_GE; } } + +/* + * Triggers or queues an 'ebb_excp' EBB exception. All checks + * but FSCR, HFSCR and msr_pr must be done beforehand. + * + * PowerISA v3.1 isn't clear about whether an EBB should be + * postponed or cancelled if the EBB facility is unavailable. + * Our assumption here is that the EBB is cancelled if both + * FSCR and HFSCR EBB facilities aren't available. + */ +static void do_ebb(CPUPPCState *env, int ebb_excp) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = CPU(cpu); + + /* + * FSCR_EBB and FSCR_IC_EBB are the same bits used with + * HFSCR. + */ + helper_fscr_facility_check(env, FSCR_EBB, 0, FSCR_IC_EBB); + helper_hfscr_facility_check(env, FSCR_EBB, "EBB", FSCR_IC_EBB); + + if (ebb_excp == POWERPC_EXCP_PERFM_EBB) { + env->spr[SPR_BESCR] |= BESCR_PMEO; + } else if (ebb_excp == POWERPC_EXCP_EXTERNAL_EBB) { + env->spr[SPR_BESCR] |= BESCR_EEO; + } + + if (msr_pr == 1) { + powerpc_excp(cpu, ebb_excp); + } else { + env->pending_interrupts |= 1 << PPC_INTERRUPT_EBB; + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + +void raise_ebb_perfm_exception(CPUPPCState *env) +{ + bool perfm_ebb_enabled = env->spr[SPR_POWER_MMCR0] & MMCR0_EBE && + env->spr[SPR_BESCR] & BESCR_PME && + env->spr[SPR_BESCR] & BESCR_GE; + + if (!perfm_ebb_enabled) { + return; + } + + do_ebb(env, POWERPC_EXCP_PERFM_EBB); +} #endif /*****************************************************************************/ diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c index d245663158..beeab5c494 100644 --- a/target/ppc/power8-pmu.c +++ b/target/ppc/power8-pmu.c @@ -307,8 +307,7 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu) 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. */ |