From 9d015c106d2c53edae8f2d11e5bdf22811206f3b Mon Sep 17 00:00:00 2001 From: Minwoo Im Date: Wed, 13 Nov 2024 18:55:22 +0900 Subject: [PATCH] vfio/device: support enable/disable specific irq This patch added 'start' parameter to 'vfio_set_irq' API to specify start IRQ number to configure to vfio-pci kernel driver. This patch also converted previous 'vfio_disable_irq' to 'vfio_disable_irq_all' to disable all enabled irqs. 'vfio_disable_irq' has been updated to disable specific irqs from the given 'start' parameter. To disable (de-assign) one or more IRQs from vfio-pci kernel driver, irq_set data -1 should be passed to irq_set->data. uapi says that value -1 with DATA_EVENTFD|ACTION_TRIGGER) will de-assign interrupts if already assigned. This patch also fixed de-assign behavior by replacing DATA_NONE to DATA_EVENTFD with data -1 along with adding a new API to disable specific interrupts with start and count. Signed-off-by: Minwoo Im --- CHANGELOG.md | 5 +++++ examples/eventfd.c | 2 +- include/vfn/vfio/device.h | 19 ++++++++++++++++--- src/vfio/device.c | 36 ++++++++++++++++++++++++++++-------- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8357e85b..b04a383b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ ``nvme_pci_init`` has been deprecated and will generate a warning. +``vfio_set_irq`` has been updated to receive ``start`` parameter to specify +start irq number to enable. With this, ``vfio_disable_irq`` has been updated +to disable specific one or more irqs from ``start`` for ``count`` of irqs. +``vfio_disable_irq_all`` has been newly added to disable all the enabled irqs. + ## v5.2.0: (unreleased) ### ``nvme_ctrl`` diff --git a/examples/eventfd.c b/examples/eventfd.c index 8e15bfca..b8cabd91 100644 --- a/examples/eventfd.c +++ b/examples/eventfd.c @@ -70,7 +70,7 @@ int main(int argc, char **argv) if (efd < 0) err(1, "failed to create eventfd"); - if (vfio_set_irq(&ctrl.pci.dev, efds, 2)) + if (vfio_set_irq(&ctrl.pci.dev, efds, 0, 2)) err(1, "failed to set irqs"); if (nvme_create_ioqpair(&ctrl, 1, 64, 1, 0x0)) diff --git a/include/vfn/vfio/device.h b/include/vfn/vfio/device.h index d4e3d6af..653141df 100644 --- a/include/vfn/vfio/device.h +++ b/include/vfn/vfio/device.h @@ -28,6 +28,7 @@ struct vfio_device { * vfio_set_irq - Enable IRQs through eventfds * @dev: &struct vfio_device * @eventfds: array of eventfds + * @start: start irq number * @count: number of eventfds * * Enable interrupts for a range of vectors. See linux/vfio.h for documentation @@ -35,17 +36,29 @@ struct vfio_device { * * Return: ``0`` on success, ``-1`` on error and sets ``errno``. */ -int vfio_set_irq(struct vfio_device *dev, int *eventfds, int count); +int vfio_set_irq(struct vfio_device *dev, int *eventfds, int start, int count); /** - * vfio_disable_irq - Disable all IRQs + * vfio_disable_irq - Disable number of count IRQs from given start + * @dev: &struct vfio_device + * @start: start irq number + * @count: number of eventfds + * + * Disable given number of IRQs from start. + * + * Return: ``0`` on success, ``-1`` on error and sets ``errno``. + */ +int vfio_disable_irq(struct vfio_device *dev, int start, int count); + +/** + * vfio_disable_irq_all - Disable all IRQs * @dev: &struct vfio_device * * Disable all IRQs. * * Return: ``0`` on success, ``-1`` on error and sets ``errno``. */ -int vfio_disable_irq(struct vfio_device *dev); +int vfio_disable_irq_all(struct vfio_device *dev); /** * vfio_reset - reset vfio device diff --git a/src/vfio/device.c b/src/vfio/device.c index 6ad7275a..8a9e2534 100644 --- a/src/vfio/device.c +++ b/src/vfio/device.c @@ -40,7 +40,7 @@ #include "ccan/minmax/minmax.h" #include "ccan/str/str.h" -int vfio_set_irq(struct vfio_device *dev, int *eventfds, int count) +int vfio_set_irq(struct vfio_device *dev, int *eventfds, int start, int count) { struct vfio_irq_set *irq_set; size_t irq_set_size; @@ -59,7 +59,7 @@ int vfio_set_irq(struct vfio_device *dev, int *eventfds, int count) .argsz = (uint32_t)irq_set_size, .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER, .index = dev->irq_info.index, - .start = 0, + .start = start, .count = count, }; @@ -76,18 +76,33 @@ int vfio_set_irq(struct vfio_device *dev, int *eventfds, int count) return 0; } -int vfio_disable_irq(struct vfio_device *dev) +int vfio_disable_irq(struct vfio_device *dev, int start, int count) { - struct vfio_irq_set irq_set; + struct vfio_irq_set *irq_set; + size_t irq_set_size; + int *data; int ret; - irq_set = (struct vfio_irq_set) { - .argsz = sizeof(irq_set), - .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, + irq_set_size = sizeof(*irq_set) + sizeof(int) * count; + irq_set = xmalloc(irq_set_size); + + data = xmalloc(sizeof(int) * count); + for (int i = 0; i < count; i++) + data[i] = -1; + + *irq_set = (struct vfio_irq_set) { + .argsz = (uint32_t)irq_set_size, + .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER, .index = dev->irq_info.index, + .start = start, + .count = count, }; - ret = ioctl(dev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); + memcpy(irq_set->data, data, sizeof(int) * count); + + ret = ioctl(dev->fd, VFIO_DEVICE_SET_IRQS, irq_set); + free(data); + free(irq_set); if (ret) { log_debug("failed to disable device irq\n"); @@ -97,6 +112,11 @@ int vfio_disable_irq(struct vfio_device *dev) return 0; } +int vfio_disable_irq_all(struct vfio_device *dev) +{ + return vfio_disable_irq(dev, 0, dev->irq_info.count); +} + int vfio_reset(struct vfio_device *dev) { if (!(dev->device_info.flags & VFIO_DEVICE_FLAGS_RESET)) {