1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
3 * Copyright 2013-2016 Freescale Semiconductor Inc.
7 #include <linux/vfio.h>
8 #include <linux/slab.h>
9 #include <linux/types.h>
10 #include <linux/eventfd.h>
11 #include <linux/msi.h>
13 #include "linux/fsl/mc.h"
14 #include "vfio_fsl_mc_private.h"
16 static int vfio_fsl_mc_irqs_allocate(struct vfio_fsl_mc_device
*vdev
)
18 struct fsl_mc_device
*mc_dev
= vdev
->mc_dev
;
19 struct vfio_fsl_mc_irq
*mc_irq
;
23 /* Device does not support any interrupt */
24 if (mc_dev
->obj_desc
.irq_count
== 0)
27 /* interrupts were already allocated for this device */
31 irq_count
= mc_dev
->obj_desc
.irq_count
;
33 mc_irq
= kcalloc(irq_count
, sizeof(*mc_irq
), GFP_KERNEL
);
38 ret
= fsl_mc_allocate_irqs(mc_dev
);
44 for (i
= 0; i
< irq_count
; i
++) {
46 mc_irq
[i
].flags
= VFIO_IRQ_INFO_EVENTFD
;
49 vdev
->mc_irqs
= mc_irq
;
54 static irqreturn_t
vfio_fsl_mc_irq_handler(int irq_num
, void *arg
)
56 struct vfio_fsl_mc_irq
*mc_irq
= (struct vfio_fsl_mc_irq
*)arg
;
58 eventfd_signal(mc_irq
->trigger
, 1);
62 static int vfio_set_trigger(struct vfio_fsl_mc_device
*vdev
,
65 struct vfio_fsl_mc_irq
*irq
= &vdev
->mc_irqs
[index
];
66 struct eventfd_ctx
*trigger
;
70 hwirq
= vdev
->mc_dev
->irqs
[index
]->msi_desc
->irq
;
74 eventfd_ctx_put(irq
->trigger
);
78 if (fd
< 0) /* Disable only */
81 irq
->name
= kasprintf(GFP_KERNEL
, "vfio-irq[%d](%s)",
82 hwirq
, dev_name(&vdev
->mc_dev
->dev
));
86 trigger
= eventfd_ctx_fdget(fd
);
87 if (IS_ERR(trigger
)) {
89 return PTR_ERR(trigger
);
92 irq
->trigger
= trigger
;
94 ret
= request_irq(hwirq
, vfio_fsl_mc_irq_handler
, 0,
98 eventfd_ctx_put(trigger
);
106 static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device
*vdev
,
107 unsigned int index
, unsigned int start
,
108 unsigned int count
, u32 flags
,
111 struct fsl_mc_device
*mc_dev
= vdev
->mc_dev
;
113 struct vfio_fsl_mc_irq
*irq
;
114 struct device
*cont_dev
= fsl_mc_cont_dev(&mc_dev
->dev
);
115 struct fsl_mc_device
*mc_cont
= to_fsl_mc_device(cont_dev
);
117 if (!count
&& (flags
& VFIO_IRQ_SET_DATA_NONE
))
118 return vfio_set_trigger(vdev
, index
, -1);
120 if (start
!= 0 || count
!= 1)
123 mutex_lock(&vdev
->reflck
->lock
);
124 ret
= fsl_mc_populate_irq_pool(mc_cont
,
125 FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS
);
129 ret
= vfio_fsl_mc_irqs_allocate(vdev
);
132 mutex_unlock(&vdev
->reflck
->lock
);
134 if (flags
& VFIO_IRQ_SET_DATA_EVENTFD
) {
135 s32 fd
= *(s32
*)data
;
137 return vfio_set_trigger(vdev
, index
, fd
);
140 hwirq
= vdev
->mc_dev
->irqs
[index
]->msi_desc
->irq
;
142 irq
= &vdev
->mc_irqs
[index
];
144 if (flags
& VFIO_IRQ_SET_DATA_NONE
) {
145 vfio_fsl_mc_irq_handler(hwirq
, irq
);
147 } else if (flags
& VFIO_IRQ_SET_DATA_BOOL
) {
148 u8 trigger
= *(u8
*)data
;
151 vfio_fsl_mc_irq_handler(hwirq
, irq
);
157 mutex_unlock(&vdev
->reflck
->lock
);
162 int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device
*vdev
,
163 u32 flags
, unsigned int index
,
164 unsigned int start
, unsigned int count
,
167 if (flags
& VFIO_IRQ_SET_ACTION_TRIGGER
)
168 return vfio_fsl_mc_set_irq_trigger(vdev
, index
, start
,
174 /* Free All IRQs for the given MC object */
175 void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device
*vdev
)
177 struct fsl_mc_device
*mc_dev
= vdev
->mc_dev
;
178 int irq_count
= mc_dev
->obj_desc
.irq_count
;
182 * Device does not support any interrupt or the interrupts
183 * were not configured
188 for (i
= 0; i
< irq_count
; i
++)
189 vfio_set_trigger(vdev
, i
, -1);
191 fsl_mc_free_irqs(mc_dev
);
192 kfree(vdev
->mc_irqs
);
193 vdev
->mc_irqs
= NULL
;