]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/vfio/mdev/mdev_core.c
Merge tag 'usb-4.10-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[karo-tx-linux.git] / drivers / vfio / mdev / mdev_core.c
1 /*
2  * Mediated device Core Driver
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/module.h>
14 #include <linux/device.h>
15 #include <linux/slab.h>
16 #include <linux/uuid.h>
17 #include <linux/sysfs.h>
18 #include <linux/mdev.h>
19
20 #include "mdev_private.h"
21
22 #define DRIVER_VERSION          "0.1"
23 #define DRIVER_AUTHOR           "NVIDIA Corporation"
24 #define DRIVER_DESC             "Mediated device Core Driver"
25
26 static LIST_HEAD(parent_list);
27 static DEFINE_MUTEX(parent_list_lock);
28 static struct class_compat *mdev_bus_compat_class;
29
30 static LIST_HEAD(mdev_list);
31 static DEFINE_MUTEX(mdev_list_lock);
32
33 struct device *mdev_parent_dev(struct mdev_device *mdev)
34 {
35         return mdev->parent->dev;
36 }
37 EXPORT_SYMBOL(mdev_parent_dev);
38
39 void *mdev_get_drvdata(struct mdev_device *mdev)
40 {
41         return mdev->driver_data;
42 }
43 EXPORT_SYMBOL(mdev_get_drvdata);
44
45 void mdev_set_drvdata(struct mdev_device *mdev, void *data)
46 {
47         mdev->driver_data = data;
48 }
49 EXPORT_SYMBOL(mdev_set_drvdata);
50
51 struct device *mdev_dev(struct mdev_device *mdev)
52 {
53         return &mdev->dev;
54 }
55 EXPORT_SYMBOL(mdev_dev);
56
57 struct mdev_device *mdev_from_dev(struct device *dev)
58 {
59         return dev_is_mdev(dev) ? to_mdev_device(dev) : NULL;
60 }
61 EXPORT_SYMBOL(mdev_from_dev);
62
63 uuid_le mdev_uuid(struct mdev_device *mdev)
64 {
65         return mdev->uuid;
66 }
67 EXPORT_SYMBOL(mdev_uuid);
68
69 static int _find_mdev_device(struct device *dev, void *data)
70 {
71         struct mdev_device *mdev;
72
73         if (!dev_is_mdev(dev))
74                 return 0;
75
76         mdev = to_mdev_device(dev);
77
78         if (uuid_le_cmp(mdev->uuid, *(uuid_le *)data) == 0)
79                 return 1;
80
81         return 0;
82 }
83
84 static bool mdev_device_exist(struct mdev_parent *parent, uuid_le uuid)
85 {
86         struct device *dev;
87
88         dev = device_find_child(parent->dev, &uuid, _find_mdev_device);
89         if (dev) {
90                 put_device(dev);
91                 return true;
92         }
93
94         return false;
95 }
96
97 /* Should be called holding parent_list_lock */
98 static struct mdev_parent *__find_parent_device(struct device *dev)
99 {
100         struct mdev_parent *parent;
101
102         list_for_each_entry(parent, &parent_list, next) {
103                 if (parent->dev == dev)
104                         return parent;
105         }
106         return NULL;
107 }
108
109 static void mdev_release_parent(struct kref *kref)
110 {
111         struct mdev_parent *parent = container_of(kref, struct mdev_parent,
112                                                   ref);
113         struct device *dev = parent->dev;
114
115         kfree(parent);
116         put_device(dev);
117 }
118
119 static
120 inline struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
121 {
122         if (parent)
123                 kref_get(&parent->ref);
124
125         return parent;
126 }
127
128 static inline void mdev_put_parent(struct mdev_parent *parent)
129 {
130         if (parent)
131                 kref_put(&parent->ref, mdev_release_parent);
132 }
133
134 static int mdev_device_create_ops(struct kobject *kobj,
135                                   struct mdev_device *mdev)
136 {
137         struct mdev_parent *parent = mdev->parent;
138         int ret;
139
140         ret = parent->ops->create(kobj, mdev);
141         if (ret)
142                 return ret;
143
144         ret = sysfs_create_groups(&mdev->dev.kobj,
145                                   parent->ops->mdev_attr_groups);
146         if (ret)
147                 parent->ops->remove(mdev);
148
149         return ret;
150 }
151
152 /*
153  * mdev_device_remove_ops gets called from sysfs's 'remove' and when parent
154  * device is being unregistered from mdev device framework.
155  * - 'force_remove' is set to 'false' when called from sysfs's 'remove' which
156  *   indicates that if the mdev device is active, used by VMM or userspace
157  *   application, vendor driver could return error then don't remove the device.
158  * - 'force_remove' is set to 'true' when called from mdev_unregister_device()
159  *   which indicate that parent device is being removed from mdev device
160  *   framework so remove mdev device forcefully.
161  */
162 static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove)
163 {
164         struct mdev_parent *parent = mdev->parent;
165         int ret;
166
167         /*
168          * Vendor driver can return error if VMM or userspace application is
169          * using this mdev device.
170          */
171         ret = parent->ops->remove(mdev);
172         if (ret && !force_remove)
173                 return -EBUSY;
174
175         sysfs_remove_groups(&mdev->dev.kobj, parent->ops->mdev_attr_groups);
176         return 0;
177 }
178
179 static int mdev_device_remove_cb(struct device *dev, void *data)
180 {
181         if (!dev_is_mdev(dev))
182                 return 0;
183
184         return mdev_device_remove(dev, data ? *(bool *)data : true);
185 }
186
187 /*
188  * mdev_register_device : Register a device
189  * @dev: device structure representing parent device.
190  * @ops: Parent device operation structure to be registered.
191  *
192  * Add device to list of registered parent devices.
193  * Returns a negative value on error, otherwise 0.
194  */
195 int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
196 {
197         int ret;
198         struct mdev_parent *parent;
199
200         /* check for mandatory ops */
201         if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups)
202                 return -EINVAL;
203
204         dev = get_device(dev);
205         if (!dev)
206                 return -EINVAL;
207
208         mutex_lock(&parent_list_lock);
209
210         /* Check for duplicate */
211         parent = __find_parent_device(dev);
212         if (parent) {
213                 ret = -EEXIST;
214                 goto add_dev_err;
215         }
216
217         parent = kzalloc(sizeof(*parent), GFP_KERNEL);
218         if (!parent) {
219                 ret = -ENOMEM;
220                 goto add_dev_err;
221         }
222
223         kref_init(&parent->ref);
224         mutex_init(&parent->lock);
225
226         parent->dev = dev;
227         parent->ops = ops;
228
229         if (!mdev_bus_compat_class) {
230                 mdev_bus_compat_class = class_compat_register("mdev_bus");
231                 if (!mdev_bus_compat_class) {
232                         ret = -ENOMEM;
233                         goto add_dev_err;
234                 }
235         }
236
237         ret = parent_create_sysfs_files(parent);
238         if (ret)
239                 goto add_dev_err;
240
241         ret = class_compat_create_link(mdev_bus_compat_class, dev, NULL);
242         if (ret)
243                 dev_warn(dev, "Failed to create compatibility class link\n");
244
245         list_add(&parent->next, &parent_list);
246         mutex_unlock(&parent_list_lock);
247
248         dev_info(dev, "MDEV: Registered\n");
249         return 0;
250
251 add_dev_err:
252         mutex_unlock(&parent_list_lock);
253         if (parent)
254                 mdev_put_parent(parent);
255         else
256                 put_device(dev);
257         return ret;
258 }
259 EXPORT_SYMBOL(mdev_register_device);
260
261 /*
262  * mdev_unregister_device : Unregister a parent device
263  * @dev: device structure representing parent device.
264  *
265  * Remove device from list of registered parent devices. Give a chance to free
266  * existing mediated devices for given device.
267  */
268
269 void mdev_unregister_device(struct device *dev)
270 {
271         struct mdev_parent *parent;
272         bool force_remove = true;
273
274         mutex_lock(&parent_list_lock);
275         parent = __find_parent_device(dev);
276
277         if (!parent) {
278                 mutex_unlock(&parent_list_lock);
279                 return;
280         }
281         dev_info(dev, "MDEV: Unregistering\n");
282
283         list_del(&parent->next);
284         class_compat_remove_link(mdev_bus_compat_class, dev, NULL);
285
286         device_for_each_child(dev, (void *)&force_remove,
287                               mdev_device_remove_cb);
288
289         parent_remove_sysfs_files(parent);
290
291         mutex_unlock(&parent_list_lock);
292         mdev_put_parent(parent);
293 }
294 EXPORT_SYMBOL(mdev_unregister_device);
295
296 static void mdev_device_release(struct device *dev)
297 {
298         struct mdev_device *mdev = to_mdev_device(dev);
299
300         dev_dbg(&mdev->dev, "MDEV: destroying\n");
301         kfree(mdev);
302 }
303
304 int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
305 {
306         int ret;
307         struct mdev_device *mdev;
308         struct mdev_parent *parent;
309         struct mdev_type *type = to_mdev_type(kobj);
310
311         parent = mdev_get_parent(type->parent);
312         if (!parent)
313                 return -EINVAL;
314
315         mutex_lock(&parent->lock);
316
317         /* Check for duplicate */
318         if (mdev_device_exist(parent, uuid)) {
319                 ret = -EEXIST;
320                 goto create_err;
321         }
322
323         mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
324         if (!mdev) {
325                 ret = -ENOMEM;
326                 goto create_err;
327         }
328
329         memcpy(&mdev->uuid, &uuid, sizeof(uuid_le));
330         mdev->parent = parent;
331         kref_init(&mdev->ref);
332
333         mdev->dev.parent  = dev;
334         mdev->dev.bus     = &mdev_bus_type;
335         mdev->dev.release = mdev_device_release;
336         dev_set_name(&mdev->dev, "%pUl", uuid.b);
337
338         ret = device_register(&mdev->dev);
339         if (ret) {
340                 put_device(&mdev->dev);
341                 goto create_err;
342         }
343
344         ret = mdev_device_create_ops(kobj, mdev);
345         if (ret)
346                 goto create_failed;
347
348         ret = mdev_create_sysfs_files(&mdev->dev, type);
349         if (ret) {
350                 mdev_device_remove_ops(mdev, true);
351                 goto create_failed;
352         }
353
354         mdev->type_kobj = kobj;
355         dev_dbg(&mdev->dev, "MDEV: created\n");
356
357         mutex_unlock(&parent->lock);
358
359         mutex_lock(&mdev_list_lock);
360         list_add(&mdev->next, &mdev_list);
361         mutex_unlock(&mdev_list_lock);
362
363         return ret;
364
365 create_failed:
366         device_unregister(&mdev->dev);
367
368 create_err:
369         mutex_unlock(&parent->lock);
370         mdev_put_parent(parent);
371         return ret;
372 }
373
374 int mdev_device_remove(struct device *dev, bool force_remove)
375 {
376         struct mdev_device *mdev, *tmp;
377         struct mdev_parent *parent;
378         struct mdev_type *type;
379         int ret;
380         bool found = false;
381
382         mdev = to_mdev_device(dev);
383
384         mutex_lock(&mdev_list_lock);
385         list_for_each_entry(tmp, &mdev_list, next) {
386                 if (tmp == mdev) {
387                         found = true;
388                         break;
389                 }
390         }
391
392         if (found)
393                 list_del(&mdev->next);
394
395         mutex_unlock(&mdev_list_lock);
396
397         if (!found)
398                 return -ENODEV;
399
400         type = to_mdev_type(mdev->type_kobj);
401         parent = mdev->parent;
402         mutex_lock(&parent->lock);
403
404         ret = mdev_device_remove_ops(mdev, force_remove);
405         if (ret) {
406                 mutex_unlock(&parent->lock);
407
408                 mutex_lock(&mdev_list_lock);
409                 list_add(&mdev->next, &mdev_list);
410                 mutex_unlock(&mdev_list_lock);
411
412                 return ret;
413         }
414
415         mdev_remove_sysfs_files(dev, type);
416         device_unregister(dev);
417         mutex_unlock(&parent->lock);
418         mdev_put_parent(parent);
419
420         return 0;
421 }
422
423 static int __init mdev_init(void)
424 {
425         int ret;
426
427         ret = mdev_bus_register();
428
429         /*
430          * Attempt to load known vfio_mdev.  This gives us a working environment
431          * without the user needing to explicitly load vfio_mdev driver.
432          */
433         if (!ret)
434                 request_module_nowait("vfio_mdev");
435
436         return ret;
437 }
438
439 static void __exit mdev_exit(void)
440 {
441         if (mdev_bus_compat_class)
442                 class_compat_unregister(mdev_bus_compat_class);
443
444         mdev_bus_unregister();
445 }
446
447 module_init(mdev_init)
448 module_exit(mdev_exit)
449
450 MODULE_VERSION(DRIVER_VERSION);
451 MODULE_LICENSE("GPL v2");
452 MODULE_AUTHOR(DRIVER_AUTHOR);
453 MODULE_DESCRIPTION(DRIVER_DESC);