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
6 This is an integrated patch of vfio for layerscape
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>
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
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/
44 +++ b/drivers/vfio/fsl-mc/Kconfig
47 + tristate "VFIO support for QorIQ DPAA2 fsl-mc bus devices"
48 + depends on VFIO && FSL_MC_BUS && EVENTFD
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.
54 + If you don't know what to do here, say N.
56 +++ b/drivers/vfio/fsl-mc/Makefile
58 +vfio-fsl_mc-y := vfio_fsl_mc.o
59 +obj-$(CONFIG_VFIO_FSL_MC) += vfio_fsl_mc.o vfio_fsl_mc_intr.o
61 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
64 + * Freescale Management Complex (MC) device passthrough using VFIO
66 + * Copyright (C) 2013-2016 Freescale Semiconductor, Inc.
67 + * Copyright 2016-2017 NXP
68 + * Author: Bharat Bhushan <bharat.bhushan@nxp.com>
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.
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>
85 +#include "vfio_fsl_mc_private.h"
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"
91 +static DEFINE_MUTEX(driver_lock);
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.
98 +static size_t aligned_region_size(struct fsl_mc_device *mc_dev, int index)
102 + size = resource_size(&mc_dev->regions[index]);
103 + return PAGE_ALIGN(size);
106 +static int vfio_fsl_mc_regions_init(struct vfio_fsl_mc_device *vdev)
108 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
109 + int count = mc_dev->obj_desc.region_count;
112 + vdev->regions = kcalloc(count, sizeof(struct vfio_fsl_mc_region),
114 + if (!vdev->regions)
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;
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;
134 + vdev->num_regions = mc_dev->obj_desc.region_count;
138 +static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev)
142 + for (i = 0; i < vdev->num_regions; i++)
143 + iounmap(vdev->regions[i].ioaddr);
145 + vdev->num_regions = 0;
146 + kfree(vdev->regions);
149 +static int vfio_fsl_mc_open(void *device_data)
151 + struct vfio_fsl_mc_device *vdev = device_data;
154 + if (!try_module_get(THIS_MODULE))
157 + mutex_lock(&driver_lock);
158 + if (!vdev->refcnt) {
159 + ret = vfio_fsl_mc_regions_init(vdev);
161 + goto error_region_init;
163 + ret = vfio_fsl_mc_irqs_init(vdev);
165 + goto error_irq_init;
169 + mutex_unlock(&driver_lock);
173 + vfio_fsl_mc_regions_cleanup(vdev);
175 + mutex_unlock(&driver_lock);
177 + module_put(THIS_MODULE);
182 +static void vfio_fsl_mc_release(void *device_data)
184 + struct vfio_fsl_mc_device *vdev = device_data;
185 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
187 + mutex_lock(&driver_lock);
189 + if (!(--vdev->refcnt)) {
190 + vfio_fsl_mc_regions_cleanup(vdev);
191 + vfio_fsl_mc_irqs_cleanup(vdev);
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);
198 + mutex_unlock(&driver_lock);
200 + module_put(THIS_MODULE);
203 +static long vfio_fsl_mc_ioctl(void *device_data, unsigned int cmd,
206 + struct vfio_fsl_mc_device *vdev = device_data;
207 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
208 + unsigned long minsz;
210 + if (WARN_ON(!mc_dev))
214 + case VFIO_DEVICE_GET_INFO:
216 + struct vfio_device_info info;
218 + minsz = offsetofend(struct vfio_device_info, num_irqs);
220 + if (copy_from_user(&info, (void __user *)arg, minsz))
223 + if (info.argsz < minsz)
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;
230 + return copy_to_user((void __user *)arg, &info, minsz);
232 + case VFIO_DEVICE_GET_REGION_INFO:
234 + struct vfio_region_info info;
236 + minsz = offsetofend(struct vfio_region_info, offset);
238 + if (copy_from_user(&info, (void __user *)arg, minsz))
241 + if (info.argsz < minsz)
244 + if (info.index >= vdev->num_regions)
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;
252 + return copy_to_user((void __user *)arg, &info, minsz);
254 + case VFIO_DEVICE_GET_IRQ_INFO:
256 + struct vfio_irq_info info;
258 + minsz = offsetofend(struct vfio_irq_info, count);
259 + if (copy_from_user(&info, (void __user *)arg, minsz))
262 + if (info.argsz < minsz)
265 + if (info.index >= mc_dev->obj_desc.irq_count)
268 + if (vdev->mc_irqs != NULL) {
269 + info.flags = vdev->mc_irqs[info.index].flags;
270 + info.count = vdev->mc_irqs[info.index].count;
273 + * If IRQs are not initialized then these can not
274 + * be configuted and used by user-space/
280 + return copy_to_user((void __user *)arg, &info, minsz);
282 + case VFIO_DEVICE_SET_IRQS:
284 + struct vfio_irq_set hdr;
288 + minsz = offsetofend(struct vfio_irq_set, count);
290 + if (copy_from_user(&hdr, (void __user *)arg, minsz))
293 + if (hdr.argsz < minsz)
296 + if (hdr.index >= mc_dev->obj_desc.irq_count)
299 + if (hdr.start != 0 || hdr.count > 1)
302 + if (hdr.count == 0 &&
303 + (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE) ||
304 + !(hdr.flags & VFIO_IRQ_SET_ACTION_TRIGGER)))
307 + if (hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
308 + VFIO_IRQ_SET_ACTION_TYPE_MASK))
311 + if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
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);
321 + if (hdr.argsz - minsz < hdr.count * size)
324 + data = memdup_user((void __user *)(arg + minsz),
327 + return PTR_ERR(data);
330 + ret = vfio_fsl_mc_set_irqs_ioctl(vdev, hdr.flags,
331 + hdr.index, hdr.start,
335 + case VFIO_DEVICE_RESET:
344 +static ssize_t vfio_fsl_mc_read(void *device_data, char __user *buf,
345 + size_t count, loff_t *ppos)
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;
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"))
359 + if (index >= vdev->num_regions)
362 + region = &vdev->regions[index];
364 + if (!(region->flags & VFIO_REGION_INFO_FLAG_READ))
367 + if (!region->type & VFIO_FSL_MC_REGION_TYPE_MMIO)
370 + if (!region->ioaddr) {
371 + region->ioaddr = ioremap_nocache(region->addr, region->size);
372 + if (!region->ioaddr)
376 + if (count != 64 || off != 0)
379 + for (i = 7; i >= 0; i--)
380 + data[i] = readq(region->ioaddr + i * sizeof(uint64_t));
382 + if (copy_to_user(buf, data, 64))
388 +#define MC_CMD_COMPLETION_TIMEOUT_MS 5000
389 +#define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS 500
391 +static int vfio_fsl_mc_dprc_wait_for_response(void __iomem *ioaddr)
393 + enum mc_cmd_status status;
394 + unsigned long timeout_usecs = MC_CMD_COMPLETION_TIMEOUT_MS * 1000;
398 + struct mc_cmd_header *resp_hdr;
400 + header = cpu_to_le64(readq_relaxed(ioaddr));
402 + resp_hdr = (struct mc_cmd_header *)&header;
403 + status = (enum mc_cmd_status)resp_hdr->status;
404 + if (status != MC_CMD_STATUS_READY)
407 + udelay(MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS);
408 + timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS;
409 + if (timeout_usecs == 0)
416 +static int vfio_fsl_mc_send_command(void __iomem *ioaddr, uint64_t *cmd_data)
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));
424 + /* Write command header in the end */
425 + writeq(cmd_data[0], ioaddr);
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.
431 + return vfio_fsl_mc_dprc_wait_for_response(ioaddr);
434 +static int vfio_handle_dprc_commands(void __iomem *ioaddr, uint64_t *cmd_data)
436 + uint64_t cmd_hdr = cmd_data[0];
437 + int cmd = (cmd_hdr >> 52) & 0xfff;
440 + case DPRC_CMDID_OPEN:
442 + return vfio_fsl_mc_send_command(ioaddr, cmd_data);
448 +static ssize_t vfio_fsl_mc_write(void *device_data, const char __user *buf,
449 + size_t count, loff_t *ppos)
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;
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"))
463 + if (index >= vdev->num_regions)
466 + region = &vdev->regions[index];
468 + if (!(region->flags & VFIO_REGION_INFO_FLAG_WRITE))
471 + if (!region->type & VFIO_FSL_MC_REGION_TYPE_MMIO)
474 + if (!region->ioaddr) {
475 + region->ioaddr = ioremap_nocache(region->addr, region->size);
476 + if (!region->ioaddr)
480 + if (count != 64 || off != 0)
483 + if (copy_from_user(&data, buf, 64))
486 + ret = vfio_handle_dprc_commands(region->ioaddr, data);
493 +static int vfio_fsl_mc_mmap_mmio(struct vfio_fsl_mc_region region,
494 + struct vm_area_struct *vma)
496 + u64 size = vma->vm_end - vma->vm_start;
499 + pgoff = vma->vm_pgoff &
500 + ((1U << (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
501 + base = pgoff << PAGE_SHIFT;
503 + if (region.size < PAGE_SIZE || base + size > region.size)
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.
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);
514 + vma->vm_page_prot = pgprot_cached_ns(vma->vm_page_prot);
516 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
518 + vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
520 + return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
521 + size, vma->vm_page_prot);
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)
527 + struct vfio_fsl_mc_device *vdev = device_data;
528 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
529 + unsigned long size, addr;
532 + index = vma->vm_pgoff >> (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT);
534 + if (vma->vm_end < vma->vm_start)
536 + if (vma->vm_start & ~PAGE_MASK)
538 + if (vma->vm_end & ~PAGE_MASK)
540 + if (!(vma->vm_flags & VM_SHARED))
542 + if (index >= vdev->num_regions)
545 + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP))
548 + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ)
549 + && (vma->vm_flags & VM_READ))
552 + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE)
553 + && (vma->vm_flags & VM_WRITE))
556 + addr = vdev->regions[index].addr;
557 + size = vdev->regions[index].size;
559 + vma->vm_private_data = mc_dev;
561 + if (vdev->regions[index].type & VFIO_FSL_MC_REGION_TYPE_MMIO)
562 + return vfio_fsl_mc_mmap_mmio(vdev->regions[index], vma);
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,
577 +static int vfio_fsl_mc_initialize_dprc(struct vfio_fsl_mc_device *vdev)
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;
587 + /* device must be DPRC */
588 + if (strcmp(mc_dev->obj_desc.type, "dprc"))
591 + /* mc_io must be un-initialized */
592 + WARN_ON(mc_dev->mc_io);
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))
599 + ret = fsl_mc_portal_allocate(to_fsl_mc_device(root_dprc_dev),
600 + FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
603 + goto clean_msi_domain;
605 + /* Reset MCP before move on */
606 + ret = fsl_mc_portal_reset(mc_dev->mc_io);
608 + dev_err(dev, "dprc portal reset failed: error = %d\n", ret);
609 + goto free_mc_portal;
612 + /* MSI domain set up */
613 + ret = fsl_mc_find_msi_domain(root_dprc_dev->parent, &mc_msi_domain);
615 + goto free_mc_portal;
617 + dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
619 + ret = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
620 + &mc_dev->mc_handle);
622 + dev_err(dev, "dprc_open() failed: error = %d\n", ret);
623 + goto free_mc_portal;
626 + /* Initialize resource pool */
627 + fsl_mc_init_all_resource_pools(mc_dev);
629 + mc_bus = to_fsl_mc_bus(mc_dev);
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);
635 + dev_err(dev, "%s: Failed to init irq-pool\n", __func__);
636 + goto clean_resource_pool;
640 + mutex_init(&mc_bus->scan_mutex);
642 + mutex_lock(&mc_bus->scan_mutex);
643 + ret = dprc_scan_objects(mc_dev, mc_dev->driver_override,
645 + mutex_unlock(&mc_bus->scan_mutex);
647 + dev_err(dev, "dprc_scan_objects() fails (%d)\n", ret);
648 + goto clean_irq_pool;
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);
660 + fsl_mc_cleanup_irq_pool(mc_bus);
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);
667 + fsl_mc_portal_free(mc_dev->mc_io);
670 + dev_set_msi_domain(&mc_dev->dev, NULL);
675 +static int vfio_fsl_mc_device_remove(struct device *dev, void *data)
677 + struct fsl_mc_device *mc_dev;
679 + WARN_ON(dev == NULL);
681 + mc_dev = to_fsl_mc_device(dev);
682 + if (WARN_ON(mc_dev == NULL))
685 + fsl_mc_device_remove(mc_dev);
689 +static void vfio_fsl_mc_cleanup_dprc(struct vfio_fsl_mc_device *vdev)
691 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
692 + struct fsl_mc_bus *mc_bus;
694 + /* device must be DPRC */
695 + if (strcmp(mc_dev->obj_desc.type, "dprc"))
698 + device_for_each_child(&mc_dev->dev, NULL, vfio_fsl_mc_device_remove);
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);
704 + dev_set_msi_domain(&mc_dev->dev, NULL);
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);
711 +static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev)
713 + struct iommu_group *group;
714 + struct vfio_fsl_mc_device *vdev;
715 + struct device *dev = &mc_dev->dev;
718 + group = vfio_iommu_group_get(dev);
720 + dev_err(dev, "%s: VFIO: No IOMMU group\n", __func__);
724 + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
726 + vfio_iommu_group_put(group, dev);
730 + vdev->mc_dev = mc_dev;
732 + ret = vfio_add_group_dev(dev, &vfio_fsl_mc_ops, vdev);
734 + dev_err(dev, "%s: Failed to add to vfio group\n", __func__);
735 + goto free_vfio_device;
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);
742 + vfio_del_group_dev(dev);
743 + goto free_vfio_device;
746 + struct fsl_mc_device *mc_bus_dev;
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;
755 + mc_dev->mc_io = mc_bus_dev->mc_io;
757 + /* Inherit parent MSI domain */
758 + dev_set_msi_domain(&mc_dev->dev,
759 + dev_get_msi_domain(mc_dev->dev.parent));
765 + vfio_iommu_group_put(group, dev);
769 +static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev)
771 + struct vfio_fsl_mc_device *vdev;
772 + struct device *dev = &mc_dev->dev;
774 + vdev = vfio_del_group_dev(dev);
778 + if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
779 + vfio_fsl_mc_cleanup_dprc(vdev);
781 + dev_set_msi_domain(&mc_dev->dev, NULL);
783 + mc_dev->mc_io = NULL;
785 + vfio_iommu_group_put(mc_dev->dev.iommu_group, dev);
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.
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,
800 + .name = "vfio-fsl-mc",
801 + .owner = THIS_MODULE,
805 +static int __init vfio_fsl_mc_driver_init(void)
807 + return fsl_mc_driver_register(&vfio_fsl_mc_driver);
810 +static void __exit vfio_fsl_mc_driver_exit(void)
812 + fsl_mc_driver_unregister(&vfio_fsl_mc_driver);
815 +module_init(vfio_fsl_mc_driver_init);
816 +module_exit(vfio_fsl_mc_driver_exit);
818 +MODULE_VERSION(DRIVER_VERSION);
819 +MODULE_LICENSE("GPL v2");
820 +MODULE_AUTHOR(DRIVER_AUTHOR);
821 +MODULE_DESCRIPTION(DRIVER_DESC);
823 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
826 + * Freescale Management Complex (MC) device passthrough using VFIO
828 + * Copyright (C) 2013-2016 Freescale Semiconductor, Inc.
829 + * Author: Bharat Bhushan <bharat.bhushan@nxp.com>
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.
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>
842 +#include "linux/fsl/mc.h"
843 +#include "vfio_fsl_mc_private.h"
845 +static irqreturn_t vfio_fsl_mc_irq_handler(int irq_num, void *arg)
847 + struct vfio_fsl_mc_irq *mc_irq = (struct vfio_fsl_mc_irq *)arg;
849 + eventfd_signal(mc_irq->trigger, 1);
850 + return IRQ_HANDLED;
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,
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,
869 +static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev,
872 + struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index];
873 + struct eventfd_ctx *trigger;
877 + hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
878 + if (irq->trigger) {
879 + free_irq(hwirq, irq);
881 + eventfd_ctx_put(irq->trigger);
882 + irq->trigger = NULL;
885 + if (fd < 0) /* Disable only */
888 + irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
889 + hwirq, dev_name(&vdev->mc_dev->dev));
893 + trigger = eventfd_ctx_fdget(fd);
894 + if (IS_ERR(trigger)) {
896 + return PTR_ERR(trigger);
899 + irq->trigger = trigger;
901 + ret = request_irq(hwirq, vfio_fsl_mc_irq_handler, 0,
905 + eventfd_ctx_put(trigger);
906 + irq->trigger = NULL;
913 +int vfio_fsl_mc_irqs_init(struct vfio_fsl_mc_device *vdev)
915 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
916 + struct vfio_fsl_mc_irq *mc_irq;
920 + /* Device does not support any interrupt */
921 + if (mc_dev->obj_desc.irq_count == 0)
924 + irq_count = mc_dev->obj_desc.irq_count;
926 + mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL);
927 + if (mc_irq == NULL)
930 + /* Allocate IRQs */
931 + ret = fsl_mc_allocate_irqs(mc_dev);
937 + for (i = 0; i < irq_count; i++) {
938 + mc_irq[i].count = 1;
939 + mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD;
942 + vdev->mc_irqs = mc_irq;
947 +/* Free All IRQs for the given MC object */
948 +void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev)
950 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
951 + int irq_count = mc_dev->obj_desc.irq_count;
954 + /* Device does not support any interrupt */
955 + if (mc_dev->obj_desc.irq_count == 0)
958 + for (i = 0; i < irq_count; i++)
959 + vfio_set_trigger(vdev, i, -1);
961 + fsl_mc_free_irqs(mc_dev);
962 + kfree(vdev->mc_irqs);
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,
970 + struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index];
973 + if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
974 + return vfio_set_trigger(vdev, index, -1);
976 + if (start != 0 || count != 1)
979 + if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
980 + int32_t fd = *(int32_t *)data;
982 + return vfio_set_trigger(vdev, index, fd);
985 + hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
987 + if (flags & VFIO_IRQ_SET_DATA_NONE) {
988 + vfio_fsl_mc_irq_handler(hwirq, irq);
990 + } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
991 + uint8_t trigger = *(uint8_t *)data;
994 + vfio_fsl_mc_irq_handler(hwirq, irq);
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,
1005 + int ret = -ENOTTY;
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,
1012 + case VFIO_IRQ_SET_ACTION_UNMASK:
1013 + ret = vfio_fsl_mc_irq_unmask(vdev, index, start, count,
1016 + case VFIO_IRQ_SET_ACTION_TRIGGER:
1017 + ret = vfio_fsl_mc_set_irq_trigger(vdev, index, start,
1018 + count, flags, data);
1025 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
1028 + * Freescale Management Complex VFIO private declarations
1030 + * Copyright (C) 2013-2016 Freescale Semiconductor, Inc.
1031 + * Copyright 2016 NXP
1032 + * Author: Bharat Bhushan <bharat.bhushan@nxp.com>
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.
1039 +#ifndef VFIO_FSL_MC_PRIVATE_H
1040 +#define VFIO_FSL_MC_PRIVATE_H
1042 +#define VFIO_FSL_MC_OFFSET_SHIFT 40
1043 +#define VFIO_FSL_MC_OFFSET_MASK (((u64)(1) << VFIO_FSL_MC_OFFSET_SHIFT) - 1)
1045 +#define VFIO_FSL_MC_OFFSET_TO_INDEX(off) (off >> VFIO_FSL_MC_OFFSET_SHIFT)
1047 +#define VFIO_FSL_MC_INDEX_TO_OFFSET(index) \
1048 + ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
1050 +struct vfio_fsl_mc_irq {
1053 + struct eventfd_ctx *trigger;
1057 +struct vfio_fsl_mc_region {
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
1065 + resource_size_t size;
1066 + void __iomem *ioaddr;
1069 +struct vfio_fsl_mc_device {
1070 + struct fsl_mc_device *mc_dev;
1073 + struct vfio_fsl_mc_region *regions;
1074 + struct vfio_fsl_mc_irq *mc_irqs;
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,
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 */