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