aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Murphy <robin.murphy@arm.com>2017-04-10 07:20:56 -0400
committerJoerg Roedel <jroedel@suse.de>2017-04-20 10:31:05 -0400
commit2a0c57545a291f257cd231b1c4b18285b84608d8 (patch)
tree2417db9a9b8d8f16cc20586d8113a5aeca656939
parent5016bdb796b3726eec043ca0ce3be981f712c756 (diff)
iommu/of: Refactor of_iommu_configure() for error handling
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>
-rw-r--r--drivers/iommu/of_iommu.c83
1 files changed, 53 insertions, 30 deletions
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 2683e9fc0dcf..8f4e59985f6e 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -96,6 +96,28 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
96} 96}
97EXPORT_SYMBOL_GPL(of_get_dma_window); 97EXPORT_SYMBOL_GPL(of_get_dma_window);
98 98
99static const struct iommu_ops
100*of_iommu_xlate(struct device *dev, struct of_phandle_args *iommu_spec)
101{
102 const struct iommu_ops *ops;
103 struct fwnode_handle *fwnode = &iommu_spec->np->fwnode;
104 int err;
105
106 ops = iommu_ops_from_fwnode(fwnode);
107 if (!ops || !ops->of_xlate)
108 return NULL;
109
110 err = iommu_fwspec_init(dev, &iommu_spec->np->fwnode, ops);
111 if (err)
112 return ERR_PTR(err);
113
114 err = ops->of_xlate(dev, iommu_spec);
115 if (err)
116 return ERR_PTR(err);
117
118 return ops;
119}
120
99static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data) 121static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
100{ 122{
101 struct of_phandle_args *iommu_spec = data; 123 struct of_phandle_args *iommu_spec = data;
@@ -105,10 +127,11 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
105} 127}
106 128
107static const struct iommu_ops 129static const struct iommu_ops
108*of_pci_iommu_configure(struct pci_dev *pdev, struct device_node *bridge_np) 130*of_pci_iommu_init(struct pci_dev *pdev, struct device_node *bridge_np)
109{ 131{
110 const struct iommu_ops *ops; 132 const struct iommu_ops *ops;
111 struct of_phandle_args iommu_spec; 133 struct of_phandle_args iommu_spec;
134 int err;
112 135
113 /* 136 /*
114 * Start by tracing the RID alias down the PCI topology as 137 * Start by tracing the RID alias down the PCI topology as
@@ -123,56 +146,56 @@ static const struct iommu_ops
123 * bus into the system beyond, and which IOMMU it ends up at. 146 * bus into the system beyond, and which IOMMU it ends up at.
124 */ 147 */
125 iommu_spec.np = NULL; 148 iommu_spec.np = NULL;
126 if (of_pci_map_rid(bridge_np, iommu_spec.args[0], "iommu-map", 149 err = of_pci_map_rid(bridge_np, iommu_spec.args[0], "iommu-map",
127 "iommu-map-mask", &iommu_spec.np, iommu_spec.args)) 150 "iommu-map-mask", &iommu_spec.np,
128 return NULL; 151 iommu_spec.args);
152 if (err)
153 return err == -ENODEV ? NULL : ERR_PTR(err);
129 154
130 ops = iommu_ops_from_fwnode(&iommu_spec.np->fwnode); 155 ops = of_iommu_xlate(&pdev->dev, &iommu_spec);
131 if (!ops || !ops->of_xlate ||
132 iommu_fwspec_init(&pdev->dev, &iommu_spec.np->fwnode, ops) ||
133 ops->of_xlate(&pdev->dev, &iommu_spec))
134 ops = NULL;
135 156
136 of_node_put(iommu_spec.np); 157 of_node_put(iommu_spec.np);
137 return ops; 158 return ops;
138} 159}
139 160
140const struct iommu_ops *of_iommu_configure(struct device *dev, 161static const struct iommu_ops
141 struct device_node *master_np) 162*of_platform_iommu_init(struct device *dev, struct device_node *np)
142{ 163{
143 struct of_phandle_args iommu_spec; 164 struct of_phandle_args iommu_spec;
144 struct device_node *np;
145 const struct iommu_ops *ops = NULL; 165 const struct iommu_ops *ops = NULL;
146 int idx = 0; 166 int idx = 0;
147 167
148 if (dev_is_pci(dev))
149 return of_pci_iommu_configure(to_pci_dev(dev), master_np);
150
151 /* 168 /*
152 * We don't currently walk up the tree looking for a parent IOMMU. 169 * We don't currently walk up the tree looking for a parent IOMMU.
153 * See the `Notes:' section of 170 * See the `Notes:' section of
154 * Documentation/devicetree/bindings/iommu/iommu.txt 171 * Documentation/devicetree/bindings/iommu/iommu.txt
155 */ 172 */
156 while (!of_parse_phandle_with_args(master_np, "iommus", 173 while (!of_parse_phandle_with_args(np, "iommus", "#iommu-cells",
157 "#iommu-cells", idx, 174 idx, &iommu_spec)) {
158 &iommu_spec)) { 175 ops = of_iommu_xlate(dev, &iommu_spec);
159 np = iommu_spec.np; 176 of_node_put(iommu_spec.np);
160 ops = iommu_ops_from_fwnode(&np->fwnode);
161
162 if (!ops || !ops->of_xlate ||
163 iommu_fwspec_init(dev, &np->fwnode, ops) ||
164 ops->of_xlate(dev, &iommu_spec))
165 goto err_put_node;
166
167 of_node_put(np);
168 idx++; 177 idx++;
178 if (IS_ERR_OR_NULL(ops))
179 break;
169 } 180 }
170 181
171 return ops; 182 return ops;
183}
184
185const struct iommu_ops *of_iommu_configure(struct device *dev,
186 struct device_node *master_np)
187{
188 const struct iommu_ops *ops;
189
190 if (!master_np)
191 return NULL;
192
193 if (dev_is_pci(dev))
194 ops = of_pci_iommu_init(to_pci_dev(dev), master_np);
195 else
196 ops = of_platform_iommu_init(dev, master_np);
172 197
173err_put_node: 198 return IS_ERR(ops) ? NULL : ops;
174 of_node_put(np);
175 return NULL;
176} 199}
177 200
178static int __init of_iommu_init(void) 201static int __init of_iommu_init(void)