11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2682704c4SAntonios Motakis /*
3682704c4SAntonios Motakis  * VFIO platform devices interrupt handling
4682704c4SAntonios Motakis  *
5682704c4SAntonios Motakis  * Copyright (C) 2013 - Virtual Open Systems
6682704c4SAntonios Motakis  * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
7682704c4SAntonios Motakis  */
8682704c4SAntonios Motakis 
9682704c4SAntonios Motakis #include <linux/eventfd.h>
10682704c4SAntonios Motakis #include <linux/interrupt.h>
11682704c4SAntonios Motakis #include <linux/slab.h>
12682704c4SAntonios Motakis #include <linux/types.h>
13682704c4SAntonios Motakis #include <linux/vfio.h>
14682704c4SAntonios Motakis #include <linux/irq.h>
15682704c4SAntonios Motakis 
16682704c4SAntonios Motakis #include "vfio_platform_private.h"
17682704c4SAntonios Motakis 
vfio_platform_mask(struct vfio_platform_irq * irq_ctx)1806211b40SAntonios Motakis static void vfio_platform_mask(struct vfio_platform_irq *irq_ctx)
1906211b40SAntonios Motakis {
2006211b40SAntonios Motakis 	unsigned long flags;
2106211b40SAntonios Motakis 
2206211b40SAntonios Motakis 	spin_lock_irqsave(&irq_ctx->lock, flags);
2306211b40SAntonios Motakis 
2406211b40SAntonios Motakis 	if (!irq_ctx->masked) {
2506211b40SAntonios Motakis 		disable_irq_nosync(irq_ctx->hwirq);
2606211b40SAntonios Motakis 		irq_ctx->masked = true;
2706211b40SAntonios Motakis 	}
2806211b40SAntonios Motakis 
2906211b40SAntonios Motakis 	spin_unlock_irqrestore(&irq_ctx->lock, flags);
3006211b40SAntonios Motakis }
3106211b40SAntonios Motakis 
vfio_platform_mask_handler(void * opaque,void * unused)32a7fa7c77SAntonios Motakis static int vfio_platform_mask_handler(void *opaque, void *unused)
33a7fa7c77SAntonios Motakis {
34a7fa7c77SAntonios Motakis 	struct vfio_platform_irq *irq_ctx = opaque;
35a7fa7c77SAntonios Motakis 
36a7fa7c77SAntonios Motakis 	vfio_platform_mask(irq_ctx);
37a7fa7c77SAntonios Motakis 
38a7fa7c77SAntonios Motakis 	return 0;
39a7fa7c77SAntonios Motakis }
40a7fa7c77SAntonios Motakis 
vfio_platform_set_irq_mask(struct vfio_platform_device * vdev,unsigned index,unsigned start,unsigned count,uint32_t flags,void * data)419a36321cSAntonios Motakis static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev,
429a36321cSAntonios Motakis 				      unsigned index, unsigned start,
439a36321cSAntonios Motakis 				      unsigned count, uint32_t flags,
449a36321cSAntonios Motakis 				      void *data)
459a36321cSAntonios Motakis {
4606211b40SAntonios Motakis 	if (start != 0 || count != 1)
479a36321cSAntonios Motakis 		return -EINVAL;
4806211b40SAntonios Motakis 
4906211b40SAntonios Motakis 	if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE))
5006211b40SAntonios Motakis 		return -EINVAL;
5106211b40SAntonios Motakis 
52a7fa7c77SAntonios Motakis 	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
53a7fa7c77SAntonios Motakis 		int32_t fd = *(int32_t *)data;
54a7fa7c77SAntonios Motakis 
55a7fa7c77SAntonios Motakis 		if (fd >= 0)
56a7fa7c77SAntonios Motakis 			return vfio_virqfd_enable((void *) &vdev->irqs[index],
57a7fa7c77SAntonios Motakis 						  vfio_platform_mask_handler,
58a7fa7c77SAntonios Motakis 						  NULL, NULL,
59a7fa7c77SAntonios Motakis 						  &vdev->irqs[index].mask, fd);
60a7fa7c77SAntonios Motakis 
61a7fa7c77SAntonios Motakis 		vfio_virqfd_disable(&vdev->irqs[index].mask);
62a7fa7c77SAntonios Motakis 		return 0;
63a7fa7c77SAntonios Motakis 	}
6406211b40SAntonios Motakis 
6506211b40SAntonios Motakis 	if (flags & VFIO_IRQ_SET_DATA_NONE) {
6606211b40SAntonios Motakis 		vfio_platform_mask(&vdev->irqs[index]);
6706211b40SAntonios Motakis 
6806211b40SAntonios Motakis 	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
6906211b40SAntonios Motakis 		uint8_t mask = *(uint8_t *)data;
7006211b40SAntonios Motakis 
7106211b40SAntonios Motakis 		if (mask)
7206211b40SAntonios Motakis 			vfio_platform_mask(&vdev->irqs[index]);
7306211b40SAntonios Motakis 	}
7406211b40SAntonios Motakis 
7506211b40SAntonios Motakis 	return 0;
7606211b40SAntonios Motakis }
7706211b40SAntonios Motakis 
vfio_platform_unmask(struct vfio_platform_irq * irq_ctx)7806211b40SAntonios Motakis static void vfio_platform_unmask(struct vfio_platform_irq *irq_ctx)
7906211b40SAntonios Motakis {
8006211b40SAntonios Motakis 	unsigned long flags;
8106211b40SAntonios Motakis 
8206211b40SAntonios Motakis 	spin_lock_irqsave(&irq_ctx->lock, flags);
8306211b40SAntonios Motakis 
8406211b40SAntonios Motakis 	if (irq_ctx->masked) {
8506211b40SAntonios Motakis 		enable_irq(irq_ctx->hwirq);
8606211b40SAntonios Motakis 		irq_ctx->masked = false;
8706211b40SAntonios Motakis 	}
8806211b40SAntonios Motakis 
8906211b40SAntonios Motakis 	spin_unlock_irqrestore(&irq_ctx->lock, flags);
909a36321cSAntonios Motakis }
919a36321cSAntonios Motakis 
vfio_platform_unmask_handler(void * opaque,void * unused)92a7fa7c77SAntonios Motakis static int vfio_platform_unmask_handler(void *opaque, void *unused)
93a7fa7c77SAntonios Motakis {
94a7fa7c77SAntonios Motakis 	struct vfio_platform_irq *irq_ctx = opaque;
95a7fa7c77SAntonios Motakis 
96a7fa7c77SAntonios Motakis 	vfio_platform_unmask(irq_ctx);
97a7fa7c77SAntonios Motakis 
98a7fa7c77SAntonios Motakis 	return 0;
99a7fa7c77SAntonios Motakis }
100a7fa7c77SAntonios Motakis 
vfio_platform_set_irq_unmask(struct vfio_platform_device * vdev,unsigned index,unsigned start,unsigned count,uint32_t flags,void * data)1019a36321cSAntonios Motakis static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev,
1029a36321cSAntonios Motakis 					unsigned index, unsigned start,
1039a36321cSAntonios Motakis 					unsigned count, uint32_t flags,
1049a36321cSAntonios Motakis 					void *data)
1059a36321cSAntonios Motakis {
10606211b40SAntonios Motakis 	if (start != 0 || count != 1)
1079a36321cSAntonios Motakis 		return -EINVAL;
10806211b40SAntonios Motakis 
10906211b40SAntonios Motakis 	if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE))
11006211b40SAntonios Motakis 		return -EINVAL;
11106211b40SAntonios Motakis 
112a7fa7c77SAntonios Motakis 	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
113a7fa7c77SAntonios Motakis 		int32_t fd = *(int32_t *)data;
114a7fa7c77SAntonios Motakis 
115a7fa7c77SAntonios Motakis 		if (fd >= 0)
116a7fa7c77SAntonios Motakis 			return vfio_virqfd_enable((void *) &vdev->irqs[index],
117a7fa7c77SAntonios Motakis 						  vfio_platform_unmask_handler,
118a7fa7c77SAntonios Motakis 						  NULL, NULL,
119a7fa7c77SAntonios Motakis 						  &vdev->irqs[index].unmask,
120a7fa7c77SAntonios Motakis 						  fd);
121a7fa7c77SAntonios Motakis 
122a7fa7c77SAntonios Motakis 		vfio_virqfd_disable(&vdev->irqs[index].unmask);
123a7fa7c77SAntonios Motakis 		return 0;
124a7fa7c77SAntonios Motakis 	}
12506211b40SAntonios Motakis 
12606211b40SAntonios Motakis 	if (flags & VFIO_IRQ_SET_DATA_NONE) {
12706211b40SAntonios Motakis 		vfio_platform_unmask(&vdev->irqs[index]);
12806211b40SAntonios Motakis 
12906211b40SAntonios Motakis 	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
13006211b40SAntonios Motakis 		uint8_t unmask = *(uint8_t *)data;
13106211b40SAntonios Motakis 
13206211b40SAntonios Motakis 		if (unmask)
13306211b40SAntonios Motakis 			vfio_platform_unmask(&vdev->irqs[index]);
13406211b40SAntonios Motakis 	}
13506211b40SAntonios Motakis 
13606211b40SAntonios Motakis 	return 0;
13706211b40SAntonios Motakis }
13806211b40SAntonios Motakis 
13962d4e43aSAlex Williamson /*
14062d4e43aSAlex Williamson  * The trigger eventfd is guaranteed valid in the interrupt path
14162d4e43aSAlex Williamson  * and protected by the igate mutex when triggered via ioctl.
14262d4e43aSAlex Williamson  */
vfio_send_eventfd(struct vfio_platform_irq * irq_ctx)14362d4e43aSAlex Williamson static void vfio_send_eventfd(struct vfio_platform_irq *irq_ctx)
14462d4e43aSAlex Williamson {
14562d4e43aSAlex Williamson 	if (likely(irq_ctx->trigger))
14662d4e43aSAlex Williamson 		eventfd_signal(irq_ctx->trigger, 1);
14762d4e43aSAlex Williamson }
14862d4e43aSAlex Williamson 
vfio_automasked_irq_handler(int irq,void * dev_id)14906211b40SAntonios Motakis static irqreturn_t vfio_automasked_irq_handler(int irq, void *dev_id)
15006211b40SAntonios Motakis {
15106211b40SAntonios Motakis 	struct vfio_platform_irq *irq_ctx = dev_id;
15206211b40SAntonios Motakis 	unsigned long flags;
15306211b40SAntonios Motakis 	int ret = IRQ_NONE;
15406211b40SAntonios Motakis 
15506211b40SAntonios Motakis 	spin_lock_irqsave(&irq_ctx->lock, flags);
15606211b40SAntonios Motakis 
15706211b40SAntonios Motakis 	if (!irq_ctx->masked) {
15806211b40SAntonios Motakis 		ret = IRQ_HANDLED;
15906211b40SAntonios Motakis 
16006211b40SAntonios Motakis 		/* automask maskable interrupts */
16106211b40SAntonios Motakis 		disable_irq_nosync(irq_ctx->hwirq);
16206211b40SAntonios Motakis 		irq_ctx->masked = true;
16306211b40SAntonios Motakis 	}
16406211b40SAntonios Motakis 
16506211b40SAntonios Motakis 	spin_unlock_irqrestore(&irq_ctx->lock, flags);
16606211b40SAntonios Motakis 
16706211b40SAntonios Motakis 	if (ret == IRQ_HANDLED)
16862d4e43aSAlex Williamson 		vfio_send_eventfd(irq_ctx);
16906211b40SAntonios Motakis 
17006211b40SAntonios Motakis 	return ret;
1719a36321cSAntonios Motakis }
1729a36321cSAntonios Motakis 
vfio_irq_handler(int irq,void * dev_id)17357f972e2SAntonios Motakis static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
17457f972e2SAntonios Motakis {
17557f972e2SAntonios Motakis 	struct vfio_platform_irq *irq_ctx = dev_id;
17657f972e2SAntonios Motakis 
17762d4e43aSAlex Williamson 	vfio_send_eventfd(irq_ctx);
17857f972e2SAntonios Motakis 
17957f972e2SAntonios Motakis 	return IRQ_HANDLED;
18057f972e2SAntonios Motakis }
18157f972e2SAntonios Motakis 
vfio_set_trigger(struct vfio_platform_device * vdev,int index,int fd)18257f972e2SAntonios Motakis static int vfio_set_trigger(struct vfio_platform_device *vdev, int index,
18362d4e43aSAlex Williamson 			    int fd)
18457f972e2SAntonios Motakis {
18557f972e2SAntonios Motakis 	struct vfio_platform_irq *irq = &vdev->irqs[index];
18657f972e2SAntonios Motakis 	struct eventfd_ctx *trigger;
18757f972e2SAntonios Motakis 
18857f972e2SAntonios Motakis 	if (irq->trigger) {
18962d4e43aSAlex Williamson 		disable_irq(irq->hwirq);
19057f972e2SAntonios Motakis 		eventfd_ctx_put(irq->trigger);
19157f972e2SAntonios Motakis 		irq->trigger = NULL;
19257f972e2SAntonios Motakis 	}
19357f972e2SAntonios Motakis 
19457f972e2SAntonios Motakis 	if (fd < 0) /* Disable only */
19557f972e2SAntonios Motakis 		return 0;
19657f972e2SAntonios Motakis 
19757f972e2SAntonios Motakis 	trigger = eventfd_ctx_fdget(fd);
19862d4e43aSAlex Williamson 	if (IS_ERR(trigger))
19957f972e2SAntonios Motakis 		return PTR_ERR(trigger);
20057f972e2SAntonios Motakis 
20157f972e2SAntonios Motakis 	irq->trigger = trigger;
20257f972e2SAntonios Motakis 
20362d4e43aSAlex Williamson 	/*
20462d4e43aSAlex Williamson 	 * irq->masked effectively provides nested disables within the overall
20562d4e43aSAlex Williamson 	 * enable relative to trigger.  Specifically request_irq() is called
20662d4e43aSAlex Williamson 	 * with NO_AUTOEN, therefore the IRQ is initially disabled.  The user
20762d4e43aSAlex Williamson 	 * may only further disable the IRQ with a MASK operations because
20862d4e43aSAlex Williamson 	 * irq->masked is initially false.
20962d4e43aSAlex Williamson 	 */
21006211b40SAntonios Motakis 	enable_irq(irq->hwirq);
21106211b40SAntonios Motakis 
21257f972e2SAntonios Motakis 	return 0;
21357f972e2SAntonios Motakis }
21457f972e2SAntonios Motakis 
vfio_platform_set_irq_trigger(struct vfio_platform_device * vdev,unsigned index,unsigned start,unsigned count,uint32_t flags,void * data)2159a36321cSAntonios Motakis static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev,
2169a36321cSAntonios Motakis 					 unsigned index, unsigned start,
2179a36321cSAntonios Motakis 					 unsigned count, uint32_t flags,
2189a36321cSAntonios Motakis 					 void *data)
2199a36321cSAntonios Motakis {
22057f972e2SAntonios Motakis 	struct vfio_platform_irq *irq = &vdev->irqs[index];
22157f972e2SAntonios Motakis 	irq_handler_t handler;
22257f972e2SAntonios Motakis 
22357f972e2SAntonios Motakis 	if (vdev->irqs[index].flags & VFIO_IRQ_INFO_AUTOMASKED)
22406211b40SAntonios Motakis 		handler = vfio_automasked_irq_handler;
22557f972e2SAntonios Motakis 	else
22657f972e2SAntonios Motakis 		handler = vfio_irq_handler;
22757f972e2SAntonios Motakis 
22857f972e2SAntonios Motakis 	if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
22962d4e43aSAlex Williamson 		return vfio_set_trigger(vdev, index, -1);
23057f972e2SAntonios Motakis 
23157f972e2SAntonios Motakis 	if (start != 0 || count != 1)
2329a36321cSAntonios Motakis 		return -EINVAL;
23357f972e2SAntonios Motakis 
23457f972e2SAntonios Motakis 	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
23557f972e2SAntonios Motakis 		int32_t fd = *(int32_t *)data;
23657f972e2SAntonios Motakis 
23762d4e43aSAlex Williamson 		return vfio_set_trigger(vdev, index, fd);
23857f972e2SAntonios Motakis 	}
23957f972e2SAntonios Motakis 
24057f972e2SAntonios Motakis 	if (flags & VFIO_IRQ_SET_DATA_NONE) {
24157f972e2SAntonios Motakis 		handler(irq->hwirq, irq);
24257f972e2SAntonios Motakis 
24357f972e2SAntonios Motakis 	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
24457f972e2SAntonios Motakis 		uint8_t trigger = *(uint8_t *)data;
24557f972e2SAntonios Motakis 
24657f972e2SAntonios Motakis 		if (trigger)
24757f972e2SAntonios Motakis 			handler(irq->hwirq, irq);
24857f972e2SAntonios Motakis 	}
24957f972e2SAntonios Motakis 
25057f972e2SAntonios Motakis 	return 0;
2519a36321cSAntonios Motakis }
2529a36321cSAntonios Motakis 
vfio_platform_set_irqs_ioctl(struct vfio_platform_device * vdev,uint32_t flags,unsigned index,unsigned start,unsigned count,void * data)2539a36321cSAntonios Motakis int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
2549a36321cSAntonios Motakis 				 uint32_t flags, unsigned index, unsigned start,
2559a36321cSAntonios Motakis 				 unsigned count, void *data)
2569a36321cSAntonios Motakis {
2579a36321cSAntonios Motakis 	int (*func)(struct vfio_platform_device *vdev, unsigned index,
2589a36321cSAntonios Motakis 		    unsigned start, unsigned count, uint32_t flags,
2599a36321cSAntonios Motakis 		    void *data) = NULL;
2609a36321cSAntonios Motakis 
26162d4e43aSAlex Williamson 	/*
26262d4e43aSAlex Williamson 	 * For compatibility, errors from request_irq() are local to the
26362d4e43aSAlex Williamson 	 * SET_IRQS path and reflected in the name pointer.  This allows,
26462d4e43aSAlex Williamson 	 * for example, polling mode fallback for an exclusive IRQ failure.
26562d4e43aSAlex Williamson 	 */
26662d4e43aSAlex Williamson 	if (IS_ERR(vdev->irqs[index].name))
26762d4e43aSAlex Williamson 		return PTR_ERR(vdev->irqs[index].name);
26862d4e43aSAlex Williamson 
2699a36321cSAntonios Motakis 	switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
2709a36321cSAntonios Motakis 	case VFIO_IRQ_SET_ACTION_MASK:
2719a36321cSAntonios Motakis 		func = vfio_platform_set_irq_mask;
2729a36321cSAntonios Motakis 		break;
2739a36321cSAntonios Motakis 	case VFIO_IRQ_SET_ACTION_UNMASK:
2749a36321cSAntonios Motakis 		func = vfio_platform_set_irq_unmask;
2759a36321cSAntonios Motakis 		break;
2769a36321cSAntonios Motakis 	case VFIO_IRQ_SET_ACTION_TRIGGER:
2779a36321cSAntonios Motakis 		func = vfio_platform_set_irq_trigger;
2789a36321cSAntonios Motakis 		break;
2799a36321cSAntonios Motakis 	}
2809a36321cSAntonios Motakis 
2819a36321cSAntonios Motakis 	if (!func)
2829a36321cSAntonios Motakis 		return -ENOTTY;
2839a36321cSAntonios Motakis 
2849a36321cSAntonios Motakis 	return func(vdev, index, start, count, flags, data);
2859a36321cSAntonios Motakis }
2869a36321cSAntonios Motakis 
vfio_platform_irq_init(struct vfio_platform_device * vdev)287682704c4SAntonios Motakis int vfio_platform_irq_init(struct vfio_platform_device *vdev)
288682704c4SAntonios Motakis {
28962d4e43aSAlex Williamson 	int cnt = 0, i, ret = 0;
290682704c4SAntonios Motakis 
291682704c4SAntonios Motakis 	while (vdev->get_irq(vdev, cnt) >= 0)
292682704c4SAntonios Motakis 		cnt++;
293682704c4SAntonios Motakis 
2947658aedaSYishai Hadas 	vdev->irqs = kcalloc(cnt, sizeof(struct vfio_platform_irq),
2957658aedaSYishai Hadas 			     GFP_KERNEL_ACCOUNT);
296682704c4SAntonios Motakis 	if (!vdev->irqs)
297682704c4SAntonios Motakis 		return -ENOMEM;
298682704c4SAntonios Motakis 
299682704c4SAntonios Motakis 	for (i = 0; i < cnt; i++) {
3009a36321cSAntonios Motakis 		int hwirq = vdev->get_irq(vdev, i);
30162d4e43aSAlex Williamson 		irq_handler_t handler = vfio_irq_handler;
3029a36321cSAntonios Motakis 
30362d4e43aSAlex Williamson 		if (hwirq < 0) {
30462d4e43aSAlex Williamson 			ret = -EINVAL;
3059a36321cSAntonios Motakis 			goto err;
30662d4e43aSAlex Williamson 		}
3079a36321cSAntonios Motakis 
30806211b40SAntonios Motakis 		spin_lock_init(&vdev->irqs[i].lock);
30906211b40SAntonios Motakis 
31057f972e2SAntonios Motakis 		vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
31157f972e2SAntonios Motakis 
31262d4e43aSAlex Williamson 		if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK) {
31357f972e2SAntonios Motakis 			vdev->irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE
31457f972e2SAntonios Motakis 						| VFIO_IRQ_INFO_AUTOMASKED;
31562d4e43aSAlex Williamson 			handler = vfio_automasked_irq_handler;
31662d4e43aSAlex Williamson 		}
31757f972e2SAntonios Motakis 
318682704c4SAntonios Motakis 		vdev->irqs[i].count = 1;
3199a36321cSAntonios Motakis 		vdev->irqs[i].hwirq = hwirq;
32006211b40SAntonios Motakis 		vdev->irqs[i].masked = false;
32162d4e43aSAlex Williamson 		vdev->irqs[i].name = kasprintf(GFP_KERNEL_ACCOUNT,
32262d4e43aSAlex Williamson 					       "vfio-irq[%d](%s)", hwirq,
32362d4e43aSAlex Williamson 					       vdev->name);
32462d4e43aSAlex Williamson 		if (!vdev->irqs[i].name) {
32562d4e43aSAlex Williamson 			ret = -ENOMEM;
32662d4e43aSAlex Williamson 			goto err;
32762d4e43aSAlex Williamson 		}
32862d4e43aSAlex Williamson 
32962d4e43aSAlex Williamson 		ret = request_irq(hwirq, handler, IRQF_NO_AUTOEN,
33062d4e43aSAlex Williamson 				  vdev->irqs[i].name, &vdev->irqs[i]);
33162d4e43aSAlex Williamson 		if (ret) {
33262d4e43aSAlex Williamson 			kfree(vdev->irqs[i].name);
33362d4e43aSAlex Williamson 			vdev->irqs[i].name = ERR_PTR(ret);
33462d4e43aSAlex Williamson 		}
335682704c4SAntonios Motakis 	}
336682704c4SAntonios Motakis 
337682704c4SAntonios Motakis 	vdev->num_irqs = cnt;
338682704c4SAntonios Motakis 
339682704c4SAntonios Motakis 	return 0;
3409a36321cSAntonios Motakis err:
34162d4e43aSAlex Williamson 	for (--i; i >= 0; i--) {
34262d4e43aSAlex Williamson 		if (!IS_ERR(vdev->irqs[i].name)) {
34362d4e43aSAlex Williamson 			free_irq(vdev->irqs[i].hwirq, &vdev->irqs[i]);
34462d4e43aSAlex Williamson 			kfree(vdev->irqs[i].name);
34562d4e43aSAlex Williamson 		}
34662d4e43aSAlex Williamson 	}
3479a36321cSAntonios Motakis 	kfree(vdev->irqs);
34862d4e43aSAlex Williamson 	return ret;
349682704c4SAntonios Motakis }
350682704c4SAntonios Motakis 
vfio_platform_irq_cleanup(struct vfio_platform_device * vdev)351682704c4SAntonios Motakis void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev)
352682704c4SAntonios Motakis {
35357f972e2SAntonios Motakis 	int i;
35457f972e2SAntonios Motakis 
35574c564b7SAlex Williamson 	for (i = 0; i < vdev->num_irqs; i++) {
35674c564b7SAlex Williamson 		vfio_virqfd_disable(&vdev->irqs[i].mask);
35774c564b7SAlex Williamson 		vfio_virqfd_disable(&vdev->irqs[i].unmask);
35862d4e43aSAlex Williamson 		if (!IS_ERR(vdev->irqs[i].name)) {
35962d4e43aSAlex Williamson 			free_irq(vdev->irqs[i].hwirq, &vdev->irqs[i]);
36062d4e43aSAlex Williamson 			if (vdev->irqs[i].trigger)
36162d4e43aSAlex Williamson 				eventfd_ctx_put(vdev->irqs[i].trigger);
36262d4e43aSAlex Williamson 			kfree(vdev->irqs[i].name);
36362d4e43aSAlex Williamson 		}
36474c564b7SAlex Williamson 	}
36557f972e2SAntonios Motakis 
366682704c4SAntonios Motakis 	vdev->num_irqs = 0;
367682704c4SAntonios Motakis 	kfree(vdev->irqs);
368682704c4SAntonios Motakis }
369