4f1e0997f7852f71aad0ca0bffa05140f602308a
[openwrt/staging/pepe2k.git] /
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
5
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.
8
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
11 required.
12
13 Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
14 Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
15 ---
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(-)
20
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)
25 {
26 struct vfio_fsl_mc_device *vdev = device_data;
27 + int ret;
28
29 mutex_lock(&vdev->reflck->lock);
30
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;
37 +
38 + mc_bus = to_fsl_mc_bus(mc_cont);
39 +
40 vfio_fsl_mc_regions_cleanup(vdev);
41
42 + /* reset the device before cleaning up the interrupts */
43 + ret = dprc_reset_container(mc_dev->mc_io, 0,
44 + mc_dev->mc_handle,
45 + mc_dev->obj_desc.id);
46 +
47 + vfio_fsl_mc_irqs_cleanup(vdev);
48 +
49 + fsl_mc_cleanup_irq_pool(mc_bus);
50 + }
51 +
52 mutex_unlock(&vdev->reflck->lock);
53
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
58 return -EINVAL;
59 }
60
61 +int vfio_fsl_mc_irqs_allocate(struct vfio_fsl_mc_device *vdev)
62 +{
63 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
64 + struct vfio_fsl_mc_irq *mc_irq;
65 + int irq_count;
66 + int ret, i;
67 +
68 + /* Device does not support any interrupt */
69 + if (mc_dev->obj_desc.irq_count == 0)
70 + return 0;
71 +
72 + /* interrupts were already allocated for this device */
73 + if (vdev->mc_irqs)
74 + return 0;
75 +
76 + irq_count = mc_dev->obj_desc.irq_count;
77 +
78 + mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL);
79 + if (mc_irq == NULL)
80 + return -ENOMEM;
81 +
82 + /* Allocate IRQs */
83 + ret = fsl_mc_allocate_irqs(mc_dev);
84 + if (ret) {
85 + kfree(mc_irq);
86 + return ret;
87 + }
88 +
89 + for (i = 0; i < irq_count; i++) {
90 + mc_irq[i].count = 1;
91 + mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD;
92 + }
93 +
94 + vdev->mc_irqs = mc_irq;
95 +
96 + return 0;
97 +}
98 +static irqreturn_t vfio_fsl_mc_irq_handler(int irq_num, void *arg)
99 +{
100 + struct vfio_fsl_mc_irq *mc_irq = (struct vfio_fsl_mc_irq *)arg;
101 +
102 + eventfd_signal(mc_irq->trigger, 1);
103 + return IRQ_HANDLED;
104 +}
105 +
106 +static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev,
107 + int index, int fd)
108 +{
109 + struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index];
110 + struct eventfd_ctx *trigger;
111 + int hwirq;
112 + int ret;
113 +
114 + hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
115 + if (irq->trigger) {
116 + free_irq(hwirq, irq);
117 + kfree(irq->name);
118 + eventfd_ctx_put(irq->trigger);
119 + irq->trigger = NULL;
120 + }
121 +
122 + if (fd < 0) /* Disable only */
123 + return 0;
124 +
125 + irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
126 + hwirq, dev_name(&vdev->mc_dev->dev));
127 + if (!irq->name)
128 + return -ENOMEM;
129 +
130 + trigger = eventfd_ctx_fdget(fd);
131 + if (IS_ERR(trigger)) {
132 + kfree(irq->name);
133 + return PTR_ERR(trigger);
134 + }
135 +
136 + irq->trigger = trigger;
137 +
138 + ret = request_irq(hwirq, vfio_fsl_mc_irq_handler, 0,
139 + irq->name, irq);
140 + if (ret) {
141 + kfree(irq->name);
142 + eventfd_ctx_put(trigger);
143 + irq->trigger = NULL;
144 + return ret;
145 + }
146 +
147 + return 0;
148 +}
149 +
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,
153 void *data)
154 {
155 - return -EINVAL;
156 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
157 + struct fsl_mc_bus *mc_bus;
158 + int ret, hwirq;
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);
162 +
163 + if (start != 0 || count != 1)
164 + return -EINVAL;
165 +
166 + mc_bus = to_fsl_mc_bus(mc_cont);
167 +
168 + mutex_lock(&vdev->reflck->lock);
169 + if (!mc_bus->irq_resources) {
170 +
171 + ret = fsl_mc_populate_irq_pool(mc_bus,
172 + FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
173 + if (ret)
174 + goto unlock;
175 + }
176 +
177 + ret = vfio_fsl_mc_irqs_allocate(vdev);
178 + if (ret)
179 + goto unlock;
180 + mutex_unlock(&vdev->reflck->lock);
181 +
182 + if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
183 + return vfio_set_trigger(vdev, index, -1);
184 +
185 + if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
186 + int32_t fd = *(int32_t *)data;
187 +
188 + return vfio_set_trigger(vdev, index, fd);
189 + }
190 +
191 + hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
192 +
193 + irq = &vdev->mc_irqs[index];
194 +
195 + if (flags & VFIO_IRQ_SET_DATA_NONE) {
196 + vfio_fsl_mc_irq_handler(hwirq, irq);
197 +
198 + } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
199 + uint8_t trigger = *(uint8_t *)data;
200 +
201 + if (trigger)
202 + vfio_fsl_mc_irq_handler(hwirq, irq);
203 + }
204 +
205 + return 0;
206 +
207 +unlock:
208 + mutex_unlock(&vdev->reflck->lock);
209 + return ret;
210 }
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
214
215 return ret;
216 }
217 +
218 +/* Free All IRQs for the given MC object */
219 +void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev)
220 +{
221 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
222 + int irq_count = mc_dev->obj_desc.irq_count;
223 + int i;
224 +
225 + /* Device does not support any interrupt or the interrupts
226 + * were not configured
227 + */
228 + if (mc_dev->obj_desc.irq_count == 0 || !vdev->mc_irqs)
229 + return;
230 +
231 + for (i = 0; i < irq_count; i++)
232 + vfio_set_trigger(vdev, i, -1);
233 +
234 + fsl_mc_free_irqs(mc_dev);
235 + kfree(vdev->mc_irqs);
236 + vdev->mc_irqs = NULL;
237 +}
238 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
239 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
240 @@ -15,6 +15,13 @@
241 #define VFIO_FSL_MC_INDEX_TO_OFFSET(index) \
242 ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
243
244 +struct vfio_fsl_mc_irq {
245 + u32 flags;
246 + u32 count;
247 + struct eventfd_ctx *trigger;
248 + char *name;
249 +};
250 +
251 struct vfio_fsl_mc_reflck {
252 struct kref kref;
253 struct mutex lock;
254 @@ -33,6 +40,7 @@ struct vfio_fsl_mc_device {
255 u32 num_regions;
256 struct vfio_fsl_mc_region *regions;
257 struct vfio_fsl_mc_reflck *reflck;
258 + struct vfio_fsl_mc_irq *mc_irqs;
259 };
260
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,
264 void *data);
265
266 +void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev);
267 +
268 #endif /* VFIO_PCI_PRIVATE_H */