diff mbox series

[1/3] iommu/arm-smmu: Make instance lookup robust

Message ID 9d2ec624a640c421e97334deff537a2e899356c7.1731088789.git.robin.murphy@arm.com (mailing list archive)
State New, archived
Headers show
Series iommu/arm-smmu: Minor probe_device related improvements | expand

Commit Message

Robin Murphy Nov. 8, 2024, 6:30 p.m. UTC
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 that code is also a perfect excuse to give it a little
dev_err_probe() tidyup as well.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---

This should in theory replace 229e6ee43d2a ("iommu/arm-smmu: Defer
probe of clients after smmu device bound"), or at least allow it to be
reverted going forward.

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  4 +--
 drivers/iommu/arm/arm-smmu/arm-smmu.c       | 31 ++++++++++-----------
 2 files changed, 16 insertions(+), 19 deletions(-)

Comments

Will Deacon Nov. 12, 2024, 3:43 p.m. UTC | #1
On Fri, Nov 08, 2024 at 06:30:15PM +0000, Robin Murphy wrote:
> 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 that code is also a perfect excuse to give it a little
> dev_err_probe() tidyup as well.
> 
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> ---
> 
> This should in theory replace 229e6ee43d2a ("iommu/arm-smmu: Defer
> probe of clients after smmu device bound"), or at least allow it to be
> reverted going forward.

Let's revert that as part of this series, then?

>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  4 +--
>  drivers/iommu/arm/arm-smmu/arm-smmu.c       | 31 ++++++++++-----------
>  2 files changed, 16 insertions(+), 19 deletions(-)

[...]

> @@ -2255,6 +2240,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");

Why is dev_err_probe() better here? I've not seen it before, so I was
trying to figure out what it does. It mainly looks to be handling
the EPROBE_DEFER case, but after your other changes to use
bus_find_device_by_fwnode() I'm wondering whether we actually hit that
(particularly in iommu_device_sysfs_add())?

I'm not saying there's a problem, just that I'm not sure why
dev_err_probe() is tidier than dev_err().

Will
Robin Murphy Nov. 12, 2024, 4:05 p.m. UTC | #2
On 12/11/2024 3:43 pm, Will Deacon wrote:
> On Fri, Nov 08, 2024 at 06:30:15PM +0000, Robin Murphy wrote:
>> 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 that code is also a perfect excuse to give it a little
>> dev_err_probe() tidyup as well.
>>
>> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
>> ---
>>
>> This should in theory replace 229e6ee43d2a ("iommu/arm-smmu: Defer
>> probe of clients after smmu device bound"), or at least allow it to be
>> reverted going forward.
> 
> Let's revert that as part of this series, then?

Sure, at time of posting I wasn't entirely sure where we'd stand on 
replace vs. revert (TBH I'd lost track and didn't even realise we're at 
rc7 already...)

>>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  4 +--
>>   drivers/iommu/arm/arm-smmu/arm-smmu.c       | 31 ++++++++++-----------
>>   2 files changed, 16 insertions(+), 19 deletions(-)
> 
> [...]
> 
>> @@ -2255,6 +2240,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");
> 
> Why is dev_err_probe() better here? I've not seen it before, so I was
> trying to figure out what it does. It mainly looks to be handling
> the EPROBE_DEFER case, but after your other changes to use
> bus_find_device_by_fwnode() I'm wondering whether we actually hit that
> (particularly in iommu_device_sysfs_add())?
> 
> I'm not saying there's a problem, just that I'm not sure why
> dev_err_probe() is tidier than dev_err().

Just that it's more concise and convenient, and as such becoming an 
established pattern for returning errors from driver probe routines, 
even in cases which don't defer.

Cheers,
Robin.
diff mbox series

Patch

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 737c5b882355..b7dcb1494aa4 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3171,8 +3171,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;
 }
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 8321962b3714..aba315aa6848 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -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;
 }
@@ -2232,21 +2232,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 */
@@ -2255,6 +2240,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()