Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 340e01248478ba8b78a6d4d1809b1eff > files > 378

kvm-83-270.el5_11.src.rpm

From c6325fd4b856e3bc939eb754470cee4aadc9f279 Mon Sep 17 00:00:00 2001
From: Gleb Natapov <gleb@redhat.com>
Date: Thu, 26 Feb 2009 15:51:50 +0200
Subject: [PATCH 1/3] handle IRQ status injection in userspace

This allows timers to keep track of injected and coalesced interrupts.

upstrem commit: ea1b668e7684dc43e9d198ba0b25fe47a0b2acd2

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
RH-Upstream-status: applied(kvm/master)
Bugzilla: 487595
Acked-by: Eduardo Habkost <ehabkost@redhat.com>
Acked-by: Marcelo Tosatti <mtosatti@redhat.com>
---
 libkvm/kvm-common.h |    2 ++
 libkvm/libkvm.c     |   19 ++++++++++++++++---
 libkvm/libkvm.h     |    2 +-
 qemu/hw/apic.c      |    5 +++++
 qemu/hw/i8259.c     |   11 ++++++++---
 qemu/hw/pc.h        |    1 +
 qemu/qemu-kvm.c     |    4 ++--
 qemu/qemu-kvm.h     |    2 +-
 user/main.c         |    2 +-
 9 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/libkvm/kvm-common.h b/libkvm/kvm-common.h
index c5beacc..ee010fb 100644
--- a/libkvm/kvm-common.h
+++ b/libkvm/kvm-common.h
@@ -55,6 +55,8 @@ struct kvm_context {
 	int no_irqchip_creation;
 	/// in-kernel irqchip status
 	int irqchip_in_kernel;
+	/// ioctl to use to inject interrupts
+	int irqchip_inject_ioctl;
 	/// do not create in-kernel pit if set
 	int no_pit_creation;
 	/// in-kernel pit status
diff --git a/libkvm/libkvm.c b/libkvm/libkvm.c
index 0408fdb..25494be 100644
--- a/libkvm/libkvm.c
+++ b/libkvm/libkvm.c
@@ -427,8 +427,16 @@ void kvm_create_irqchip(kvm_context_t kvm)
 		r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_IRQCHIP);
 		if (r > 0) {	/* kernel irqchip supported */
 			r = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
-			if (r >= 0)
+			if (r >= 0) {
+				kvm->irqchip_inject_ioctl = KVM_IRQ_LINE;
+#if defined(KVM_CAP_IRQ_INJECT_STATUS) && defined(KVM_IRQ_LINE_STATUS)
+				r = ioctl(kvm->fd, KVM_CHECK_EXTENSION,
+			  KVM_CAP_IRQ_INJECT_STATUS);
+				if (r > 0)
+					kvm->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
+#endif
 				kvm->irqchip_in_kernel = 1;
+			}
 			else
 				fprintf(stderr, "Create kernel PIC irqchip failed\n");
 		}
@@ -638,7 +646,7 @@ int kvm_get_dirty_pages_range(kvm_context_t kvm, unsigned long phys_addr,
 
 #ifdef KVM_CAP_IRQCHIP
 
-int kvm_set_irq_level(kvm_context_t kvm, int irq, int level)
+int kvm_set_irq_level(kvm_context_t kvm, int irq, int level, int *status)
 {
 	struct kvm_irq_level event;
 	int r;
@@ -647,9 +655,14 @@ int kvm_set_irq_level(kvm_context_t kvm, int irq, int level)
 		return 0;
 	event.level = level;
 	event.irq = irq;
-	r = ioctl(kvm->vm_fd, KVM_IRQ_LINE, &event);
+	r = ioctl(kvm->vm_fd, kvm->irqchip_inject_ioctl, &event);
 	if (r == -1)
 		perror("kvm_set_irq_level");
+
+	if (status)
+		*status = (kvm->irqchip_inject_ioctl == KVM_IRQ_LINE) ?
+			1 : event.status;
+
 	return 1;
 }
 
diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h
index ee1ba68..b24b655 100644
--- a/libkvm/libkvm.h
+++ b/libkvm/libkvm.h
@@ -509,7 +509,7 @@ int kvm_get_mem_map_range(kvm_context_t kvm, unsigned long phys_addr,
 			   unsigned long len, void *buf, void *opaque,
 			   int (*cb)(unsigned long start,unsigned long len,
 				     void* bitmap, void* opaque));
-int kvm_set_irq_level(kvm_context_t kvm, int irq, int level);
+int kvm_set_irq_level(kvm_context_t kvm, int irq, int level, int *status);
 
 int kvm_dirty_pages_log_enable_slot(kvm_context_t kvm,
 				    uint64_t phys_start,
diff --git a/qemu/hw/apic.c b/qemu/hw/apic.c
index 782b398..416eee9 100644
--- a/qemu/hw/apic.c
+++ b/qemu/hw/apic.c
@@ -377,6 +377,11 @@ int apic_get_irq_delivered(void)
     return apic_irq_delivered;
 }
 
+void apic_set_irq_delivered(void)
+{
+    apic_irq_delivered = 1;
+}
+
 static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
 {
     apic_irq_delivered += !get_bit(s->irr, vector_num);
diff --git a/qemu/hw/i8259.c b/qemu/hw/i8259.c
index 6d41a5e..9da4360 100644
--- a/qemu/hw/i8259.c
+++ b/qemu/hw/i8259.c
@@ -186,9 +186,14 @@ static void i8259_set_irq(void *opaque, int irq, int level)
 {
     PicState2 *s = opaque;
 #ifdef KVM_CAP_IRQCHIP
-    if (kvm_enabled())
-	if (kvm_set_irq(irq, level))
-	    return;
+    if (kvm_enabled()) {
+        int pic_ret;
+        if (kvm_set_irq(irq, level, &pic_ret)) {
+            if (pic_ret != 0)
+                apic_set_irq_delivered();
+            return;
+        }
+    }
 #endif
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
     if (level != irq_level[irq]) {
diff --git a/qemu/hw/pc.h b/qemu/hw/pc.h
index c42277e..016c036 100644
--- a/qemu/hw/pc.h
+++ b/qemu/hw/pc.h
@@ -48,6 +48,7 @@ IOAPICState *ioapic_init(void);
 void ioapic_set_irq(void *opaque, int vector, int level);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
+void apic_set_irq_delivered(void);
 
 /* i8254.c */
 
diff --git a/qemu/qemu-kvm.c b/qemu/qemu-kvm.c
index 789e637..6bff43a 100644
--- a/qemu/qemu-kvm.c
+++ b/qemu/qemu-kvm.c
@@ -1254,9 +1254,9 @@ int kvm_get_phys_ram_page_bitmap(unsigned char *bitmap)
 
 #ifdef KVM_CAP_IRQCHIP
 
-int kvm_set_irq(int irq, int level)
+int kvm_set_irq(int irq, int level, int *status)
 {
-    return kvm_set_irq_level(kvm_context, irq, level);
+    return kvm_set_irq_level(kvm_context, irq, level, status);
 }
 
 #endif
diff --git a/qemu/qemu-kvm.h b/qemu/qemu-kvm.h
index eebf7ab..8795362 100644
--- a/qemu/qemu-kvm.h
+++ b/qemu/qemu-kvm.h
@@ -31,7 +31,7 @@ int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap);
 int kvm_qemu_init_env(CPUState *env);
 int kvm_qemu_check_extension(int ext);
 void kvm_apic_init(CPUState *env);
-int kvm_set_irq(int irq, int level);
+int kvm_set_irq(int irq, int level, int *status);
 
 int kvm_physical_memory_set_dirty_tracking(int enable);
 int kvm_update_dirty_pages_log(void);
diff --git a/user/main.c b/user/main.c
index 93c7418..1530ae2 100644
--- a/user/main.c
+++ b/user/main.c
@@ -200,7 +200,7 @@ static int irqchip_io(void *opaque, int size, int is_write,
 	addr -= IRQCHIP_IO_BASE;
 
 	if (is_write) {
-		kvm_set_irq_level(kvm, addr, *value);
+		kvm_set_irq_level(kvm, addr, *value, NULL);
 	}
 	return 0;
 }
-- 
1.6.1