Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * VFIO platform devices interrupt handling
0004  *
0005  * Copyright (C) 2013 - Virtual Open Systems
0006  * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
0007  */
0008 
0009 #include <linux/eventfd.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/slab.h>
0012 #include <linux/types.h>
0013 #include <linux/vfio.h>
0014 #include <linux/irq.h>
0015 
0016 #include "vfio_platform_private.h"
0017 
0018 static void vfio_platform_mask(struct vfio_platform_irq *irq_ctx)
0019 {
0020     unsigned long flags;
0021 
0022     spin_lock_irqsave(&irq_ctx->lock, flags);
0023 
0024     if (!irq_ctx->masked) {
0025         disable_irq_nosync(irq_ctx->hwirq);
0026         irq_ctx->masked = true;
0027     }
0028 
0029     spin_unlock_irqrestore(&irq_ctx->lock, flags);
0030 }
0031 
0032 static int vfio_platform_mask_handler(void *opaque, void *unused)
0033 {
0034     struct vfio_platform_irq *irq_ctx = opaque;
0035 
0036     vfio_platform_mask(irq_ctx);
0037 
0038     return 0;
0039 }
0040 
0041 static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev,
0042                       unsigned index, unsigned start,
0043                       unsigned count, uint32_t flags,
0044                       void *data)
0045 {
0046     if (start != 0 || count != 1)
0047         return -EINVAL;
0048 
0049     if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE))
0050         return -EINVAL;
0051 
0052     if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
0053         int32_t fd = *(int32_t *)data;
0054 
0055         if (fd >= 0)
0056             return vfio_virqfd_enable((void *) &vdev->irqs[index],
0057                           vfio_platform_mask_handler,
0058                           NULL, NULL,
0059                           &vdev->irqs[index].mask, fd);
0060 
0061         vfio_virqfd_disable(&vdev->irqs[index].mask);
0062         return 0;
0063     }
0064 
0065     if (flags & VFIO_IRQ_SET_DATA_NONE) {
0066         vfio_platform_mask(&vdev->irqs[index]);
0067 
0068     } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
0069         uint8_t mask = *(uint8_t *)data;
0070 
0071         if (mask)
0072             vfio_platform_mask(&vdev->irqs[index]);
0073     }
0074 
0075     return 0;
0076 }
0077 
0078 static void vfio_platform_unmask(struct vfio_platform_irq *irq_ctx)
0079 {
0080     unsigned long flags;
0081 
0082     spin_lock_irqsave(&irq_ctx->lock, flags);
0083 
0084     if (irq_ctx->masked) {
0085         enable_irq(irq_ctx->hwirq);
0086         irq_ctx->masked = false;
0087     }
0088 
0089     spin_unlock_irqrestore(&irq_ctx->lock, flags);
0090 }
0091 
0092 static int vfio_platform_unmask_handler(void *opaque, void *unused)
0093 {
0094     struct vfio_platform_irq *irq_ctx = opaque;
0095 
0096     vfio_platform_unmask(irq_ctx);
0097 
0098     return 0;
0099 }
0100 
0101 static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev,
0102                     unsigned index, unsigned start,
0103                     unsigned count, uint32_t flags,
0104                     void *data)
0105 {
0106     if (start != 0 || count != 1)
0107         return -EINVAL;
0108 
0109     if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE))
0110         return -EINVAL;
0111 
0112     if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
0113         int32_t fd = *(int32_t *)data;
0114 
0115         if (fd >= 0)
0116             return vfio_virqfd_enable((void *) &vdev->irqs[index],
0117                           vfio_platform_unmask_handler,
0118                           NULL, NULL,
0119                           &vdev->irqs[index].unmask,
0120                           fd);
0121 
0122         vfio_virqfd_disable(&vdev->irqs[index].unmask);
0123         return 0;
0124     }
0125 
0126     if (flags & VFIO_IRQ_SET_DATA_NONE) {
0127         vfio_platform_unmask(&vdev->irqs[index]);
0128 
0129     } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
0130         uint8_t unmask = *(uint8_t *)data;
0131 
0132         if (unmask)
0133             vfio_platform_unmask(&vdev->irqs[index]);
0134     }
0135 
0136     return 0;
0137 }
0138 
0139 static irqreturn_t vfio_automasked_irq_handler(int irq, void *dev_id)
0140 {
0141     struct vfio_platform_irq *irq_ctx = dev_id;
0142     unsigned long flags;
0143     int ret = IRQ_NONE;
0144 
0145     spin_lock_irqsave(&irq_ctx->lock, flags);
0146 
0147     if (!irq_ctx->masked) {
0148         ret = IRQ_HANDLED;
0149 
0150         /* automask maskable interrupts */
0151         disable_irq_nosync(irq_ctx->hwirq);
0152         irq_ctx->masked = true;
0153     }
0154 
0155     spin_unlock_irqrestore(&irq_ctx->lock, flags);
0156 
0157     if (ret == IRQ_HANDLED)
0158         eventfd_signal(irq_ctx->trigger, 1);
0159 
0160     return ret;
0161 }
0162 
0163 static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
0164 {
0165     struct vfio_platform_irq *irq_ctx = dev_id;
0166 
0167     eventfd_signal(irq_ctx->trigger, 1);
0168 
0169     return IRQ_HANDLED;
0170 }
0171 
0172 static int vfio_set_trigger(struct vfio_platform_device *vdev, int index,
0173                 int fd, irq_handler_t handler)
0174 {
0175     struct vfio_platform_irq *irq = &vdev->irqs[index];
0176     struct eventfd_ctx *trigger;
0177     int ret;
0178 
0179     if (irq->trigger) {
0180         irq_clear_status_flags(irq->hwirq, IRQ_NOAUTOEN);
0181         free_irq(irq->hwirq, irq);
0182         kfree(irq->name);
0183         eventfd_ctx_put(irq->trigger);
0184         irq->trigger = NULL;
0185     }
0186 
0187     if (fd < 0) /* Disable only */
0188         return 0;
0189 
0190     irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
0191                         irq->hwirq, vdev->name);
0192     if (!irq->name)
0193         return -ENOMEM;
0194 
0195     trigger = eventfd_ctx_fdget(fd);
0196     if (IS_ERR(trigger)) {
0197         kfree(irq->name);
0198         return PTR_ERR(trigger);
0199     }
0200 
0201     irq->trigger = trigger;
0202 
0203     irq_set_status_flags(irq->hwirq, IRQ_NOAUTOEN);
0204     ret = request_irq(irq->hwirq, handler, 0, irq->name, irq);
0205     if (ret) {
0206         kfree(irq->name);
0207         eventfd_ctx_put(trigger);
0208         irq->trigger = NULL;
0209         return ret;
0210     }
0211 
0212     if (!irq->masked)
0213         enable_irq(irq->hwirq);
0214 
0215     return 0;
0216 }
0217 
0218 static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev,
0219                      unsigned index, unsigned start,
0220                      unsigned count, uint32_t flags,
0221                      void *data)
0222 {
0223     struct vfio_platform_irq *irq = &vdev->irqs[index];
0224     irq_handler_t handler;
0225 
0226     if (vdev->irqs[index].flags & VFIO_IRQ_INFO_AUTOMASKED)
0227         handler = vfio_automasked_irq_handler;
0228     else
0229         handler = vfio_irq_handler;
0230 
0231     if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
0232         return vfio_set_trigger(vdev, index, -1, handler);
0233 
0234     if (start != 0 || count != 1)
0235         return -EINVAL;
0236 
0237     if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
0238         int32_t fd = *(int32_t *)data;
0239 
0240         return vfio_set_trigger(vdev, index, fd, handler);
0241     }
0242 
0243     if (flags & VFIO_IRQ_SET_DATA_NONE) {
0244         handler(irq->hwirq, irq);
0245 
0246     } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
0247         uint8_t trigger = *(uint8_t *)data;
0248 
0249         if (trigger)
0250             handler(irq->hwirq, irq);
0251     }
0252 
0253     return 0;
0254 }
0255 
0256 int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
0257                  uint32_t flags, unsigned index, unsigned start,
0258                  unsigned count, void *data)
0259 {
0260     int (*func)(struct vfio_platform_device *vdev, unsigned index,
0261             unsigned start, unsigned count, uint32_t flags,
0262             void *data) = NULL;
0263 
0264     switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
0265     case VFIO_IRQ_SET_ACTION_MASK:
0266         func = vfio_platform_set_irq_mask;
0267         break;
0268     case VFIO_IRQ_SET_ACTION_UNMASK:
0269         func = vfio_platform_set_irq_unmask;
0270         break;
0271     case VFIO_IRQ_SET_ACTION_TRIGGER:
0272         func = vfio_platform_set_irq_trigger;
0273         break;
0274     }
0275 
0276     if (!func)
0277         return -ENOTTY;
0278 
0279     return func(vdev, index, start, count, flags, data);
0280 }
0281 
0282 int vfio_platform_irq_init(struct vfio_platform_device *vdev)
0283 {
0284     int cnt = 0, i;
0285 
0286     while (vdev->get_irq(vdev, cnt) >= 0)
0287         cnt++;
0288 
0289     vdev->irqs = kcalloc(cnt, sizeof(struct vfio_platform_irq), GFP_KERNEL);
0290     if (!vdev->irqs)
0291         return -ENOMEM;
0292 
0293     for (i = 0; i < cnt; i++) {
0294         int hwirq = vdev->get_irq(vdev, i);
0295 
0296         if (hwirq < 0)
0297             goto err;
0298 
0299         spin_lock_init(&vdev->irqs[i].lock);
0300 
0301         vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
0302 
0303         if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK)
0304             vdev->irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE
0305                         | VFIO_IRQ_INFO_AUTOMASKED;
0306 
0307         vdev->irqs[i].count = 1;
0308         vdev->irqs[i].hwirq = hwirq;
0309         vdev->irqs[i].masked = false;
0310     }
0311 
0312     vdev->num_irqs = cnt;
0313 
0314     return 0;
0315 err:
0316     kfree(vdev->irqs);
0317     return -EINVAL;
0318 }
0319 
0320 void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev)
0321 {
0322     int i;
0323 
0324     for (i = 0; i < vdev->num_irqs; i++)
0325         vfio_set_trigger(vdev, i, -1, NULL);
0326 
0327     vdev->num_irqs = 0;
0328     kfree(vdev->irqs);
0329 }