From e6b784985c14afe9805bfc8706858884b0259ab5 Mon Sep 17 00:00:00 2001
From: Sheng Yang <sheng@linux.intel.com>
Date: Thu, 2 Oct 2008 14:20:22 +0800
Subject: [PATCH 1/2] KVM: Separate interrupt sources

Keep a record of current interrupt state before update, and don't
assert/deassert repeatly. So that every caller of kvm_set_irq() can be identify
as a separate interrupt sources for IOAPIC/PIC to implement logical OR of level
trig interrupts on one IRQ line.

Notice that userspace devices are treated as one device for each IRQ line. The
correctness of sharing interrupt for each IRQ line should be ensured by
userspace program (QEmu).

Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
 arch/x86/kvm/x86.c       |   25 +++++++++++++++++++++----
 include/linux/kvm_host.h |    3 +++
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ad7a227..e685d48 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -135,8 +135,11 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
 	 * finer-grained lock, update this
 	 */
 	mutex_lock(&assigned_dev->kvm->lock);
-	kvm_set_irq(assigned_dev->kvm,
-		    assigned_dev->guest_irq, 1);
+	if (assigned_dev->irq_state == 0) {
+		kvm_set_irq(assigned_dev->kvm,
+				assigned_dev->guest_irq, 1);
+		assigned_dev->irq_state = 1;
+	}
 	mutex_unlock(&assigned_dev->kvm->lock);
 	kvm_put_kvm(assigned_dev->kvm);
 }
@@ -165,7 +168,10 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
 
 	dev = container_of(kian, struct kvm_assigned_dev_kernel,
 			   ack_notifier);
-	kvm_set_irq(dev->kvm, dev->guest_irq, 0);
+	if (dev->irq_state == 1) {
+		kvm_set_irq(dev->kvm, dev->guest_irq, 0);
+		dev->irq_state = 0;
+	}
 	enable_irq(dev->host_irq);
 }
 
@@ -1993,7 +1999,18 @@ long kvm_arch_vm_ioctl(struct file *filp,
 			goto out;
 		if (irqchip_in_kernel(kvm)) {
 			mutex_lock(&kvm->lock);
-			kvm_set_irq(kvm, irq_event.irq, irq_event.level);
+			/*
+			 * Take one IRQ line as from one device, shared IRQ
+			 * line should also be handled in the userspace before
+			 * use KVM_IRQ_LINE ioctl to change IRQ line state.
+			 */
+			if (kvm->userspace_intrsource_states[irq_event.irq]
+					!= irq_event.level) {
+				kvm_set_irq(kvm, irq_event.irq,
+						irq_event.level);
+				kvm->userspace_intrsource_states[irq_event.irq]
+						= irq_event.level;
+			}
 			mutex_unlock(&kvm->lock);
 			r = 0;
 		}
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 73b7c52..8c2a504 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -129,6 +129,8 @@ struct kvm {
 	unsigned long mmu_notifier_seq;
 	long mmu_notifier_count;
 #endif
+
+	int userspace_intrsource_states[KVM_IOAPIC_NUM_PINS];
 };
 
 /* The guest did something we don't support. */
@@ -303,6 +305,7 @@ struct kvm_assigned_dev_kernel {
 	int host_irq;
 	int guest_irq;
 	int irq_requested;
+	int irq_state;
 	struct pci_dev *dev;
 	struct kvm *kvm;
 };
-- 
1.5.3

