iommu/of: Refactor of_iommu_configure() for error handling
authorRobin Murphy <robin.murphy@arm.com>
Mon, 10 Apr 2017 11:20:56 +0000 (16:50 +0530)
committerJoerg Roedel <jroedel@suse.de>
Thu, 20 Apr 2017 14:31:05 +0000 (16:31 +0200)
In preparation for some upcoming cleverness, rework the control flow in
of_iommu_configure() to minimise duplication and improve the propogation
of errors. It's also as good a time as any to switch over from the
now-just-a-compatibility-wrapper of_iommu_get_ops() to using the generic
IOMMU instance interface directly.

Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/of_iommu.c

index 2683e9fc0dcf5cc0886034b7fccafb8861d958f1..8f4e59985f6ec81bf5db1220703e357c67db3c89 100644 (file)
@@ -96,6 +96,28 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
 }
 EXPORT_SYMBOL_GPL(of_get_dma_window);
 
+static const struct iommu_ops
+*of_iommu_xlate(struct device *dev, struct of_phandle_args *iommu_spec)
+{
+       const struct iommu_ops *ops;
+       struct fwnode_handle *fwnode = &iommu_spec->np->fwnode;
+       int err;
+
+       ops = iommu_ops_from_fwnode(fwnode);
+       if (!ops || !ops->of_xlate)
+               return NULL;
+
+       err = iommu_fwspec_init(dev, &iommu_spec->np->fwnode, ops);
+       if (err)
+               return ERR_PTR(err);
+
+       err = ops->of_xlate(dev, iommu_spec);
+       if (err)
+               return ERR_PTR(err);
+
+       return ops;
+}
+
 static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
 {
        struct of_phandle_args *iommu_spec = data;
@@ -105,10 +127,11 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
 }
 
 static const struct iommu_ops
-*of_pci_iommu_configure(struct pci_dev *pdev, struct device_node *bridge_np)
+*of_pci_iommu_init(struct pci_dev *pdev, struct device_node *bridge_np)
 {
        const struct iommu_ops *ops;
        struct of_phandle_args iommu_spec;
+       int err;
 
        /*
         * Start by tracing the RID alias down the PCI topology as
@@ -123,56 +146,56 @@ static const struct iommu_ops
         * bus into the system beyond, and which IOMMU it ends up at.
         */
        iommu_spec.np = NULL;
-       if (of_pci_map_rid(bridge_np, iommu_spec.args[0], "iommu-map",
-                          "iommu-map-mask", &iommu_spec.np, iommu_spec.args))
-               return NULL;
+       err = of_pci_map_rid(bridge_np, iommu_spec.args[0], "iommu-map",
+                            "iommu-map-mask", &iommu_spec.np,
+                            iommu_spec.args);
+       if (err)
+               return err == -ENODEV ? NULL : ERR_PTR(err);
 
-       ops = iommu_ops_from_fwnode(&iommu_spec.np->fwnode);
-       if (!ops || !ops->of_xlate ||
-           iommu_fwspec_init(&pdev->dev, &iommu_spec.np->fwnode, ops) ||
-           ops->of_xlate(&pdev->dev, &iommu_spec))
-               ops = NULL;
+       ops = of_iommu_xlate(&pdev->dev, &iommu_spec);
 
        of_node_put(iommu_spec.np);
        return ops;
 }
 
-const struct iommu_ops *of_iommu_configure(struct device *dev,
-                                          struct device_node *master_np)
+static const struct iommu_ops
+*of_platform_iommu_init(struct device *dev, struct device_node *np)
 {
        struct of_phandle_args iommu_spec;
-       struct device_node *np;
        const struct iommu_ops *ops = NULL;
        int idx = 0;
 
-       if (dev_is_pci(dev))
-               return of_pci_iommu_configure(to_pci_dev(dev), master_np);
-
        /*
         * We don't currently walk up the tree looking for a parent IOMMU.
         * See the `Notes:' section of
         * Documentation/devicetree/bindings/iommu/iommu.txt
         */
-       while (!of_parse_phandle_with_args(master_np, "iommus",
-                                          "#iommu-cells", idx,
-                                          &iommu_spec)) {
-               np = iommu_spec.np;
-               ops = iommu_ops_from_fwnode(&np->fwnode);
-
-               if (!ops || !ops->of_xlate ||
-                   iommu_fwspec_init(dev, &np->fwnode, ops) ||
-                   ops->of_xlate(dev, &iommu_spec))
-                       goto err_put_node;
-
-               of_node_put(np);
+       while (!of_parse_phandle_with_args(np, "iommus", "#iommu-cells",
+                                          idx, &iommu_spec)) {
+               ops = of_iommu_xlate(dev, &iommu_spec);
+               of_node_put(iommu_spec.np);
                idx++;
+               if (IS_ERR_OR_NULL(ops))
+                       break;
        }
 
        return ops;
+}
+
+const struct iommu_ops *of_iommu_configure(struct device *dev,
+                                          struct device_node *master_np)
+{
+       const struct iommu_ops *ops;
+
+       if (!master_np)
+               return NULL;
+
+       if (dev_is_pci(dev))
+               ops = of_pci_iommu_init(to_pci_dev(dev), master_np);
+       else
+               ops = of_platform_iommu_init(dev, master_np);
 
-err_put_node:
-       of_node_put(np);
-       return NULL;
+       return IS_ERR(ops) ? NULL : ops;
 }
 
 static int __init of_iommu_init(void)