Linux Audio

Check our new training course

Loading...
v5.4
  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 <cjia@nvidia.com>
  7 *             Kirti Wankhede <kwankhede@nvidia.com>
  8 */
  9
 10#include <linux/module.h>
 11#include <linux/device.h>
 12#include <linux/slab.h>
 13#include <linux/uuid.h>
 14#include <linux/sysfs.h>
 15#include <linux/mdev.h>
 16
 17#include "mdev_private.h"
 18
 19#define DRIVER_VERSION		"0.1"
 20#define DRIVER_AUTHOR		"NVIDIA Corporation"
 21#define DRIVER_DESC		"Mediated device Core Driver"
 22
 23static LIST_HEAD(parent_list);
 24static DEFINE_MUTEX(parent_list_lock);
 25static struct class_compat *mdev_bus_compat_class;
 26
 27static LIST_HEAD(mdev_list);
 28static DEFINE_MUTEX(mdev_list_lock);
 29
 30struct device *mdev_parent_dev(struct mdev_device *mdev)
 31{
 32	return mdev->parent->dev;
 33}
 34EXPORT_SYMBOL(mdev_parent_dev);
 35
 36void *mdev_get_drvdata(struct mdev_device *mdev)
 37{
 38	return mdev->driver_data;
 39}
 40EXPORT_SYMBOL(mdev_get_drvdata);
 41
 42void mdev_set_drvdata(struct mdev_device *mdev, void *data)
 43{
 44	mdev->driver_data = data;
 45}
 46EXPORT_SYMBOL(mdev_set_drvdata);
 47
 48struct device *mdev_dev(struct mdev_device *mdev)
 49{
 50	return &mdev->dev;
 51}
 52EXPORT_SYMBOL(mdev_dev);
 53
 54struct mdev_device *mdev_from_dev(struct device *dev)
 55{
 56	return dev_is_mdev(dev) ? to_mdev_device(dev) : NULL;
 57}
 58EXPORT_SYMBOL(mdev_from_dev);
 59
 60const guid_t *mdev_uuid(struct mdev_device *mdev)
 61{
 62	return &mdev->uuid;
 63}
 64EXPORT_SYMBOL(mdev_uuid);
 65
 66/* Should be called holding parent_list_lock */
 67static struct mdev_parent *__find_parent_device(struct device *dev)
 68{
 69	struct mdev_parent *parent;
 70
 71	list_for_each_entry(parent, &parent_list, next) {
 72		if (parent->dev == dev)
 73			return parent;
 74	}
 75	return NULL;
 76}
 77
 78static void mdev_release_parent(struct kref *kref)
 79{
 80	struct mdev_parent *parent = container_of(kref, struct mdev_parent,
 81						  ref);
 82	struct device *dev = parent->dev;
 83
 84	kfree(parent);
 85	put_device(dev);
 86}
 87
 88static struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
 89{
 90	if (parent)
 91		kref_get(&parent->ref);
 92
 93	return parent;
 94}
 95
 96static void mdev_put_parent(struct mdev_parent *parent)
 97{
 98	if (parent)
 99		kref_put(&parent->ref, mdev_release_parent);
100}
101
102/* Caller must hold parent unreg_sem read or write lock */
103static void mdev_device_remove_common(struct mdev_device *mdev)
104{
105	struct mdev_parent *parent;
106	struct mdev_type *type;
107	int ret;
108
109	type = to_mdev_type(mdev->type_kobj);
110	mdev_remove_sysfs_files(&mdev->dev, type);
111	device_del(&mdev->dev);
112	parent = mdev->parent;
113	lockdep_assert_held(&parent->unreg_sem);
114	ret = parent->ops->remove(mdev);
115	if (ret)
116		dev_err(&mdev->dev, "Remove failed: err=%d\n", ret);
117
118	/* Balances with device_initialize() */
119	put_device(&mdev->dev);
120	mdev_put_parent(parent);
121}
122
123static int mdev_device_remove_cb(struct device *dev, void *data)
124{
125	if (dev_is_mdev(dev)) {
126		struct mdev_device *mdev;
127
128		mdev = to_mdev_device(dev);
129		mdev_device_remove_common(mdev);
130	}
131	return 0;
132}
133
134/*
135 * mdev_register_device : Register a device
136 * @dev: device structure representing parent device.
137 * @ops: Parent device operation structure to be registered.
138 *
139 * Add device to list of registered parent devices.
140 * Returns a negative value on error, otherwise 0.
141 */
142int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
143{
144	int ret;
145	struct mdev_parent *parent;
146	char *env_string = "MDEV_STATE=registered";
147	char *envp[] = { env_string, NULL };
148
149	/* check for mandatory ops */
150	if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups)
151		return -EINVAL;
152
153	dev = get_device(dev);
154	if (!dev)
155		return -EINVAL;
156
157	mutex_lock(&parent_list_lock);
158
159	/* Check for duplicate */
160	parent = __find_parent_device(dev);
161	if (parent) {
162		parent = NULL;
163		ret = -EEXIST;
164		goto add_dev_err;
165	}
166
167	parent = kzalloc(sizeof(*parent), GFP_KERNEL);
168	if (!parent) {
169		ret = -ENOMEM;
170		goto add_dev_err;
171	}
172
173	kref_init(&parent->ref);
174	init_rwsem(&parent->unreg_sem);
175
176	parent->dev = dev;
177	parent->ops = ops;
178
179	if (!mdev_bus_compat_class) {
180		mdev_bus_compat_class = class_compat_register("mdev_bus");
181		if (!mdev_bus_compat_class) {
182			ret = -ENOMEM;
183			goto add_dev_err;
184		}
185	}
186
187	ret = parent_create_sysfs_files(parent);
188	if (ret)
189		goto add_dev_err;
190
191	ret = class_compat_create_link(mdev_bus_compat_class, dev, NULL);
192	if (ret)
193		dev_warn(dev, "Failed to create compatibility class link\n");
194
195	list_add(&parent->next, &parent_list);
196	mutex_unlock(&parent_list_lock);
197
198	dev_info(dev, "MDEV: Registered\n");
199	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
200
201	return 0;
202
203add_dev_err:
204	mutex_unlock(&parent_list_lock);
205	if (parent)
206		mdev_put_parent(parent);
207	else
208		put_device(dev);
209	return ret;
210}
211EXPORT_SYMBOL(mdev_register_device);
212
213/*
214 * mdev_unregister_device : Unregister a parent device
215 * @dev: device structure representing parent device.
216 *
217 * Remove device from list of registered parent devices. Give a chance to free
218 * existing mediated devices for given device.
219 */
220
221void mdev_unregister_device(struct device *dev)
222{
223	struct mdev_parent *parent;
224	char *env_string = "MDEV_STATE=unregistered";
225	char *envp[] = { env_string, NULL };
226
227	mutex_lock(&parent_list_lock);
228	parent = __find_parent_device(dev);
229
230	if (!parent) {
231		mutex_unlock(&parent_list_lock);
232		return;
233	}
234	dev_info(dev, "MDEV: Unregistering\n");
235
236	list_del(&parent->next);
237	mutex_unlock(&parent_list_lock);
238
239	down_write(&parent->unreg_sem);
240
241	class_compat_remove_link(mdev_bus_compat_class, dev, NULL);
242
243	device_for_each_child(dev, NULL, mdev_device_remove_cb);
244
245	parent_remove_sysfs_files(parent);
246	up_write(&parent->unreg_sem);
247
248	mdev_put_parent(parent);
249
250	/* We still have the caller's reference to use for the uevent */
251	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
252}
253EXPORT_SYMBOL(mdev_unregister_device);
254
255static void mdev_device_free(struct mdev_device *mdev)
256{
257	mutex_lock(&mdev_list_lock);
258	list_del(&mdev->next);
259	mutex_unlock(&mdev_list_lock);
260
261	dev_dbg(&mdev->dev, "MDEV: destroying\n");
262	kfree(mdev);
263}
264
265static void mdev_device_release(struct device *dev)
266{
267	struct mdev_device *mdev = to_mdev_device(dev);
268
269	mdev_device_free(mdev);
270}
271
272int mdev_device_create(struct kobject *kobj,
273		       struct device *dev, const guid_t *uuid)
274{
275	int ret;
276	struct mdev_device *mdev, *tmp;
277	struct mdev_parent *parent;
278	struct mdev_type *type = to_mdev_type(kobj);
279
280	parent = mdev_get_parent(type->parent);
281	if (!parent)
282		return -EINVAL;
283
284	mutex_lock(&mdev_list_lock);
285
286	/* Check for duplicate */
287	list_for_each_entry(tmp, &mdev_list, next) {
288		if (guid_equal(&tmp->uuid, uuid)) {
289			mutex_unlock(&mdev_list_lock);
290			ret = -EEXIST;
291			goto mdev_fail;
292		}
293	}
294
295	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
296	if (!mdev) {
297		mutex_unlock(&mdev_list_lock);
298		ret = -ENOMEM;
299		goto mdev_fail;
300	}
301
302	guid_copy(&mdev->uuid, uuid);
303	list_add(&mdev->next, &mdev_list);
304	mutex_unlock(&mdev_list_lock);
305
306	mdev->parent = parent;
307
308	/* Check if parent unregistration has started */
309	if (!down_read_trylock(&parent->unreg_sem)) {
310		mdev_device_free(mdev);
311		ret = -ENODEV;
312		goto mdev_fail;
313	}
314
315	device_initialize(&mdev->dev);
316	mdev->dev.parent  = dev;
317	mdev->dev.bus     = &mdev_bus_type;
318	mdev->dev.release = mdev_device_release;
319	dev_set_name(&mdev->dev, "%pUl", uuid);
320	mdev->dev.groups = parent->ops->mdev_attr_groups;
321	mdev->type_kobj = kobj;
322
323	ret = parent->ops->create(kobj, mdev);
324	if (ret)
325		goto ops_create_fail;
326
327	ret = device_add(&mdev->dev);
328	if (ret)
329		goto add_fail;
330
331	ret = mdev_create_sysfs_files(&mdev->dev, type);
332	if (ret)
333		goto sysfs_fail;
334
335	mdev->active = true;
336	dev_dbg(&mdev->dev, "MDEV: created\n");
337	up_read(&parent->unreg_sem);
338
339	return 0;
340
341sysfs_fail:
342	device_del(&mdev->dev);
343add_fail:
344	parent->ops->remove(mdev);
345ops_create_fail:
346	up_read(&parent->unreg_sem);
347	put_device(&mdev->dev);
348mdev_fail:
349	mdev_put_parent(parent);
350	return ret;
351}
352
353int mdev_device_remove(struct device *dev)
354{
355	struct mdev_device *mdev, *tmp;
356	struct mdev_parent *parent;
357
358	mdev = to_mdev_device(dev);
359
360	mutex_lock(&mdev_list_lock);
361	list_for_each_entry(tmp, &mdev_list, next) {
362		if (tmp == mdev)
363			break;
364	}
365
366	if (tmp != mdev) {
367		mutex_unlock(&mdev_list_lock);
368		return -ENODEV;
369	}
370
371	if (!mdev->active) {
372		mutex_unlock(&mdev_list_lock);
373		return -EAGAIN;
374	}
375
376	mdev->active = false;
377	mutex_unlock(&mdev_list_lock);
378
379	parent = mdev->parent;
380	/* Check if parent unregistration has started */
381	if (!down_read_trylock(&parent->unreg_sem))
382		return -ENODEV;
383
384	mdev_device_remove_common(mdev);
385	up_read(&parent->unreg_sem);
386	return 0;
387}
388
389int mdev_set_iommu_device(struct device *dev, struct device *iommu_device)
390{
391	struct mdev_device *mdev = to_mdev_device(dev);
392
393	mdev->iommu_device = iommu_device;
394
395	return 0;
396}
397EXPORT_SYMBOL(mdev_set_iommu_device);
398
399struct device *mdev_get_iommu_device(struct device *dev)
400{
401	struct mdev_device *mdev = to_mdev_device(dev);
402
403	return mdev->iommu_device;
404}
405EXPORT_SYMBOL(mdev_get_iommu_device);
406
407static int __init mdev_init(void)
408{
409	return mdev_bus_register();
410}
411
412static void __exit mdev_exit(void)
413{
414	if (mdev_bus_compat_class)
415		class_compat_unregister(mdev_bus_compat_class);
416
417	mdev_bus_unregister();
418}
419
420module_init(mdev_init)
421module_exit(mdev_exit)
422
423MODULE_VERSION(DRIVER_VERSION);
424MODULE_LICENSE("GPL v2");
425MODULE_AUTHOR(DRIVER_AUTHOR);
426MODULE_DESCRIPTION(DRIVER_DESC);
427MODULE_SOFTDEP("post: vfio_mdev");
v5.9
  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 <cjia@nvidia.com>
  7 *             Kirti Wankhede <kwankhede@nvidia.com>
  8 */
  9
 10#include <linux/module.h>
 11#include <linux/device.h>
 12#include <linux/slab.h>
 13#include <linux/uuid.h>
 14#include <linux/sysfs.h>
 15#include <linux/mdev.h>
 16
 17#include "mdev_private.h"
 18
 19#define DRIVER_VERSION		"0.1"
 20#define DRIVER_AUTHOR		"NVIDIA Corporation"
 21#define DRIVER_DESC		"Mediated device Core Driver"
 22
 23static LIST_HEAD(parent_list);
 24static DEFINE_MUTEX(parent_list_lock);
 25static struct class_compat *mdev_bus_compat_class;
 26
 27static LIST_HEAD(mdev_list);
 28static DEFINE_MUTEX(mdev_list_lock);
 29
 30struct device *mdev_parent_dev(struct mdev_device *mdev)
 31{
 32	return mdev->parent->dev;
 33}
 34EXPORT_SYMBOL(mdev_parent_dev);
 35
 36void *mdev_get_drvdata(struct mdev_device *mdev)
 37{
 38	return mdev->driver_data;
 39}
 40EXPORT_SYMBOL(mdev_get_drvdata);
 41
 42void mdev_set_drvdata(struct mdev_device *mdev, void *data)
 43{
 44	mdev->driver_data = data;
 45}
 46EXPORT_SYMBOL(mdev_set_drvdata);
 47
 48struct device *mdev_dev(struct mdev_device *mdev)
 49{
 50	return &mdev->dev;
 51}
 52EXPORT_SYMBOL(mdev_dev);
 53
 54struct mdev_device *mdev_from_dev(struct device *dev)
 55{
 56	return dev_is_mdev(dev) ? to_mdev_device(dev) : NULL;
 57}
 58EXPORT_SYMBOL(mdev_from_dev);
 59
 60const guid_t *mdev_uuid(struct mdev_device *mdev)
 61{
 62	return &mdev->uuid;
 63}
 64EXPORT_SYMBOL(mdev_uuid);
 65
 66/* Should be called holding parent_list_lock */
 67static struct mdev_parent *__find_parent_device(struct device *dev)
 68{
 69	struct mdev_parent *parent;
 70
 71	list_for_each_entry(parent, &parent_list, next) {
 72		if (parent->dev == dev)
 73			return parent;
 74	}
 75	return NULL;
 76}
 77
 78static void mdev_release_parent(struct kref *kref)
 79{
 80	struct mdev_parent *parent = container_of(kref, struct mdev_parent,
 81						  ref);
 82	struct device *dev = parent->dev;
 83
 84	kfree(parent);
 85	put_device(dev);
 86}
 87
 88static struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
 89{
 90	if (parent)
 91		kref_get(&parent->ref);
 92
 93	return parent;
 94}
 95
 96static void mdev_put_parent(struct mdev_parent *parent)
 97{
 98	if (parent)
 99		kref_put(&parent->ref, mdev_release_parent);
100}
101
102/* Caller must hold parent unreg_sem read or write lock */
103static void mdev_device_remove_common(struct mdev_device *mdev)
104{
105	struct mdev_parent *parent;
106	struct mdev_type *type;
107	int ret;
108
109	type = to_mdev_type(mdev->type_kobj);
110	mdev_remove_sysfs_files(&mdev->dev, type);
111	device_del(&mdev->dev);
112	parent = mdev->parent;
113	lockdep_assert_held(&parent->unreg_sem);
114	ret = parent->ops->remove(mdev);
115	if (ret)
116		dev_err(&mdev->dev, "Remove failed: err=%d\n", ret);
117
118	/* Balances with device_initialize() */
119	put_device(&mdev->dev);
120	mdev_put_parent(parent);
121}
122
123static int mdev_device_remove_cb(struct device *dev, void *data)
124{
125	if (dev_is_mdev(dev)) {
126		struct mdev_device *mdev;
127
128		mdev = to_mdev_device(dev);
129		mdev_device_remove_common(mdev);
130	}
131	return 0;
132}
133
134/*
135 * mdev_register_device : Register a device
136 * @dev: device structure representing parent device.
137 * @ops: Parent device operation structure to be registered.
138 *
139 * Add device to list of registered parent devices.
140 * Returns a negative value on error, otherwise 0.
141 */
142int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
143{
144	int ret;
145	struct mdev_parent *parent;
146	char *env_string = "MDEV_STATE=registered";
147	char *envp[] = { env_string, NULL };
148
149	/* check for mandatory ops */
150	if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups)
151		return -EINVAL;
152
153	dev = get_device(dev);
154	if (!dev)
155		return -EINVAL;
156
157	mutex_lock(&parent_list_lock);
158
159	/* Check for duplicate */
160	parent = __find_parent_device(dev);
161	if (parent) {
162		parent = NULL;
163		ret = -EEXIST;
164		goto add_dev_err;
165	}
166
167	parent = kzalloc(sizeof(*parent), GFP_KERNEL);
168	if (!parent) {
169		ret = -ENOMEM;
170		goto add_dev_err;
171	}
172
173	kref_init(&parent->ref);
174	init_rwsem(&parent->unreg_sem);
175
176	parent->dev = dev;
177	parent->ops = ops;
178
179	if (!mdev_bus_compat_class) {
180		mdev_bus_compat_class = class_compat_register("mdev_bus");
181		if (!mdev_bus_compat_class) {
182			ret = -ENOMEM;
183			goto add_dev_err;
184		}
185	}
186
187	ret = parent_create_sysfs_files(parent);
188	if (ret)
189		goto add_dev_err;
190
191	ret = class_compat_create_link(mdev_bus_compat_class, dev, NULL);
192	if (ret)
193		dev_warn(dev, "Failed to create compatibility class link\n");
194
195	list_add(&parent->next, &parent_list);
196	mutex_unlock(&parent_list_lock);
197
198	dev_info(dev, "MDEV: Registered\n");
199	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
200
201	return 0;
202
203add_dev_err:
204	mutex_unlock(&parent_list_lock);
205	if (parent)
206		mdev_put_parent(parent);
207	else
208		put_device(dev);
209	return ret;
210}
211EXPORT_SYMBOL(mdev_register_device);
212
213/*
214 * mdev_unregister_device : Unregister a parent device
215 * @dev: device structure representing parent device.
216 *
217 * Remove device from list of registered parent devices. Give a chance to free
218 * existing mediated devices for given device.
219 */
220
221void mdev_unregister_device(struct device *dev)
222{
223	struct mdev_parent *parent;
224	char *env_string = "MDEV_STATE=unregistered";
225	char *envp[] = { env_string, NULL };
226
227	mutex_lock(&parent_list_lock);
228	parent = __find_parent_device(dev);
229
230	if (!parent) {
231		mutex_unlock(&parent_list_lock);
232		return;
233	}
234	dev_info(dev, "MDEV: Unregistering\n");
235
236	list_del(&parent->next);
237	mutex_unlock(&parent_list_lock);
238
239	down_write(&parent->unreg_sem);
240
241	class_compat_remove_link(mdev_bus_compat_class, dev, NULL);
242
243	device_for_each_child(dev, NULL, mdev_device_remove_cb);
244
245	parent_remove_sysfs_files(parent);
246	up_write(&parent->unreg_sem);
247
248	mdev_put_parent(parent);
249
250	/* We still have the caller's reference to use for the uevent */
251	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
252}
253EXPORT_SYMBOL(mdev_unregister_device);
254
255static void mdev_device_free(struct mdev_device *mdev)
256{
257	mutex_lock(&mdev_list_lock);
258	list_del(&mdev->next);
259	mutex_unlock(&mdev_list_lock);
260
261	dev_dbg(&mdev->dev, "MDEV: destroying\n");
262	kfree(mdev);
263}
264
265static void mdev_device_release(struct device *dev)
266{
267	struct mdev_device *mdev = to_mdev_device(dev);
268
269	mdev_device_free(mdev);
270}
271
272int mdev_device_create(struct kobject *kobj,
273		       struct device *dev, const guid_t *uuid)
274{
275	int ret;
276	struct mdev_device *mdev, *tmp;
277	struct mdev_parent *parent;
278	struct mdev_type *type = to_mdev_type(kobj);
279
280	parent = mdev_get_parent(type->parent);
281	if (!parent)
282		return -EINVAL;
283
284	mutex_lock(&mdev_list_lock);
285
286	/* Check for duplicate */
287	list_for_each_entry(tmp, &mdev_list, next) {
288		if (guid_equal(&tmp->uuid, uuid)) {
289			mutex_unlock(&mdev_list_lock);
290			ret = -EEXIST;
291			goto mdev_fail;
292		}
293	}
294
295	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
296	if (!mdev) {
297		mutex_unlock(&mdev_list_lock);
298		ret = -ENOMEM;
299		goto mdev_fail;
300	}
301
302	guid_copy(&mdev->uuid, uuid);
303	list_add(&mdev->next, &mdev_list);
304	mutex_unlock(&mdev_list_lock);
305
306	mdev->parent = parent;
307
308	/* Check if parent unregistration has started */
309	if (!down_read_trylock(&parent->unreg_sem)) {
310		mdev_device_free(mdev);
311		ret = -ENODEV;
312		goto mdev_fail;
313	}
314
315	device_initialize(&mdev->dev);
316	mdev->dev.parent  = dev;
317	mdev->dev.bus     = &mdev_bus_type;
318	mdev->dev.release = mdev_device_release;
319	dev_set_name(&mdev->dev, "%pUl", uuid);
320	mdev->dev.groups = parent->ops->mdev_attr_groups;
321	mdev->type_kobj = kobj;
322
323	ret = parent->ops->create(kobj, mdev);
324	if (ret)
325		goto ops_create_fail;
326
327	ret = device_add(&mdev->dev);
328	if (ret)
329		goto add_fail;
330
331	ret = mdev_create_sysfs_files(&mdev->dev, type);
332	if (ret)
333		goto sysfs_fail;
334
335	mdev->active = true;
336	dev_dbg(&mdev->dev, "MDEV: created\n");
337	up_read(&parent->unreg_sem);
338
339	return 0;
340
341sysfs_fail:
342	device_del(&mdev->dev);
343add_fail:
344	parent->ops->remove(mdev);
345ops_create_fail:
346	up_read(&parent->unreg_sem);
347	put_device(&mdev->dev);
348mdev_fail:
349	mdev_put_parent(parent);
350	return ret;
351}
352
353int mdev_device_remove(struct device *dev)
354{
355	struct mdev_device *mdev, *tmp;
356	struct mdev_parent *parent;
357
358	mdev = to_mdev_device(dev);
359
360	mutex_lock(&mdev_list_lock);
361	list_for_each_entry(tmp, &mdev_list, next) {
362		if (tmp == mdev)
363			break;
364	}
365
366	if (tmp != mdev) {
367		mutex_unlock(&mdev_list_lock);
368		return -ENODEV;
369	}
370
371	if (!mdev->active) {
372		mutex_unlock(&mdev_list_lock);
373		return -EAGAIN;
374	}
375
376	mdev->active = false;
377	mutex_unlock(&mdev_list_lock);
378
379	parent = mdev->parent;
380	/* Check if parent unregistration has started */
381	if (!down_read_trylock(&parent->unreg_sem))
382		return -ENODEV;
383
384	mdev_device_remove_common(mdev);
385	up_read(&parent->unreg_sem);
386	return 0;
387}
388
389int mdev_set_iommu_device(struct device *dev, struct device *iommu_device)
390{
391	struct mdev_device *mdev = to_mdev_device(dev);
392
393	mdev->iommu_device = iommu_device;
394
395	return 0;
396}
397EXPORT_SYMBOL(mdev_set_iommu_device);
398
399struct device *mdev_get_iommu_device(struct device *dev)
400{
401	struct mdev_device *mdev = to_mdev_device(dev);
402
403	return mdev->iommu_device;
404}
405EXPORT_SYMBOL(mdev_get_iommu_device);
406
407static int __init mdev_init(void)
408{
409	return mdev_bus_register();
410}
411
412static void __exit mdev_exit(void)
413{
414	if (mdev_bus_compat_class)
415		class_compat_unregister(mdev_bus_compat_class);
416
417	mdev_bus_unregister();
418}
419
420module_init(mdev_init)
421module_exit(mdev_exit)
422
423MODULE_VERSION(DRIVER_VERSION);
424MODULE_LICENSE("GPL v2");
425MODULE_AUTHOR(DRIVER_AUTHOR);
426MODULE_DESCRIPTION(DRIVER_DESC);
427MODULE_SOFTDEP("post: vfio_mdev");