diff --git a/hw/ppc.c b/hw/ppc.c
index 2a77eb9..f46f9e7 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -28,6 +28,7 @@
 #include "nvram.h"
 #include "qemu-log.h"
 #include "loader.h"
+#include "kvm.h"
 
 //#define PPC_DEBUG_IRQ
 //#define PPC_DEBUG_TB
@@ -50,6 +51,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 +61,11 @@ 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) {
+        kvm_ppc_set_interrupt(env, n_IRQ, level);
+    }
+
     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);
diff --git a/kvm-stub.c b/kvm-stub.c
index d45f9fa..cea2eff 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -141,3 +141,10 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign)
 {
     return -ENOSYS;
 }
+
+#ifdef TARGET_PPC
+int kvm_ppc_set_interrupt(CPUState *env, int irq, int level)
+{
+    return 0;
+}
+#endif
diff --git a/kvm.h b/kvm.h
index 50b6c01..6472bcc 100644
--- a/kvm.h
+++ b/kvm.h
@@ -151,6 +151,10 @@ void kvm_cpu_synchronize_state(CPUState *env);
 void kvm_cpu_synchronize_post_reset(CPUState *env);
 void kvm_cpu_synchronize_post_init(CPUState *env);
 
+#ifdef TARGET_PPC
+int kvm_ppc_set_interrupt(CPUState *env, int irq, int level);
+#endif
+
 /* generic hooks - to be moved/refactored once there are more users */
 
 static inline void cpu_synchronize_state(CPUState *env)
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 14d6365..5f4f7b5 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -37,6 +37,9 @@
     do { } while (0)
 #endif
 
+static int cap_interrupt_unset = false;
+static int cap_interrupt_level = false;
+
 /* XXX We have a race condition where we actually have a level triggered
  *     interrupt, but the infrastructure can't expose that yet, so the guest
  *     takes but ignores it, goes to sleep and never gets notified that there's
@@ -55,6 +58,18 @@ static void kvm_kick_env(void *env)
 
 int kvm_arch_init(KVMState *s, int smp_cpus)
 {
+#ifdef KVM_CAP_PPC_UNSET_IRQ
+    cap_interrupt_unset = kvm_check_extension(s, KVM_CAP_PPC_UNSET_IRQ);
+#endif
+#ifdef KVM_CAP_PPC_IRQ_LEVEL
+    cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL);
+#endif
+
+    if (!cap_interrupt_level) {
+        fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
+                        "VM to stall at times!\n");
+    }
+
     return 0;
 }
 
@@ -178,6 +193,23 @@ int kvm_arch_get_registers(CPUState *env)
     return 0;
 }
 
+int kvm_ppc_set_interrupt(CPUState *env, int irq, int level)
+{
+    unsigned virq = level ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET;
+
+    if (irq != PPC_INTERRUPT_EXT) {
+        return 0;
+    }
+
+    if (!kvm_enabled() || !cap_interrupt_unset || !cap_interrupt_level) {
+        return 0;
+    }
+
+    kvm_vcpu_ioctl(env, KVM_INTERRUPT, &virq);
+
+    return 0;
+}
+
 #if defined(TARGET_PPCEMB)
 #define PPC_INPUT_INT PPC40x_INPUT_INT
 #elif defined(TARGET_PPC64)
@@ -193,7 +225,8 @@ int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
 
     /* PowerPC Qemu tracks the various core input pins (interrupt, critical
      * interrupt, reset, etc) in PPC-specific env->irq_input_state. */
-    if (run->ready_for_interrupt_injection &&
+    if (!cap_interrupt_level &&
+        run->ready_for_interrupt_injection &&
         (env->interrupt_request & CPU_INTERRUPT_HARD) &&
         (env->irq_input_state & (1<<PPC_INPUT_INT)))
     {
@@ -201,7 +234,7 @@ int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
          * future KVM could cache it in-kernel to avoid a heavyweight exit
          * when reading the UIC.
          */
-        irq = -1U;
+        irq = KVM_INTERRUPT_SET;
 
         dprintf("injected interrupt %d\n", irq);
         r = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &irq);
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 65e31c9..e88423a 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -17,4 +17,16 @@ int kvmppc_read_host_property(const char *node_path, const char *prop,
 uint32_t kvmppc_get_tbfreq(void);
 int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
 
+#ifndef KVM_INTERRUPT_SET
+#define KVM_INTERRUPT_SET -1
+#endif
+
+#ifndef KVM_INTERRUPT_UNSET
+#define KVM_INTERRUPT_UNSET -2
+#endif
+
+#ifndef KVM_INTERRUPT_SET_LEVEL
+#define KVM_INTERRUPT_SET_LEVEL -3
+#endif
+
 #endif /* __KVM_PPC_H__ */
