diff mbox

KVM: IRQFD: equip irqfd and resamplefd with polarity

Message ID 1378963707-1259-1-git-send-email-pingfank@linux.vnet.ibm.com
State New
Headers show

Commit Message

pingfan liu Sept. 12, 2013, 5:28 a.m. UTC
Nowadays, irqfd can emulate trigger mode, but it can not emulate
trigger polarity. While in some cases, ioapic ioredtbl[x] expects
_low_ active. So equipping irqfd with the ability. Correspondingly,
resamplefd will have the same polarity as irqfd.

Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
---
This helps to step around making the interrupt component re-entrance
in qemu
---
 include/linux/kvm_host.h |  1 +
 include/uapi/linux/kvm.h |  2 ++
 virt/kvm/eventfd.c       | 32 ++++++++++++++++++++++----------
 3 files changed, 25 insertions(+), 10 deletions(-)
diff mbox

Patch

diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index a63d83e..0b8c3b1 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -678,6 +678,7 @@  bool kvm_is_mmio_pfn(pfn_t pfn);
 struct kvm_irq_ack_notifier {
 	struct hlist_node link;
 	unsigned gsi;
+	int polarity; /* 0 high active */
 	void (*irq_acked)(struct kvm_irq_ack_notifier *kian);
 };
 
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index acccd08..bba3a1b 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -740,6 +740,8 @@  struct kvm_xen_hvm_config {
  * emlation.  See Documentation/virtual/kvm/api.txt.
  */
 #define KVM_IRQFD_FLAG_RESAMPLE (1 << 1)
+/* 0: high-active */
+#define KVM_IRQFD_FLAG_POLARITY (1<<2)
 
 struct kvm_irqfd {
 	__u32 fd;
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index 1550637..865c656 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -77,6 +77,7 @@  struct _irqfd {
 	struct kvm_kernel_irq_routing_entry __rcu *irq_entry;
 	/* Used for level IRQ fast-path */
 	int gsi;
+	int polarity; /* 0 high active */
 	struct work_struct inject;
 	/* The resampler used by this irqfd (resampler-only) */
 	struct _irqfd_resampler *resampler;
@@ -100,13 +101,13 @@  irqfd_inject(struct work_struct *work)
 	struct kvm *kvm = irqfd->kvm;
 
 	if (!irqfd->resampler) {
-		kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1,
-				false);
-		kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0,
-				false);
+		kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi,
+				!irqfd->polarity, false);
+		kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi,
+				!!irqfd->polarity, false);
 	} else
 		kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
-			    irqfd->gsi, 1, false);
+			    irqfd->gsi, !irqfd->polarity, false);
 }
 
 /*
@@ -123,7 +124,8 @@  irqfd_resampler_ack(struct kvm_irq_ack_notifier *kian)
 	resampler = container_of(kian, struct _irqfd_resampler, notifier);
 
 	kvm_set_irq(resampler->kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
-		    resampler->notifier.gsi, 0, false);
+		resampler->notifier.gsi,
+		!!resampler->notifier.polarity, false);
 
 	rcu_read_lock();
 
@@ -148,7 +150,7 @@  irqfd_resampler_shutdown(struct _irqfd *irqfd)
 		list_del(&resampler->link);
 		kvm_unregister_irq_ack_notifier(kvm, &resampler->notifier);
 		kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
-			    resampler->notifier.gsi, 0, false);
+			    resampler->notifier.gsi, !!irqfd->polarity, false);
 		kfree(resampler);
 	}
 
@@ -302,6 +304,7 @@  kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
 
 	irqfd->kvm = kvm;
 	irqfd->gsi = args->gsi;
+	irqfd->polarity = !!(args->flags & KVM_IRQFD_FLAG_POLARITY);
 	INIT_LIST_HEAD(&irqfd->list);
 	INIT_WORK(&irqfd->inject, irqfd_inject);
 	INIT_WORK(&irqfd->shutdown, irqfd_shutdown);
@@ -337,8 +340,15 @@  kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
 		list_for_each_entry(resampler,
 				    &kvm->irqfds.resampler_list, link) {
 			if (resampler->notifier.gsi == irqfd->gsi) {
-				irqfd->resampler = resampler;
-				break;
+				if (likely(resampler->notifier.polarity ==
+					irqfd->polarity)) {
+					irqfd->resampler = resampler;
+					break;
+				} else {
+					ret = -EBUSY;
+					mutex_unlock(&kvm->irqfds.resampler_lock);
+					goto fail;
+				}
 			}
 		}
 
@@ -353,6 +363,7 @@  kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
 			resampler->kvm = kvm;
 			INIT_LIST_HEAD(&resampler->list);
 			resampler->notifier.gsi = irqfd->gsi;
+			resampler->notifier.polarity = irqfd->polarity;
 			resampler->notifier.irq_acked = irqfd_resampler_ack;
 			INIT_LIST_HEAD(&resampler->link);
 
@@ -489,7 +500,8 @@  kvm_irqfd_deassign(struct kvm *kvm, struct kvm_irqfd *args)
 int
 kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
 {
-	if (args->flags & ~(KVM_IRQFD_FLAG_DEASSIGN | KVM_IRQFD_FLAG_RESAMPLE))
+	if (args->flags & ~(KVM_IRQFD_FLAG_DEASSIGN | KVM_IRQFD_FLAG_RESAMPLE
+		| KVM_IRQFD_FLAG_POLARITY))
 		return -EINVAL;
 
 	if (args->flags & KVM_IRQFD_FLAG_DEASSIGN)