Re: [PATCH v9 13/19] vfio/platform: support for level sensitive interrupts

2014-11-05 Thread Antonios Motakis
On Fri, Oct 31, 2014 at 8:36 PM, Alex Williamson
alex.william...@redhat.com wrote:
 On Mon, 2014-10-27 at 19:07 +0100, Antonios Motakis wrote:
 Level sensitive interrupts are exposed as maskable and automasked
 interrupts and are masked and disabled automatically when they fire.

 Signed-off-by: Antonios Motakis a.mota...@virtualopensystems.com
 ---
  drivers/vfio/platform/vfio_platform_irq.c | 102 
 +-
  drivers/vfio/platform/vfio_platform_private.h |   2 +
  2 files changed, 100 insertions(+), 4 deletions(-)

 diff --git a/drivers/vfio/platform/vfio_platform_irq.c 
 b/drivers/vfio/platform/vfio_platform_irq.c
 index 2ac8ed7..563abf6 100644
 --- a/drivers/vfio/platform/vfio_platform_irq.c
 +++ b/drivers/vfio/platform/vfio_platform_irq.c
 @@ -31,18 +31,108 @@

  #include vfio_platform_private.h

 +static void vfio_platform_mask(struct vfio_platform_irq *irq_ctx)
 +{
 + unsigned long flags;
 +
 + spin_lock_irqsave(irq_ctx-lock, flags);
 +
 + if (!irq_ctx-masked) {
 + disable_irq(irq_ctx-hwirq);
 + irq_ctx-masked = true;
 + }
 +
 + spin_unlock_irqrestore(irq_ctx-lock, flags);
 +}
 +
  static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev,
   unsigned index, unsigned start,
   unsigned count, uint32_t flags, void *data)
  {
 - return -EINVAL;
 + if (start != 0 || count != 1)
 + return -EINVAL;
 +
 + if (!(vdev-irqs[index].flags  VFIO_IRQ_INFO_MASKABLE))
 + return -EINVAL;
 +
 + if (flags  VFIO_IRQ_SET_DATA_EVENTFD)
 + return -EINVAL; /* not implemented yet */
 +
 + if (flags  VFIO_IRQ_SET_DATA_NONE) {
 + vfio_platform_mask(vdev-irqs[index]);
 +
 + } else if (flags  VFIO_IRQ_SET_DATA_BOOL) {
 + uint8_t mask = *(uint8_t *)data;
 +
 + if (mask)
 + vfio_platform_mask(vdev-irqs[index]);
 + }
 +
 + return 0;
 +}
 +
 +static void vfio_platform_unmask(struct vfio_platform_irq *irq_ctx)
 +{
 + unsigned long flags;
 +
 + spin_lock_irqsave(irq_ctx-lock, flags);
 +
 + if (irq_ctx-masked) {
 + enable_irq(irq_ctx-hwirq);
 + irq_ctx-masked = false;
 + }
 +
 + spin_unlock_irqrestore(irq_ctx-lock, flags);
  }

  static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev,
   unsigned index, unsigned start,
   unsigned count, uint32_t flags, void *data)
  {
 - return -EINVAL;
 + if (start != 0 || count != 1)
 + return -EINVAL;
 +
 + if (!(vdev-irqs[index].flags  VFIO_IRQ_INFO_MASKABLE))
 + return -EINVAL;
 +
 + if (flags  VFIO_IRQ_SET_DATA_EVENTFD)
 + return -EINVAL; /* not implemented yet */
 +
 + if (flags  VFIO_IRQ_SET_DATA_NONE) {
 + vfio_platform_unmask(vdev-irqs[index]);
 +
 + } else if (flags  VFIO_IRQ_SET_DATA_BOOL) {
 + uint8_t unmask = *(uint8_t *)data;
 +
 + if (unmask)
 + vfio_platform_unmask(vdev-irqs[index]);
 + }
 +
 + return 0;
 +}
 +
 +static irqreturn_t vfio_maskable_irq_handler(int irq, void *dev_id)
 +{
 + struct vfio_platform_irq *irq_ctx = dev_id;
 + unsigned long flags;
 + int ret = IRQ_NONE;
 +
 + spin_lock_irqsave(irq_ctx-lock, flags);
 +
 + if (!irq_ctx-masked) {
 + ret = IRQ_HANDLED;
 +
 + /* automask maskable interrupts */
 + disable_irq_nosync(irq_ctx-hwirq);
 + irq_ctx-masked = true;
 + }
 +
 + spin_unlock_irqrestore(irq_ctx-lock, flags);
 +
 + if (ret == IRQ_HANDLED)
 + eventfd_signal(irq_ctx-trigger, 1);
 +
 + return ret;

 This is not just a maskable irq handler, but specifically a level (aka
 automasked) handler.  So this should only be used for AUTOMASKED irqs.

  }

  static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
 @@ -103,7 +193,7 @@ static int vfio_platform_set_irq_trigger(struct 
 vfio_platform_device *vdev,
   irq_handler_t handler;

   if (vdev-irqs[index].flags  VFIO_IRQ_INFO_MASKABLE)
 - return -EINVAL; /* not implemented */
 + handler = vfio_maskable_irq_handler;

 As noted in the previous patch, this should be a test for AUTOMASKED,
 not just MASKABLE.

Ack.

Thanks for your comments.
Antonios


   else
   handler = vfio_irq_handler;

 @@ -175,13 +265,17 @@ int vfio_platform_irq_init(struct vfio_platform_device 
 *vdev)
   if (hwirq  0)
   goto err;

 + spin_lock_init(vdev-irqs[i].lock);
 +
   vdev-irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;

   if (irq_get_trigger_type(hwirq)  IRQ_TYPE_LEVEL_MASK)
 - vdev-irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE;
 + vdev-irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE
 +   

Re: [PATCH v9 13/19] vfio/platform: support for level sensitive interrupts

2014-10-31 Thread Alex Williamson
On Mon, 2014-10-27 at 19:07 +0100, Antonios Motakis wrote:
 Level sensitive interrupts are exposed as maskable and automasked
 interrupts and are masked and disabled automatically when they fire.
 
 Signed-off-by: Antonios Motakis a.mota...@virtualopensystems.com
 ---
  drivers/vfio/platform/vfio_platform_irq.c | 102 
 +-
  drivers/vfio/platform/vfio_platform_private.h |   2 +
  2 files changed, 100 insertions(+), 4 deletions(-)
 
 diff --git a/drivers/vfio/platform/vfio_platform_irq.c 
 b/drivers/vfio/platform/vfio_platform_irq.c
 index 2ac8ed7..563abf6 100644
 --- a/drivers/vfio/platform/vfio_platform_irq.c
 +++ b/drivers/vfio/platform/vfio_platform_irq.c
 @@ -31,18 +31,108 @@
  
  #include vfio_platform_private.h
  
 +static void vfio_platform_mask(struct vfio_platform_irq *irq_ctx)
 +{
 + unsigned long flags;
 +
 + spin_lock_irqsave(irq_ctx-lock, flags);
 +
 + if (!irq_ctx-masked) {
 + disable_irq(irq_ctx-hwirq);
 + irq_ctx-masked = true;
 + }
 +
 + spin_unlock_irqrestore(irq_ctx-lock, flags);
 +}
 +
  static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev,
   unsigned index, unsigned start,
   unsigned count, uint32_t flags, void *data)
  {
 - return -EINVAL;
 + if (start != 0 || count != 1)
 + return -EINVAL;
 +
 + if (!(vdev-irqs[index].flags  VFIO_IRQ_INFO_MASKABLE))
 + return -EINVAL;
 +
 + if (flags  VFIO_IRQ_SET_DATA_EVENTFD)
 + return -EINVAL; /* not implemented yet */
 +
 + if (flags  VFIO_IRQ_SET_DATA_NONE) {
 + vfio_platform_mask(vdev-irqs[index]);
 +
 + } else if (flags  VFIO_IRQ_SET_DATA_BOOL) {
 + uint8_t mask = *(uint8_t *)data;
 +
 + if (mask)
 + vfio_platform_mask(vdev-irqs[index]);
 + }
 +
 + return 0;
 +}
 +
 +static void vfio_platform_unmask(struct vfio_platform_irq *irq_ctx)
 +{
 + unsigned long flags;
 +
 + spin_lock_irqsave(irq_ctx-lock, flags);
 +
 + if (irq_ctx-masked) {
 + enable_irq(irq_ctx-hwirq);
 + irq_ctx-masked = false;
 + }
 +
 + spin_unlock_irqrestore(irq_ctx-lock, flags);
  }
  
  static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev,
   unsigned index, unsigned start,
   unsigned count, uint32_t flags, void *data)
  {
 - return -EINVAL;
 + if (start != 0 || count != 1)
 + return -EINVAL;
 +
 + if (!(vdev-irqs[index].flags  VFIO_IRQ_INFO_MASKABLE))
 + return -EINVAL;
 +
 + if (flags  VFIO_IRQ_SET_DATA_EVENTFD)
 + return -EINVAL; /* not implemented yet */
 +
 + if (flags  VFIO_IRQ_SET_DATA_NONE) {
 + vfio_platform_unmask(vdev-irqs[index]);
 +
 + } else if (flags  VFIO_IRQ_SET_DATA_BOOL) {
 + uint8_t unmask = *(uint8_t *)data;
 +
 + if (unmask)
 + vfio_platform_unmask(vdev-irqs[index]);
 + }
 +
 + return 0;
 +}
 +
 +static irqreturn_t vfio_maskable_irq_handler(int irq, void *dev_id)
 +{
 + struct vfio_platform_irq *irq_ctx = dev_id;
 + unsigned long flags;
 + int ret = IRQ_NONE;
 +
 + spin_lock_irqsave(irq_ctx-lock, flags);
 +
 + if (!irq_ctx-masked) {
 + ret = IRQ_HANDLED;
 +
 + /* automask maskable interrupts */
 + disable_irq_nosync(irq_ctx-hwirq);
 + irq_ctx-masked = true;
 + }
 +
 + spin_unlock_irqrestore(irq_ctx-lock, flags);
 +
 + if (ret == IRQ_HANDLED)
 + eventfd_signal(irq_ctx-trigger, 1);
 +
 + return ret;

This is not just a maskable irq handler, but specifically a level (aka
automasked) handler.  So this should only be used for AUTOMASKED irqs.

  }
  
  static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
 @@ -103,7 +193,7 @@ static int vfio_platform_set_irq_trigger(struct 
 vfio_platform_device *vdev,
   irq_handler_t handler;
  
   if (vdev-irqs[index].flags  VFIO_IRQ_INFO_MASKABLE)
 - return -EINVAL; /* not implemented */
 + handler = vfio_maskable_irq_handler;

As noted in the previous patch, this should be a test for AUTOMASKED,
not just MASKABLE.

   else
   handler = vfio_irq_handler;
  
 @@ -175,13 +265,17 @@ int vfio_platform_irq_init(struct vfio_platform_device 
 *vdev)
   if (hwirq  0)
   goto err;
  
 + spin_lock_init(vdev-irqs[i].lock);
 +
   vdev-irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
  
   if (irq_get_trigger_type(hwirq)  IRQ_TYPE_LEVEL_MASK)
 - vdev-irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE;
 + vdev-irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE
 + | VFIO_IRQ_INFO_AUTOMASKED;
  
   vdev-irqs[i].count = 1;