Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vfio: VFIO based driver for Mediated devices

vfio_mdev driver registers with mdev core driver.
mdev core driver creates mediated device and calls probe routine of
vfio_mdev driver for each device.
Probe routine of vfio_mdev driver adds mediated device to VFIO core module

This driver forms a shim layer that pass through VFIO devices operations
to vendor driver for mediated devices.

Signed-off-by: Kirti Wankhede <kwankhede@nvidia.com>
Signed-off-by: Neo Jia <cjia@nvidia.com>
Reviewed-by: Jike Song <jike.song@intel.com>
Reviewed-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>

authored by

Kirti Wankhede and committed by
Alex Williamson
fa3da00c 7b96953b

+168 -1
+7
drivers/vfio/mdev/Kconfig
··· 7 7 Provides a framework to virtualize devices. 8 8 9 9 If you don't know what do here, say N. 10 + 11 + config VFIO_MDEV_DEVICE 12 + tristate "VFIO driver for Mediated devices" 13 + depends on VFIO && VFIO_MDEV 14 + default n 15 + help 16 + VFIO based driver for Mediated devices.
+1
drivers/vfio/mdev/Makefile
··· 2 2 mdev-y := mdev_core.o mdev_sysfs.o mdev_driver.o 3 3 4 4 obj-$(CONFIG_VFIO_MDEV) += mdev.o 5 + obj-$(CONFIG_VFIO_MDEV_DEVICE) += vfio_mdev.o
+12 -1
drivers/vfio/mdev/mdev_core.c
··· 354 354 355 355 static int __init mdev_init(void) 356 356 { 357 - return mdev_bus_register(); 357 + int ret; 358 + 359 + ret = mdev_bus_register(); 360 + 361 + /* 362 + * Attempt to load known vfio_mdev. This gives us a working environment 363 + * without the user needing to explicitly load vfio_mdev driver. 364 + */ 365 + if (!ret) 366 + request_module_nowait("vfio_mdev"); 367 + 368 + return ret; 358 369 } 359 370 360 371 static void __exit mdev_exit(void)
+148
drivers/vfio/mdev/vfio_mdev.c
··· 1 + /* 2 + * VFIO based driver for Mediated device 3 + * 4 + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 5 + * Author: Neo Jia <cjia@nvidia.com> 6 + * Kirti Wankhede <kwankhede@nvidia.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + 13 + #include <linux/init.h> 14 + #include <linux/module.h> 15 + #include <linux/device.h> 16 + #include <linux/kernel.h> 17 + #include <linux/slab.h> 18 + #include <linux/vfio.h> 19 + #include <linux/mdev.h> 20 + 21 + #include "mdev_private.h" 22 + 23 + #define DRIVER_VERSION "0.1" 24 + #define DRIVER_AUTHOR "NVIDIA Corporation" 25 + #define DRIVER_DESC "VFIO based driver for Mediated device" 26 + 27 + static int vfio_mdev_open(void *device_data) 28 + { 29 + struct mdev_device *mdev = device_data; 30 + struct parent_device *parent = mdev->parent; 31 + int ret; 32 + 33 + if (unlikely(!parent->ops->open)) 34 + return -EINVAL; 35 + 36 + if (!try_module_get(THIS_MODULE)) 37 + return -ENODEV; 38 + 39 + ret = parent->ops->open(mdev); 40 + if (ret) 41 + module_put(THIS_MODULE); 42 + 43 + return ret; 44 + } 45 + 46 + static void vfio_mdev_release(void *device_data) 47 + { 48 + struct mdev_device *mdev = device_data; 49 + struct parent_device *parent = mdev->parent; 50 + 51 + if (likely(parent->ops->release)) 52 + parent->ops->release(mdev); 53 + 54 + module_put(THIS_MODULE); 55 + } 56 + 57 + static long vfio_mdev_unlocked_ioctl(void *device_data, 58 + unsigned int cmd, unsigned long arg) 59 + { 60 + struct mdev_device *mdev = device_data; 61 + struct parent_device *parent = mdev->parent; 62 + 63 + if (unlikely(!parent->ops->ioctl)) 64 + return -EINVAL; 65 + 66 + return parent->ops->ioctl(mdev, cmd, arg); 67 + } 68 + 69 + static ssize_t vfio_mdev_read(void *device_data, char __user *buf, 70 + size_t count, loff_t *ppos) 71 + { 72 + struct mdev_device *mdev = device_data; 73 + struct parent_device *parent = mdev->parent; 74 + 75 + if (unlikely(!parent->ops->read)) 76 + return -EINVAL; 77 + 78 + return parent->ops->read(mdev, buf, count, ppos); 79 + } 80 + 81 + static ssize_t vfio_mdev_write(void *device_data, const char __user *buf, 82 + size_t count, loff_t *ppos) 83 + { 84 + struct mdev_device *mdev = device_data; 85 + struct parent_device *parent = mdev->parent; 86 + 87 + if (unlikely(!parent->ops->write)) 88 + return -EINVAL; 89 + 90 + return parent->ops->write(mdev, buf, count, ppos); 91 + } 92 + 93 + static int vfio_mdev_mmap(void *device_data, struct vm_area_struct *vma) 94 + { 95 + struct mdev_device *mdev = device_data; 96 + struct parent_device *parent = mdev->parent; 97 + 98 + if (unlikely(!parent->ops->mmap)) 99 + return -EINVAL; 100 + 101 + return parent->ops->mmap(mdev, vma); 102 + } 103 + 104 + static const struct vfio_device_ops vfio_mdev_dev_ops = { 105 + .name = "vfio-mdev", 106 + .open = vfio_mdev_open, 107 + .release = vfio_mdev_release, 108 + .ioctl = vfio_mdev_unlocked_ioctl, 109 + .read = vfio_mdev_read, 110 + .write = vfio_mdev_write, 111 + .mmap = vfio_mdev_mmap, 112 + }; 113 + 114 + int vfio_mdev_probe(struct device *dev) 115 + { 116 + struct mdev_device *mdev = to_mdev_device(dev); 117 + 118 + return vfio_add_group_dev(dev, &vfio_mdev_dev_ops, mdev); 119 + } 120 + 121 + void vfio_mdev_remove(struct device *dev) 122 + { 123 + vfio_del_group_dev(dev); 124 + } 125 + 126 + struct mdev_driver vfio_mdev_driver = { 127 + .name = "vfio_mdev", 128 + .probe = vfio_mdev_probe, 129 + .remove = vfio_mdev_remove, 130 + }; 131 + 132 + static int __init vfio_mdev_init(void) 133 + { 134 + return mdev_register_driver(&vfio_mdev_driver, THIS_MODULE); 135 + } 136 + 137 + static void __exit vfio_mdev_exit(void) 138 + { 139 + mdev_unregister_driver(&vfio_mdev_driver); 140 + } 141 + 142 + module_init(vfio_mdev_init) 143 + module_exit(vfio_mdev_exit) 144 + 145 + MODULE_VERSION(DRIVER_VERSION); 146 + MODULE_LICENSE("GPL v2"); 147 + MODULE_AUTHOR(DRIVER_AUTHOR); 148 + MODULE_DESCRIPTION(DRIVER_DESC);