aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/821-vfio-0008-vfio-fsl-mc-trigger-an-interrupt-via-eventfd.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-5.4/821-vfio-0008-vfio-fsl-mc-trigger-an-interrupt-via-eventfd.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/821-vfio-0008-vfio-fsl-mc-trigger-an-interrupt-via-eventfd.patch268
1 files changed, 268 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0008-vfio-fsl-mc-trigger-an-interrupt-via-eventfd.patch b/target/linux/layerscape/patches-5.4/821-vfio-0008-vfio-fsl-mc-trigger-an-interrupt-via-eventfd.patch
new file mode 100644
index 0000000000..4f1e0997f7
--- /dev/null
+++ b/target/linux/layerscape/patches-5.4/821-vfio-0008-vfio-fsl-mc-trigger-an-interrupt-via-eventfd.patch
@@ -0,0 +1,268 @@
+From 8f0239c9385028a0c15306966c66a56315b11dbc Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Tue, 1 Oct 2019 16:44:04 +0300
+Subject: [PATCH] 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 handle
+correctly DPRC container interrupt where re-scanning on container is
+required.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c | 20 +++-
+ drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c | 165 +++++++++++++++++++++++++++++-
+ drivers/vfio/fsl-mc/vfio_fsl_mc_private.h | 10 ++
+ 3 files changed, 193 insertions(+), 2 deletions(-)
+
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -144,12 +144,30 @@ err_reg_init:
+ static void vfio_fsl_mc_release(void *device_data)
+ {
+ struct vfio_fsl_mc_device *vdev = device_data;
++ int ret;
+
+ mutex_lock(&vdev->reflck->lock);
+
+- if (!(--vdev->refcnt))
++ if (!(--vdev->refcnt)) {
++ struct fsl_mc_device *mc_dev = vdev->mc_dev;
++ struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev);
++ struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev);
++ struct fsl_mc_bus *mc_bus;
++
++ mc_bus = to_fsl_mc_bus(mc_cont);
++
+ vfio_fsl_mc_regions_cleanup(vdev);
+
++ /* reset the device before cleaning up the interrupts */
++ ret = dprc_reset_container(mc_dev->mc_io, 0,
++ mc_dev->mc_handle,
++ mc_dev->obj_desc.id);
++
++ vfio_fsl_mc_irqs_cleanup(vdev);
++
++ fsl_mc_cleanup_irq_pool(mc_bus);
++ }
++
+ mutex_unlock(&vdev->reflck->lock);
+
+ module_put(THIS_MODULE);
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
+@@ -29,12 +29,154 @@ static int vfio_fsl_mc_irq_unmask(struct
+ return -EINVAL;
+ }
+
++int vfio_fsl_mc_irqs_allocate(struct vfio_fsl_mc_device *vdev)
++{
++ struct fsl_mc_device *mc_dev = vdev->mc_dev;
++ struct vfio_fsl_mc_irq *mc_irq;
++ int irq_count;
++ int ret, i;
++
++ /* Device does not support any interrupt */
++ if (mc_dev->obj_desc.irq_count == 0)
++ return 0;
++
++ /* interrupts were already allocated for this device */
++ if (vdev->mc_irqs)
++ return 0;
++
++ irq_count = mc_dev->obj_desc.irq_count;
++
++ mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL);
++ if (mc_irq == NULL)
++ return -ENOMEM;
++
++ /* Allocate IRQs */
++ ret = fsl_mc_allocate_irqs(mc_dev);
++ if (ret) {
++ kfree(mc_irq);
++ return ret;
++ }
++
++ for (i = 0; i < irq_count; i++) {
++ mc_irq[i].count = 1;
++ mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD;
++ }
++
++ vdev->mc_irqs = mc_irq;
++
++ return 0;
++}
++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_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;
++}
++
+ 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 fsl_mc_device *mc_dev = vdev->mc_dev;
++ struct fsl_mc_bus *mc_bus;
++ int ret, hwirq;
++ struct vfio_fsl_mc_irq *irq;
++ struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev);
++ struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev);
++
++ if (start != 0 || count != 1)
++ return -EINVAL;
++
++ mc_bus = to_fsl_mc_bus(mc_cont);
++
++ mutex_lock(&vdev->reflck->lock);
++ if (!mc_bus->irq_resources) {
++
++ ret = fsl_mc_populate_irq_pool(mc_bus,
++ FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
++ if (ret)
++ goto unlock;
++ }
++
++ ret = vfio_fsl_mc_irqs_allocate(vdev);
++ if (ret)
++ goto unlock;
++ mutex_unlock(&vdev->reflck->lock);
++
++ if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
++ return vfio_set_trigger(vdev, index, -1);
++
++ 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;
++
++ irq = &vdev->mc_irqs[index];
++
++ 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;
++
++unlock:
++ mutex_unlock(&vdev->reflck->lock);
++ return ret;
+ }
+ int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
+ uint32_t flags, unsigned int index,
+@@ -60,3 +202,24 @@ int vfio_fsl_mc_set_irqs_ioctl(struct vf
+
+ return ret;
+ }
++
++/* Free All IRQs for the given MC object */
++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 or the interrupts
++ * were not configured
++ */
++ if (mc_dev->obj_desc.irq_count == 0 || !vdev->mc_irqs)
++ return;
++
++ for (i = 0; i < irq_count; i++)
++ vfio_set_trigger(vdev, i, -1);
++
++ fsl_mc_free_irqs(mc_dev);
++ kfree(vdev->mc_irqs);
++ vdev->mc_irqs = NULL;
++}
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+@@ -15,6 +15,13 @@
+ #define VFIO_FSL_MC_INDEX_TO_OFFSET(index) \
+ ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
+
++struct vfio_fsl_mc_irq {
++ u32 flags;
++ u32 count;
++ struct eventfd_ctx *trigger;
++ char *name;
++};
++
+ struct vfio_fsl_mc_reflck {
+ struct kref kref;
+ struct mutex lock;
+@@ -33,6 +40,7 @@ struct vfio_fsl_mc_device {
+ u32 num_regions;
+ struct vfio_fsl_mc_region *regions;
+ struct vfio_fsl_mc_reflck *reflck;
++ struct vfio_fsl_mc_irq *mc_irqs;
+ };
+
+ int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
+@@ -40,4 +48,6 @@ int vfio_fsl_mc_set_irqs_ioctl(struct vf
+ unsigned int start, unsigned int count,
+ void *data);
+
++void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev);
++
+ #endif /* VFIO_PCI_PRIVATE_H */