1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * VFIO platform devices interrupt handling
4  *
5  * Copyright (C) 2013 - Virtual Open Systems
6  * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
7  */
8 
9 #include <linux/eventfd.h>
10 #include <linux/interrupt.h>
11 #include <linux/slab.h>
12 #include <linux/types.h>
13 #include <linux/vfio.h>
14 #include <linux/irq.h>
15 
16 #include "vfio_platform_private.h"
17 
18 static void vfio_platform_mask(struct vfio_platform_irq *irq_ctx)
19 {
20 	unsigned long flags;
21 
22 	spin_lock_irqsave(&irq_ctx->lock, flags);
23 
24 	if (!irq_ctx->masked) {
25 		disable_irq_nosync(irq_ctx->hwirq);
26 		irq_ctx->masked = true;
27 	}
28 
29 	spin_unlock_irqrestore(&irq_ctx->lock, flags);
30 }
31 
32 static int vfio_platform_mask_handler(void *opaque, void *unused)
33 {
34 	struct vfio_platform_irq *irq_ctx = opaque;
35 
36 	vfio_platform_mask(irq_ctx);
37 
38 	return 0;
39 }
40 
41 static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev,
42 				      unsigned index, unsigned start,
43 				      unsigned count, uint32_t flags,
44 				      void *data)
45 {
46 	if (start != 0 || count != 1)
47 		return -EINVAL;
48 
49 	if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE))
50 		return -EINVAL;
51 
52 	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
53 		int32_t fd = *(int32_t *)data;
54 
55 		if (fd >= 0)
56 			return vfio_virqfd_enable((void *) &vdev->irqs[index],
57 						  vfio_platform_mask_handler,
58 						  NULL, NULL,
59 						  &vdev->irqs[index].mask, fd);
60 
61 		vfio_virqfd_disable(&vdev->irqs[index].mask);
62 		return 0;
63 	}
64 
65 	if (flags & VFIO_IRQ_SET_DATA_NONE) {
66 		vfio_platform_mask(&vdev->irqs[index]);
67 
68 	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
69 		uint8_t mask = *(uint8_t *)data;
70 
71 		if (mask)
72 			vfio_platform_mask(&vdev->irqs[index]);
73 	}
74 
75 	return 0;
76 }
77 
78 static void vfio_platform_unmask(struct vfio_platform_irq *irq_ctx)
79 {
80 	unsigned long flags;
81 
82 	spin_lock_irqsave(&irq_ctx->lock, flags);
83 
84 	if (irq_ctx->masked) {
85 		enable_irq(irq_ctx->hwirq);
86 		irq_ctx->masked = false;
87 	}
88 
89 	spin_unlock_irqrestore(&irq_ctx->lock, flags);
90 }
91 
92 static int vfio_platform_unmask_handler(void *opaque, void *unused)
93 {
94 	struct vfio_platform_irq *irq_ctx = opaque;
95 
96 	vfio_platform_unmask(irq_ctx);
97 
98 	return 0;
99 }
100 
101 static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev,
102 					unsigned index, unsigned start,
103 					unsigned count, uint32_t flags,
104 					void *data)
105 {
106 	if (start != 0 || count != 1)
107 		return -EINVAL;
108 
109 	if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE))
110 		return -EINVAL;
111 
112 	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
113 		int32_t fd = *(int32_t *)data;
114 
115 		if (fd >= 0)
116 			return vfio_virqfd_enable((void *) &vdev->irqs[index],
117 						  vfio_platform_unmask_handler,
118 						  NULL, NULL,
119 						  &vdev->irqs[index].unmask,
120 						  fd);
121 
122 		vfio_virqfd_disable(&vdev->irqs[index].unmask);
123 		return 0;
124 	}
125 
126 	if (flags & VFIO_IRQ_SET_DATA_NONE) {
127 		vfio_platform_unmask(&vdev->irqs[index]);
128 
129 	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
130 		uint8_t unmask = *(uint8_t *)data;
131 
132 		if (unmask)
133 			vfio_platform_unmask(&vdev->irqs[index]);
134 	}
135 
136 	return 0;
137 }
138 
139 static irqreturn_t vfio_automasked_irq_handler(int irq, void *dev_id)
140 {
141 	struct vfio_platform_irq *irq_ctx = dev_id;
142 	unsigned long flags;
143 	int ret = IRQ_NONE;
144 
145 	spin_lock_irqsave(&irq_ctx->lock, flags);
146 
147 	if (!irq_ctx->masked) {
148 		ret = IRQ_HANDLED;
149 
150 		/* automask maskable interrupts */
151 		disable_irq_nosync(irq_ctx->hwirq);
152 		irq_ctx->masked = true;
153 	}
154 
155 	spin_unlock_irqrestore(&irq_ctx->lock, flags);
156 
157 	if (ret == IRQ_HANDLED)
158 		eventfd_signal(irq_ctx->trigger, 1);
159 
160 	return ret;
161 }
162 
163 static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
164 {
165 	struct vfio_platform_irq *irq_ctx = dev_id;
166 
167 	eventfd_signal(irq_ctx->trigger, 1);
168 
169 	return IRQ_HANDLED;
170 }
171 
172 static int vfio_set_trigger(struct vfio_platform_device *vdev, int index,
173 			    int fd, irq_handler_t handler)
174 {
175 	struct vfio_platform_irq *irq = &vdev->irqs[index];
176 	struct eventfd_ctx *trigger;
177 	int ret;
178 
179 	if (irq->trigger) {
180 		irq_clear_status_flags(irq->hwirq, IRQ_NOAUTOEN);
181 		free_irq(irq->hwirq, irq);
182 		kfree(irq->name);
183 		eventfd_ctx_put(irq->trigger);
184 		irq->trigger = NULL;
185 	}
186 
187 	if (fd < 0) /* Disable only */
188 		return 0;
189 	irq->name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-irq[%d](%s)",
190 			      irq->hwirq, vdev->name);
191 	if (!irq->name)
192 		return -ENOMEM;
193 
194 	trigger = eventfd_ctx_fdget(fd);
195 	if (IS_ERR(trigger)) {
196 		kfree(irq->name);
197 		return PTR_ERR(trigger);
198 	}
199 
200 	irq->trigger = trigger;
201 
202 	irq_set_status_flags(irq->hwirq, IRQ_NOAUTOEN);
203 	ret = request_irq(irq->hwirq, handler, 0, irq->name, irq);
204 	if (ret) {
205 		kfree(irq->name);
206 		eventfd_ctx_put(trigger);
207 		irq->trigger = NULL;
208 		return ret;
209 	}
210 
211 	if (!irq->masked)
212 		enable_irq(irq->hwirq);
213 
214 	return 0;
215 }
216 
217 static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev,
218 					 unsigned index, unsigned start,
219 					 unsigned count, uint32_t flags,
220 					 void *data)
221 {
222 	struct vfio_platform_irq *irq = &vdev->irqs[index];
223 	irq_handler_t handler;
224 
225 	if (vdev->irqs[index].flags & VFIO_IRQ_INFO_AUTOMASKED)
226 		handler = vfio_automasked_irq_handler;
227 	else
228 		handler = vfio_irq_handler;
229 
230 	if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
231 		return vfio_set_trigger(vdev, index, -1, handler);
232 
233 	if (start != 0 || count != 1)
234 		return -EINVAL;
235 
236 	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
237 		int32_t fd = *(int32_t *)data;
238 
239 		return vfio_set_trigger(vdev, index, fd, handler);
240 	}
241 
242 	if (flags & VFIO_IRQ_SET_DATA_NONE) {
243 		handler(irq->hwirq, irq);
244 
245 	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
246 		uint8_t trigger = *(uint8_t *)data;
247 
248 		if (trigger)
249 			handler(irq->hwirq, irq);
250 	}
251 
252 	return 0;
253 }
254 
255 int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
256 				 uint32_t flags, unsigned index, unsigned start,
257 				 unsigned count, void *data)
258 {
259 	int (*func)(struct vfio_platform_device *vdev, unsigned index,
260 		    unsigned start, unsigned count, uint32_t flags,
261 		    void *data) = NULL;
262 
263 	switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
264 	case VFIO_IRQ_SET_ACTION_MASK:
265 		func = vfio_platform_set_irq_mask;
266 		break;
267 	case VFIO_IRQ_SET_ACTION_UNMASK:
268 		func = vfio_platform_set_irq_unmask;
269 		break;
270 	case VFIO_IRQ_SET_ACTION_TRIGGER:
271 		func = vfio_platform_set_irq_trigger;
272 		break;
273 	}
274 
275 	if (!func)
276 		return -ENOTTY;
277 
278 	return func(vdev, index, start, count, flags, data);
279 }
280 
281 int vfio_platform_irq_init(struct vfio_platform_device *vdev)
282 {
283 	int cnt = 0, i;
284 
285 	while (vdev->get_irq(vdev, cnt) >= 0)
286 		cnt++;
287 
288 	vdev->irqs = kcalloc(cnt, sizeof(struct vfio_platform_irq),
289 			     GFP_KERNEL_ACCOUNT);
290 	if (!vdev->irqs)
291 		return -ENOMEM;
292 
293 	for (i = 0; i < cnt; i++) {
294 		int hwirq = vdev->get_irq(vdev, i);
295 
296 		if (hwirq < 0)
297 			goto err;
298 
299 		spin_lock_init(&vdev->irqs[i].lock);
300 
301 		vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
302 
303 		if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK)
304 			vdev->irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE
305 						| VFIO_IRQ_INFO_AUTOMASKED;
306 
307 		vdev->irqs[i].count = 1;
308 		vdev->irqs[i].hwirq = hwirq;
309 		vdev->irqs[i].masked = false;
310 	}
311 
312 	vdev->num_irqs = cnt;
313 
314 	return 0;
315 err:
316 	kfree(vdev->irqs);
317 	return -EINVAL;
318 }
319 
320 void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev)
321 {
322 	int i;
323 
324 	for (i = 0; i < vdev->num_irqs; i++)
325 		vfio_set_trigger(vdev, i, -1, NULL);
326 
327 	vdev->num_irqs = 0;
328 	kfree(vdev->irqs);
329 }
330