aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc.c
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2010-08-30 13:49:15 +0200
committerAlexander Graf <agraf@suse.de>2010-09-05 11:50:48 +0200
commitfc87e185302a96c2675a1c3a86ca47c6a2d657ff (patch)
tree8dbd20e489ab8caf8acc122d134fea3dfe31c8e5 /hw/ppc.c
parentba5e7f82169f32ab8163c707d97c799ca09f8924 (diff)
downloadqemu-fc87e185302a96c2675a1c3a86ca47c6a2d657ff.zip
qemu-fc87e185302a96c2675a1c3a86ca47c6a2d657ff.tar.gz
qemu-fc87e185302a96c2675a1c3a86ca47c6a2d657ff.tar.bz2
KVM: PPC: Add level based interrupt logic
KVM on PowerPC used to have completely broken interrupt logic. Usually, interrupts work by having a PIC that pulls a line up/down, so the CPU knows that an interrupt is active. This line stays active until some action is done to the PIC to release the line. On KVM for PPC, we just checked if there was an interrupt pending and pulled a line in the kernel module. We never released it though, hoping that kernel space would just declare an interrupt as released when injected - which is wrong. To fix this, we need to completely redesign the interrupt injection logic. Whenever an interrupt line gets triggered, we need to notify kernel space that the line is up. Whenever it gets released, we do the same. This way we can assure that the interrupt state is always known to kernel space. This fixes random stalls in KVM guests on PowerPC that were waiting for an interrupt while everyone else thought they received it already. Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/ppc.c')
-rw-r--r--hw/ppc.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/hw/ppc.c b/hw/ppc.c
index 2a77eb9..55e3808 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -28,6 +28,8 @@
#include "nvram.h"
#include "qemu-log.h"
#include "loader.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
//#define PPC_DEBUG_IRQ
//#define PPC_DEBUG_TB
@@ -50,6 +52,8 @@ static void cpu_ppc_tb_start (CPUState *env);
static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
{
+ unsigned int old_pending = env->pending_interrupts;
+
if (level) {
env->pending_interrupts |= 1 << n_IRQ;
cpu_interrupt(env, CPU_INTERRUPT_HARD);
@@ -58,6 +62,13 @@ static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
if (env->pending_interrupts == 0)
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
}
+
+ if (old_pending != env->pending_interrupts) {
+#ifdef CONFIG_KVM
+ kvmppc_set_interrupt(env, n_IRQ, level);
+#endif
+ }
+
LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
"req %08x\n", __func__, env, n_IRQ, level,
env->pending_interrupts, env->interrupt_request);