The current interrupt controller emulation model supports two functions
for pulling interrupts from the controller into the processor:

  kvm_cpu_has_interrupt(vcpu) - is an interrupt pending for the core
  kvm_cpu_get_interrupt(vcpu) - get pending interrupt and ack it

This presents a problem when we try fail to inject an interrupt, since it
has already been acked.  Currently subarch specific code carries this acked
interrupt around, but code is quite complex and difficult to follow.

This patch changes the model to

  kvm_cpu_get_interrupt(vcpu, irq) - get pending interrupt, if any
  irq->ack()                       - acknowledge interrupt

Which allows acking only after the core has accepted the interrupt.  Currently
we use the new model with the old semantics by calling ack() immediately
after we see a pending interrupt.

Signed-off-by: Avi Kivity <[EMAIL PROTECTED]>
---
 drivers/kvm/i8259.c    |   44 +++++++++++++++++++++++++-------------------
 drivers/kvm/irq.c      |   38 ++++++--------------------------------
 drivers/kvm/irq.h      |   13 +++++++++----
 drivers/kvm/kvm_main.c |    3 ++-
 drivers/kvm/lapic.c    |   20 ++++++++++++++------
 drivers/kvm/svm.c      |    6 ++++--
 drivers/kvm/vmx.c      |    6 ++++--
 7 files changed, 64 insertions(+), 66 deletions(-)

diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c
index f0dc2ee..dd933d7 100644
--- a/drivers/kvm/i8259.c
+++ b/drivers/kvm/i8259.c
@@ -27,6 +27,7 @@
  */
 #include <linux/mm.h>
 #include "irq.h"
+#include "x86.h"
 
 /*
  * set irq level. If an edge is detected, then the IRR is set to 1
@@ -149,36 +150,41 @@ static inline void pic_intack(struct kvm_kpic_state *s, 
int irq)
                s->irr &= ~(1 << irq);
 }
 
-int kvm_pic_read_irq(struct kvm_pic *s)
+static void kvm_pic_ack_irq(struct kvm_vcpu *vcpu, unsigned irq)
+{
+       struct kvm_pic *s;
+
+       s = pic_irqchip(vcpu->kvm);
+       s->output = 0;
+       if (irq < 8)
+               pic_intack(&s->pics[0], irq);
+       else {
+               pic_intack(&s->pics[0], 2);
+               pic_intack(&s->pics[1], irq - 8);
+       }
+       pic_update_irq(s);
+}
+
+bool kvm_pic_read_irq(struct kvm_pic *s, struct kvm_pending_irq *pirq)
 {
        int irq, irq2, intno;
 
        irq = pic_get_irq(&s->pics[0]);
        if (irq >= 0) {
-               pic_intack(&s->pics[0], irq);
                if (irq == 2) {
                        irq2 = pic_get_irq(&s->pics[1]);
-                       if (irq2 >= 0)
-                               pic_intack(&s->pics[1], irq2);
-                       else
-                               /*
-                                * spurious IRQ on slave controller
-                                */
-                               irq2 = 7;
+                       if (irq2 < 0)
+                               irq2 = 7; /* spurious */
                        intno = s->pics[1].irq_base + irq2;
                        irq = irq2 + 8;
                } else
                        intno = s->pics[0].irq_base + irq;
-       } else {
-               /*
-                * spurious IRQ on host controller
-                */
-               irq = 7;
-               intno = s->pics[0].irq_base + irq;
-       }
-       pic_update_irq(s);
-
-       return intno;
+               pirq->vector = intno;
+               pirq->ack = kvm_pic_ack_irq;
+               pirq->info = irq;
+               return true;
+       } else
+               return false;
 }
 
 void kvm_pic_reset(struct kvm_kpic_state *s)
diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c
index 59b47c5..66d1a91 100644
--- a/drivers/kvm/irq.c
+++ b/drivers/kvm/irq.c
@@ -26,41 +26,15 @@
 #include "irq.h"
 
 /*
- * check if there is pending interrupt without
- * intack.
- */
-int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
-{
-       struct kvm_pic *s;
-
-       if (kvm_apic_has_interrupt(v) == -1) {  /* LAPIC */
-               if (kvm_apic_accept_pic_intr(v)) {
-                       s = pic_irqchip(v->kvm);        /* PIC */
-                       return s->output;
-               } else
-                       return 0;
-       }
-       return 1;
-}
-EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
-
-/*
  * Read pending interrupt vector and intack.
  */
-int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
+bool kvm_cpu_get_interrupt(struct kvm_vcpu *v, struct kvm_pending_irq *irq)
 {
-       struct kvm_pic *s;
-       int vector;
-
-       vector = kvm_get_apic_interrupt(v);     /* APIC */
-       if (vector == -1) {
-               if (kvm_apic_accept_pic_intr(v)) {
-                       s = pic_irqchip(v->kvm);
-                       s->output = 0;          /* PIC */
-                       vector = kvm_pic_read_irq(s);
-               }
-       }
-       return vector;
+       if (kvm_get_apic_interrupt(v, irq))
+               return true;
+       if (kvm_apic_accept_pic_intr(v))
+               return kvm_pic_read_irq(pic_irqchip(v->kvm), irq);
+       return false;
 }
 EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
 
diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h
index 75f5f18..49af30b 100644
--- a/drivers/kvm/irq.h
+++ b/drivers/kvm/irq.h
@@ -26,6 +26,12 @@
 
 typedef void irq_request_func(void *opaque, int level);
 
+struct kvm_pending_irq {
+       unsigned vector;
+       void (*ack)(struct kvm_vcpu *vcpu, unsigned info);
+       unsigned info;
+};
+
 struct kvm_kpic_state {
        u8 last_irr;    /* edge detection */
        u8 irr;         /* interrupt request register */
@@ -56,9 +62,8 @@ struct kvm_pic {
 
 struct kvm_pic *kvm_create_pic(struct kvm *kvm);
 void kvm_pic_set_irq(void *opaque, int irq, int level);
-int kvm_pic_read_irq(struct kvm_pic *s);
-int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
-int kvm_cpu_has_interrupt(struct kvm_vcpu *v);
+bool kvm_pic_read_irq(struct kvm_pic *s, struct kvm_pending_irq *irq);
+bool kvm_cpu_get_interrupt(struct kvm_vcpu *v, struct kvm_pending_irq *irq);
 void kvm_pic_update_irq(struct kvm_pic *s);
 
 #define IOAPIC_NUM_PINS  KVM_IOAPIC_NUM_PINS
@@ -144,7 +149,7 @@ do {                                                        
                \
 void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
 int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
 int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
-int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
+bool kvm_get_apic_interrupt(struct kvm_vcpu *vcpu, struct kvm_pending_irq 
*irq);
 int kvm_create_lapic(struct kvm_vcpu *vcpu);
 void kvm_lapic_reset(struct kvm_vcpu *vcpu);
 void kvm_pic_reset(struct kvm_kpic_state *s);
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 7b5129e..41658d7 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -637,13 +637,14 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
 void kvm_vcpu_block(struct kvm_vcpu *vcpu)
 {
        DECLARE_WAITQUEUE(wait, current);
+       struct kvm_pending_irq irq;
 
        add_wait_queue(&vcpu->wq, &wait);
 
        /*
         * We will block until either an interrupt or a signal wakes us up
         */
-       while (!kvm_cpu_has_interrupt(vcpu)
+       while (!kvm_cpu_get_interrupt(vcpu, &irq)
               && !signal_pending(current)
               && vcpu->mp_state != VCPU_MP_STATE_RUNNABLE
               && vcpu->mp_state != VCPU_MP_STATE_SIPI_RECEIVED) {
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c
index 5efa6c0..804a177 100644
--- a/drivers/kvm/lapic.c
+++ b/drivers/kvm/lapic.c
@@ -1044,18 +1044,26 @@ void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, 
int vec)
                                apic->timer.period);
 }
 
-int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
+static void kvm_apic_ack_interrupt(struct kvm_vcpu *vcpu, unsigned vector)
 {
-       int vector = kvm_apic_has_interrupt(vcpu);
        struct kvm_lapic *apic = vcpu->apic;
 
-       if (vector == -1)
-               return -1;
-
        apic_set_vector(vector, apic->regs + APIC_ISR);
        apic_update_ppr(apic);
        apic_clear_irr(vector, apic);
-       return vector;
+}
+
+bool kvm_get_apic_interrupt(struct kvm_vcpu *vcpu, struct kvm_pending_irq *irq)
+{
+       int vector = kvm_apic_has_interrupt(vcpu);
+
+       if (vector == -1)
+               return false;
+
+       irq->vector = vector;
+       irq->ack = kvm_apic_ack_interrupt;
+       irq->info = vector;
+       return true;
 }
 
 void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 8b1cc60..155b266 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -1316,6 +1316,7 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu)
        struct vcpu_svm *svm = to_svm(vcpu);
        struct vmcb *vmcb = svm->vmcb;
        int intr_vector = -1;
+       struct kvm_pending_irq irq;
 
        if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) &&
            ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) {
@@ -1329,7 +1330,7 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu)
        if (vmcb->control.int_ctl & V_IRQ_MASK)
                return;
 
-       if (!kvm_cpu_has_interrupt(vcpu))
+       if (!kvm_cpu_get_interrupt(vcpu, &irq))
                return;
 
        if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
@@ -1341,7 +1342,8 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu)
                return;
        }
        /* Okay, we can deliver the interrupt: grab it and update PIC state. */
-       intr_vector = kvm_cpu_get_interrupt(vcpu);
+       irq.ack(vcpu, irq.info);
+       intr_vector = irq.vector;
        svm_inject_irq(svm, intr_vector);
        kvm_timer_intr_post(vcpu, intr_vector);
 }
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index aa6bf2b..ed14849 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -2249,11 +2249,12 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        u32 idtv_info_field, intr_info_field;
        int has_ext_irq, interrupt_window_open;
+       struct kvm_pending_irq irq;
        int vector;
 
        update_tpr_threshold(vcpu);
 
-       has_ext_irq = kvm_cpu_has_interrupt(vcpu);
+       has_ext_irq = kvm_cpu_get_interrupt(vcpu, &irq);
        intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
        idtv_info_field = vmx->idt_vectoring_info;
        if (intr_info_field & INTR_INFO_VALID_MASK) {
@@ -2294,7 +2295,8 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)
                ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
                 (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
        if (interrupt_window_open) {
-               vector = kvm_cpu_get_interrupt(vcpu);
+               irq.ack(vcpu, irq.info);
+               vector = irq.vector;
                vmx_inject_irq(vcpu, vector);
                kvm_timer_intr_post(vcpu, vector);
        } else
-- 
1.5.3


-------------------------------------------------------------------------
SF.Net email is sponsored by: The Future of Linux Business White Paper
from Novell.  From the desktop to the data center, Linux is going
mainstream.  Let it simplify your IT future.
http://altfarm.mediaplex.com/ad/ck/8857-50307-18918-4
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to