at v5.2-rc6 145 lines 3.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * VFIO based driver for Mediated device 4 * 5 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 6 * Author: Neo Jia <cjia@nvidia.com> 7 * Kirti Wankhede <kwankhede@nvidia.com> 8 */ 9 10#include <linux/init.h> 11#include <linux/module.h> 12#include <linux/device.h> 13#include <linux/kernel.h> 14#include <linux/slab.h> 15#include <linux/vfio.h> 16#include <linux/mdev.h> 17 18#include "mdev_private.h" 19 20#define DRIVER_VERSION "0.1" 21#define DRIVER_AUTHOR "NVIDIA Corporation" 22#define DRIVER_DESC "VFIO based driver for Mediated device" 23 24static int vfio_mdev_open(void *device_data) 25{ 26 struct mdev_device *mdev = device_data; 27 struct mdev_parent *parent = mdev->parent; 28 int ret; 29 30 if (unlikely(!parent->ops->open)) 31 return -EINVAL; 32 33 if (!try_module_get(THIS_MODULE)) 34 return -ENODEV; 35 36 ret = parent->ops->open(mdev); 37 if (ret) 38 module_put(THIS_MODULE); 39 40 return ret; 41} 42 43static void vfio_mdev_release(void *device_data) 44{ 45 struct mdev_device *mdev = device_data; 46 struct mdev_parent *parent = mdev->parent; 47 48 if (likely(parent->ops->release)) 49 parent->ops->release(mdev); 50 51 module_put(THIS_MODULE); 52} 53 54static long vfio_mdev_unlocked_ioctl(void *device_data, 55 unsigned int cmd, unsigned long arg) 56{ 57 struct mdev_device *mdev = device_data; 58 struct mdev_parent *parent = mdev->parent; 59 60 if (unlikely(!parent->ops->ioctl)) 61 return -EINVAL; 62 63 return parent->ops->ioctl(mdev, cmd, arg); 64} 65 66static ssize_t vfio_mdev_read(void *device_data, char __user *buf, 67 size_t count, loff_t *ppos) 68{ 69 struct mdev_device *mdev = device_data; 70 struct mdev_parent *parent = mdev->parent; 71 72 if (unlikely(!parent->ops->read)) 73 return -EINVAL; 74 75 return parent->ops->read(mdev, buf, count, ppos); 76} 77 78static ssize_t vfio_mdev_write(void *device_data, const char __user *buf, 79 size_t count, loff_t *ppos) 80{ 81 struct mdev_device *mdev = device_data; 82 struct mdev_parent *parent = mdev->parent; 83 84 if (unlikely(!parent->ops->write)) 85 return -EINVAL; 86 87 return parent->ops->write(mdev, buf, count, ppos); 88} 89 90static int vfio_mdev_mmap(void *device_data, struct vm_area_struct *vma) 91{ 92 struct mdev_device *mdev = device_data; 93 struct mdev_parent *parent = mdev->parent; 94 95 if (unlikely(!parent->ops->mmap)) 96 return -EINVAL; 97 98 return parent->ops->mmap(mdev, vma); 99} 100 101static const struct vfio_device_ops vfio_mdev_dev_ops = { 102 .name = "vfio-mdev", 103 .open = vfio_mdev_open, 104 .release = vfio_mdev_release, 105 .ioctl = vfio_mdev_unlocked_ioctl, 106 .read = vfio_mdev_read, 107 .write = vfio_mdev_write, 108 .mmap = vfio_mdev_mmap, 109}; 110 111static int vfio_mdev_probe(struct device *dev) 112{ 113 struct mdev_device *mdev = to_mdev_device(dev); 114 115 return vfio_add_group_dev(dev, &vfio_mdev_dev_ops, mdev); 116} 117 118static void vfio_mdev_remove(struct device *dev) 119{ 120 vfio_del_group_dev(dev); 121} 122 123static struct mdev_driver vfio_mdev_driver = { 124 .name = "vfio_mdev", 125 .probe = vfio_mdev_probe, 126 .remove = vfio_mdev_remove, 127}; 128 129static int __init vfio_mdev_init(void) 130{ 131 return mdev_register_driver(&vfio_mdev_driver, THIS_MODULE); 132} 133 134static void __exit vfio_mdev_exit(void) 135{ 136 mdev_unregister_driver(&vfio_mdev_driver); 137} 138 139module_init(vfio_mdev_init) 140module_exit(vfio_mdev_exit) 141 142MODULE_VERSION(DRIVER_VERSION); 143MODULE_LICENSE("GPL v2"); 144MODULE_AUTHOR(DRIVER_AUTHOR); 145MODULE_DESCRIPTION(DRIVER_DESC);