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 
vfio_mdev_open(struct vfio_device * core_vdev)24 static 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 
vfio_mdev_release(struct vfio_device * core_vdev)44 static 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 
vfio_mdev_unlocked_ioctl(struct vfio_device * core_vdev,unsigned int cmd,unsigned long arg)55 static 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 
vfio_mdev_read(struct vfio_device * core_vdev,char __user * buf,size_t count,loff_t * ppos)67 static 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 
vfio_mdev_write(struct vfio_device * core_vdev,const char __user * buf,size_t count,loff_t * ppos)79 static 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 
vfio_mdev_mmap(struct vfio_device * core_vdev,struct vm_area_struct * vma)92 static 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 
vfio_mdev_request(struct vfio_device * core_vdev,unsigned int count)104 static 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 
116 static 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 
vfio_mdev_probe(struct mdev_device * mdev)127 static 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 
vfio_mdev_remove(struct mdev_device * mdev)146 static 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 
154 static 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 
vfio_mdev_init(void)164 static int __init vfio_mdev_init(void)
165 {
166 	return mdev_register_driver(&vfio_mdev_driver);
167 }
168 
vfio_mdev_exit(void)169 static void __exit vfio_mdev_exit(void)
170 {
171 	mdev_unregister_driver(&vfio_mdev_driver);
172 }
173 
174 module_init(vfio_mdev_init)
175 module_exit(vfio_mdev_exit)
176 
177 MODULE_VERSION(DRIVER_VERSION);
178 MODULE_LICENSE("GPL v2");
179 MODULE_AUTHOR(DRIVER_AUTHOR);
180 MODULE_DESCRIPTION(DRIVER_DESC);
181