#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
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);
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);
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
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;
}
return 0;
}
+int kvmppc_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)
/* 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)))
{
* 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);
uint32_t kvmppc_get_tbfreq(void);
int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
+int kvmppc_set_interrupt(CPUState *env, int irq, int level);
+
+#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__ */