diff mbox

[RFC,3/3] hw/vfio/platform: add forwarded irq support

Message ID 1423800020-10940-4-git-send-email-eric.auger@linaro.org
State New
Headers show

Commit Message

Auger Eric Feb. 13, 2015, 4 a.m. UTC
Tests whether the forwarded IRQ modality is available.
In the positive device IRQs are forwarded. This control is
achieved with KVM-VFIO device. with such a modality injection
still is handled through irqfds. However end of interrupt is
not trapped anymore. As soon as the guest completes its virtual
IRQ, the corresponding physical IRQ is completed and the same
physical IRQ can hit again.

A new x-forward property enables to force forwarding off although
enabled by the kernel.

Signed-off-by: Eric Auger <eric.auger@linaro.org>

---

v8 -> v9:
- use new kvm_vfio_dev_irq struct
---
 hw/vfio/platform.c              | 64 +++++++++++++++++++++++++++++++++++++++++
 include/hw/vfio/vfio-platform.h |  3 ++
 trace-events                    |  1 +
 3 files changed, 68 insertions(+)
diff mbox

Patch

diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index cadc824..b6ba5b3 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -238,6 +238,63 @@  static int vfio_start_eventfd_injection(VFIOINTp *intp)
 }
 
 /*
+ * Functions used with forwarding capability
+ */
+
+#ifdef CONFIG_KVM
+
+static bool has_kvm_vfio_forward_capability(void)
+{
+    struct kvm_device_attr attr = {
+         .group = KVM_DEV_VFIO_DEVICE,
+         .attr = KVM_DEV_VFIO_DEVICE_FORWARD_IRQ};
+
+    if (ioctl(vfio_kvm_device_fd, KVM_HAS_DEVICE_ATTR, &attr) == 0) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static int vfio_set_forwarding(VFIOINTp *intp)
+{
+    int argsz;
+    struct kvm_device_attr attr = {
+         .group = KVM_DEV_VFIO_DEVICE,
+         .attr = KVM_DEV_VFIO_DEVICE_FORWARD_IRQ};
+    __u32 *pvirq;
+
+    if (intp->forwarded) {
+        return -EINVAL;
+    }
+
+    argsz = sizeof(*intp->fwd_irq) + sizeof(*pvirq);
+    intp->fwd_irq = g_malloc0(argsz);
+    intp->fwd_irq->argsz = argsz;
+    intp->fwd_irq->fd = intp->vdev->vbasedev.fd;
+    intp->fwd_irq->index = intp->pin;
+    intp->fwd_irq->start = 0;
+    intp->fwd_irq->count = 1;
+    pvirq = (__u32 *)&intp->fwd_irq->gsi;
+    *pvirq = (uint32_t)intp->virtualID;
+
+    attr.addr = (uint64_t)(unsigned long)intp->fwd_irq;
+
+    if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
+            error_report("Failed to forward IRQ %d through KVM VFIO device",
+                         intp->pin);
+            g_free(intp->fwd_irq);
+            return -errno;
+    }
+    trace_vfio_start_fwd_injection(intp->pin);
+    intp->forwarded = true;
+
+    return 0;
+}
+
+#endif
+
+/*
  * Functions used for irqfd
  */
 
@@ -289,6 +346,11 @@  static int vfio_start_irqfd_injection(VFIOINTp *intp)
         .flags = KVM_IRQFD_FLAG_RESAMPLE,
     };
 
+    if (has_kvm_vfio_forward_capability() &&
+                 intp->vdev->forward_allowed) {
+        vfio_set_forwarding(intp);
+    }
+
     if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) {
         error_report("vfio: Error: Failed to assign the irqfd: %m");
         goto fail_irqfd;
@@ -384,6 +446,7 @@  static VFIOINTp *vfio_init_intp(VFIODevice *vbasedev, unsigned int index)
     intp->vdev = vdev;
     intp->pin = index;
     intp->state = VFIO_IRQ_INACTIVE;
+    intp->forwarded = false;
     sysbus_init_irq(sbdev, &intp->qemuirq);
 
     /* Get an eventfd for trigger */
@@ -716,6 +779,7 @@  static Property vfio_platform_dev_properties[] = {
     DEFINE_PROP_UINT32("mmap-timeout-ms", VFIOPlatformDevice,
                        mmap_timeout, 1100),
     DEFINE_PROP_BOOL("x-irqfd", VFIOPlatformDevice, irqfd_allowed, true),
+    DEFINE_PROP_BOOL("x-forward", VFIOPlatformDevice, forward_allowed, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/include/hw/vfio/vfio-platform.h b/include/hw/vfio/vfio-platform.h
index 097448b..693066d 100644
--- a/include/hw/vfio/vfio-platform.h
+++ b/include/hw/vfio/vfio-platform.h
@@ -42,6 +42,8 @@  typedef struct VFIOINTp {
     bool kvm_accel; /* set when QEMU bypass through KVM enabled */
     uint8_t pin; /* index */
     uint32_t virtualID; /* virtual IRQ */
+    struct kvm_vfio_dev_irq *fwd_irq;
+    bool forwarded;
 } VFIOINTp;
 
 typedef int (*start_irq_fn_t)(VFIOINTp *intp);
@@ -59,6 +61,7 @@  typedef struct VFIOPlatformDevice {
     start_irq_fn_t start_irq_fn;
     QemuMutex  intp_mutex;
     bool irqfd_allowed; /* debug option to force irqfd on/off */
+    bool forward_allowed; /* debug option to force forwarding on/off */
 } VFIOPlatformDevice;
 
 
diff --git a/trace-events b/trace-events
index 7a6a6aa..9a138d6 100644
--- a/trace-events
+++ b/trace-events
@@ -1557,6 +1557,7 @@  vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions,
 vfio_put_base_device(int fd) "close vdev->fd=%d"
 
 # hw/vfio/platform.c
+vfio_start_fwd_injection(int pin) "forwarding set for IRQ pin %d"
 vfio_platform_eoi(int pin, int fd) "EOI IRQ pin %d (fd=%d)"
 vfio_platform_mmap_set_enabled(bool enabled) "fast path = %d"
 vfio_platform_intp_mmap_enable(int pin) "IRQ #%d still active, stay in slow path"