|
@@ -543,6 +543,14 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
|
|
|
const struct iommu_ops *ops = NULL;
|
|
|
int ret = -ENODEV;
|
|
|
struct fwnode_handle *iort_fwnode;
|
|
|
+ struct iommu_fwspec *fwspec = dev->iommu_fwspec;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we already translated the fwspec there
|
|
|
+ * is nothing left to do, return the iommu_ops.
|
|
|
+ */
|
|
|
+ if (fwspec && fwspec->ops)
|
|
|
+ return fwspec->ops;
|
|
|
|
|
|
if (node) {
|
|
|
iort_fwnode = iort_get_fwnode(node);
|
|
@@ -550,8 +558,17 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
|
|
|
return NULL;
|
|
|
|
|
|
ops = iommu_ops_from_fwnode(iort_fwnode);
|
|
|
+ /*
|
|
|
+ * If the ops look-up fails, this means that either
|
|
|
+ * the SMMU drivers have not been probed yet or that
|
|
|
+ * the SMMU drivers are not built in the kernel;
|
|
|
+ * Depending on whether the SMMU drivers are built-in
|
|
|
+ * in the kernel or not, defer the IOMMU configuration
|
|
|
+ * or just abort it.
|
|
|
+ */
|
|
|
if (!ops)
|
|
|
- return NULL;
|
|
|
+ return iort_iommu_driver_enabled(node->type) ?
|
|
|
+ ERR_PTR(-EPROBE_DEFER) : NULL;
|
|
|
|
|
|
ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
|
|
|
}
|
|
@@ -625,12 +642,26 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
|
|
|
|
|
|
while (parent) {
|
|
|
ops = iort_iommu_xlate(dev, parent, streamid);
|
|
|
+ if (IS_ERR_OR_NULL(ops))
|
|
|
+ return ops;
|
|
|
|
|
|
parent = iort_node_get_id(node, &streamid,
|
|
|
IORT_IOMMU_TYPE, i++);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * If we have reason to believe the IOMMU driver missed the initial
|
|
|
+ * add_device callback for dev, replay it to get things in order.
|
|
|
+ */
|
|
|
+ if (!IS_ERR_OR_NULL(ops) && ops->add_device &&
|
|
|
+ dev->bus && !dev->iommu_group) {
|
|
|
+ int err = ops->add_device(dev);
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ ops = ERR_PTR(err);
|
|
|
+ }
|
|
|
+
|
|
|
return ops;
|
|
|
}
|
|
|
|