diff options
author | Robin Murphy <robin.murphy@arm.com> | 2017-04-10 07:20:56 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2017-04-20 10:31:05 -0400 |
commit | 2a0c57545a291f257cd231b1c4b18285b84608d8 (patch) | |
tree | 2417db9a9b8d8f16cc20586d8113a5aeca656939 | |
parent | 5016bdb796b3726eec043ca0ce3be981f712c756 (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.c | 83 |
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 | } |
97 | EXPORT_SYMBOL_GPL(of_get_dma_window); | 97 | EXPORT_SYMBOL_GPL(of_get_dma_window); |
98 | 98 | ||
99 | static 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 | |||
99 | static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data) | 121 | static 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 | ||
107 | static const struct iommu_ops | 129 | static 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 | ||
140 | const struct iommu_ops *of_iommu_configure(struct device *dev, | 161 | static 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 | |||
185 | const 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 | ||
173 | err_put_node: | 198 | return IS_ERR(ops) ? NULL : ops; |
174 | of_node_put(np); | ||
175 | return NULL; | ||
176 | } | 199 | } |
177 | 200 | ||
178 | static int __init of_iommu_init(void) | 201 | static int __init of_iommu_init(void) |