kernel: bump 4.14 to 4.14.125 (FS#2305 FS#2297)
[oweals/openwrt.git] / target / linux / layerscape / patches-4.14 / 808-vfio-support-layerscape.patch
1 From 03ce521cd071706f755e3d2304ab1b8c47fd4910 Mon Sep 17 00:00:00 2001
2 From: Biwen Li <biwen.li@nxp.com>
3 Date: Wed, 17 Apr 2019 18:59:09 +0800
4 Subject: [PATCH] vfio: support layerscape
5
6 This is an integrated patch of vfio for layerscape
7
8 Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
9 Signed-off-by: Biwen Li <biwen.li@nxp.com>
10 Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
11 Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
12 ---
13  drivers/vfio/Kconfig                      |   1 +
14  drivers/vfio/Makefile                     |   1 +
15  drivers/vfio/fsl-mc/Kconfig               |   9 +
16  drivers/vfio/fsl-mc/Makefile              |   2 +
17  drivers/vfio/fsl-mc/vfio_fsl_mc.c         | 759 ++++++++++++++++++++++
18  drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c    | 199 ++++++
19  drivers/vfio/fsl-mc/vfio_fsl_mc_private.h |  57 ++
20  include/uapi/linux/vfio.h                 |   1 +
21  8 files changed, 1029 insertions(+)
22  create mode 100644 drivers/vfio/fsl-mc/Kconfig
23  create mode 100644 drivers/vfio/fsl-mc/Makefile
24  create mode 100644 drivers/vfio/fsl-mc/vfio_fsl_mc.c
25  create mode 100644 drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
26  create mode 100644 drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
27
28 --- a/drivers/vfio/Kconfig
29 +++ b/drivers/vfio/Kconfig
30 @@ -47,4 +47,5 @@ menuconfig VFIO_NOIOMMU
31  source "drivers/vfio/pci/Kconfig"
32  source "drivers/vfio/platform/Kconfig"
33  source "drivers/vfio/mdev/Kconfig"
34 +source "drivers/vfio/fsl-mc/Kconfig"
35  source "virt/lib/Kconfig"
36 --- a/drivers/vfio/Makefile
37 +++ b/drivers/vfio/Makefile
38 @@ -9,3 +9,4 @@ obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spa
39  obj-$(CONFIG_VFIO_PCI) += pci/
40  obj-$(CONFIG_VFIO_PLATFORM) += platform/
41  obj-$(CONFIG_VFIO_MDEV) += mdev/
42 +obj-$(CONFIG_VFIO_FSL_MC) += fsl-mc/
43 --- /dev/null
44 +++ b/drivers/vfio/fsl-mc/Kconfig
45 @@ -0,0 +1,9 @@
46 +config VFIO_FSL_MC
47 +       tristate "VFIO support for QorIQ DPAA2 fsl-mc bus devices"
48 +       depends on VFIO && FSL_MC_BUS && EVENTFD
49 +       help
50 +         Driver to enable support for the VFIO QorIQ DPAA2 fsl-mc
51 +         (Management Complex) devices. This is required to passthrough
52 +         fsl-mc bus devices using the VFIO framework.
53 +
54 +         If you don't know what to do here, say N.
55 --- /dev/null
56 +++ b/drivers/vfio/fsl-mc/Makefile
57 @@ -0,0 +1,2 @@
58 +vfio-fsl_mc-y := vfio_fsl_mc.o
59 +obj-$(CONFIG_VFIO_FSL_MC) += vfio_fsl_mc.o vfio_fsl_mc_intr.o
60 --- /dev/null
61 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
62 @@ -0,0 +1,759 @@
63 +/*
64 + * Freescale Management Complex (MC) device passthrough using VFIO
65 + *
66 + * Copyright (C) 2013-2016 Freescale Semiconductor, Inc.
67 + * Copyright 2016-2017 NXP
68 + * Author: Bharat Bhushan <bharat.bhushan@nxp.com>
69 + *
70 + * This file is licensed under the terms of the GNU General Public
71 + * License version 2. This program is licensed "as is" without any
72 + * warranty of any kind, whether express or implied.
73 + */
74 +
75 +#include <linux/device.h>
76 +#include <linux/iommu.h>
77 +#include <linux/module.h>
78 +#include <linux/mutex.h>
79 +#include <linux/slab.h>
80 +#include <linux/types.h>
81 +#include <linux/vfio.h>
82 +#include <linux/delay.h>
83 +#include <linux/fsl/mc.h>
84 +
85 +#include "vfio_fsl_mc_private.h"
86 +
87 +#define DRIVER_VERSION "0.10"
88 +#define DRIVER_AUTHOR  "Bharat Bhushan <bharat.bhushan@nxp.com>"
89 +#define DRIVER_DESC    "VFIO for FSL-MC devices - User Level meta-driver"
90 +
91 +static DEFINE_MUTEX(driver_lock);
92 +
93 +/* FSl-MC device regions (address and size) are aligned to 64K.
94 + * While MC firmware reports size less than 64K for some objects (it actually
95 + * reports size which does not include reserved space beyond valid bytes).
96 + * Align the size to PAGE_SIZE for userspace to mmap.
97 + */
98 +static size_t aligned_region_size(struct fsl_mc_device *mc_dev, int index)
99 +{
100 +       size_t size;
101 +
102 +       size = resource_size(&mc_dev->regions[index]);
103 +       return PAGE_ALIGN(size);
104 +}
105 +
106 +static int vfio_fsl_mc_regions_init(struct vfio_fsl_mc_device *vdev)
107 +{
108 +       struct fsl_mc_device *mc_dev = vdev->mc_dev;
109 +       int count = mc_dev->obj_desc.region_count;
110 +       int i;
111 +
112 +       vdev->regions = kcalloc(count, sizeof(struct vfio_fsl_mc_region),
113 +                               GFP_KERNEL);
114 +       if (!vdev->regions)
115 +               return -ENOMEM;
116 +
117 +       for (i = 0; i < mc_dev->obj_desc.region_count; i++) {
118 +               vdev->regions[i].addr = mc_dev->regions[i].start;
119 +               vdev->regions[i].size = aligned_region_size(mc_dev, i);
120 +               vdev->regions[i].type = VFIO_FSL_MC_REGION_TYPE_MMIO;
121 +               if (mc_dev->regions[i].flags & IORESOURCE_CACHEABLE)
122 +                       vdev->regions[i].type |=
123 +                                       VFIO_FSL_MC_REGION_TYPE_CACHEABLE;
124 +               if (mc_dev->regions[i].flags & IORESOURCE_MEM)
125 +                       vdev->regions[i].type |=
126 +                                       VFIO_FSL_MC_REGION_TYPE_SHAREABLE;
127 +
128 +               vdev->regions[i].flags = VFIO_REGION_INFO_FLAG_MMAP;
129 +               vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ;
130 +               if (!(mc_dev->regions[i].flags & IORESOURCE_READONLY))
131 +                       vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_WRITE;
132 +       }
133 +
134 +       vdev->num_regions = mc_dev->obj_desc.region_count;
135 +       return 0;
136 +}
137 +
138 +static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev)
139 +{
140 +       int i;
141 +
142 +       for (i = 0; i < vdev->num_regions; i++)
143 +               iounmap(vdev->regions[i].ioaddr);
144 +
145 +       vdev->num_regions = 0;
146 +       kfree(vdev->regions);
147 +}
148 +
149 +static int vfio_fsl_mc_open(void *device_data)
150 +{
151 +       struct vfio_fsl_mc_device *vdev = device_data;
152 +       int ret;
153 +
154 +       if (!try_module_get(THIS_MODULE))
155 +               return -ENODEV;
156 +
157 +       mutex_lock(&driver_lock);
158 +       if (!vdev->refcnt) {
159 +               ret = vfio_fsl_mc_regions_init(vdev);
160 +               if (ret)
161 +                       goto error_region_init;
162 +
163 +               ret = vfio_fsl_mc_irqs_init(vdev);
164 +               if (ret)
165 +                       goto error_irq_init;
166 +       }
167 +
168 +       vdev->refcnt++;
169 +       mutex_unlock(&driver_lock);
170 +       return 0;
171 +
172 +error_irq_init:
173 +       vfio_fsl_mc_regions_cleanup(vdev);
174 +error_region_init:
175 +       mutex_unlock(&driver_lock);
176 +       if (ret)
177 +               module_put(THIS_MODULE);
178 +
179 +       return ret;
180 +}
181 +
182 +static void vfio_fsl_mc_release(void *device_data)
183 +{
184 +       struct vfio_fsl_mc_device *vdev = device_data;
185 +       struct fsl_mc_device *mc_dev = vdev->mc_dev;
186 +
187 +       mutex_lock(&driver_lock);
188 +
189 +       if (!(--vdev->refcnt)) {
190 +               vfio_fsl_mc_regions_cleanup(vdev);
191 +               vfio_fsl_mc_irqs_cleanup(vdev);
192 +       }
193 +
194 +       if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
195 +               dprc_reset_container(mc_dev->mc_io, 0, mc_dev->mc_handle,
196 +                                    mc_dev->obj_desc.id);
197 +
198 +       mutex_unlock(&driver_lock);
199 +
200 +       module_put(THIS_MODULE);
201 +}
202 +
203 +static long vfio_fsl_mc_ioctl(void *device_data, unsigned int cmd,
204 +                             unsigned long arg)
205 +{
206 +       struct vfio_fsl_mc_device *vdev = device_data;
207 +       struct fsl_mc_device *mc_dev = vdev->mc_dev;
208 +       unsigned long minsz;
209 +
210 +       if (WARN_ON(!mc_dev))
211 +               return -ENODEV;
212 +
213 +       switch (cmd) {
214 +       case VFIO_DEVICE_GET_INFO:
215 +       {
216 +               struct vfio_device_info info;
217 +
218 +               minsz = offsetofend(struct vfio_device_info, num_irqs);
219 +
220 +               if (copy_from_user(&info, (void __user *)arg, minsz))
221 +                       return -EFAULT;
222 +
223 +               if (info.argsz < minsz)
224 +                       return -EINVAL;
225 +
226 +               info.flags = VFIO_DEVICE_FLAGS_FSL_MC;
227 +               info.num_regions = mc_dev->obj_desc.region_count;
228 +               info.num_irqs = mc_dev->obj_desc.irq_count;
229 +
230 +               return copy_to_user((void __user *)arg, &info, minsz);
231 +       }
232 +       case VFIO_DEVICE_GET_REGION_INFO:
233 +       {
234 +               struct vfio_region_info info;
235 +
236 +               minsz = offsetofend(struct vfio_region_info, offset);
237 +
238 +               if (copy_from_user(&info, (void __user *)arg, minsz))
239 +                       return -EFAULT;
240 +
241 +               if (info.argsz < minsz)
242 +                       return -EINVAL;
243 +
244 +               if (info.index >= vdev->num_regions)
245 +                       return -EINVAL;
246 +
247 +               /* map offset to the physical address  */
248 +               info.offset = VFIO_FSL_MC_INDEX_TO_OFFSET(info.index);
249 +               info.size = vdev->regions[info.index].size;
250 +               info.flags = vdev->regions[info.index].flags;
251 +
252 +               return copy_to_user((void __user *)arg, &info, minsz);
253 +       }
254 +       case VFIO_DEVICE_GET_IRQ_INFO:
255 +       {
256 +               struct vfio_irq_info info;
257 +
258 +               minsz = offsetofend(struct vfio_irq_info, count);
259 +               if (copy_from_user(&info, (void __user *)arg, minsz))
260 +                       return -EFAULT;
261 +
262 +               if (info.argsz < minsz)
263 +                       return -EINVAL;
264 +
265 +               if (info.index >= mc_dev->obj_desc.irq_count)
266 +                       return -EINVAL;
267 +
268 +               if (vdev->mc_irqs != NULL) {
269 +                       info.flags = vdev->mc_irqs[info.index].flags;
270 +                       info.count = vdev->mc_irqs[info.index].count;
271 +               } else {
272 +                       /*
273 +                        * If IRQs are not initialized then these can not
274 +                        * be configuted and used by user-space/
275 +                        */
276 +                       info.flags = 0;
277 +                       info.count = 0;
278 +               }
279 +
280 +               return copy_to_user((void __user *)arg, &info, minsz);
281 +       }
282 +       case VFIO_DEVICE_SET_IRQS:
283 +       {
284 +               struct vfio_irq_set hdr;
285 +               u8 *data = NULL;
286 +               int ret = 0;
287 +
288 +               minsz = offsetofend(struct vfio_irq_set, count);
289 +
290 +               if (copy_from_user(&hdr, (void __user *)arg, minsz))
291 +                       return -EFAULT;
292 +
293 +               if (hdr.argsz < minsz)
294 +                       return -EINVAL;
295 +
296 +               if (hdr.index >= mc_dev->obj_desc.irq_count)
297 +                       return -EINVAL;
298 +
299 +               if (hdr.start != 0 || hdr.count > 1)
300 +                       return -EINVAL;
301 +
302 +               if (hdr.count == 0 &&
303 +                   (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE) ||
304 +                   !(hdr.flags & VFIO_IRQ_SET_ACTION_TRIGGER)))
305 +                       return -EINVAL;
306 +
307 +               if (hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
308 +                                 VFIO_IRQ_SET_ACTION_TYPE_MASK))
309 +                       return -EINVAL;
310 +
311 +               if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
312 +                       size_t size;
313 +
314 +                       if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
315 +                               size = sizeof(uint8_t);
316 +                       else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD)
317 +                               size = sizeof(int32_t);
318 +                       else
319 +                               return -EINVAL;
320 +
321 +                       if (hdr.argsz - minsz < hdr.count * size)
322 +                               return -EINVAL;
323 +
324 +                       data = memdup_user((void __user *)(arg + minsz),
325 +                                          hdr.count * size);
326 +                       if (IS_ERR(data))
327 +                               return PTR_ERR(data);
328 +               }
329 +
330 +               ret = vfio_fsl_mc_set_irqs_ioctl(vdev, hdr.flags,
331 +                                                hdr.index, hdr.start,
332 +                                                hdr.count, data);
333 +               return ret;
334 +       }
335 +       case VFIO_DEVICE_RESET:
336 +       {
337 +               return -EINVAL;
338 +       }
339 +       default:
340 +               return -EINVAL;
341 +       }
342 +}
343 +
344 +static ssize_t vfio_fsl_mc_read(void *device_data, char __user *buf,
345 +                               size_t count, loff_t *ppos)
346 +{
347 +       struct vfio_fsl_mc_device *vdev = device_data;
348 +       unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos);
349 +       loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK;
350 +       struct vfio_fsl_mc_region *region;
351 +       uint64_t data[8];
352 +       int i;
353 +
354 +       /* Read ioctl supported only for DPRC and DPMCP device */
355 +       if (strcmp(vdev->mc_dev->obj_desc.type, "dprc") &&
356 +           strcmp(vdev->mc_dev->obj_desc.type, "dpmcp"))
357 +               return -EINVAL;
358 +
359 +       if (index >= vdev->num_regions)
360 +               return -EINVAL;
361 +
362 +       region = &vdev->regions[index];
363 +
364 +       if (!(region->flags & VFIO_REGION_INFO_FLAG_READ))
365 +               return -EINVAL;
366 +
367 +       if (!region->type & VFIO_FSL_MC_REGION_TYPE_MMIO)
368 +               return -EINVAL;
369 +
370 +       if (!region->ioaddr) {
371 +               region->ioaddr = ioremap_nocache(region->addr, region->size);
372 +               if (!region->ioaddr)
373 +                       return -ENOMEM;
374 +       }
375 +
376 +       if (count != 64 || off != 0)
377 +               return -EINVAL;
378 +
379 +       for (i = 7; i >= 0; i--)
380 +               data[i] = readq(region->ioaddr + i * sizeof(uint64_t));
381 +
382 +       if (copy_to_user(buf, data, 64))
383 +               return -EFAULT;
384 +
385 +       return count;
386 +}
387 +
388 +#define MC_CMD_COMPLETION_TIMEOUT_MS   5000
389 +#define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS    500
390 +
391 +static int vfio_fsl_mc_dprc_wait_for_response(void __iomem *ioaddr)
392 +{
393 +       enum mc_cmd_status status;
394 +       unsigned long timeout_usecs = MC_CMD_COMPLETION_TIMEOUT_MS * 1000;
395 +
396 +       for (;;) {
397 +               u64 header;
398 +               struct mc_cmd_header *resp_hdr;
399 +
400 +               header = cpu_to_le64(readq_relaxed(ioaddr));
401 +
402 +               resp_hdr = (struct mc_cmd_header *)&header;
403 +               status = (enum mc_cmd_status)resp_hdr->status;
404 +               if (status != MC_CMD_STATUS_READY)
405 +                       break;
406 +
407 +               udelay(MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS);
408 +               timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS;
409 +               if (timeout_usecs == 0)
410 +                       return -ETIMEDOUT;
411 +       }
412 +
413 +       return 0;
414 +}
415 +
416 +static int vfio_fsl_mc_send_command(void __iomem *ioaddr, uint64_t *cmd_data)
417 +{
418 +       int i;
419 +
420 +       /* Write at command parameter into portal */
421 +       for (i = 7; i >= 1; i--)
422 +               writeq_relaxed(cmd_data[i], ioaddr + i * sizeof(uint64_t));
423 +
424 +       /* Write command header in the end */
425 +       writeq(cmd_data[0], ioaddr);
426 +
427 +       /* Wait for response before returning to user-space
428 +        * This can be optimized in future to even prepare response
429 +        * before returning to user-space and avoid read ioctl.
430 +        */
431 +       return vfio_fsl_mc_dprc_wait_for_response(ioaddr);
432 +}
433 +
434 +static int vfio_handle_dprc_commands(void __iomem *ioaddr, uint64_t *cmd_data)
435 +{
436 +       uint64_t cmd_hdr = cmd_data[0];
437 +       int cmd = (cmd_hdr >> 52) & 0xfff;
438 +
439 +       switch (cmd) {
440 +       case DPRC_CMDID_OPEN:
441 +       default:
442 +               return vfio_fsl_mc_send_command(ioaddr, cmd_data);
443 +       }
444 +
445 +       return 0;
446 +}
447 +
448 +static ssize_t vfio_fsl_mc_write(void *device_data, const char __user *buf,
449 +                                size_t count, loff_t *ppos)
450 +{
451 +       struct vfio_fsl_mc_device *vdev = device_data;
452 +       unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos);
453 +       loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK;
454 +       struct vfio_fsl_mc_region *region;
455 +       uint64_t data[8];
456 +       int ret;
457 +
458 +       /* Write ioctl supported only for DPRC and DPMCP device */
459 +       if (strcmp(vdev->mc_dev->obj_desc.type, "dprc") &&
460 +           strcmp(vdev->mc_dev->obj_desc.type, "dpmcp"))
461 +               return -EINVAL;
462 +
463 +       if (index >= vdev->num_regions)
464 +               return -EINVAL;
465 +
466 +       region = &vdev->regions[index];
467 +
468 +       if (!(region->flags & VFIO_REGION_INFO_FLAG_WRITE))
469 +               return -EINVAL;
470 +
471 +       if (!region->type & VFIO_FSL_MC_REGION_TYPE_MMIO)
472 +               return -EINVAL;
473 +
474 +       if (!region->ioaddr) {
475 +               region->ioaddr = ioremap_nocache(region->addr, region->size);
476 +               if (!region->ioaddr)
477 +                       return -ENOMEM;
478 +       }
479 +
480 +       if (count != 64 || off != 0)
481 +               return -EINVAL;
482 +
483 +       if (copy_from_user(&data, buf, 64))
484 +               return -EFAULT;
485 +
486 +       ret = vfio_handle_dprc_commands(region->ioaddr, data);
487 +       if (ret)
488 +               return ret;
489 +
490 +       return count;
491 +}
492 +
493 +static int vfio_fsl_mc_mmap_mmio(struct vfio_fsl_mc_region region,
494 +                                struct vm_area_struct *vma)
495 +{
496 +       u64 size = vma->vm_end - vma->vm_start;
497 +       u64 pgoff, base;
498 +
499 +       pgoff = vma->vm_pgoff &
500 +               ((1U << (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
501 +       base = pgoff << PAGE_SHIFT;
502 +
503 +       if (region.size < PAGE_SIZE || base + size > region.size)
504 +               return -EINVAL;
505 +       /*
506 +        * Set the REGION_TYPE_CACHEABLE (QBman CENA regs) to be the
507 +        * cache inhibited area of the portal to avoid coherency issues
508 +        * if a user migrates to another core.
509 +        */
510 +       if (region.type & VFIO_FSL_MC_REGION_TYPE_CACHEABLE) {
511 +               if (region.type & VFIO_FSL_MC_REGION_TYPE_SHAREABLE)
512 +                       vma->vm_page_prot = pgprot_cached(vma->vm_page_prot);
513 +               else
514 +                       vma->vm_page_prot = pgprot_cached_ns(vma->vm_page_prot);
515 +       } else
516 +               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
517 +
518 +       vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
519 +
520 +       return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
521 +                              size, vma->vm_page_prot);
522 +}
523 +
524 +/* Allows mmaping fsl_mc device regions in assigned DPRC */
525 +static int vfio_fsl_mc_mmap(void *device_data, struct vm_area_struct *vma)
526 +{
527 +       struct vfio_fsl_mc_device *vdev = device_data;
528 +       struct fsl_mc_device *mc_dev = vdev->mc_dev;
529 +       unsigned long size, addr;
530 +       int index;
531 +
532 +       index = vma->vm_pgoff >> (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT);
533 +
534 +       if (vma->vm_end < vma->vm_start)
535 +               return -EINVAL;
536 +       if (vma->vm_start & ~PAGE_MASK)
537 +               return -EINVAL;
538 +       if (vma->vm_end & ~PAGE_MASK)
539 +               return -EINVAL;
540 +       if (!(vma->vm_flags & VM_SHARED))
541 +               return -EINVAL;
542 +       if (index >= vdev->num_regions)
543 +               return -EINVAL;
544 +
545 +       if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP))
546 +               return -EINVAL;
547 +
548 +       if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ)
549 +                       && (vma->vm_flags & VM_READ))
550 +               return -EINVAL;
551 +
552 +       if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE)
553 +                       && (vma->vm_flags & VM_WRITE))
554 +               return -EINVAL;
555 +
556 +       addr = vdev->regions[index].addr;
557 +       size = vdev->regions[index].size;
558 +
559 +       vma->vm_private_data = mc_dev;
560 +
561 +       if (vdev->regions[index].type & VFIO_FSL_MC_REGION_TYPE_MMIO)
562 +               return vfio_fsl_mc_mmap_mmio(vdev->regions[index], vma);
563 +
564 +       return -EFAULT;
565 +}
566 +
567 +static const struct vfio_device_ops vfio_fsl_mc_ops = {
568 +       .name           = "vfio-fsl-mc",
569 +       .open           = vfio_fsl_mc_open,
570 +       .release        = vfio_fsl_mc_release,
571 +       .ioctl          = vfio_fsl_mc_ioctl,
572 +       .read           = vfio_fsl_mc_read,
573 +       .write          = vfio_fsl_mc_write,
574 +       .mmap           = vfio_fsl_mc_mmap,
575 +};
576 +
577 +static int vfio_fsl_mc_initialize_dprc(struct vfio_fsl_mc_device *vdev)
578 +{
579 +       struct device *root_dprc_dev;
580 +       struct fsl_mc_device *mc_dev = vdev->mc_dev;
581 +       struct device *dev = &mc_dev->dev;
582 +       struct fsl_mc_bus *mc_bus;
583 +       struct irq_domain *mc_msi_domain;
584 +       unsigned int irq_count;
585 +       int ret;
586 +
587 +       /* device must be DPRC */
588 +       if (strcmp(mc_dev->obj_desc.type, "dprc"))
589 +               return -EINVAL;
590 +
591 +       /* mc_io must be un-initialized */
592 +       WARN_ON(mc_dev->mc_io);
593 +
594 +       /* allocate a portal from the root DPRC for vfio use */
595 +       fsl_mc_get_root_dprc(dev, &root_dprc_dev);
596 +       if (WARN_ON(!root_dprc_dev))
597 +               return -EINVAL;
598 +
599 +       ret = fsl_mc_portal_allocate(to_fsl_mc_device(root_dprc_dev),
600 +                                    FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
601 +                                    &mc_dev->mc_io);
602 +       if (ret < 0)
603 +               goto clean_msi_domain;
604 +
605 +       /* Reset MCP before move on */
606 +       ret = fsl_mc_portal_reset(mc_dev->mc_io);
607 +       if (ret < 0) {
608 +               dev_err(dev, "dprc portal reset failed: error = %d\n", ret);
609 +               goto free_mc_portal;
610 +       }
611 +
612 +       /* MSI domain set up */
613 +       ret = fsl_mc_find_msi_domain(root_dprc_dev->parent, &mc_msi_domain);
614 +       if (ret < 0)
615 +               goto free_mc_portal;
616 +
617 +       dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
618 +
619 +       ret = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
620 +                       &mc_dev->mc_handle);
621 +       if (ret) {
622 +               dev_err(dev, "dprc_open() failed: error = %d\n", ret);
623 +               goto free_mc_portal;
624 +       }
625 +
626 +       /* Initialize resource pool */
627 +       fsl_mc_init_all_resource_pools(mc_dev);
628 +
629 +       mc_bus = to_fsl_mc_bus(mc_dev);
630 +
631 +       if (!mc_bus->irq_resources) {
632 +               irq_count = FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS;
633 +               ret = fsl_mc_populate_irq_pool(mc_bus, irq_count);
634 +               if (ret < 0) {
635 +                       dev_err(dev, "%s: Failed to init irq-pool\n", __func__);
636 +                       goto clean_resource_pool;
637 +               }
638 +       }
639 +
640 +       mutex_init(&mc_bus->scan_mutex);
641 +
642 +       mutex_lock(&mc_bus->scan_mutex);
643 +       ret = dprc_scan_objects(mc_dev, mc_dev->driver_override,
644 +                               &irq_count);
645 +       mutex_unlock(&mc_bus->scan_mutex);
646 +       if (ret) {
647 +               dev_err(dev, "dprc_scan_objects() fails (%d)\n", ret);
648 +               goto clean_irq_pool;
649 +       }
650 +
651 +       if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
652 +               dev_warn(&mc_dev->dev,
653 +                        "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
654 +                        irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
655 +       }
656 +
657 +       return 0;
658 +
659 +clean_irq_pool:
660 +       fsl_mc_cleanup_irq_pool(mc_bus);
661 +
662 +clean_resource_pool:
663 +       fsl_mc_cleanup_all_resource_pools(mc_dev);
664 +       dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
665 +
666 +free_mc_portal:
667 +       fsl_mc_portal_free(mc_dev->mc_io);
668 +
669 +clean_msi_domain:
670 +       dev_set_msi_domain(&mc_dev->dev, NULL);
671 +
672 +       return ret;
673 +}
674 +
675 +static int vfio_fsl_mc_device_remove(struct device *dev, void *data)
676 +{
677 +       struct fsl_mc_device *mc_dev;
678 +
679 +       WARN_ON(dev == NULL);
680 +
681 +       mc_dev = to_fsl_mc_device(dev);
682 +       if (WARN_ON(mc_dev == NULL))
683 +               return -ENODEV;
684 +
685 +       fsl_mc_device_remove(mc_dev);
686 +       return 0;
687 +}
688 +
689 +static void vfio_fsl_mc_cleanup_dprc(struct vfio_fsl_mc_device *vdev)
690 +{
691 +       struct fsl_mc_device *mc_dev = vdev->mc_dev;
692 +       struct fsl_mc_bus *mc_bus;
693 +
694 +       /* device must be DPRC */
695 +       if (strcmp(mc_dev->obj_desc.type, "dprc"))
696 +               return;
697 +
698 +       device_for_each_child(&mc_dev->dev, NULL, vfio_fsl_mc_device_remove);
699 +
700 +       mc_bus = to_fsl_mc_bus(mc_dev);
701 +       if (dev_get_msi_domain(&mc_dev->dev))
702 +               fsl_mc_cleanup_irq_pool(mc_bus);
703 +
704 +       dev_set_msi_domain(&mc_dev->dev, NULL);
705 +
706 +       fsl_mc_cleanup_all_resource_pools(mc_dev);
707 +       dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
708 +       fsl_mc_portal_free(mc_dev->mc_io);
709 +}
710 +
711 +static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev)
712 +{
713 +       struct iommu_group *group;
714 +       struct vfio_fsl_mc_device *vdev;
715 +       struct device *dev = &mc_dev->dev;
716 +       int ret;
717 +
718 +       group = vfio_iommu_group_get(dev);
719 +       if (!group) {
720 +               dev_err(dev, "%s: VFIO: No IOMMU group\n", __func__);
721 +               return -EINVAL;
722 +       }
723 +
724 +       vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
725 +       if (!vdev) {
726 +               vfio_iommu_group_put(group, dev);
727 +               return -ENOMEM;
728 +       }
729 +
730 +       vdev->mc_dev = mc_dev;
731 +
732 +       ret = vfio_add_group_dev(dev, &vfio_fsl_mc_ops, vdev);
733 +       if (ret) {
734 +               dev_err(dev, "%s: Failed to add to vfio group\n", __func__);
735 +               goto free_vfio_device;
736 +       }
737 +
738 +       /* DPRC container scanned and it's chilren bound with vfio driver */
739 +       if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) {
740 +               ret = vfio_fsl_mc_initialize_dprc(vdev);
741 +               if (ret) {
742 +                       vfio_del_group_dev(dev);
743 +                       goto free_vfio_device;
744 +               }
745 +       } else {
746 +               struct fsl_mc_device *mc_bus_dev;
747 +
748 +               /* Non-dprc devices share mc_io from the parent dprc */
749 +               mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
750 +               if (mc_bus_dev == NULL) {
751 +                       vfio_del_group_dev(dev);
752 +                       goto free_vfio_device;
753 +               }
754 +
755 +               mc_dev->mc_io = mc_bus_dev->mc_io;
756 +
757 +               /* Inherit parent MSI domain */
758 +               dev_set_msi_domain(&mc_dev->dev,
759 +                                  dev_get_msi_domain(mc_dev->dev.parent));
760 +       }
761 +       return 0;
762 +
763 +free_vfio_device:
764 +       kfree(vdev);
765 +       vfio_iommu_group_put(group, dev);
766 +       return ret;
767 +}
768 +
769 +static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev)
770 +{
771 +       struct vfio_fsl_mc_device *vdev;
772 +       struct device *dev = &mc_dev->dev;
773 +
774 +       vdev = vfio_del_group_dev(dev);
775 +       if (!vdev)
776 +               return -EINVAL;
777 +
778 +       if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
779 +               vfio_fsl_mc_cleanup_dprc(vdev);
780 +       else
781 +               dev_set_msi_domain(&mc_dev->dev, NULL);
782 +
783 +       mc_dev->mc_io = NULL;
784 +
785 +       vfio_iommu_group_put(mc_dev->dev.iommu_group, dev);
786 +       kfree(vdev);
787 +
788 +       return 0;
789 +}
790 +
791 +/*
792 + * vfio-fsl_mc is a meta-driver, so use driver_override interface to
793 + * bind a fsl_mc container with this driver and match_id_table is NULL.
794 + */
795 +static struct fsl_mc_driver vfio_fsl_mc_driver = {
796 +       .probe          = vfio_fsl_mc_probe,
797 +       .remove         = vfio_fsl_mc_remove,
798 +       .match_id_table = NULL,
799 +       .driver = {
800 +               .name   = "vfio-fsl-mc",
801 +               .owner  = THIS_MODULE,
802 +       },
803 +};
804 +
805 +static int __init vfio_fsl_mc_driver_init(void)
806 +{
807 +       return fsl_mc_driver_register(&vfio_fsl_mc_driver);
808 +}
809 +
810 +static void __exit vfio_fsl_mc_driver_exit(void)
811 +{
812 +       fsl_mc_driver_unregister(&vfio_fsl_mc_driver);
813 +}
814 +
815 +module_init(vfio_fsl_mc_driver_init);
816 +module_exit(vfio_fsl_mc_driver_exit);
817 +
818 +MODULE_VERSION(DRIVER_VERSION);
819 +MODULE_LICENSE("GPL v2");
820 +MODULE_AUTHOR(DRIVER_AUTHOR);
821 +MODULE_DESCRIPTION(DRIVER_DESC);
822 --- /dev/null
823 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
824 @@ -0,0 +1,199 @@
825 +/*
826 + * Freescale Management Complex (MC) device passthrough using VFIO
827 + *
828 + * Copyright (C) 2013-2016 Freescale Semiconductor, Inc.
829 + * Author: Bharat Bhushan <bharat.bhushan@nxp.com>
830 + *
831 + * This file is licensed under the terms of the GNU General Public
832 + * License version 2. This program is licensed "as is" without any
833 + * warranty of any kind, whether express or implied.
834 + */
835 +
836 +#include <linux/vfio.h>
837 +#include <linux/slab.h>
838 +#include <linux/types.h>
839 +#include <linux/eventfd.h>
840 +#include <linux/msi.h>
841 +
842 +#include "linux/fsl/mc.h"
843 +#include "vfio_fsl_mc_private.h"
844 +
845 +static irqreturn_t vfio_fsl_mc_irq_handler(int irq_num, void *arg)
846 +{
847 +       struct vfio_fsl_mc_irq *mc_irq = (struct vfio_fsl_mc_irq *)arg;
848 +
849 +       eventfd_signal(mc_irq->trigger, 1);
850 +       return IRQ_HANDLED;
851 +}
852 +
853 +static int vfio_fsl_mc_irq_mask(struct vfio_fsl_mc_device *vdev,
854 +                               unsigned int index, unsigned int start,
855 +                               unsigned int count, uint32_t flags,
856 +                               void *data)
857 +{
858 +       return -EINVAL;
859 +}
860 +
861 +static int vfio_fsl_mc_irq_unmask(struct vfio_fsl_mc_device *vdev,
862 +                               unsigned int index, unsigned int start,
863 +                               unsigned int count, uint32_t flags,
864 +                               void *data)
865 +{
866 +       return -EINVAL;
867 +}
868 +
869 +static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev,
870 +                           int index, int fd)
871 +{
872 +       struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index];
873 +       struct eventfd_ctx *trigger;
874 +       int hwirq;
875 +       int ret;
876 +
877 +       hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
878 +       if (irq->trigger) {
879 +               free_irq(hwirq, irq);
880 +               kfree(irq->name);
881 +               eventfd_ctx_put(irq->trigger);
882 +               irq->trigger = NULL;
883 +       }
884 +
885 +       if (fd < 0) /* Disable only */
886 +               return 0;
887 +
888 +       irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
889 +                                       hwirq, dev_name(&vdev->mc_dev->dev));
890 +       if (!irq->name)
891 +               return -ENOMEM;
892 +
893 +       trigger = eventfd_ctx_fdget(fd);
894 +       if (IS_ERR(trigger)) {
895 +               kfree(irq->name);
896 +               return PTR_ERR(trigger);
897 +       }
898 +
899 +       irq->trigger = trigger;
900 +
901 +       ret = request_irq(hwirq, vfio_fsl_mc_irq_handler, 0,
902 +                         irq->name, irq);
903 +       if (ret) {
904 +               kfree(irq->name);
905 +               eventfd_ctx_put(trigger);
906 +               irq->trigger = NULL;
907 +               return ret;
908 +       }
909 +
910 +       return 0;
911 +}
912 +
913 +int vfio_fsl_mc_irqs_init(struct vfio_fsl_mc_device *vdev)
914 +{
915 +       struct fsl_mc_device *mc_dev = vdev->mc_dev;
916 +       struct vfio_fsl_mc_irq *mc_irq;
917 +       int irq_count;
918 +       int ret, i;
919 +
920 +       /* Device does not support any interrupt */
921 +       if (mc_dev->obj_desc.irq_count == 0)
922 +               return 0;
923 +
924 +       irq_count = mc_dev->obj_desc.irq_count;
925 +
926 +       mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL);
927 +       if (mc_irq == NULL)
928 +               return -ENOMEM;
929 +
930 +       /* Allocate IRQs */
931 +       ret = fsl_mc_allocate_irqs(mc_dev);
932 +       if  (ret) {
933 +               kfree(mc_irq);
934 +               return ret;
935 +       }
936 +
937 +       for (i = 0; i < irq_count; i++) {
938 +               mc_irq[i].count = 1;
939 +               mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD;
940 +       }
941 +
942 +       vdev->mc_irqs = mc_irq;
943 +
944 +       return 0;
945 +}
946 +
947 +/* Free All IRQs for the given MC object */
948 +void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev)
949 +{
950 +       struct fsl_mc_device *mc_dev = vdev->mc_dev;
951 +       int irq_count = mc_dev->obj_desc.irq_count;
952 +       int i;
953 +
954 +       /* Device does not support any interrupt */
955 +       if (mc_dev->obj_desc.irq_count == 0)
956 +               return;
957 +
958 +       for (i = 0; i < irq_count; i++)
959 +               vfio_set_trigger(vdev, i, -1);
960 +
961 +       fsl_mc_free_irqs(mc_dev);
962 +       kfree(vdev->mc_irqs);
963 +}
964 +
965 +static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device *vdev,
966 +                                      unsigned int index, unsigned int start,
967 +                                      unsigned int count, uint32_t flags,
968 +                                      void *data)
969 +{
970 +       struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index];
971 +       int hwirq;
972 +
973 +       if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
974 +               return vfio_set_trigger(vdev, index, -1);
975 +
976 +       if (start != 0 || count != 1)
977 +               return -EINVAL;
978 +
979 +       if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
980 +               int32_t fd = *(int32_t *)data;
981 +
982 +               return vfio_set_trigger(vdev, index, fd);
983 +       }
984 +
985 +       hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
986 +
987 +       if (flags & VFIO_IRQ_SET_DATA_NONE) {
988 +               vfio_fsl_mc_irq_handler(hwirq, irq);
989 +
990 +       } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
991 +               uint8_t trigger = *(uint8_t *)data;
992 +
993 +               if (trigger)
994 +                       vfio_fsl_mc_irq_handler(hwirq, irq);
995 +       }
996 +
997 +       return 0;
998 +}
999 +
1000 +int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
1001 +                              uint32_t flags, unsigned int index,
1002 +                              unsigned int start, unsigned int count,
1003 +                              void *data)
1004 +{
1005 +       int ret = -ENOTTY;
1006 +
1007 +       switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
1008 +       case VFIO_IRQ_SET_ACTION_MASK:
1009 +               ret = vfio_fsl_mc_irq_mask(vdev, index, start, count,
1010 +                                          flags, data);
1011 +               break;
1012 +       case VFIO_IRQ_SET_ACTION_UNMASK:
1013 +               ret = vfio_fsl_mc_irq_unmask(vdev, index, start, count,
1014 +                                            flags, data);
1015 +               break;
1016 +       case VFIO_IRQ_SET_ACTION_TRIGGER:
1017 +               ret = vfio_fsl_mc_set_irq_trigger(vdev, index, start,
1018 +                                                 count, flags, data);
1019 +               break;
1020 +       }
1021 +
1022 +       return ret;
1023 +}
1024 --- /dev/null
1025 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
1026 @@ -0,0 +1,57 @@
1027 +/*
1028 + * Freescale Management Complex VFIO private declarations
1029 + *
1030 + * Copyright (C) 2013-2016 Freescale Semiconductor, Inc.
1031 + * Copyright 2016 NXP
1032 + * Author: Bharat Bhushan <bharat.bhushan@nxp.com>
1033 + *
1034 + * This file is licensed under the terms of the GNU General Public
1035 + * License version 2. This program is licensed "as is" without any
1036 + * warranty of any kind, whether express or implied.
1037 + */
1038 +
1039 +#ifndef VFIO_FSL_MC_PRIVATE_H
1040 +#define VFIO_FSL_MC_PRIVATE_H
1041 +
1042 +#define VFIO_FSL_MC_OFFSET_SHIFT    40
1043 +#define VFIO_FSL_MC_OFFSET_MASK (((u64)(1) << VFIO_FSL_MC_OFFSET_SHIFT) - 1)
1044 +
1045 +#define VFIO_FSL_MC_OFFSET_TO_INDEX(off) (off >> VFIO_FSL_MC_OFFSET_SHIFT)
1046 +
1047 +#define VFIO_FSL_MC_INDEX_TO_OFFSET(index)     \
1048 +       ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
1049 +
1050 +struct vfio_fsl_mc_irq {
1051 +       u32                     flags;
1052 +       u32                     count;
1053 +       struct eventfd_ctx      *trigger;
1054 +       char                    *name;
1055 +};
1056 +
1057 +struct vfio_fsl_mc_region {
1058 +       u32                     flags;
1059 +#define VFIO_FSL_MC_REGION_TYPE_MMIO  1
1060 +#define VFIO_FSL_MC_REGION_TYPE_CACHEABLE  2
1061 +#define VFIO_FSL_MC_REGION_TYPE_SHAREABLE  4
1062 +
1063 +       u32                     type;
1064 +       u64                     addr;
1065 +       resource_size_t         size;
1066 +       void __iomem            *ioaddr;
1067 +};
1068 +
1069 +struct vfio_fsl_mc_device {
1070 +       struct fsl_mc_device            *mc_dev;
1071 +       int                             refcnt;
1072 +       u32                             num_regions;
1073 +       struct vfio_fsl_mc_region       *regions;
1074 +       struct vfio_fsl_mc_irq          *mc_irqs;
1075 +};
1076 +
1077 +int vfio_fsl_mc_irqs_init(struct vfio_fsl_mc_device *vdev);
1078 +void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev);
1079 +int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
1080 +                              uint32_t flags, unsigned int index,
1081 +                              unsigned int start, unsigned int count,
1082 +                              void *data);
1083 +#endif /* VFIO_PCI_PRIVATE_H */
1084 --- a/include/uapi/linux/vfio.h
1085 +++ b/include/uapi/linux/vfio.h
1086 @@ -200,6 +200,7 @@ struct vfio_device_info {
1087  #define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2)    /* vfio-platform device */
1088  #define VFIO_DEVICE_FLAGS_AMBA  (1 << 3)       /* vfio-amba device */
1089  #define VFIO_DEVICE_FLAGS_CCW  (1 << 4)        /* vfio-ccw device */
1090 +#define VFIO_DEVICE_FLAGS_FSL_MC (1 << 5)      /* vfio-fsl-mc device */
1091         __u32   num_regions;    /* Max region index + 1 */
1092         __u32   num_irqs;       /* Max IRQ index + 1 */
1093  };