]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/iommu/iommu.c
iommu: Clean up after a failed bus initialization
[karo-tx-linux.git] / drivers / iommu / iommu.c
index d4f527e5667936454bfb49e01db931703b180e73..f0e0a233c902efb13f030bad471f9f5774a832e3 100644 (file)
@@ -16,7 +16,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#define pr_fmt(fmt)    "%s: " fmt, __func__
+#define pr_fmt(fmt)    "iommu: " fmt
 
 #include <linux/device.h>
 #include <linux/kernel.h>
@@ -128,6 +128,8 @@ static void iommu_group_release(struct kobject *kobj)
 {
        struct iommu_group *group = to_iommu_group(kobj);
 
+       pr_debug("Releasing group %d\n", group->id);
+
        if (group->iommu_data_release)
                group->iommu_data_release(group->iommu_data);
 
@@ -207,6 +209,8 @@ again:
         */
        kobject_put(&group->kobj);
 
+       pr_debug("Allocated group %d\n", group->id);
+
        return group;
 }
 EXPORT_SYMBOL_GPL(iommu_group_alloc);
@@ -372,6 +376,9 @@ rename:
                                     IOMMU_GROUP_NOTIFY_ADD_DEVICE, dev);
 
        trace_add_device_to_group(group->id, dev);
+
+       pr_info("Adding device %s to group %d\n", dev_name(dev), group->id);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(iommu_group_add_device);
@@ -388,6 +395,8 @@ void iommu_group_remove_device(struct device *dev)
        struct iommu_group *group = dev->iommu_group;
        struct iommu_device *tmp_device, *device = NULL;
 
+       pr_info("Removing device %s from group %d\n", dev_name(dev), group->id);
+
        /* Pre-notify listeners that a device is being removed. */
        blocking_notifier_call_chain(&group->notifier,
                                     IOMMU_GROUP_NOTIFY_DEL_DEVICE, dev);
@@ -741,7 +750,16 @@ static int add_iommu_group(struct device *dev, void *data)
 
        WARN_ON(dev->iommu_group);
 
-       ops->add_device(dev);
+       return ops->add_device(dev);
+}
+
+static int remove_iommu_group(struct device *dev, void *data)
+{
+       struct iommu_callback_data *cb = data;
+       const struct iommu_ops *ops = cb->ops;
+
+       if (ops->remove_device && dev->iommu_group)
+               ops->remove_device(dev);
 
        return 0;
 }
@@ -814,19 +832,25 @@ static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops)
        nb->notifier_call = iommu_bus_notifier;
 
        err = bus_register_notifier(bus, nb);
-       if (err) {
-               kfree(nb);
-               return err;
-       }
+       if (err)
+               goto out_free;
 
        err = bus_for_each_dev(bus, NULL, &cb, add_iommu_group);
-       if (err) {
-               bus_unregister_notifier(bus, nb);
-               kfree(nb);
-               return err;
-       }
+       if (err)
+               goto out_err;
+
 
        return 0;
+
+out_err:
+       /* Clean up */
+       bus_for_each_dev(bus, NULL, &cb, remove_iommu_group);
+       bus_unregister_notifier(bus, nb);
+
+out_free:
+       kfree(nb);
+
+       return err;
 }
 
 /**