1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2 /* 3 * Copyright 2013-2016 Freescale Semiconductor Inc. 4 * Copyright 2019 NXP 5 */ 6 7 #include <linux/vfio.h> 8 #include <linux/slab.h> 9 #include <linux/types.h> 10 #include <linux/eventfd.h> 11 12 #include "linux/fsl/mc.h" 13 #include "vfio_fsl_mc_private.h" 14 15 static int vfio_fsl_mc_irqs_allocate(struct vfio_fsl_mc_device *vdev) 16 { 17 struct fsl_mc_device *mc_dev = vdev->mc_dev; 18 struct vfio_fsl_mc_irq *mc_irq; 19 int irq_count; 20 int ret, i; 21 22 /* Device does not support any interrupt */ 23 if (mc_dev->obj_desc.irq_count == 0) 24 return 0; 25 26 /* interrupts were already allocated for this device */ 27 if (vdev->mc_irqs) 28 return 0; 29 30 irq_count = mc_dev->obj_desc.irq_count; 31 32 mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL_ACCOUNT); 33 if (!mc_irq) 34 return -ENOMEM; 35 36 /* Allocate IRQs */ 37 ret = fsl_mc_allocate_irqs(mc_dev); 38 if (ret) { 39 kfree(mc_irq); 40 return ret; 41 } 42 43 for (i = 0; i < irq_count; i++) { 44 mc_irq[i].count = 1; 45 mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD; 46 } 47 48 vdev->mc_irqs = mc_irq; 49 50 return 0; 51 } 52 53 static irqreturn_t vfio_fsl_mc_irq_handler(int irq_num, void *arg) 54 { 55 struct vfio_fsl_mc_irq *mc_irq = (struct vfio_fsl_mc_irq *)arg; 56 57 eventfd_signal(mc_irq->trigger); 58 return IRQ_HANDLED; 59 } 60 61 static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev, 62 int index, int fd) 63 { 64 struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index]; 65 struct eventfd_ctx *trigger; 66 int hwirq; 67 int ret; 68 69 hwirq = vdev->mc_dev->irqs[index]->virq; 70 if (irq->trigger) { 71 free_irq(hwirq, irq); 72 kfree(irq->name); 73 eventfd_ctx_put(irq->trigger); 74 irq->trigger = NULL; 75 } 76 77 if (fd < 0) /* Disable only */ 78 return 0; 79 80 irq->name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-irq[%d](%s)", 81 hwirq, dev_name(&vdev->mc_dev->dev)); 82 if (!irq->name) 83 return -ENOMEM; 84 85 trigger = eventfd_ctx_fdget(fd); 86 if (IS_ERR(trigger)) { 87 kfree(irq->name); 88 return PTR_ERR(trigger); 89 } 90 91 irq->trigger = trigger; 92 93 ret = request_irq(hwirq, vfio_fsl_mc_irq_handler, 0, 94 irq->name, irq); 95 if (ret) { 96 kfree(irq->name); 97 eventfd_ctx_put(trigger); 98 irq->trigger = NULL; 99 return ret; 100 } 101 102 return 0; 103 } 104 105 static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device *vdev, 106 unsigned int index, unsigned int start, 107 unsigned int count, u32 flags, 108 void *data) 109 { 110 struct fsl_mc_device *mc_dev = vdev->mc_dev; 111 struct vfio_fsl_mc_irq *irq; 112 struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev); 113 struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev); 114 int ret; 115 116 if (!count && (flags & VFIO_IRQ_SET_DATA_NONE)) 117 return vfio_set_trigger(vdev, index, -1); 118 119 if (start != 0 || count != 1) 120 return -EINVAL; 121 122 mutex_lock(&vdev->vdev.dev_set->lock); 123 ret = fsl_mc_populate_irq_pool(mc_cont, 124 FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); 125 if (ret) 126 goto unlock; 127 128 ret = vfio_fsl_mc_irqs_allocate(vdev); 129 if (ret) 130 goto unlock; 131 mutex_unlock(&vdev->vdev.dev_set->lock); 132 133 if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { 134 s32 fd = *(s32 *)data; 135 136 return vfio_set_trigger(vdev, index, fd); 137 } 138 139 irq = &vdev->mc_irqs[index]; 140 141 if (flags & VFIO_IRQ_SET_DATA_NONE) { 142 if (irq->trigger) 143 eventfd_signal(irq->trigger); 144 145 } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { 146 u8 trigger = *(u8 *)data; 147 148 if (trigger && irq->trigger) 149 eventfd_signal(irq->trigger); 150 } 151 152 return 0; 153 154 unlock: 155 mutex_unlock(&vdev->vdev.dev_set->lock); 156 return ret; 157 158 } 159 160 int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev, 161 u32 flags, unsigned int index, 162 unsigned int start, unsigned int count, 163 void *data) 164 { 165 if (flags & VFIO_IRQ_SET_ACTION_TRIGGER) 166 return vfio_fsl_mc_set_irq_trigger(vdev, index, start, 167 count, flags, data); 168 else 169 return -EINVAL; 170 } 171 172 /* Free All IRQs for the given MC object */ 173 void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev) 174 { 175 struct fsl_mc_device *mc_dev = vdev->mc_dev; 176 int irq_count = mc_dev->obj_desc.irq_count; 177 int i; 178 179 /* 180 * Device does not support any interrupt or the interrupts 181 * were not configured 182 */ 183 if (!vdev->mc_irqs) 184 return; 185 186 for (i = 0; i < irq_count; i++) 187 vfio_set_trigger(vdev, i, -1); 188 189 fsl_mc_free_irqs(mc_dev); 190 kfree(vdev->mc_irqs); 191 vdev->mc_irqs = NULL; 192 } 193