]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/iommu/iommu.c
Merge branches 'iommu/fixes', 'arm/exynos', 'arm/renesas', 'arm/smmu', 'arm/mediatek...
[mirror_ubuntu-bionic-kernel.git] / drivers / iommu / iommu.c
index c37d701ddaa2bf9683ca14b065163586cedb4c3e..8ea14f41a979fd4e72e3a6093e5fa8d2a0eff24a 100644 (file)
@@ -55,7 +55,7 @@ struct iommu_group {
        struct iommu_domain *domain;
 };
 
-struct iommu_device {
+struct group_device {
        struct list_head list;
        struct device *dev;
        char *name;
@@ -83,6 +83,25 @@ struct iommu_group_attribute iommu_group_attr_##_name =              \
 #define to_iommu_group(_kobj)          \
        container_of(_kobj, struct iommu_group, kobj)
 
+static LIST_HEAD(iommu_device_list);
+static DEFINE_SPINLOCK(iommu_device_lock);
+
+int iommu_device_register(struct iommu_device *iommu)
+{
+       spin_lock(&iommu_device_lock);
+       list_add_tail(&iommu->list, &iommu_device_list);
+       spin_unlock(&iommu_device_lock);
+
+       return 0;
+}
+
+void iommu_device_unregister(struct iommu_device *iommu)
+{
+       spin_lock(&iommu_device_lock);
+       list_del(&iommu->list);
+       spin_unlock(&iommu_device_lock);
+}
+
 static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
                                                 unsigned type);
 static int __iommu_attach_device(struct iommu_domain *domain,
@@ -218,7 +237,7 @@ iommu_insert_device_resv_regions(struct list_head *dev_resv_regions,
 int iommu_get_group_resv_regions(struct iommu_group *group,
                                 struct list_head *head)
 {
-       struct iommu_device *device;
+       struct group_device *device;
        int ret = 0;
 
        mutex_lock(&group->mutex);
@@ -511,7 +530,7 @@ out:
 int iommu_group_add_device(struct iommu_group *group, struct device *dev)
 {
        int ret, i = 0;
-       struct iommu_device *device;
+       struct group_device *device;
 
        device = kzalloc(sizeof(*device), GFP_KERNEL);
        if (!device)
@@ -520,36 +539,30 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
        device->dev = dev;
 
        ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group");
-       if (ret) {
-               kfree(device);
-               return ret;
-       }
+       if (ret)
+               goto err_free_device;
 
        device->name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj));
 rename:
        if (!device->name) {
-               sysfs_remove_link(&dev->kobj, "iommu_group");
-               kfree(device);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err_remove_link;
        }
 
        ret = sysfs_create_link_nowarn(group->devices_kobj,
                                       &dev->kobj, device->name);
        if (ret) {
-               kfree(device->name);
                if (ret == -EEXIST && i >= 0) {
                        /*
                         * Account for the slim chance of collision
                         * and append an instance to the name.
                         */
+                       kfree(device->name);
                        device->name = kasprintf(GFP_KERNEL, "%s.%d",
                                                 kobject_name(&dev->kobj), i++);
                        goto rename;
                }
-
-               sysfs_remove_link(&dev->kobj, "iommu_group");
-               kfree(device);
-               return ret;
+               goto err_free_name;
        }
 
        kobject_get(group->devices_kobj);
@@ -561,8 +574,10 @@ rename:
        mutex_lock(&group->mutex);
        list_add_tail(&device->list, &group->devices);
        if (group->domain)
-               __iommu_attach_device(group->domain, dev);
+               ret = __iommu_attach_device(group->domain, dev);
        mutex_unlock(&group->mutex);
+       if (ret)
+               goto err_put_group;
 
        /* Notify any listeners about change to group. */
        blocking_notifier_call_chain(&group->notifier,
@@ -573,6 +588,21 @@ rename:
        pr_info("Adding device %s to group %d\n", dev_name(dev), group->id);
 
        return 0;
+
+err_put_group:
+       mutex_lock(&group->mutex);
+       list_del(&device->list);
+       mutex_unlock(&group->mutex);
+       dev->iommu_group = NULL;
+       kobject_put(group->devices_kobj);
+err_free_name:
+       kfree(device->name);
+err_remove_link:
+       sysfs_remove_link(&dev->kobj, "iommu_group");
+err_free_device:
+       kfree(device);
+       pr_err("Failed to add device %s to group %d: %d\n", dev_name(dev), group->id, ret);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(iommu_group_add_device);
 
@@ -586,7 +616,7 @@ EXPORT_SYMBOL_GPL(iommu_group_add_device);
 void iommu_group_remove_device(struct device *dev)
 {
        struct iommu_group *group = dev->iommu_group;
-       struct iommu_device *tmp_device, *device = NULL;
+       struct group_device *tmp_device, *device = NULL;
 
        pr_info("Removing device %s from group %d\n", dev_name(dev), group->id);
 
@@ -621,7 +651,7 @@ EXPORT_SYMBOL_GPL(iommu_group_remove_device);
 
 static int iommu_group_device_count(struct iommu_group *group)
 {
-       struct iommu_device *entry;
+       struct group_device *entry;
        int ret = 0;
 
        list_for_each_entry(entry, &group->devices, list)
@@ -644,7 +674,7 @@ static int iommu_group_device_count(struct iommu_group *group)
 static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
                                      int (*fn)(struct device *, void *))
 {
-       struct iommu_device *device;
+       struct group_device *device;
        int ret = 0;
 
        list_for_each_entry(device, &group->devices, list) {
@@ -1783,43 +1813,18 @@ out:
        return ret;
 }
 
-struct iommu_instance {
-       struct list_head list;
-       struct fwnode_handle *fwnode;
-       const struct iommu_ops *ops;
-};
-static LIST_HEAD(iommu_instance_list);
-static DEFINE_SPINLOCK(iommu_instance_lock);
-
-void iommu_register_instance(struct fwnode_handle *fwnode,
-                            const struct iommu_ops *ops)
-{
-       struct iommu_instance *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
-
-       if (WARN_ON(!iommu))
-               return;
-
-       of_node_get(to_of_node(fwnode));
-       INIT_LIST_HEAD(&iommu->list);
-       iommu->fwnode = fwnode;
-       iommu->ops = ops;
-       spin_lock(&iommu_instance_lock);
-       list_add_tail(&iommu->list, &iommu_instance_list);
-       spin_unlock(&iommu_instance_lock);
-}
-
-const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode)
+const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode)
 {
-       struct iommu_instance *instance;
        const struct iommu_ops *ops = NULL;
+       struct iommu_device *iommu;
 
-       spin_lock(&iommu_instance_lock);
-       list_for_each_entry(instance, &iommu_instance_list, list)
-               if (instance->fwnode == fwnode) {
-                       ops = instance->ops;
+       spin_lock(&iommu_device_lock);
+       list_for_each_entry(iommu, &iommu_device_list, list)
+               if (iommu->fwnode == fwnode) {
+                       ops = iommu->ops;
                        break;
                }
-       spin_unlock(&iommu_instance_lock);
+       spin_unlock(&iommu_device_lock);
        return ops;
 }