* [Qemu-devel] [RFC v2 3/4] kvm: add kvm_vfio_get_device_irq
2015-05-04 12:49 [Qemu-devel] [RFC v2 0/4] VFIO Platform device featuring IRQ forwarding Eric Auger
2015-05-04 12:49 ` [Qemu-devel] [RFC v2 1/4] linux-headers: Update KVM header for KVM-VFIO FORWARD/UNFORWARD Eric Auger
2015-05-04 12:49 ` [Qemu-devel] [RFC v2 2/4] hw/vfio/common: vfio_kvm_device_fd moved in the common header Eric Auger
@ 2015-05-04 12:49 ` Eric Auger
2015-05-04 12:49 ` [Qemu-devel] [RFC v2 4/4] hw/vfio/platform: add forwarded irq support Eric Auger
3 siblings, 0 replies; 5+ messages in thread
From: Eric Auger @ 2015-05-04 12:49 UTC (permalink / raw)
To: eric.auger, eric.auger, qemu-devel, alex.williamson
Cc: b.reynal, kvmarm, christoffer.dall, patches
Since the introduction of the qemu_irq/gsi hash table in kvm,
the gsi information is stored in kvm. New functions are introduced
to allocate/populate a kvm_vfio_dev_irq struct pointer from a
qemu_irq object and free it.
Signed-off-by: Eric Auger <eric.auger@linaro.org>
---
include/sysemu/kvm.h | 5 +++++
kvm-all.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+)
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index bc3f230..42cc6c4 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -423,6 +423,11 @@ int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n,
qemu_irq irq);
void kvm_irqchip_set_qemuirq_gsi(KVMState *s, qemu_irq irq, int gsi);
+struct kvm_vfio_dev_irq;
+int kvm_vfio_get_device_irq(KVMState *s, int fd, int index,
+ int start, int count, qemu_irq irq,
+ struct kvm_vfio_dev_irq **vfio_dev_irq);
+void kvm_vfio_put_device_irq(struct kvm_vfio_dev_irq *vfio_dev_irq);
void kvm_pc_gsi_handler(void *opaque, int n, int level);
void kvm_pc_setup_irq_routing(bool pci_enabled);
void kvm_init_irq_routing(KVMState *s);
diff --git a/kvm-all.c b/kvm-all.c
index d2cb7ed..83a9689 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1454,6 +1454,38 @@ static int kvm_irqchip_create(MachineState *machine, KVMState *s)
return 0;
}
+int kvm_vfio_get_device_irq(KVMState *s, int fd, int index,
+ int start, int count, qemu_irq irq,
+ struct kvm_vfio_dev_irq **vfio_dev_irq)
+{
+ gpointer key, gsi;
+ gboolean found = g_hash_table_lookup_extended(s->gsimap, irq, &key, &gsi);
+ struct kvm_vfio_dev_irq *pirq;
+ __u32 *pgsi;
+ int argsz;
+
+ if (!found) {
+ return -ENXIO;
+ }
+
+ argsz = sizeof(*pirq) + sizeof(*pgsi);
+ pirq = g_malloc0(argsz);
+ pirq->argsz = argsz;
+ pirq->fd = fd;
+ pirq->index = index;
+ pirq->start = start;
+ pirq->count = count;
+ pgsi = (__u32 *)&pirq->gsi;
+ *pgsi = GPOINTER_TO_INT(gsi);
+ *vfio_dev_irq = pirq;
+ return 0;
+}
+
+void kvm_vfio_put_device_irq(struct kvm_vfio_dev_irq *vfio_dev_irq)
+{
+ g_free(vfio_dev_irq);
+}
+
/* Find number of supported CPUs using the recommended
* procedure from the kernel API documentation to cope with
* older kernels that may be missing capabilities.
--
1.8.3.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [RFC v2 4/4] hw/vfio/platform: add forwarded irq support
2015-05-04 12:49 [Qemu-devel] [RFC v2 0/4] VFIO Platform device featuring IRQ forwarding Eric Auger
` (2 preceding siblings ...)
2015-05-04 12:49 ` [Qemu-devel] [RFC v2 3/4] kvm: add kvm_vfio_get_device_irq Eric Auger
@ 2015-05-04 12:49 ` Eric Auger
3 siblings, 0 replies; 5+ messages in thread
From: Eric Auger @ 2015-05-04 12:49 UTC (permalink / raw)
To: eric.auger, eric.auger, qemu-devel, alex.williamson
Cc: b.reynal, kvmarm, christoffer.dall, patches
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>
---
v1 -> v2:
- use kvm_vfio_get|put_device_irq, new irq connect notifier and
integrate with 2 stage eventfd/irqfd setup
v1:
- moved in a separate series
v8 -> v9 (KVM platform device passthrough series):
- use new kvm_vfio_dev_irq struct
Signed-off-by: Eric Auger <eric.auger@linaro.org>
---
hw/vfio/platform.c | 103 +++++++++++++++++++++++++++++++++++++---
include/hw/vfio/vfio-platform.h | 3 ++
trace-events | 1 +
3 files changed, 100 insertions(+), 7 deletions(-)
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index 901b98e..52c6d59 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -411,6 +411,88 @@ fail_irqfd:
return;
}
+/*
+ * Functions used with forwarding capability
+ */
+
+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 void vfio_start_forward_injection(SysBusDevice *sbdev, qemu_irq irq)
+{
+ VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
+ VFIOINTp *intp;
+ bool found = false;
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_VFIO_DEVICE,
+ .attr = KVM_DEV_VFIO_DEVICE_FORWARD_IRQ};
+
+ QLIST_FOREACH(intp, &vdev->intp_list, next) {
+ if (intp->qemuirq == irq) {
+ found = true;
+ break;
+ }
+ }
+ assert(found);
+
+ if (intp->forwarded) {
+ return;
+ }
+
+ /*
+ * stop VFIO signaling and unmask the physical IRQ since
+ * forwarding cannot be set if the IRQ is active or vfio masked
+ */
+ vfio_disable_irqindex(&intp->vdev->vbasedev, intp->pin);
+ vfio_unmask_single_irqindex(&intp->vdev->vbasedev, intp->pin);
+
+ kvm_vfio_get_device_irq(kvm_state, intp->vdev->vbasedev.fd,
+ intp->pin, 0, 1, intp->qemuirq, &intp->fwd_irq);
+
+ attr.addr = (uint64_t)(unsigned long)intp->fwd_irq;
+
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr) < 0) {
+ error_report("vfio: failed to forward irq %d, do standard irqfd",
+ intp->pin);
+ kvm_vfio_put_device_irq(intp->fwd_irq);
+ } else {
+ trace_vfio_platform_start_fwd_injection(intp->pin);
+ intp->forwarded = true;
+ }
+
+ if (kvm_irqchip_add_irqfd_notifier(kvm_state, &intp->interrupt,
+ &intp->unmask, irq) < 0) {
+ goto fail_irqfd;
+ }
+
+ if (vfio_set_trigger_eventfd(intp, NULL) < 0) {
+ goto fail_vfio;
+ }
+ /* only used if forwarding setup failed */
+ if (vfio_set_resample_eventfd(intp) < 0) {
+ goto fail_vfio;
+ }
+
+ intp->kvm_accel = true;
+ return;
+fail_vfio:
+ kvm_irqchip_remove_irqfd_notifier(kvm_state, &intp->interrupt, irq);
+fail_irqfd:
+ vfio_start_eventfd_injection(intp);
+ vfio_unmask_single_irqindex(&vdev->vbasedev, intp->pin);
+ return;
+}
+
#endif /* CONFIG_KVM */
/* VFIO skeleton */
@@ -655,13 +737,6 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
vbasedev->type = VFIO_DEVICE_TYPE_PLATFORM;
vbasedev->ops = &vfio_platform_ops;
-#ifdef CONFIG_KVM
- if (kvm_irqfds_enabled() && kvm_resamplefds_enabled() &&
- vdev->irqfd_allowed) {
- sbc->connect_irq_notifier = vfio_start_irqfd_injection;
- }
-#endif
-
trace_vfio_platform_realize(vbasedev->name, vdev->compat);
ret = vfio_base_device_init(vbasedev);
@@ -679,6 +754,19 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
QLIST_FOREACH(intp, &vdev->intp_list, next) {
vfio_start_eventfd_injection(intp);
}
+
+#ifdef CONFIG_KVM
+ if (kvm_irqfds_enabled() && kvm_resamplefds_enabled() &&
+ vdev->irqfd_allowed) {
+ if (has_kvm_vfio_forward_capability() &&
+ vdev->forward_allowed) {
+ sbc->connect_irq_notifier = vfio_start_forward_injection;
+ } else {
+ sbc->connect_irq_notifier = vfio_start_irqfd_injection;
+ }
+ }
+#endif
+
}
static const VMStateDescription vfio_platform_vmstate = {
@@ -692,6 +780,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 c5cf1d7..900f918 100644
--- a/include/hw/vfio/vfio-platform.h
+++ b/include/hw/vfio/vfio-platform.h
@@ -42,6 +42,8 @@ typedef struct VFIOINTp {
uint8_t pin; /* index */
uint32_t flags; /* IRQ info flags */
bool kvm_accel; /* set when QEMU bypass through KVM enabled */
+ struct kvm_vfio_dev_irq *fwd_irq;
+ bool forwarded;
} VFIOINTp;
/* function type for user side eventfd handler */
@@ -59,6 +61,7 @@ typedef struct VFIOPlatformDevice {
QEMUTimer *mmap_timer; /* allows fast-path resume after IRQ hit */
QemuMutex intp_mutex; /* protect the intp_list IRQ state */
bool irqfd_allowed; /* debug option to force irqfd on/off */
+ bool forward_allowed; /* debug option to force forwarding on/off */
} VFIOPlatformDevice;
typedef struct VFIOPlatformDeviceClass {
diff --git a/trace-events b/trace-events
index cb6381a..99d2b9c 100644
--- a/trace-events
+++ b/trace-events
@@ -1572,6 +1572,7 @@ vfio_platform_intp_inject_pending_lockheld(int pin, int fd) "Inject pending IRQ
vfio_platform_populate_interrupts(int pin, int count, int flags) "- IRQ index %d: count %d, flags=0x%x"
vfio_intp_interrupt_set_pending(int index) "irq %d is set PENDING"
vfio_platform_start_irqfd_injection(int index, int fd, int resamplefd) "IRQ index=%d, fd = %d, resamplefd = %d"
+vfio_platform_start_fwd_injection(int pin) "forwarding set for IRQ pin %d"
#hw/acpi/memory_hotplug.c
mhp_acpi_invalid_slot_selected(uint32_t slot) "0x%"PRIx32
--
1.8.3.2
^ permalink raw reply related [flat|nested] 5+ messages in thread