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