xref: /linux-6.15/drivers/vfio/mdev/mdev_core.c (revision bdef2b78)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Mediated device Core Driver
4  *
5  * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
6  *     Author: Neo Jia <[email protected]>
7  *             Kirti Wankhede <[email protected]>
8  */
9 
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/sysfs.h>
13 #include <linux/mdev.h>
14 
15 #include "mdev_private.h"
16 
17 #define DRIVER_VERSION		"0.1"
18 #define DRIVER_AUTHOR		"NVIDIA Corporation"
19 #define DRIVER_DESC		"Mediated device Core Driver"
20 
21 static LIST_HEAD(parent_list);
22 static DEFINE_MUTEX(parent_list_lock);
23 static struct class_compat *mdev_bus_compat_class;
24 
25 static LIST_HEAD(mdev_list);
26 static DEFINE_MUTEX(mdev_list_lock);
27 
28 struct device *mdev_parent_dev(struct mdev_device *mdev)
29 {
30 	return mdev->type->parent->dev;
31 }
32 EXPORT_SYMBOL(mdev_parent_dev);
33 
34 /*
35  * Return the index in supported_type_groups that this mdev_device was created
36  * from.
37  */
38 unsigned int mdev_get_type_group_id(struct mdev_device *mdev)
39 {
40 	return mdev->type->type_group_id;
41 }
42 EXPORT_SYMBOL(mdev_get_type_group_id);
43 
44 /*
45  * Used in mdev_type_attribute sysfs functions to return the index in the
46  * supported_type_groups that the sysfs is called from.
47  */
48 unsigned int mtype_get_type_group_id(struct mdev_type *mtype)
49 {
50 	return mtype->type_group_id;
51 }
52 EXPORT_SYMBOL(mtype_get_type_group_id);
53 
54 /*
55  * Used in mdev_type_attribute sysfs functions to return the parent struct
56  * device
57  */
58 struct device *mtype_get_parent_dev(struct mdev_type *mtype)
59 {
60 	return mtype->parent->dev;
61 }
62 EXPORT_SYMBOL(mtype_get_parent_dev);
63 
64 /* Should be called holding parent_list_lock */
65 static struct mdev_parent *__find_parent_device(struct device *dev)
66 {
67 	struct mdev_parent *parent;
68 
69 	list_for_each_entry(parent, &parent_list, next) {
70 		if (parent->dev == dev)
71 			return parent;
72 	}
73 	return NULL;
74 }
75 
76 void mdev_release_parent(struct kref *kref)
77 {
78 	struct mdev_parent *parent = container_of(kref, struct mdev_parent,
79 						  ref);
80 	struct device *dev = parent->dev;
81 
82 	kfree(parent);
83 	put_device(dev);
84 }
85 
86 /* Caller must hold parent unreg_sem read or write lock */
87 static void mdev_device_remove_common(struct mdev_device *mdev)
88 {
89 	struct mdev_parent *parent = mdev->type->parent;
90 
91 	mdev_remove_sysfs_files(mdev);
92 	device_del(&mdev->dev);
93 	lockdep_assert_held(&parent->unreg_sem);
94 	/* Balances with device_initialize() */
95 	put_device(&mdev->dev);
96 }
97 
98 static int mdev_device_remove_cb(struct device *dev, void *data)
99 {
100 	struct mdev_device *mdev = mdev_from_dev(dev);
101 
102 	if (mdev)
103 		mdev_device_remove_common(mdev);
104 	return 0;
105 }
106 
107 /*
108  * mdev_register_device : Register a device
109  * @dev: device structure representing parent device.
110  * @mdev_driver: Device driver to bind to the newly created mdev
111  *
112  * Add device to list of registered parent devices.
113  * Returns a negative value on error, otherwise 0.
114  */
115 int mdev_register_device(struct device *dev, struct mdev_driver *mdev_driver)
116 {
117 	int ret;
118 	struct mdev_parent *parent;
119 	char *env_string = "MDEV_STATE=registered";
120 	char *envp[] = { env_string, NULL };
121 
122 	/* check for mandatory ops */
123 	if (!mdev_driver->supported_type_groups)
124 		return -EINVAL;
125 
126 	dev = get_device(dev);
127 	if (!dev)
128 		return -EINVAL;
129 
130 	mutex_lock(&parent_list_lock);
131 
132 	/* Check for duplicate */
133 	parent = __find_parent_device(dev);
134 	if (parent) {
135 		parent = NULL;
136 		ret = -EEXIST;
137 		goto add_dev_err;
138 	}
139 
140 	parent = kzalloc(sizeof(*parent), GFP_KERNEL);
141 	if (!parent) {
142 		ret = -ENOMEM;
143 		goto add_dev_err;
144 	}
145 
146 	kref_init(&parent->ref);
147 	init_rwsem(&parent->unreg_sem);
148 
149 	parent->dev = dev;
150 	parent->mdev_driver = mdev_driver;
151 
152 	if (!mdev_bus_compat_class) {
153 		mdev_bus_compat_class = class_compat_register("mdev_bus");
154 		if (!mdev_bus_compat_class) {
155 			ret = -ENOMEM;
156 			goto add_dev_err;
157 		}
158 	}
159 
160 	ret = parent_create_sysfs_files(parent);
161 	if (ret)
162 		goto add_dev_err;
163 
164 	ret = class_compat_create_link(mdev_bus_compat_class, dev, NULL);
165 	if (ret)
166 		dev_warn(dev, "Failed to create compatibility class link\n");
167 
168 	list_add(&parent->next, &parent_list);
169 	mutex_unlock(&parent_list_lock);
170 
171 	dev_info(dev, "MDEV: Registered\n");
172 	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
173 
174 	return 0;
175 
176 add_dev_err:
177 	mutex_unlock(&parent_list_lock);
178 	if (parent)
179 		mdev_put_parent(parent);
180 	else
181 		put_device(dev);
182 	return ret;
183 }
184 EXPORT_SYMBOL(mdev_register_device);
185 
186 /*
187  * mdev_unregister_device : Unregister a parent device
188  * @dev: device structure representing parent device.
189  *
190  * Remove device from list of registered parent devices. Give a chance to free
191  * existing mediated devices for given device.
192  */
193 
194 void mdev_unregister_device(struct device *dev)
195 {
196 	struct mdev_parent *parent;
197 	char *env_string = "MDEV_STATE=unregistered";
198 	char *envp[] = { env_string, NULL };
199 
200 	mutex_lock(&parent_list_lock);
201 	parent = __find_parent_device(dev);
202 
203 	if (!parent) {
204 		mutex_unlock(&parent_list_lock);
205 		return;
206 	}
207 	dev_info(dev, "MDEV: Unregistering\n");
208 
209 	list_del(&parent->next);
210 	mutex_unlock(&parent_list_lock);
211 
212 	down_write(&parent->unreg_sem);
213 
214 	class_compat_remove_link(mdev_bus_compat_class, dev, NULL);
215 
216 	device_for_each_child(dev, NULL, mdev_device_remove_cb);
217 
218 	parent_remove_sysfs_files(parent);
219 	up_write(&parent->unreg_sem);
220 
221 	mdev_put_parent(parent);
222 
223 	/* We still have the caller's reference to use for the uevent */
224 	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
225 }
226 EXPORT_SYMBOL(mdev_unregister_device);
227 
228 static void mdev_device_release(struct device *dev)
229 {
230 	struct mdev_device *mdev = to_mdev_device(dev);
231 
232 	/* Pairs with the get in mdev_device_create() */
233 	kobject_put(&mdev->type->kobj);
234 
235 	mutex_lock(&mdev_list_lock);
236 	list_del(&mdev->next);
237 	mutex_unlock(&mdev_list_lock);
238 
239 	dev_dbg(&mdev->dev, "MDEV: destroying\n");
240 	kfree(mdev);
241 }
242 
243 int mdev_device_create(struct mdev_type *type, const guid_t *uuid)
244 {
245 	int ret;
246 	struct mdev_device *mdev, *tmp;
247 	struct mdev_parent *parent = type->parent;
248 	struct mdev_driver *drv = parent->mdev_driver;
249 
250 	mutex_lock(&mdev_list_lock);
251 
252 	/* Check for duplicate */
253 	list_for_each_entry(tmp, &mdev_list, next) {
254 		if (guid_equal(&tmp->uuid, uuid)) {
255 			mutex_unlock(&mdev_list_lock);
256 			return -EEXIST;
257 		}
258 	}
259 
260 	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
261 	if (!mdev) {
262 		mutex_unlock(&mdev_list_lock);
263 		return -ENOMEM;
264 	}
265 
266 	device_initialize(&mdev->dev);
267 	mdev->dev.parent  = parent->dev;
268 	mdev->dev.bus = &mdev_bus_type;
269 	mdev->dev.release = mdev_device_release;
270 	mdev->dev.groups = mdev_device_groups;
271 	mdev->type = type;
272 	/* Pairs with the put in mdev_device_release() */
273 	kobject_get(&type->kobj);
274 
275 	guid_copy(&mdev->uuid, uuid);
276 	list_add(&mdev->next, &mdev_list);
277 	mutex_unlock(&mdev_list_lock);
278 
279 	ret = dev_set_name(&mdev->dev, "%pUl", uuid);
280 	if (ret)
281 		goto out_put_device;
282 
283 	/* Check if parent unregistration has started */
284 	if (!down_read_trylock(&parent->unreg_sem)) {
285 		ret = -ENODEV;
286 		goto out_put_device;
287 	}
288 
289 	ret = device_add(&mdev->dev);
290 	if (ret)
291 		goto out_unlock;
292 
293 	ret = device_driver_attach(&drv->driver, &mdev->dev);
294 	if (ret)
295 		goto out_del;
296 
297 	ret = mdev_create_sysfs_files(mdev);
298 	if (ret)
299 		goto out_del;
300 
301 	mdev->active = true;
302 	dev_dbg(&mdev->dev, "MDEV: created\n");
303 	up_read(&parent->unreg_sem);
304 
305 	return 0;
306 
307 out_del:
308 	device_del(&mdev->dev);
309 out_unlock:
310 	up_read(&parent->unreg_sem);
311 out_put_device:
312 	put_device(&mdev->dev);
313 	return ret;
314 }
315 
316 int mdev_device_remove(struct mdev_device *mdev)
317 {
318 	struct mdev_device *tmp;
319 	struct mdev_parent *parent = mdev->type->parent;
320 
321 	mutex_lock(&mdev_list_lock);
322 	list_for_each_entry(tmp, &mdev_list, next) {
323 		if (tmp == mdev)
324 			break;
325 	}
326 
327 	if (tmp != mdev) {
328 		mutex_unlock(&mdev_list_lock);
329 		return -ENODEV;
330 	}
331 
332 	if (!mdev->active) {
333 		mutex_unlock(&mdev_list_lock);
334 		return -EAGAIN;
335 	}
336 
337 	mdev->active = false;
338 	mutex_unlock(&mdev_list_lock);
339 
340 	/* Check if parent unregistration has started */
341 	if (!down_read_trylock(&parent->unreg_sem))
342 		return -ENODEV;
343 
344 	mdev_device_remove_common(mdev);
345 	up_read(&parent->unreg_sem);
346 	return 0;
347 }
348 
349 static int __init mdev_init(void)
350 {
351 	return bus_register(&mdev_bus_type);
352 }
353 
354 static void __exit mdev_exit(void)
355 {
356 	if (mdev_bus_compat_class)
357 		class_compat_unregister(mdev_bus_compat_class);
358 	bus_unregister(&mdev_bus_type);
359 }
360 
361 subsys_initcall(mdev_init)
362 module_exit(mdev_exit)
363 
364 MODULE_VERSION(DRIVER_VERSION);
365 MODULE_LICENSE("GPL v2");
366 MODULE_AUTHOR(DRIVER_AUTHOR);
367 MODULE_DESCRIPTION(DRIVER_DESC);
368