@@ -39,23 +39,42 @@ static void mdev_remove_attribute_group(struct device *dev,
sysfs_remove_groups(&dev->kobj, groups);
}
-/* Should be called holding parent->mdev_list_lock */
+struct mdev_info {
+ uuid_le uuid;
+ int instance;
+};
+
+static int __find_mdev_device(struct device *dev, void *data)
+{
+ struct mdev_device *mdev = dev_to_mdev(dev);
+ struct mdev_info *info = data;
+
+ if ((uuid_le_cmp(mdev->uuid, info->uuid) == 0) &&
+ (mdev->instance == info->instance))
+ return 1;
+
+ return 0;
+}
+
static struct mdev_device *find_mdev_device(struct parent_device *parent,
uuid_le uuid, int instance)
{
- struct mdev_device *mdev;
+ struct device *dev;
+ struct mdev_info info = {
+ .uuid = uuid,
+ .instance = instance,
+ };
- list_for_each_entry(mdev, &parent->mdev_list, next) {
- if ((uuid_le_cmp(mdev->uuid, uuid) == 0) &&
- (mdev->instance == instance))
- return mdev;
- }
- return NULL;
+ dev = device_find_child(&parent->dev, &info, __find_mdev_device);
+ if (!dev)
+ return NULL;
+
+ return dev_to_mdev(dev);
}
static int mdev_device_create_ops(struct mdev_device *mdev, char *mdev_params)
{
- struct parent_device *parent = mdev->parent;
+ struct parent_device *parent = dev_to_parent_dev(mdev->dev.parent);
int ret;
ret = parent->ops->create(mdev, mdev_params);
@@ -72,7 +91,7 @@ static int mdev_device_create_ops(struct mdev_device *mdev, char *mdev_params)
static int mdev_device_destroy_ops(struct mdev_device *mdev, bool force)
{
- struct parent_device *parent = mdev->parent;
+ struct parent_device *parent = dev_to_parent_dev(mdev->dev.parent);
int ret = 0;
/*
@@ -89,34 +108,6 @@ static int mdev_device_destroy_ops(struct mdev_device *mdev, bool force)
return ret;
}
-static void mdev_release_device(struct kref *kref)
-{
- struct mdev_device *mdev = container_of(kref, struct mdev_device, ref);
- struct parent_device *parent = mdev->parent;
-
- list_del(&mdev->next);
- mutex_unlock(&parent->mdev_list_lock);
-
- device_unregister(&mdev->dev);
- wake_up(&parent->release_done);
-}
-
-struct mdev_device *mdev_get_device(struct mdev_device *mdev)
-{
- kref_get(&mdev->ref);
- return mdev;
-}
-EXPORT_SYMBOL(mdev_get_device);
-
-void mdev_put_device(struct mdev_device *mdev)
-{
- struct parent_device *parent = mdev->parent;
-
- kref_put_mutex(&mdev->ref, mdev_release_device,
- &parent->mdev_list_lock);
-}
-EXPORT_SYMBOL(mdev_put_device);
-
/*
* mdev_register_device : Register a device
* @dev: device structure representing parent device.
@@ -145,9 +136,6 @@ int mdev_register_device(struct device *dev, const struct parent_ops *ops)
parent->dev.parent = dev;
parent->ops = ops;
- mutex_init(&parent->mdev_list_lock);
- INIT_LIST_HEAD(&parent->mdev_list);
- init_waitqueue_head(&parent->release_done);
ret = device_register(&parent->dev);
if (ret)
@@ -176,63 +164,53 @@ add_dev_err:
}
EXPORT_SYMBOL(mdev_register_device);
+static int __mdev_device_destroy(struct device *dev, void *data)
+{
+ struct mdev_device *mdev = dev_to_mdev(dev);
+ int ret, force = (unsigned long)data;
+
+ ret = mdev_device_destroy_ops(mdev, force);
+
+ /* can not fail if foce = true. */
+ WARN_ON(force && ret);
+ if (ret)
+ goto destroy_err;
+
+ device_unregister(&mdev->dev);
+
+destroy_err:
+ return ret;
+}
+
/*
* mdev_unregister_device : Unregister a parent device
- * @dev: device structure representing parent device which is returned by
- * mdev_register_device.
+ * @dev: device structure representing parent device
*
* Remove device from list of registered parent devices. Give a chance to free
* existing mediated devices for given device.
*/
-void mdev_unregister_device(struct parent_device *parent)
+void mdev_unregister_device(struct device *dev)
{
- struct mdev_device *mdev, *n;
- int ret;
-
+ struct parent_device *parent = dev_to_parent_dev(dev);
dev_info(&parent->dev, "MDEV: Unregistering\n");
/*
* Remove parent from the list and remove create and destroy sysfs
* files so that no new mediated device could be created for this parent
*/
- mdev_remove_sysfs_files(&parent->dev);
+ mdev_remove_sysfs_files(dev);
- mdev_remove_attribute_group(&parent->dev,
- parent->ops->dev_attr_groups);
+ mdev_remove_attribute_group(dev, parent->ops->dev_attr_groups);
- mutex_lock(&parent->mdev_list_lock);
- list_for_each_entry_safe(mdev, n, &parent->mdev_list, next) {
- mdev_device_destroy_ops(mdev, true);
- mutex_unlock(&parent->mdev_list_lock);
- mdev_put_device(mdev);
- mutex_lock(&parent->mdev_list_lock);
- }
- mutex_unlock(&parent->mdev_list_lock);
-
- do {
- ret = wait_event_interruptible_timeout(parent->release_done,
- list_empty(&parent->mdev_list), HZ * 10);
- if (ret == -ERESTARTSYS) {
- dev_warn(&parent->dev, "Mediated devices are in use, task"
- " \"%s\" (%d) "
- "blocked until all are released",
- current->comm, task_pid_nr(current));
- }
- } while (ret <= 0);
+ device_for_each_child(dev, (void *)true, __mdev_device_destroy);
+
+ device_unregister(dev);
}
EXPORT_SYMBOL(mdev_unregister_device);
/*
* Functions required for mdev_sysfs
*/
-static void mdev_device_release(struct device *dev)
-{
- struct mdev_device *mdev = to_mdev_device(dev);
-
- dev_dbg(&mdev->dev, "MDEV: destroying\n");
- kfree(mdev);
-}
-
int mdev_device_create(struct device *dev, uuid_le uuid, uint32_t instance,
char *mdev_params)
{
@@ -240,7 +218,6 @@ int mdev_device_create(struct device *dev, uuid_le uuid, uint32_t instance,
struct mdev_device *mdev;
struct parent_device *parent = dev_to_parent_dev(dev);
- mutex_lock(&parent->mdev_list_lock);
/* Check for duplicate */
mdev = find_mdev_device(parent, uuid, instance);
if (mdev) {
@@ -256,13 +233,10 @@ int mdev_device_create(struct device *dev, uuid_le uuid, uint32_t instance,
memcpy(&mdev->uuid, &uuid, sizeof(uuid_le));
mdev->instance = instance;
- mdev->parent = parent;
- kref_init(&mdev->ref);
mdev->dev.parent = dev;
mdev->dev.class = &mdev_class;
mdev->dev.bus = &mdev_bus_type;
- mdev->dev.release = mdev_device_release;
dev_set_name(&mdev->dev, "%pUl-%d", uuid.b, instance);
ret = device_register(&mdev->dev);
@@ -275,9 +249,6 @@ int mdev_device_create(struct device *dev, uuid_le uuid, uint32_t instance,
if (ret)
goto create_failed;
- list_add(&mdev->next, &parent->mdev_list);
- mutex_unlock(&parent->mdev_list_lock);
-
dev_dbg(&mdev->dev, "MDEV: created\n");
return ret;
@@ -286,35 +257,19 @@ create_failed:
device_unregister(&mdev->dev);
create_err:
- mutex_unlock(&parent->mdev_list_lock);
return ret;
}
int mdev_device_destroy(struct device *dev, uuid_le uuid, uint32_t instance)
{
struct mdev_device *mdev;
- int ret;
struct parent_device *parent = dev_to_parent_dev(dev);
- mutex_lock(&parent->mdev_list_lock);
mdev = find_mdev_device(parent, uuid, instance);
- if (!mdev) {
- ret = -EINVAL;
- goto destroy_err;
- }
-
- ret = mdev_device_destroy_ops(mdev, false);
- if (ret)
- goto destroy_err;
-
- mutex_unlock(&parent->mdev_list_lock);
- mdev_put_device(mdev);
-
- return ret;
+ if (!mdev)
+ return -EINVAL;
-destroy_err:
- mutex_unlock(&parent->mdev_list_lock);
- return ret;
+ return __mdev_device_destroy(&mdev->dev, (void *)false);
}
int mdev_device_invalidate_mapping(struct mdev_device *mdev,
@@ -440,7 +395,6 @@ int mdev_device_start(struct device *dev, bool start)
struct mdev_device *mdev = dev_to_mdev(dev);
struct parent_device *parent = dev_to_parent_dev(dev->parent);
- mdev_get_device(mdev);
if (start && parent->ops->start)
ret = parent->ops->start(mdev->uuid);
else if (!start && parent->ops->stop)
@@ -452,8 +406,6 @@ int mdev_device_start(struct device *dev, bool start)
kobject_uevent(&mdev->dev.kobj,
start ? KOBJ_ONLINE : KOBJ_OFFLINE);
- mdev_put_device(mdev);
-
return ret;
}
@@ -215,17 +215,20 @@ int mdev_create_sysfs_files(struct device *dev)
ret = sysfs_create_file(&dev->kobj, &dev_attr_mdev_create.attr);
if (ret) {
pr_err("Failed to create mdev_create sysfs entry\n");
- goto create_sysfs_failed;
+ goto create_failed;
}
ret = sysfs_create_file(&dev->kobj, &dev_attr_mdev_destroy.attr);
if (ret) {
pr_err("Failed to create mdev_destroy sysfs entry\n");
- sysfs_remove_file(&dev->kobj, &dev_attr_mdev_create.attr);
- } else
- return ret;
+ goto destroy_failed;
+ }
-create_sysfs_failed:
+ return ret;
+
+destroy_failed:
+ sysfs_remove_file(&dev->kobj, &dev_attr_mdev_create.attr);
+create_failed:
sysfs_remove_file(&dev->kobj, &dev_attr_mdev_supported_types.attr);
return ret;
}
@@ -38,7 +38,8 @@ static int vfio_mpci_open(void *device_data)
{
int ret = 0;
struct vfio_mdev *vmdev = device_data;
- struct parent_device *parent = vmdev->mdev->parent;
+ struct mdev_device *mdev = vmdev->mdev;
+ struct parent_device *parent = dev_to_parent_dev(mdev->dev.parent);
if (!try_module_get(THIS_MODULE))
return -ENODEV;
@@ -83,7 +84,7 @@ static void vfio_mpci_close(void *device_data)
static u8 mpci_find_pci_capability(struct mdev_device *mdev, u8 capability)
{
loff_t pos = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_CONFIG_REGION_INDEX);
- struct parent_device *parent = mdev->parent;
+ struct parent_device *parent = dev_to_parent_dev(mdev->dev.parent);
u16 status;
u8 cap_ptr, cap_id = 0xff;
@@ -112,7 +113,7 @@ static int mpci_get_irq_count(struct vfio_mdev *vmdev, int irq_type)
{
loff_t pos = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_CONFIG_REGION_INDEX);
struct mdev_device *mdev = vmdev->mdev;
- struct parent_device *parent = mdev->parent;
+ struct parent_device *parent = dev_to_parent_dev(mdev->dev.parent);
if (irq_type == VFIO_PCI_INTX_IRQ_INDEX) {
u8 pin;
@@ -161,13 +162,14 @@ static long vfio_mpci_unlocked_ioctl(void *device_data,
{
int ret = 0;
struct vfio_mdev *vmdev = device_data;
+ struct mdev_device *mdev = vmdev->mdev;
+ struct parent_device *parent = dev_to_parent_dev(mdev->dev.parent);
unsigned long minsz;
switch (cmd) {
case VFIO_DEVICE_GET_INFO:
{
struct vfio_device_info info;
- struct parent_device *parent = vmdev->mdev->parent;
minsz = offsetofend(struct vfio_device_info, num_irqs);
@@ -258,8 +260,6 @@ static long vfio_mpci_unlocked_ioctl(void *device_data,
case VFIO_DEVICE_SET_IRQS:
{
struct vfio_irq_set hdr;
- struct mdev_device *mdev = vmdev->mdev;
- struct parent_device *parent = mdev->parent;
u8 *data = NULL, *ptr = NULL;
minsz = offsetofend(struct vfio_irq_set, count);
@@ -302,8 +302,6 @@ static long vfio_mpci_unlocked_ioctl(void *device_data,
}
case VFIO_DEVICE_RESET:
{
- struct parent_device *parent = vmdev->mdev->parent;
-
if (parent->ops->reset)
return parent->ops->reset(vmdev->mdev);
@@ -318,7 +316,7 @@ static ssize_t vfio_mpci_read(void *device_data, char __user *buf,
{
struct vfio_mdev *vmdev = device_data;
struct mdev_device *mdev = vmdev->mdev;
- struct parent_device *parent = mdev->parent;
+ struct parent_device *parent = dev_to_parent_dev(mdev->dev.parent);
int ret = 0;
if (!count)
@@ -351,7 +349,7 @@ static ssize_t vfio_mpci_write(void *device_data, const char __user *buf,
{
struct vfio_mdev *vmdev = device_data;
struct mdev_device *mdev = vmdev->mdev;
- struct parent_device *parent = mdev->parent;
+ struct parent_device *parent = dev_to_parent_dev(mdev->dev.parent);
int ret = 0;
if (!count)
@@ -390,7 +388,7 @@ static int mdev_dev_mmio_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
return -EINVAL;
mdev = vmdev->mdev;
- parent = mdev->parent;
+ parent = dev_to_parent_dev(mdev->dev.parent);
pg_prot = vma->vm_page_prot;
@@ -482,7 +480,7 @@ int vfio_mpci_probe(struct device *dev)
if (IS_ERR(vmdev))
return PTR_ERR(vmdev);
- vmdev->mdev = mdev_get_device(mdev);
+ vmdev->mdev = mdev;
vmdev->group = mdev->group;
mutex_init(&vmdev->vfio_mdev_lock);
@@ -490,7 +488,6 @@ int vfio_mpci_probe(struct device *dev)
if (ret)
kfree(vmdev);
- mdev_put_device(mdev);
return ret;
}
@@ -35,16 +35,12 @@ struct mdev_phys_mapping {
struct mdev_device {
struct device dev;
- struct parent_device *parent;
struct iommu_group *group;
uuid_le uuid;
uint32_t instance;
void *driver_data;
/* internal only */
- struct kref ref;
- struct list_head next;
-
struct mdev_phys_mapping phys_mappings;
};
@@ -157,15 +153,9 @@ struct parent_ops {
/*
* Parent Device
*/
-
struct parent_device {
struct device dev;
const struct parent_ops *ops;
-
- /* internal */
- struct list_head mdev_list;
- struct mutex mdev_list_lock;
- wait_queue_head_t release_done;
};
/**
@@ -212,14 +202,11 @@ extern struct bus_type mdev_bus_type;
extern int mdev_register_device(struct device *dev,
const struct parent_ops *ops);
-extern void mdev_unregister_device(struct parent_device *parent);
+extern void mdev_unregister_device(struct device *dev);
extern int mdev_register_driver(struct mdev_driver *drv, struct module *owner);
extern void mdev_unregister_driver(struct mdev_driver *drv);
-extern struct mdev_device *mdev_get_device(struct mdev_device *mdev);
-extern void mdev_put_device(struct mdev_device *mdev);
-
extern struct mdev_device *mdev_get_device_by_group(struct iommu_group *group);
extern int mdev_device_invalidate_mapping(struct mdev_device *mdev,