[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH 03/13] target/ppc: move interrupt masking out of ppc_hw_inter
From: |
Matheus Ferst |
Subject: |
[RFC PATCH 03/13] target/ppc: move interrupt masking out of ppc_hw_interrupt |
Date: |
Mon, 15 Aug 2022 13:20:09 -0300 |
Move the interrupt masking logic to a new method, ppc_pending_interrupt,
and only handle the interrupt processing in ppc_hw_interrupt.
Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
target/ppc/excp_helper.c | 228 ++++++++++++++++++++++++---------------
1 file changed, 141 insertions(+), 87 deletions(-)
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index ae9576546f..8690017c70 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,29 +1678,22 @@ void ppc_cpu_do_interrupt(CPUState *cs)
powerpc_excp(cpu, cs->exception_index);
}
-static void ppc_hw_interrupt(CPUPPCState *env)
+static int ppc_pending_interrupt(CPUPPCState *env)
{
- PowerPCCPU *cpu = env_archcpu(env);
bool async_deliver;
/* External reset */
if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
- env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
- powerpc_excp(cpu, POWERPC_EXCP_RESET);
- return;
+ return PPC_INTERRUPT_RESET;
}
/* Machine check exception */
if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
- env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
- powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
- return;
+ return PPC_INTERRUPT_MCK;
}
#if 0 /* TODO */
/* External debug exception */
if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
- env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
- powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
- return;
+ return PPC_INTERRUPT_DEBUG;
}
#endif
@@ -1718,9 +1711,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
/* HDEC clears on delivery */
- env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
- powerpc_excp(cpu, POWERPC_EXCP_HDECR);
- return;
+ return PPC_INTERRUPT_HDECR;
}
}
@@ -1729,8 +1720,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
/* LPCR will be clear when not supported so this will work */
bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
- powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
- return;
+ return PPC_INTERRUPT_HVIRT;
}
}
@@ -1742,77 +1732,47 @@ static void ppc_hw_interrupt(CPUPPCState *env)
if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
!FIELD_EX64(env->msr, MSR, PR))) ||
(env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
- if (books_vhyp_promotes_external_to_hvirt(cpu)) {
- powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
- } else {
- powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
- }
- return;
+ return PPC_INTERRUPT_EXT;
}
}
if (FIELD_EX64(env->msr, MSR, CE)) {
/* External critical interrupt */
if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
- powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
- return;
+ return PPC_INTERRUPT_CEXT;
}
}
if (async_deliver != 0) {
/* Watchdog timer on embedded PowerPC */
if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
- env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
- powerpc_excp(cpu, POWERPC_EXCP_WDT);
- return;
+ return PPC_INTERRUPT_WDT;
}
if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
- env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
- powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
- return;
+ return PPC_INTERRUPT_CDOORBELL;
}
/* Fixed interval timer on embedded PowerPC */
if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
- env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
- powerpc_excp(cpu, POWERPC_EXCP_FIT);
- return;
+ return PPC_INTERRUPT_FIT;
}
/* Programmable interval timer on embedded PowerPC */
if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
- env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
- powerpc_excp(cpu, POWERPC_EXCP_PIT);
- return;
+ return PPC_INTERRUPT_PIT;
}
/* Decrementer exception */
if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
- if (ppc_decr_clear_on_delivery(env)) {
- env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
- }
- powerpc_excp(cpu, POWERPC_EXCP_DECR);
- return;
+ return PPC_INTERRUPT_DECR;
}
if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
- env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
- if (is_book3s_arch2x(env)) {
- powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
- } else {
- powerpc_excp(cpu, POWERPC_EXCP_DOORI);
- }
- return;
+ return PPC_INTERRUPT_DOORBELL;
}
if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
- env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
- powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
- return;
+ return PPC_INTERRUPT_HDOORBELL;
}
if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
- env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
- powerpc_excp(cpu, POWERPC_EXCP_PERFM);
- return;
+ return PPC_INTERRUPT_PERFM;
}
/* Thermal interrupt */
if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
- env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
- powerpc_excp(cpu, POWERPC_EXCP_THERM);
- return;
+ return PPC_INTERRUPT_THERM;
}
/* EBB exception */
if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
@@ -1822,33 +1782,104 @@ static void ppc_hw_interrupt(CPUPPCState *env)
*/
if (FIELD_EX64(env->msr, MSR, PR) &&
(env->spr[SPR_BESCR] & BESCR_GE)) {
- env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
-
- if (env->spr[SPR_BESCR] & BESCR_PMEO) {
- powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
- } else if (env->spr[SPR_BESCR] & BESCR_EEO) {
- powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
- }
-
- return;
+ return PPC_INTERRUPT_EBB;
}
}
}
- if (env->resume_as_sreset) {
- /*
- * This is a bug ! It means that has_work took us out of halt without
- * anything to deliver while in a PM state that requires getting
- * out via a 0x100
- *
- * This means we will incorrectly execute past the power management
- * instruction instead of triggering a reset.
- *
- * It generally means a discrepancy between the wakeup conditions in
the
- * processor has_work implementation and the logic in this function.
- */
- cpu_abort(env_cpu(env),
- "Wakeup from PM state but interrupt Undelivered");
+ return 0;
+}
+
+static void ppc_hw_interrupt(CPUPPCState *env, int pending_interrupt)
+{
+ PowerPCCPU *cpu = env_archcpu(env);
+
+ switch (pending_interrupt) {
+ case PPC_INTERRUPT_RESET: /* External reset */
+ env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+ powerpc_excp(cpu, POWERPC_EXCP_RESET);
+ break;
+ case PPC_INTERRUPT_MCK: /* Machine check exception */
+ env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+ powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+ break;
+#if 0 /* TODO */
+ case PPC_INTERRUPT_DEBUG: /* External debug exception */
+ env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+ powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+ break;
+#endif
+
+ case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+ /* HDEC clears on delivery */
+ env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+ powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+ break;
+ case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+ powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+ break;
+
+ case PPC_INTERRUPT_EXT:
+ if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+ powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+ } else {
+ powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+ }
+ break;
+ case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+ powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+ break;
+
+ case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+ env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+ powerpc_excp(cpu, POWERPC_EXCP_WDT);
+ break;
+ case PPC_INTERRUPT_CDOORBELL:
+ env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+ powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+ break;
+ case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+ env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+ powerpc_excp(cpu, POWERPC_EXCP_FIT);
+ break;
+ case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC
*/
+ env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+ powerpc_excp(cpu, POWERPC_EXCP_PIT);
+ break;
+ case PPC_INTERRUPT_DECR: /* Decrementer exception */
+ if (ppc_decr_clear_on_delivery(env)) {
+ env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+ }
+ powerpc_excp(cpu, POWERPC_EXCP_DECR);
+ break;
+ case PPC_INTERRUPT_DOORBELL:
+ env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+ if (is_book3s_arch2x(env)) {
+ powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+ } else {
+ powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+ }
+ break;
+ case PPC_INTERRUPT_HDOORBELL:
+ env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+ powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+ break;
+ case PPC_INTERRUPT_PERFM:
+ env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+ powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+ break;
+ case PPC_INTERRUPT_THERM: /* Thermal interrupt */
+ env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+ powerpc_excp(cpu, POWERPC_EXCP_THERM);
+ break;
+ case PPC_INTERRUPT_EBB: /* EBB exception */
+ env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+ if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+ powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+ } else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+ powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+ }
+ break;
}
}
@@ -1884,15 +1915,38 @@ bool ppc_cpu_exec_interrupt(CPUState *cs, int
interrupt_request)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
+ int pending_interrupt;
- if (interrupt_request & CPU_INTERRUPT_HARD) {
- ppc_hw_interrupt(env);
- if (env->pending_interrupts == 0) {
- cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
- }
- return true;
+ if ((interrupt_request & CPU_INTERRUPT_HARD) == 0) {
+ return false;
}
- return false;
+
+ pending_interrupt = ppc_pending_interrupt(env);
+ if (pending_interrupt == 0) {
+ if (env->resume_as_sreset) {
+ /*
+ * This is a bug ! It means that has_work took us out of halt
+ * without anything to deliver while in a PM state that requires
+ * getting out via a 0x100
+ *
+ * This means we will incorrectly execute past the power management
+ * instruction instead of triggering a reset.
+ *
+ * It generally means a discrepancy between the wakeup conditions
in
+ * the processor has_work implementation and the logic in this
+ * function.
+ */
+ cpu_abort(env_cpu(env),
+ "Wakeup from PM state but interrupt Undelivered");
+ }
+ return false;
+ }
+
+ ppc_hw_interrupt(env, pending_interrupt);
+ if (env->pending_interrupts == 0) {
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+ }
+ return true;
}
#endif /* !CONFIG_USER_ONLY */
--
2.25.1