On Tue, 2014-09-23 at 16:46 +0200, Antonios Motakis wrote:
> This patch allows to set an eventfd for a patform device's interrupt,
> and also to trigger the interrupt eventfd from userspace for testing.
> 
> Signed-off-by: Antonios Motakis <[email protected]>
> ---
>  drivers/vfio/platform/vfio_platform_irq.c     | 89 
> ++++++++++++++++++++++++++-
>  drivers/vfio/platform/vfio_platform_private.h |  2 +
>  2 files changed, 89 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/vfio/platform/vfio_platform_irq.c 
> b/drivers/vfio/platform/vfio_platform_irq.c
> index 007b386..25a7825 100644
> --- a/drivers/vfio/platform/vfio_platform_irq.c
> +++ b/drivers/vfio/platform/vfio_platform_irq.c
> @@ -45,11 +45,91 @@ static int vfio_platform_set_irq_unmask(struct 
> vfio_platform_device *vdev,
>       return -EINVAL;
>  }
>  
> +static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
> +{
> +     struct vfio_platform_irq *irq_ctx = dev_id;
> +
> +     eventfd_signal(irq_ctx->trigger, 1);
> +
> +     return IRQ_HANDLED;
> +}
> +
> +static int vfio_set_trigger(struct vfio_platform_device *vdev,
> +                         int index, int fd)
> +{
> +     struct vfio_platform_irq *irq = &vdev->irqs[index];
> +     struct eventfd_ctx *trigger;
> +     int ret;
> +
> +     if (irq->trigger) {
> +             free_irq(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)",
> +                                             irq->hwirq, vdev->name);
> +     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(irq->hwirq, vfio_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_platform_set_irq_trigger(struct vfio_platform_device *vdev,
>                                    unsigned index, unsigned start,
>                                    unsigned count, uint32_t flags, void *data)
>  {
> -     return -EINVAL;
> +     struct vfio_platform_irq *irq = &vdev->irqs[index];
> +     uint8_t irq_bitmap;

Minor nit here and also present in the next patch, I believe when we
have DATA_BOOL, it's defined to be a u8 array, where each byte is a
bool, not each bit.  So it's not actually a bitmap.  The PCI code
handles any non-zero byte as true, not just bit0.  Thanks,

Alex

> +     int32_t fd;
> +
> +     switch (flags & VFIO_IRQ_SET_DATA_TYPE_MASK) {
> +     case VFIO_IRQ_SET_DATA_NONE:
> +             if (count == 0)
> +                     return vfio_set_trigger(vdev, index, -1);
> +
> +             vfio_irq_handler(irq->hwirq, irq);
> +             return 0;
> +
> +     case VFIO_IRQ_SET_DATA_BOOL:
> +             if (copy_from_user(&irq_bitmap, data, sizeof(uint8_t)))
> +                     return -EFAULT;
> +
> +             if (irq_bitmap == 0x1) {
> +                     vfio_irq_handler(irq->hwirq, irq);
> +                     return 0;
> +             }
> +
> +             return -EINVAL;
> +
> +     case VFIO_IRQ_SET_DATA_EVENTFD:
> +             if (copy_from_user(&fd, data, sizeof(int32_t)))
> +                     return -EFAULT;
> +
> +             return vfio_set_trigger(vdev, index, fd);
> +     }
> +
> +     return -EFAULT;
>  }
>  
>  int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
> @@ -95,7 +175,7 @@ int vfio_platform_irq_init(struct vfio_platform_device 
> *vdev)
>               if (hwirq < 0)
>                       goto err;
>  
> -             vdev->irqs[i].flags = 0;
> +             vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
>               vdev->irqs[i].count = 1;
>               vdev->irqs[i].hwirq = hwirq;
>       }
> @@ -110,6 +190,11 @@ err:
>  
>  void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev)
>  {
> +     int i;
> +
> +     for (i = 0; i < vdev->num_irqs; i++)
> +             vfio_set_trigger(vdev, i, -1);
> +
>       vdev->num_irqs = 0;
>       kfree(vdev->irqs);
>  }
> diff --git a/drivers/vfio/platform/vfio_platform_private.h 
> b/drivers/vfio/platform/vfio_platform_private.h
> index 4201b94..765b371 100644
> --- a/drivers/vfio/platform/vfio_platform_private.h
> +++ b/drivers/vfio/platform/vfio_platform_private.h
> @@ -28,6 +28,8 @@ struct vfio_platform_irq {
>       u32                     flags;
>       u32                     count;
>       int                     hwirq;
> +     char                    *name;
> +     struct eventfd_ctx      *trigger;
>  };
>  
>  struct vfio_platform_region {



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to