diff options
author | Bharat Bhushan <Bharat.Bhushan@nxp.com> | 2017-05-11 09:19:24 (GMT) |
---|---|---|
committer | Xie Xiaobo <xiaobo.xie@nxp.com> | 2017-09-25 07:25:34 (GMT) |
commit | 0e5a422311485f57d67b038bef77ce0b7ae46cfe (patch) | |
tree | 438bdd8a14ab3ea9cae73400dbbf2f701e605199 | |
parent | a26d3d79654d18462b3359745867731fbb070f20 (diff) | |
download | linux-0e5a422311485f57d67b038bef77ce0b7ae46cfe.tar.xz |
vfio fsl-mc: trigger an interrupt via eventfd
This patch allows to set an eventfd for fsl-mc device interrupt
and also to trigger the interrupt eventfd from userspace for testing.
All fsl-mc device interrupts are MSI type. This does not yet handler
correctly DPRC container interrupt where re-scanning on container is
required.
Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
-rw-r--r-- | drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c | 124 | ||||
-rw-r--r-- | drivers/vfio/fsl-mc/vfio_fsl_mc_private.h | 2 |
2 files changed, 107 insertions, 19 deletions
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c index b7baf10..eb244bb 100644 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c @@ -12,9 +12,79 @@ #include <linux/vfio.h> #include <linux/slab.h> #include <linux/types.h> +#include <linux/eventfd.h> +#include <linux/msi.h> -#include "vfio_fsl_mc_private.h" #include "../../staging/fsl-mc/include/mc.h" +#include "vfio_fsl_mc_private.h" + +static irqreturn_t vfio_fsl_mc_irq_handler(int irq_num, void *arg) +{ + struct vfio_fsl_mc_irq *mc_irq = (struct vfio_fsl_mc_irq *)arg; + + eventfd_signal(mc_irq->trigger, 1); + return IRQ_HANDLED; +} + +static int vfio_fsl_mc_irq_mask(struct vfio_fsl_mc_device *vdev, + unsigned int index, unsigned int start, + unsigned int count, uint32_t flags, + void *data) +{ + return -EINVAL; +} + +static int vfio_fsl_mc_irq_unmask(struct vfio_fsl_mc_device *vdev, + unsigned int index, unsigned int start, + unsigned int count, uint32_t flags, + void *data) +{ + return -EINVAL; +} + +static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev, + int index, int fd) +{ + struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index]; + struct eventfd_ctx *trigger; + int hwirq; + int ret; + + hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq; + if (irq->trigger) { + free_irq(hwirq, irq); + kfree(irq->name); + eventfd_ctx_put(irq->trigger); + irq->trigger = NULL; + } + + if (fd < 0) /* Disable only */ + return 0; + + irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)", + hwirq, dev_name(&vdev->mc_dev->dev)); + if (!irq->name) + return -ENOMEM; + + trigger = eventfd_ctx_fdget(fd); + if (IS_ERR(trigger)) { + kfree(irq->name); + return PTR_ERR(trigger); + } + + irq->trigger = trigger; + + ret = request_irq(hwirq, vfio_fsl_mc_irq_handler, 0, + irq->name, irq); + if (ret) { + kfree(irq->name); + eventfd_ctx_put(trigger); + irq->trigger = NULL; + return ret; + } + + return 0; +} int vfio_fsl_mc_irqs_init(struct vfio_fsl_mc_device *vdev) { @@ -42,7 +112,7 @@ int vfio_fsl_mc_irqs_init(struct vfio_fsl_mc_device *vdev) for (i = 0; i < irq_count; i++) { mc_irq[i].count = 1; - mc_irq[i].flags = 0; + mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD; } vdev->mc_irqs = mc_irq; @@ -54,37 +124,53 @@ int vfio_fsl_mc_irqs_init(struct vfio_fsl_mc_device *vdev) void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev) { struct fsl_mc_device *mc_dev = vdev->mc_dev; + int irq_count = mc_dev->obj_desc.irq_count; + int i; /* Device does not support any interrupt */ if (mc_dev->obj_desc.irq_count == 0) return; + for (i = 0; i < irq_count; i++) + vfio_set_trigger(vdev, i, -1); + fsl_mc_free_irqs(mc_dev); kfree(vdev->mc_irqs); } -static int vfio_fsl_mc_irq_mask(struct vfio_fsl_mc_device *vdev, - unsigned int index, unsigned int start, - unsigned int count, uint32_t flags, - void *data) -{ - return -EINVAL; -} - -static int vfio_fsl_mc_irq_unmask(struct vfio_fsl_mc_device *vdev, - unsigned int index, unsigned int start, - unsigned int count, uint32_t flags, - void *data) -{ - return -EINVAL; -} - static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device *vdev, unsigned int index, unsigned int start, unsigned int count, uint32_t flags, void *data) { - return -EINVAL; + struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index]; + int hwirq; + + if (!count && (flags & VFIO_IRQ_SET_DATA_NONE)) + return vfio_set_trigger(vdev, index, -1); + + if (start != 0 || count != 1) + return -EINVAL; + + if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { + int32_t fd = *(int32_t *)data; + + return vfio_set_trigger(vdev, index, fd); + } + + hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq; + + if (flags & VFIO_IRQ_SET_DATA_NONE) { + vfio_fsl_mc_irq_handler(hwirq, irq); + + } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { + uint8_t trigger = *(uint8_t *)data; + + if (trigger) + vfio_fsl_mc_irq_handler(hwirq, irq); + } + + return 0; } int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev, diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h index 3063fe9..46a0585 100644 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h @@ -24,6 +24,8 @@ struct vfio_fsl_mc_irq { u32 flags; u32 count; + struct eventfd_ctx *trigger; + char *name; }; struct vfio_fsl_mc_region { |