From patchwork Sun May 31 18:59:32 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Michael S. Tsirkin" X-Patchwork-Id: 27133 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n4VIxnRq006409 for ; Sun, 31 May 2009 18:59:49 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751907AbZEaS7o (ORCPT ); Sun, 31 May 2009 14:59:44 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752056AbZEaS7o (ORCPT ); Sun, 31 May 2009 14:59:44 -0400 Received: from mx2.redhat.com ([66.187.237.31]:43316 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751614AbZEaS7o (ORCPT ); Sun, 31 May 2009 14:59:44 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n4VIxj12016197; Sun, 31 May 2009 14:59:45 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n4VIxjKq019030; Sun, 31 May 2009 14:59:45 -0400 Received: from redhat.com (vpn-10-98.str.redhat.com [10.32.10.98]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n4VIxgTj019755; Sun, 31 May 2009 14:59:42 -0400 Date: Sun, 31 May 2009 21:59:32 +0300 From: "Michael S. Tsirkin" To: Gregory Haskins , kvm@vger.kernel.org, avi@redhat.com, mtosatti@redhat.com Subject: [PATCH 3/3] virt_irq: virtual device for injecting interrupts Message-ID: <20090531185932.GD10043@redhat.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.17+20080114 (2008-01-14) X-Scanned-By: MIMEDefang 2.58 on 172.16.27.26 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org 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 --- 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 + */ + +#include +#include +#include +#include +#include + +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 + +/* 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