Skip to content

Commit

Permalink
iommu/of: Prepare for deferred IOMMU configuration
Browse files Browse the repository at this point in the history
IOMMU configuration represents unchanging properties of the hardware,
and as such should only need happen once in a device's lifetime, but
the necessary interaction with the IOMMU device and driver complicates
exactly when that point should be.

Since the only reasonable tool available for handling the inter-device
dependency is probe deferral, we need to prepare of_iommu_configure()
to run later than it is currently called (i.e. at driver probe rather
than device creation), to handle being retried, and to tell whether a
not-yet present IOMMU should be waited for or skipped (by virtue of
having declared a built-in driver or not).

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>
  • Loading branch information
Robin Murphy authored and Joerg Roedel committed Apr 20, 2017
1 parent 2a0c575 commit d7b0558
Showing 1 changed file with 42 additions and 1 deletion.
43 changes: 42 additions & 1 deletion drivers/iommu/of_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
}
EXPORT_SYMBOL_GPL(of_get_dma_window);

static bool of_iommu_driver_present(struct device_node *np)
{
/*
* If the IOMMU still isn't ready by the time we reach init, assume
* it never will be. We don't want to defer indefinitely, nor attempt
* to dereference __iommu_of_table after it's been freed.
*/
if (system_state > SYSTEM_BOOTING)
return false;

return of_match_node(&__iommu_of_table, np);
}

static const struct iommu_ops
*of_iommu_xlate(struct device *dev, struct of_phandle_args *iommu_spec)
{
Expand All @@ -104,12 +117,20 @@ static const struct iommu_ops
int err;

ops = iommu_ops_from_fwnode(fwnode);
if (!ops || !ops->of_xlate)
if ((ops && !ops->of_xlate) ||
(!ops && !of_iommu_driver_present(iommu_spec->np)))
return NULL;

err = iommu_fwspec_init(dev, &iommu_spec->np->fwnode, ops);
if (err)
return ERR_PTR(err);
/*
* The otherwise-empty fwspec handily serves to indicate the specific
* IOMMU device we're waiting for, which will be useful if we ever get
* a proper probe-ordering dependency mechanism in future.
*/
if (!ops)
return ERR_PTR(-EPROBE_DEFER);

err = ops->of_xlate(dev, iommu_spec);
if (err)
Expand Down Expand Up @@ -186,14 +207,34 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
struct device_node *master_np)
{
const struct iommu_ops *ops;
struct iommu_fwspec *fwspec = dev->iommu_fwspec;

if (!master_np)
return NULL;

if (fwspec) {
if (fwspec->ops)
return fwspec->ops;

/* In the deferred case, start again from scratch */
iommu_fwspec_free(dev);
}

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);
/*
* 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 IS_ERR(ops) ? NULL : ops;
}
Expand Down

0 comments on commit d7b0558

Please sign in to comment.