]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommu/arm-smmu: Make instance lookup robust
authorRobin Murphy <robin.murphy@arm.com>
Thu, 5 Dec 2024 16:33:55 +0000 (16:33 +0000)
committerWill Deacon <will@kernel.org>
Mon, 9 Dec 2024 22:46:53 +0000 (22:46 +0000)
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>
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
drivers/iommu/arm/arm-smmu/arm-smmu.c

index 45e87ce4b973ef6fbfecdd27d6497b4fd888829d..dbacf8986fa764c3c1083eb01c6b17a9bd312206 100644 (file)
@@ -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;
 }
index 650664e0f6e3ff4cf8a2bf212af8cff14470367a..0949f2734e5de71efbac80f828ad496aca52fa9b 100644 (file)
@@ -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,29 +2227,26 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
                                        i, irq);
        }
 
+       platform_set_drvdata(pdev, smmu);
+
+       /* Check for RMRs and install bypass SMRs if any */
+       arm_smmu_rmr_install_bypass_smr(smmu);
+
+       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) {
-               dev_err(dev, "Failed to register iommu in sysfs\n");
-               return err;
-       }
+       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) {
-               dev_err(dev, "Failed to register iommu\n");
                iommu_device_sysfs_remove(&smmu->iommu);
-               return err;
+               return dev_err_probe(dev, err, "Failed to register iommu\n");
        }
 
-       platform_set_drvdata(pdev, smmu);
-
-       /* Check for RMRs and install bypass SMRs if any */
-       arm_smmu_rmr_install_bypass_smr(smmu);
-
-       arm_smmu_device_reset(smmu);
-       arm_smmu_test_smr_masks(smmu);
-
        /*
         * We want to avoid touching dev->power.lock in fastpaths unless
         * it's really going to do something useful - pm_runtime_enabled()