Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.13-rc3 180 lines 4.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(struct vfio_device *core_vdev) 25{ 26 struct mdev_device *mdev = to_mdev_device(core_vdev->dev); 27 struct mdev_parent *parent = mdev->type->parent; 28 29 int ret; 30 31 if (unlikely(!parent->ops->open)) 32 return -EINVAL; 33 34 if (!try_module_get(THIS_MODULE)) 35 return -ENODEV; 36 37 ret = parent->ops->open(mdev); 38 if (ret) 39 module_put(THIS_MODULE); 40 41 return ret; 42} 43 44static void vfio_mdev_release(struct vfio_device *core_vdev) 45{ 46 struct mdev_device *mdev = to_mdev_device(core_vdev->dev); 47 struct mdev_parent *parent = mdev->type->parent; 48 49 if (likely(parent->ops->release)) 50 parent->ops->release(mdev); 51 52 module_put(THIS_MODULE); 53} 54 55static long vfio_mdev_unlocked_ioctl(struct vfio_device *core_vdev, 56 unsigned int cmd, unsigned long arg) 57{ 58 struct mdev_device *mdev = to_mdev_device(core_vdev->dev); 59 struct mdev_parent *parent = mdev->type->parent; 60 61 if (unlikely(!parent->ops->ioctl)) 62 return -EINVAL; 63 64 return parent->ops->ioctl(mdev, cmd, arg); 65} 66 67static ssize_t vfio_mdev_read(struct vfio_device *core_vdev, char __user *buf, 68 size_t count, loff_t *ppos) 69{ 70 struct mdev_device *mdev = to_mdev_device(core_vdev->dev); 71 struct mdev_parent *parent = mdev->type->parent; 72 73 if (unlikely(!parent->ops->read)) 74 return -EINVAL; 75 76 return parent->ops->read(mdev, buf, count, ppos); 77} 78 79static ssize_t vfio_mdev_write(struct vfio_device *core_vdev, 80 const char __user *buf, size_t count, 81 loff_t *ppos) 82{ 83 struct mdev_device *mdev = to_mdev_device(core_vdev->dev); 84 struct mdev_parent *parent = mdev->type->parent; 85 86 if (unlikely(!parent->ops->write)) 87 return -EINVAL; 88 89 return parent->ops->write(mdev, buf, count, ppos); 90} 91 92static int vfio_mdev_mmap(struct vfio_device *core_vdev, 93 struct vm_area_struct *vma) 94{ 95 struct mdev_device *mdev = to_mdev_device(core_vdev->dev); 96 struct mdev_parent *parent = mdev->type->parent; 97 98 if (unlikely(!parent->ops->mmap)) 99 return -EINVAL; 100 101 return parent->ops->mmap(mdev, vma); 102} 103 104static void vfio_mdev_request(struct vfio_device *core_vdev, unsigned int count) 105{ 106 struct mdev_device *mdev = to_mdev_device(core_vdev->dev); 107 struct mdev_parent *parent = mdev->type->parent; 108 109 if (parent->ops->request) 110 parent->ops->request(mdev, count); 111 else if (count == 0) 112 dev_notice(mdev_dev(mdev), 113 "No mdev vendor driver request callback support, blocked until released by user\n"); 114} 115 116static const struct vfio_device_ops vfio_mdev_dev_ops = { 117 .name = "vfio-mdev", 118 .open = vfio_mdev_open, 119 .release = vfio_mdev_release, 120 .ioctl = vfio_mdev_unlocked_ioctl, 121 .read = vfio_mdev_read, 122 .write = vfio_mdev_write, 123 .mmap = vfio_mdev_mmap, 124 .request = vfio_mdev_request, 125}; 126 127static int vfio_mdev_probe(struct mdev_device *mdev) 128{ 129 struct vfio_device *vdev; 130 int ret; 131 132 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); 133 if (!vdev) 134 return -ENOMEM; 135 136 vfio_init_group_dev(vdev, &mdev->dev, &vfio_mdev_dev_ops); 137 ret = vfio_register_group_dev(vdev); 138 if (ret) { 139 kfree(vdev); 140 return ret; 141 } 142 dev_set_drvdata(&mdev->dev, vdev); 143 return 0; 144} 145 146static void vfio_mdev_remove(struct mdev_device *mdev) 147{ 148 struct vfio_device *vdev = dev_get_drvdata(&mdev->dev); 149 150 vfio_unregister_group_dev(vdev); 151 kfree(vdev); 152} 153 154static struct mdev_driver vfio_mdev_driver = { 155 .driver = { 156 .name = "vfio_mdev", 157 .owner = THIS_MODULE, 158 .mod_name = KBUILD_MODNAME, 159 }, 160 .probe = vfio_mdev_probe, 161 .remove = vfio_mdev_remove, 162}; 163 164static int __init vfio_mdev_init(void) 165{ 166 return mdev_register_driver(&vfio_mdev_driver); 167} 168 169static void __exit vfio_mdev_exit(void) 170{ 171 mdev_unregister_driver(&vfio_mdev_driver); 172} 173 174module_init(vfio_mdev_init) 175module_exit(vfio_mdev_exit) 176 177MODULE_VERSION(DRIVER_VERSION); 178MODULE_LICENSE("GPL v2"); 179MODULE_AUTHOR(DRIVER_AUTHOR); 180MODULE_DESCRIPTION(DRIVER_DESC);