1 From 8f0239c9385028a0c15306966c66a56315b11dbc Mon Sep 17 00:00:00 2001
2 From: Diana Craciun <diana.craciun@nxp.com>
3 Date: Tue, 1 Oct 2019 16:44:04 +0300
4 Subject: [PATCH] vfio/fsl-mc: trigger an interrupt via eventfd
6 This patch allows to set an eventfd for fsl-mc device interrupt
7 and also to trigger the interrupt eventfd from userspace for testing.
9 All fsl-mc device interrupts are MSI type. This does not yet handle
10 correctly DPRC container interrupt where re-scanning on container is
13 Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
14 Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
16 drivers/vfio/fsl-mc/vfio_fsl_mc.c | 20 +++-
17 drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c | 165 +++++++++++++++++++++++++++++-
18 drivers/vfio/fsl-mc/vfio_fsl_mc_private.h | 10 ++
19 3 files changed, 193 insertions(+), 2 deletions(-)
21 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
22 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
23 @@ -144,12 +144,30 @@ err_reg_init:
24 static void vfio_fsl_mc_release(void *device_data)
26 struct vfio_fsl_mc_device *vdev = device_data;
29 mutex_lock(&vdev->reflck->lock);
31 - if (!(--vdev->refcnt))
32 + if (!(--vdev->refcnt)) {
33 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
34 + struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev);
35 + struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev);
36 + struct fsl_mc_bus *mc_bus;
38 + mc_bus = to_fsl_mc_bus(mc_cont);
40 vfio_fsl_mc_regions_cleanup(vdev);
42 + /* reset the device before cleaning up the interrupts */
43 + ret = dprc_reset_container(mc_dev->mc_io, 0,
45 + mc_dev->obj_desc.id);
47 + vfio_fsl_mc_irqs_cleanup(vdev);
49 + fsl_mc_cleanup_irq_pool(mc_bus);
52 mutex_unlock(&vdev->reflck->lock);
54 module_put(THIS_MODULE);
55 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
56 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
57 @@ -29,12 +29,154 @@ static int vfio_fsl_mc_irq_unmask(struct
61 +int vfio_fsl_mc_irqs_allocate(struct vfio_fsl_mc_device *vdev)
63 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
64 + struct vfio_fsl_mc_irq *mc_irq;
68 + /* Device does not support any interrupt */
69 + if (mc_dev->obj_desc.irq_count == 0)
72 + /* interrupts were already allocated for this device */
76 + irq_count = mc_dev->obj_desc.irq_count;
78 + mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL);
83 + ret = fsl_mc_allocate_irqs(mc_dev);
89 + for (i = 0; i < irq_count; i++) {
90 + mc_irq[i].count = 1;
91 + mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD;
94 + vdev->mc_irqs = mc_irq;
98 +static irqreturn_t vfio_fsl_mc_irq_handler(int irq_num, void *arg)
100 + struct vfio_fsl_mc_irq *mc_irq = (struct vfio_fsl_mc_irq *)arg;
102 + eventfd_signal(mc_irq->trigger, 1);
103 + return IRQ_HANDLED;
106 +static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev,
109 + struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index];
110 + struct eventfd_ctx *trigger;
114 + hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
115 + if (irq->trigger) {
116 + free_irq(hwirq, irq);
118 + eventfd_ctx_put(irq->trigger);
119 + irq->trigger = NULL;
122 + if (fd < 0) /* Disable only */
125 + irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
126 + hwirq, dev_name(&vdev->mc_dev->dev));
130 + trigger = eventfd_ctx_fdget(fd);
131 + if (IS_ERR(trigger)) {
133 + return PTR_ERR(trigger);
136 + irq->trigger = trigger;
138 + ret = request_irq(hwirq, vfio_fsl_mc_irq_handler, 0,
142 + eventfd_ctx_put(trigger);
143 + irq->trigger = NULL;
150 static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device *vdev,
151 unsigned int index, unsigned int start,
152 unsigned int count, uint32_t flags,
156 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
157 + struct fsl_mc_bus *mc_bus;
159 + struct vfio_fsl_mc_irq *irq;
160 + struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev);
161 + struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev);
163 + if (start != 0 || count != 1)
166 + mc_bus = to_fsl_mc_bus(mc_cont);
168 + mutex_lock(&vdev->reflck->lock);
169 + if (!mc_bus->irq_resources) {
171 + ret = fsl_mc_populate_irq_pool(mc_bus,
172 + FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
177 + ret = vfio_fsl_mc_irqs_allocate(vdev);
180 + mutex_unlock(&vdev->reflck->lock);
182 + if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
183 + return vfio_set_trigger(vdev, index, -1);
185 + if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
186 + int32_t fd = *(int32_t *)data;
188 + return vfio_set_trigger(vdev, index, fd);
191 + hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
193 + irq = &vdev->mc_irqs[index];
195 + if (flags & VFIO_IRQ_SET_DATA_NONE) {
196 + vfio_fsl_mc_irq_handler(hwirq, irq);
198 + } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
199 + uint8_t trigger = *(uint8_t *)data;
202 + vfio_fsl_mc_irq_handler(hwirq, irq);
208 + mutex_unlock(&vdev->reflck->lock);
211 int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
212 uint32_t flags, unsigned int index,
213 @@ -60,3 +202,24 @@ int vfio_fsl_mc_set_irqs_ioctl(struct vf
218 +/* Free All IRQs for the given MC object */
219 +void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev)
221 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
222 + int irq_count = mc_dev->obj_desc.irq_count;
225 + /* Device does not support any interrupt or the interrupts
226 + * were not configured
228 + if (mc_dev->obj_desc.irq_count == 0 || !vdev->mc_irqs)
231 + for (i = 0; i < irq_count; i++)
232 + vfio_set_trigger(vdev, i, -1);
234 + fsl_mc_free_irqs(mc_dev);
235 + kfree(vdev->mc_irqs);
236 + vdev->mc_irqs = NULL;
238 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
239 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
241 #define VFIO_FSL_MC_INDEX_TO_OFFSET(index) \
242 ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
244 +struct vfio_fsl_mc_irq {
247 + struct eventfd_ctx *trigger;
251 struct vfio_fsl_mc_reflck {
254 @@ -33,6 +40,7 @@ struct vfio_fsl_mc_device {
256 struct vfio_fsl_mc_region *regions;
257 struct vfio_fsl_mc_reflck *reflck;
258 + struct vfio_fsl_mc_irq *mc_irqs;
261 int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
262 @@ -40,4 +48,6 @@ int vfio_fsl_mc_set_irqs_ioctl(struct vf
263 unsigned int start, unsigned int count,
266 +void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev);
268 #endif /* VFIO_PCI_PRIVATE_H */