public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
Subject: [PATCH 5/7] KVM: Add explicit acks to interrupt controller model
Date: Tue,  4 Dec 2007 11:44:12 +0200	[thread overview]
Message-ID: <11967614553148-git-send-email-avi@qumranet.com> (raw)
In-Reply-To: <11967614542283-git-send-email-avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>

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 <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
---
 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

  parent reply	other threads:[~2007-12-04  9:44 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-12-04  9:44 [PATCH 0/7] Rework irq injection infrastructure Avi Kivity
     [not found] ` <11967614542283-git-send-email-avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-12-04  9:44   ` [PATCH 1/7] KVM: Generalize exception injection mechanism Avi Kivity
2007-12-04  9:44   ` [PATCH 2/7] KVM: Replace page fault injection by the generalized exception queue Avi Kivity
2007-12-04  9:44   ` [PATCH 3/7] KVM: Replace #GP " Avi Kivity
2007-12-04  9:44   ` [PATCH 4/7] KVM: Use generalized exception queue for injecting #UD Avi Kivity
2007-12-04  9:44   ` Avi Kivity [this message]
2007-12-04  9:44   ` [PATCH 6/7] KVM: Move tpr threshold calculation into common code Avi Kivity
2007-12-04  9:44   ` [PATCH 7/7] KVM: Ack interrupts only after they have successfully been injected Avi Kivity
2007-12-04 16:51   ` [PATCH 0/7] Rework irq injection infrastructure Joerg Roedel
     [not found]     ` <20071204165101.GA23093-5C7GfCeVMHo@public.gmane.org>
2007-12-04 16:56       ` Avi Kivity
2007-12-06  7:50   ` Dong, Eddie
     [not found]     ` <10EA09EFD8728347A513008B6B0DA77A0279CC10-wq7ZOvIWXbNpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2007-12-06  8:28       ` Avi Kivity
     [not found]         ` <4757B2C3.3000402-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-12-06  9:33           ` Dong, Eddie
     [not found]             ` <10EA09EFD8728347A513008B6B0DA77A0279CCE0-wq7ZOvIWXbNpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2007-12-06 10:10               ` Avi Kivity
     [not found]                 ` <4757CA93.1090704-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-12-06 10:26                   ` Dong, Eddie
     [not found]                     ` <10EA09EFD8728347A513008B6B0DA77A0279CCF2-wq7ZOvIWXbNpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2007-12-06 13:24                       ` Dong, Eddie
     [not found]                         ` <10EA09EFD8728347A513008B6B0DA77A0279CD1C-wq7ZOvIWXbNpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2007-12-06 14:19                           ` Avi Kivity

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=11967614553148-git-send-email-avi@qumranet.com \
    --to=avi-atkuwr5tajbwk0htik3j/w@public.gmane.org \
    --cc=kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox