Factor the wired IRQ eventfd and KVM irqfd setup and teardown out of vfio_pci_enable_intx() and vfio_pci_disable_intx() into vfio_irq_enable() and vfio_irq_disable() in vfio/core.c, and move union vfio_irq_eventfd to vfio.h so both PCI INTx and VFIO platform devices can share them. The is a mechanical code move, no functional change. Signed-off-by: Mostafa Saleh --- include/kvm/vfio.h | 27 +++++++++-- vfio/core.c | 107 +++++++++++++++++++++++++++++++++++++++++++ vfio/pci.c | 110 +++------------------------------------------ 3 files changed, 137 insertions(+), 107 deletions(-) diff --git a/include/kvm/vfio.h b/include/kvm/vfio.h index ac7b622..9a5783e 100644 --- a/include/kvm/vfio.h +++ b/include/kvm/vfio.h @@ -6,6 +6,7 @@ #include "kvm/pci.h" #include +#include #define vfio_dev_err(vdev, fmt, ...) \ pr_err("%s: " fmt, (vdev)->params->name, ##__VA_ARGS__) @@ -70,13 +71,17 @@ struct vfio_pci_msi_common { #define VFIO_PCI_IRQ_MODE_MSI (1 << 1) #define VFIO_PCI_IRQ_MODE_MSIX (1 << 2) +struct vfio_irq { + int gsi; + int trigger_fd; + int unmask_fd; +}; + struct vfio_pci_device { struct pci_device_header hdr; unsigned long irq_modes; - int intx_fd; - int unmask_fd; - unsigned int intx_gsi; + struct vfio_irq intx; struct vfio_pci_msi_common msi; struct vfio_pci_msi_common msix; struct vfio_pci_msix_table msix_table; @@ -119,10 +124,26 @@ struct vfio_group { struct list_head list; }; +/* Wrapper around UAPI vfio_irq_set */ +union vfio_irq_eventfd { + struct vfio_irq_set irq; + u8 buffer[sizeof(struct vfio_irq_set) + sizeof(int)]; +}; + +static inline void set_vfio_irq_eventd_payload(union vfio_irq_eventfd *evfd, + int fd) +{ + memcpy(&evfd->irq.data, &fd, sizeof(fd)); +} + int vfio_device_parser(const struct option *opt, const char *arg, int unset); int vfio_map_region(struct kvm *kvm, struct vfio_device *vdev, struct vfio_region *region); void vfio_unmap_region(struct kvm *kvm, struct vfio_region *region); +int vfio_irq_enable(struct kvm *kvm, struct vfio_device *vdev, + unsigned int index, struct vfio_irq *irq); +void vfio_irq_disable(struct kvm *kvm, struct vfio_device *vdev, + unsigned int index, struct vfio_irq *irq); int vfio_pci_setup_device(struct kvm *kvm, struct vfio_device *device); void vfio_pci_teardown_device(struct kvm *kvm, struct vfio_device *vdev); diff --git a/vfio/core.c b/vfio/core.c index e0c56ab..24d3f2d 100644 --- a/vfio/core.c +++ b/vfio/core.c @@ -1,8 +1,10 @@ +#include "kvm/irq.h" #include "kvm/kvm.h" #include "kvm/vfio.h" #include "kvm/ioport.h" #include +#include #include #define VFIO_DEV_DIR "/dev/vfio" @@ -282,6 +284,111 @@ void vfio_unmap_region(struct kvm *kvm, struct vfio_region *region) } } +void vfio_irq_disable(struct kvm *kvm, struct vfio_device *vdev, + unsigned int index, struct vfio_irq *irq) +{ + int gsi = irq->gsi; + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, + .index = index, + }; + + if (irq->trigger_fd == -1) + return; + + ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); + irq__del_irqfd(kvm, gsi, irq->trigger_fd); + + close(irq->trigger_fd); + close(irq->unmask_fd); + irq->trigger_fd = -1; +} + +int vfio_irq_enable(struct kvm *kvm, struct vfio_device *vdev, + unsigned int index, struct vfio_irq *irq) +{ + int ret; + int trigger_fd, unmask_fd; + union vfio_irq_eventfd trigger; + union vfio_irq_eventfd unmask; + int gsi = irq->gsi; + + if (irq->trigger_fd != -1) + return 0; + + /* + * PCI IRQ is level-triggered, so we use two eventfds. trigger_fd + * signals an interrupt from host to guest, and unmask_fd signals the + * deassertion of the line from guest to host. + */ + trigger_fd = eventfd(0, 0); + if (trigger_fd < 0) { + vfio_dev_err(vdev, "failed to create trigger eventfd"); + return trigger_fd; + } + + unmask_fd = eventfd(0, 0); + if (unmask_fd < 0) { + vfio_dev_err(vdev, "failed to create unmask eventfd"); + close(trigger_fd); + return unmask_fd; + } + + ret = irq__add_irqfd(kvm, gsi, trigger_fd, unmask_fd); + if (ret) + goto err_close; + + trigger.irq = (struct vfio_irq_set) { + .argsz = sizeof(trigger), + .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER, + .index = index, + .start = 0, + .count = 1, + }; + set_vfio_irq_eventd_payload(&trigger, trigger_fd); + + ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &trigger); + if (ret < 0) { + vfio_dev_err(vdev, "failed to setup VFIO IRQ"); + goto err_delete_line; + } + + unmask.irq = (struct vfio_irq_set) { + .argsz = sizeof(unmask), + .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK, + .index = index, + .start = 0, + .count = 1, + }; + set_vfio_irq_eventd_payload(&unmask, unmask_fd); + + ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &unmask); + if (ret < 0) { + vfio_dev_err(vdev, "failed to setup unmask IRQ"); + goto err_remove_event; + } + + irq->trigger_fd = trigger_fd; + irq->unmask_fd = unmask_fd; + + return 0; + +err_remove_event: + /* Remove trigger event */ + trigger.irq.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER; + trigger.irq.count = 0; + ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &trigger); + +err_delete_line: + irq__del_irqfd(kvm, gsi, trigger_fd); + +err_close: + close(trigger_fd); + close(unmask_fd); + return ret; +} + static int vfio_configure_device(struct kvm *kvm, struct vfio_device *vdev) { int ret; diff --git a/vfio/pci.c b/vfio/pci.c index 0bcd60e..fb98435 100644 --- a/vfio/pci.c +++ b/vfio/pci.c @@ -17,17 +17,6 @@ #define PCI_CAP_EXP_RC_ENDPOINT_SIZEOF_V1 12 #endif -/* Wrapper around UAPI vfio_irq_set */ -union vfio_irq_eventfd { - struct vfio_irq_set irq; - u8 buffer[sizeof(struct vfio_irq_set) + sizeof(int)]; -}; - -static void set_vfio_irq_eventd_payload(union vfio_irq_eventfd *evfd, int fd) -{ - memcpy(&evfd->irq.data, &fd, sizeof(fd)); -} - /* * To support MSI and MSI-X with common code, track the host and guest states of * the MSI/MSI-X capability, and of individual vectors. @@ -1213,108 +1202,21 @@ static int vfio_pci_init_msis(struct kvm *kvm, struct vfio_device *vdev, static void vfio_pci_disable_intx(struct kvm *kvm, struct vfio_device *vdev) { struct vfio_pci_device *pdev = &vdev->pci; - int gsi = pdev->intx_gsi; - struct vfio_irq_set irq_set = { - .argsz = sizeof(irq_set), - .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, - .index = VFIO_PCI_INTX_IRQ_INDEX, - }; + int gsi = pdev->intx.gsi; - if (pdev->intx_fd == -1) + if (pdev->intx.trigger_fd == -1) return; pr_debug("user requested MSI, disabling INTx %d", gsi); - ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); - irq__del_irqfd(kvm, gsi, pdev->intx_fd); - - close(pdev->intx_fd); - close(pdev->unmask_fd); - pdev->intx_fd = -1; + vfio_irq_disable(kvm, vdev, VFIO_PCI_INTX_IRQ_INDEX, &pdev->intx); } static int vfio_pci_enable_intx(struct kvm *kvm, struct vfio_device *vdev) { - int ret; - int trigger_fd, unmask_fd; - union vfio_irq_eventfd trigger; - union vfio_irq_eventfd unmask; struct vfio_pci_device *pdev = &vdev->pci; - int gsi = pdev->intx_gsi; - if (pdev->intx_fd != -1) - return 0; - - /* - * PCI IRQ is level-triggered, so we use two eventfds. trigger_fd - * signals an interrupt from host to guest, and unmask_fd signals the - * deassertion of the line from guest to host. - */ - trigger_fd = eventfd(0, 0); - if (trigger_fd < 0) { - vfio_dev_err(vdev, "failed to create trigger eventfd"); - return trigger_fd; - } - - unmask_fd = eventfd(0, 0); - if (unmask_fd < 0) { - vfio_dev_err(vdev, "failed to create unmask eventfd"); - close(trigger_fd); - return unmask_fd; - } - - ret = irq__add_irqfd(kvm, gsi, trigger_fd, unmask_fd); - if (ret) - goto err_close; - - trigger.irq = (struct vfio_irq_set) { - .argsz = sizeof(trigger), - .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER, - .index = VFIO_PCI_INTX_IRQ_INDEX, - .start = 0, - .count = 1, - }; - set_vfio_irq_eventd_payload(&trigger, trigger_fd); - - ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &trigger); - if (ret < 0) { - vfio_dev_err(vdev, "failed to setup VFIO IRQ"); - goto err_delete_line; - } - - unmask.irq = (struct vfio_irq_set) { - .argsz = sizeof(unmask), - .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK, - .index = VFIO_PCI_INTX_IRQ_INDEX, - .start = 0, - .count = 1, - }; - set_vfio_irq_eventd_payload(&unmask, unmask_fd); - - ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &unmask); - if (ret < 0) { - vfio_dev_err(vdev, "failed to setup unmask IRQ"); - goto err_remove_event; - } - - pdev->intx_fd = trigger_fd; - pdev->unmask_fd = unmask_fd; - - return 0; - -err_remove_event: - /* Remove trigger event */ - trigger.irq.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER; - trigger.irq.count = 0; - ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &trigger); - -err_delete_line: - irq__del_irqfd(kvm, gsi, trigger_fd); - -err_close: - close(trigger_fd); - close(unmask_fd); - return ret; + return vfio_irq_enable(kvm, vdev, VFIO_PCI_INTX_IRQ_INDEX, &pdev->intx); } static int vfio_pci_init_intx(struct kvm *kvm, struct vfio_device *vdev) @@ -1345,9 +1247,9 @@ static int vfio_pci_init_intx(struct kvm *kvm, struct vfio_device *vdev) } /* Guest is going to ovewrite our irq_line... */ - pdev->intx_gsi = pdev->hdr.irq_line - KVM_IRQ_OFFSET; + pdev->intx.gsi = pdev->hdr.irq_line - KVM_IRQ_OFFSET; - pdev->intx_fd = -1; + pdev->intx.trigger_fd = -1; return 0; } -- 2.56.0.307.g5fe7bd680c-goog