mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-08-26 01:02:46 +00:00
iommu/arm-smmu: Make instance lookup robust
Relying on the driver list was a cute idea for minimising the scope of our SMMU device lookups, however it turns out to have a subtle flaw. The SMMU device only gets added to that list after arm_smmu_device_probe() returns success, so there's actually no way the iommu_device_register() call from there could ever work as intended, even if it wasn't already hampered by the fwspec setup not happening early enough. Switch both arm_smmu_get_by_fwnode() implementations to use a platform bus lookup instead, which *will* reliably work. Also make sure that we don't register SMMUv2 instances until we've fully initialised them, to avoid similar consequences of the lookup now finding a device with no drvdata. Moving the error returns is also a perfect excuse to streamline them with dev_err_probe() in the process. Signed-off-by: Robin Murphy <robin.murphy@arm.com> Link: https://lore.kernel.org/r/6d7ce1dc31873abdb75c895fb8bd2097cce098b4.1733406914.git.robin.murphy@arm.com Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
9b640ae7fb
commit
7d835134d4
@ -3351,8 +3351,8 @@ static struct platform_driver arm_smmu_driver;
|
||||
static
|
||||
struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct device *dev = driver_find_device_by_fwnode(&arm_smmu_driver.driver,
|
||||
fwnode);
|
||||
struct device *dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode);
|
||||
|
||||
put_device(dev);
|
||||
return dev ? dev_get_drvdata(dev) : NULL;
|
||||
}
|
||||
|
@ -1411,8 +1411,8 @@ static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap)
|
||||
static
|
||||
struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct device *dev = driver_find_device_by_fwnode(&arm_smmu_driver.driver,
|
||||
fwnode);
|
||||
struct device *dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode);
|
||||
|
||||
put_device(dev);
|
||||
return dev ? dev_get_drvdata(dev) : NULL;
|
||||
}
|
||||
@ -2227,21 +2227,6 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
||||
i, irq);
|
||||
}
|
||||
|
||||
err = iommu_device_sysfs_add(&smmu->iommu, smmu->dev, NULL,
|
||||
"smmu.%pa", &smmu->ioaddr);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to register iommu in sysfs\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = iommu_device_register(&smmu->iommu, &arm_smmu_ops,
|
||||
using_legacy_binding ? NULL : dev);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to register iommu\n");
|
||||
iommu_device_sysfs_remove(&smmu->iommu);
|
||||
return err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, smmu);
|
||||
|
||||
/* Check for RMRs and install bypass SMRs if any */
|
||||
@ -2250,6 +2235,18 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
||||
arm_smmu_device_reset(smmu);
|
||||
arm_smmu_test_smr_masks(smmu);
|
||||
|
||||
err = iommu_device_sysfs_add(&smmu->iommu, smmu->dev, NULL,
|
||||
"smmu.%pa", &smmu->ioaddr);
|
||||
if (err)
|
||||
return dev_err_probe(dev, err, "Failed to register iommu in sysfs\n");
|
||||
|
||||
err = iommu_device_register(&smmu->iommu, &arm_smmu_ops,
|
||||
using_legacy_binding ? NULL : dev);
|
||||
if (err) {
|
||||
iommu_device_sysfs_remove(&smmu->iommu);
|
||||
return dev_err_probe(dev, err, "Failed to register iommu\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to avoid touching dev->power.lock in fastpaths unless
|
||||
* it's really going to do something useful - pm_runtime_enabled()
|
||||
|
Loading…
Reference in New Issue
Block a user