• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
vfio_platform_mask(struct vfio_platform_irq * irq_ctx)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 
vfio_platform_mask_handler(void * opaque,void * unused)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 
vfio_platform_set_irq_mask(struct vfio_platform_device * vdev,unsigned index,unsigned start,unsigned count,uint32_t flags,void * data)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 
vfio_platform_unmask(struct vfio_platform_irq * irq_ctx)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 
vfio_platform_unmask_handler(void * opaque,void * unused)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 
vfio_platform_set_irq_unmask(struct vfio_platform_device * vdev,unsigned index,unsigned start,unsigned count,uint32_t flags,void * data)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 /*
140  * The trigger eventfd is guaranteed valid in the interrupt path
141  * and protected by the igate mutex when triggered via ioctl.
142  */
vfio_send_eventfd(struct vfio_platform_irq * irq_ctx)143 static void vfio_send_eventfd(struct vfio_platform_irq *irq_ctx)
144 {
145 	if (likely(irq_ctx->trigger))
146 		eventfd_signal(irq_ctx->trigger, 1);
147 }
148 
vfio_automasked_irq_handler(int irq,void * dev_id)149 static irqreturn_t vfio_automasked_irq_handler(int irq, void *dev_id)
150 {
151 	struct vfio_platform_irq *irq_ctx = dev_id;
152 	unsigned long flags;
153 	int ret = IRQ_NONE;
154 
155 	spin_lock_irqsave(&irq_ctx->lock, flags);
156 
157 	if (!irq_ctx->masked) {
158 		ret = IRQ_HANDLED;
159 
160 		/* automask maskable interrupts */
161 		disable_irq_nosync(irq_ctx->hwirq);
162 		irq_ctx->masked = true;
163 	}
164 
165 	spin_unlock_irqrestore(&irq_ctx->lock, flags);
166 
167 	if (ret == IRQ_HANDLED)
168 		vfio_send_eventfd(irq_ctx);
169 
170 	return ret;
171 }
172 
vfio_irq_handler(int irq,void * dev_id)173 static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
174 {
175 	struct vfio_platform_irq *irq_ctx = dev_id;
176 
177 	vfio_send_eventfd(irq_ctx);
178 
179 	return IRQ_HANDLED;
180 }
181 
vfio_set_trigger(struct vfio_platform_device * vdev,int index,int fd)182 static int vfio_set_trigger(struct vfio_platform_device *vdev, int index,
183 			    int fd)
184 {
185 	struct vfio_platform_irq *irq = &vdev->irqs[index];
186 	struct eventfd_ctx *trigger;
187 
188 	if (irq->trigger) {
189 		disable_irq(irq->hwirq);
190 		eventfd_ctx_put(irq->trigger);
191 		irq->trigger = NULL;
192 	}
193 
194 	if (fd < 0) /* Disable only */
195 		return 0;
196 
197 	trigger = eventfd_ctx_fdget(fd);
198 	if (IS_ERR(trigger))
199 		return PTR_ERR(trigger);
200 
201 	irq->trigger = trigger;
202 
203 	/*
204 	 * irq->masked effectively provides nested disables within the overall
205 	 * enable relative to trigger.  Specifically request_irq() is called
206 	 * with NO_AUTOEN, therefore the IRQ is initially disabled.  The user
207 	 * may only further disable the IRQ with a MASK operations because
208 	 * irq->masked is initially false.
209 	 */
210 	enable_irq(irq->hwirq);
211 
212 	return 0;
213 }
214 
vfio_platform_set_irq_trigger(struct vfio_platform_device * vdev,unsigned index,unsigned start,unsigned count,uint32_t flags,void * data)215 static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev,
216 					 unsigned index, unsigned start,
217 					 unsigned count, uint32_t flags,
218 					 void *data)
219 {
220 	struct vfio_platform_irq *irq = &vdev->irqs[index];
221 	irq_handler_t handler;
222 
223 	if (vdev->irqs[index].flags & VFIO_IRQ_INFO_AUTOMASKED)
224 		handler = vfio_automasked_irq_handler;
225 	else
226 		handler = vfio_irq_handler;
227 
228 	if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
229 		return vfio_set_trigger(vdev, index, -1);
230 
231 	if (start != 0 || count != 1)
232 		return -EINVAL;
233 
234 	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
235 		int32_t fd = *(int32_t *)data;
236 
237 		return vfio_set_trigger(vdev, index, fd);
238 	}
239 
240 	if (flags & VFIO_IRQ_SET_DATA_NONE) {
241 		handler(irq->hwirq, irq);
242 
243 	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
244 		uint8_t trigger = *(uint8_t *)data;
245 
246 		if (trigger)
247 			handler(irq->hwirq, irq);
248 	}
249 
250 	return 0;
251 }
252 
vfio_platform_set_irqs_ioctl(struct vfio_platform_device * vdev,uint32_t flags,unsigned index,unsigned start,unsigned count,void * data)253 int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
254 				 uint32_t flags, unsigned index, unsigned start,
255 				 unsigned count, void *data)
256 {
257 	int (*func)(struct vfio_platform_device *vdev, unsigned index,
258 		    unsigned start, unsigned count, uint32_t flags,
259 		    void *data) = NULL;
260 
261 	/*
262 	 * For compatibility, errors from request_irq() are local to the
263 	 * SET_IRQS path and reflected in the name pointer.  This allows,
264 	 * for example, polling mode fallback for an exclusive IRQ failure.
265 	 */
266 	if (IS_ERR(vdev->irqs[index].name))
267 		return PTR_ERR(vdev->irqs[index].name);
268 
269 	switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
270 	case VFIO_IRQ_SET_ACTION_MASK:
271 		func = vfio_platform_set_irq_mask;
272 		break;
273 	case VFIO_IRQ_SET_ACTION_UNMASK:
274 		func = vfio_platform_set_irq_unmask;
275 		break;
276 	case VFIO_IRQ_SET_ACTION_TRIGGER:
277 		func = vfio_platform_set_irq_trigger;
278 		break;
279 	}
280 
281 	if (!func)
282 		return -ENOTTY;
283 
284 	return func(vdev, index, start, count, flags, data);
285 }
286 
vfio_platform_irq_init(struct vfio_platform_device * vdev)287 int vfio_platform_irq_init(struct vfio_platform_device *vdev)
288 {
289 	int cnt = 0, i, ret = 0;
290 
291 	while (vdev->get_irq(vdev, cnt) >= 0)
292 		cnt++;
293 
294 	vdev->irqs = kcalloc(cnt, sizeof(struct vfio_platform_irq),
295 			     GFP_KERNEL_ACCOUNT);
296 	if (!vdev->irqs)
297 		return -ENOMEM;
298 
299 	for (i = 0; i < cnt; i++) {
300 		int hwirq = vdev->get_irq(vdev, i);
301 		irq_handler_t handler = vfio_irq_handler;
302 
303 		if (hwirq < 0) {
304 			ret = -EINVAL;
305 			goto err;
306 		}
307 
308 		spin_lock_init(&vdev->irqs[i].lock);
309 
310 		vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
311 
312 		if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK) {
313 			vdev->irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE
314 						| VFIO_IRQ_INFO_AUTOMASKED;
315 			handler = vfio_automasked_irq_handler;
316 		}
317 
318 		vdev->irqs[i].count = 1;
319 		vdev->irqs[i].hwirq = hwirq;
320 		vdev->irqs[i].masked = false;
321 		vdev->irqs[i].name = kasprintf(GFP_KERNEL_ACCOUNT,
322 					       "vfio-irq[%d](%s)", hwirq,
323 					       vdev->name);
324 		if (!vdev->irqs[i].name) {
325 			ret = -ENOMEM;
326 			goto err;
327 		}
328 
329 		ret = request_irq(hwirq, handler, IRQF_NO_AUTOEN,
330 				  vdev->irqs[i].name, &vdev->irqs[i]);
331 		if (ret) {
332 			kfree(vdev->irqs[i].name);
333 			vdev->irqs[i].name = ERR_PTR(ret);
334 		}
335 	}
336 
337 	vdev->num_irqs = cnt;
338 
339 	return 0;
340 err:
341 	for (--i; i >= 0; i--) {
342 		if (!IS_ERR(vdev->irqs[i].name)) {
343 			free_irq(vdev->irqs[i].hwirq, &vdev->irqs[i]);
344 			kfree(vdev->irqs[i].name);
345 		}
346 	}
347 	kfree(vdev->irqs);
348 	return ret;
349 }
350 
vfio_platform_irq_cleanup(struct vfio_platform_device * vdev)351 void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev)
352 {
353 	int i;
354 
355 	for (i = 0; i < vdev->num_irqs; i++) {
356 		vfio_virqfd_disable(&vdev->irqs[i].mask);
357 		vfio_virqfd_disable(&vdev->irqs[i].unmask);
358 		if (!IS_ERR(vdev->irqs[i].name)) {
359 			free_irq(vdev->irqs[i].hwirq, &vdev->irqs[i]);
360 			if (vdev->irqs[i].trigger)
361 				eventfd_ctx_put(vdev->irqs[i].trigger);
362 			kfree(vdev->irqs[i].name);
363 		}
364 	}
365 
366 	vdev->num_irqs = 0;
367 	kfree(vdev->irqs);
368 }
369