[PATCH 3/3] virt_irq: virtual device for injecting interrupts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



virt_irq is an alternative to irqfd interface, based
on the virt core infrastructure, which also serves
as an example of virt core usage.

The main advantage here compared to irqfd is the use of fd
created by the virt core, which avoids any possibility of
deadlock issues with eventfd and kvm file descriptors
referencing each other.

As a minor positive side effect, we don't need an
extra lock and don't need to schedule work to inject
the interrupt.

Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx>
---
 drivers/virt/Kconfig     |    6 +++
 drivers/virt/Makefile    |    1 +
 drivers/virt/virt_irq.c  |   78 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/virt_irq.h |   19 +++++++++++
 4 files changed, 104 insertions(+), 0 deletions(-)
 create mode 100644 drivers/virt/virt_irq.c
 create mode 100644 include/linux/virt_irq.h

diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig
index ace7b2e..060c8da 100644
--- a/drivers/virt/Kconfig
+++ b/drivers/virt/Kconfig
@@ -3,3 +3,9 @@ config VIRT_CORE
 	---help---
 	  Core support for binding kernel drivers to virtual devices.
 	  Make sure to also select any drivers you wish to use.
+
+config VIRT_IRQ
+	tristate "Virtual device for injecting interrupts from userspace"
+	depends on VIRT_CORE
+	---help---
+	  Simple virtual device that supports injecting interrupts.
diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile
index 7a77047..0072530 100644
--- a/drivers/virt/Makefile
+++ b/drivers/virt/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_VIRT_CORE) += virt_core.o
+obj-$(CONFIG_VIRT_IRQ) += virt_irq.o
diff --git a/drivers/virt/virt_irq.c b/drivers/virt/virt_irq.c
new file mode 100644
index 0000000..c10087e
--- /dev/null
+++ b/drivers/virt/virt_irq.c
@@ -0,0 +1,78 @@
+/*
+ * Virt irq device: simple virtual device for interrupt injection.
+ *
+ * Copyright (c) 2009 Red Hat Inc.
+ *
+ * Author: Michael S. Tsirkin <mst@xxxxxxxxxx>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/virt.h>
+#include <linux/virt_irq.h>
+
+struct virt_irq_dev {
+	int irq;
+};
+
+static ssize_t virt_irq_write(struct file *f, const char __user *p, size_t s,
+			      loff_t *o)
+{
+	struct virt_dev *dev = virt_dev_get(f);
+	struct virt_irq_dev *vdev = dev->driver_ctx;
+	int r = dev->hypervisor->set_irq(dev->hypervisor, vdev->irq, 0, 1);
+	dev->hypervisor->set_irq(dev->hypervisor, vdev->irq, 0, 0);
+	return r < 0 ? r : 0;
+}
+
+int virt_irq_probe(struct virt_driver *driver, struct virt_dev *dev,
+		    const void *id, int id_len)
+{
+	struct virt_irq_dev *vdev;
+	const struct virt_irq_id *irq_id;
+	if (!dev->hypervisor->set_irq)
+		return -ENODEV;
+	if (id_len != sizeof id)
+		return -ENODEV;
+	irq_id = id;
+	if (memcmp(irq_id->name, "irq", sizeof irq_id->name))
+		return -ENODEV;
+	
+	vdev = kmalloc(sizeof *vdev, GFP_KERNEL);
+	if (!vdev)
+		return -ENOMEM;
+	vdev->irq = irq_id->irq;
+	dev->driver_ctx = vdev;
+	return 0;
+}
+
+void virt_irq_remove(struct virt_driver *driver, struct virt_dev *dev)
+{
+	kfree(dev->driver_ctx);
+}
+
+static struct file_operations virt_irq_fops = {
+	.owner	 = THIS_MODULE,
+	.write   = virt_irq_write,
+};
+
+static struct virt_driver virt_irq_driver = {
+	.name = "virt_irq",
+	.device_probe = virt_irq_probe,
+	.device_remove = virt_irq_remove,
+};
+
+static int __init virt_irq_init(void)
+{
+	virt_driver_register(&virt_irq_driver, &virt_irq_fops);
+	return 0;
+}
+
+static void __exit virt_irq_cleanup(void)
+{
+	virt_driver_unregister(&virt_irq_driver);
+}
+
+module_init(virt_irq_init);
+module_exit(virt_irq_cleanup);
diff --git a/include/linux/virt_irq.h b/include/linux/virt_irq.h
new file mode 100644
index 0000000..6b3421d
--- /dev/null
+++ b/include/linux/virt_irq.h
@@ -0,0 +1,19 @@
+#ifndef LINUX_VIRT_IRQ_H
+#define LINUX_VIRT_IRQ_H
+
+#include <linux/types.h>
+
+/* Format for IRQ device id */
+
+struct virt_irq_id {
+	__u8 name[4]; /* Must be "irq\0" */
+	__u32 irq;
+};
+
+static inline void virt_irq_id_init(struct virt_irq_id *id, int irq)
+{
+	memcpy(id->name, "irq", sizeof id->name);
+	id->irq = irq;
+}
+
+#endif
-- 
1.6.3.1.175.g3be7e0
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux