ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 821-vfio-0008-vfio-fsl-mc-trigger-an-interrupt-via-eventfd.patch
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 */