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>
12 #include "linux/fsl/mc.h"
13 #include "vfio_fsl_mc_private.h"
15 static int vfio_fsl_mc_irqs_allocate(struct vfio_fsl_mc_device
*vdev
)
17 struct fsl_mc_device
*mc_dev
= vdev
->mc_dev
;
18 struct vfio_fsl_mc_irq
*mc_irq
;
22 /* Device does not support any interrupt */
23 if (mc_dev
->obj_desc
.irq_count
== 0)
26 /* interrupts were already allocated for this device */
30 irq_count
= mc_dev
->obj_desc
.irq_count
;
32 mc_irq
= kcalloc(irq_count
, sizeof(*mc_irq
), GFP_KERNEL_ACCOUNT
);
37 ret
= fsl_mc_allocate_irqs(mc_dev
);
43 for (i
= 0; i
< irq_count
; i
++) {
45 mc_irq
[i
].flags
= VFIO_IRQ_INFO_EVENTFD
;
48 vdev
->mc_irqs
= mc_irq
;
53 static irqreturn_t
vfio_fsl_mc_irq_handler(int irq_num
, void *arg
)
55 struct vfio_fsl_mc_irq
*mc_irq
= (struct vfio_fsl_mc_irq
*)arg
;
57 eventfd_signal(mc_irq
->trigger
);
61 static int vfio_set_trigger(struct vfio_fsl_mc_device
*vdev
,
64 struct vfio_fsl_mc_irq
*irq
= &vdev
->mc_irqs
[index
];
65 struct eventfd_ctx
*trigger
;
69 hwirq
= vdev
->mc_dev
->irqs
[index
]->virq
;
73 eventfd_ctx_put(irq
->trigger
);
77 if (fd
< 0) /* Disable only */
80 irq
->name
= kasprintf(GFP_KERNEL_ACCOUNT
, "vfio-irq[%d](%s)",
81 hwirq
, dev_name(&vdev
->mc_dev
->dev
));
85 trigger
= eventfd_ctx_fdget(fd
);
86 if (IS_ERR(trigger
)) {
88 return PTR_ERR(trigger
);
91 irq
->trigger
= trigger
;
93 ret
= request_irq(hwirq
, vfio_fsl_mc_irq_handler
, 0,
97 eventfd_ctx_put(trigger
);
105 static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device
*vdev
,
106 unsigned int index
, unsigned int start
,
107 unsigned int count
, u32 flags
,
110 struct fsl_mc_device
*mc_dev
= vdev
->mc_dev
;
111 struct vfio_fsl_mc_irq
*irq
;
112 struct device
*cont_dev
= fsl_mc_cont_dev(&mc_dev
->dev
);
113 struct fsl_mc_device
*mc_cont
= to_fsl_mc_device(cont_dev
);
116 if (!count
&& (flags
& VFIO_IRQ_SET_DATA_NONE
))
117 return vfio_set_trigger(vdev
, index
, -1);
119 if (start
!= 0 || count
!= 1)
122 mutex_lock(&vdev
->vdev
.dev_set
->lock
);
123 ret
= fsl_mc_populate_irq_pool(mc_cont
,
124 FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS
);
128 ret
= vfio_fsl_mc_irqs_allocate(vdev
);
131 mutex_unlock(&vdev
->vdev
.dev_set
->lock
);
133 if (flags
& VFIO_IRQ_SET_DATA_EVENTFD
) {
134 s32 fd
= *(s32
*)data
;
136 return vfio_set_trigger(vdev
, index
, fd
);
139 irq
= &vdev
->mc_irqs
[index
];
141 if (flags
& VFIO_IRQ_SET_DATA_NONE
) {
143 eventfd_signal(irq
->trigger
);
145 } else if (flags
& VFIO_IRQ_SET_DATA_BOOL
) {
146 u8 trigger
= *(u8
*)data
;
148 if (trigger
&& irq
->trigger
)
149 eventfd_signal(irq
->trigger
);
155 mutex_unlock(&vdev
->vdev
.dev_set
->lock
);
160 int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device
*vdev
,
161 u32 flags
, unsigned int index
,
162 unsigned int start
, unsigned int count
,
165 if (flags
& VFIO_IRQ_SET_ACTION_TRIGGER
)
166 return vfio_fsl_mc_set_irq_trigger(vdev
, index
, start
,
172 /* Free All IRQs for the given MC object */
173 void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device
*vdev
)
175 struct fsl_mc_device
*mc_dev
= vdev
->mc_dev
;
176 int irq_count
= mc_dev
->obj_desc
.irq_count
;
180 * Device does not support any interrupt or the interrupts
181 * were not configured
186 for (i
= 0; i
< irq_count
; i
++)
187 vfio_set_trigger(vdev
, i
, -1);
189 fsl_mc_free_irqs(mc_dev
);
190 kfree(vdev
->mc_irqs
);
191 vdev
->mc_irqs
= NULL
;