drivers/iommu/apple-dart.c | 2 ++ drivers/iommu/arm/arm-smmu/qcom_iommu.c | 10 +++----- drivers/iommu/exynos-iommu.c | 9 +++---- drivers/iommu/ipmmu-vmsa.c | 2 ++ drivers/iommu/mtk_iommu.c | 33 +++++++++++++++++-------- drivers/iommu/mtk_iommu_v1.c | 28 +++++++++++++++++---- drivers/iommu/omap-iommu.c | 32 +++++++++++++++--------- drivers/iommu/sun50i-iommu.c | 2 ++ drivers/iommu/tegra-smmu.c | 5 ++-- 9 files changed, 81 insertions(+), 42 deletions(-)
This series fixes device leaks in the iommu drivers, which pretty consistently failed to drop the reference taken by of_find_device_by_node() when looking up iommu platform devices. Included are also a couple of related cleanups. Johan Johan Hovold (14): iommu/apple-dart: fix device leak on of_xlate() iommu/qcom: fix device leak on of_xlate() iommu/exynos: fix device leak on of_xlate() iommu/ipmmu-vmsa: fix device leak on of_xlate() iommu/mediatek: fix device leak on of_xlate() iommu/mediatek: fix device leaks on probe() iommu/mediatek: simplify dt parsing error handling iommu/mediatek-v1: fix device leak on probe_device() iommu/mediatek-v1: fix device leaks on probe() iommu/mediatek-v1: add missing larb count sanity check iommu/omap: fix device leaks on probe_device() iommu/omap: simplify probe_device() error handling iommu/sun50i: fix device leak on of_xlate() iommu/tegra: fix device leak on probe_device() drivers/iommu/apple-dart.c | 2 ++ drivers/iommu/arm/arm-smmu/qcom_iommu.c | 10 +++----- drivers/iommu/exynos-iommu.c | 9 +++---- drivers/iommu/ipmmu-vmsa.c | 2 ++ drivers/iommu/mtk_iommu.c | 33 +++++++++++++++++-------- drivers/iommu/mtk_iommu_v1.c | 28 +++++++++++++++++---- drivers/iommu/omap-iommu.c | 32 +++++++++++++++--------- drivers/iommu/sun50i-iommu.c | 2 ++ drivers/iommu/tegra-smmu.c | 5 ++-- 9 files changed, 81 insertions(+), 42 deletions(-) -- 2.49.1
On 2025-09-25 1:27 pm, Johan Hovold wrote: > This series fixes device leaks in the iommu drivers, which pretty > consistently failed to drop the reference taken by > of_find_device_by_node() when looking up iommu platform devices. > > Included are also a couple of related cleanups. Modulo the nitpick for OMAP, Acked-by: Robin Murphy <robin.murphy@arm.com> We could in fact also clean up nearly all the NULL checks in these areas that are now entirely redundant since per-instance ops lookup, but that might just le;ad to more patches from the static checker brigade trying to put them back... :/ Thanks, Robin. > Johan > > > Johan Hovold (14): > iommu/apple-dart: fix device leak on of_xlate() > iommu/qcom: fix device leak on of_xlate() > iommu/exynos: fix device leak on of_xlate() > iommu/ipmmu-vmsa: fix device leak on of_xlate() > iommu/mediatek: fix device leak on of_xlate() > iommu/mediatek: fix device leaks on probe() > iommu/mediatek: simplify dt parsing error handling > iommu/mediatek-v1: fix device leak on probe_device() > iommu/mediatek-v1: fix device leaks on probe() > iommu/mediatek-v1: add missing larb count sanity check > iommu/omap: fix device leaks on probe_device() > iommu/omap: simplify probe_device() error handling > iommu/sun50i: fix device leak on of_xlate() > iommu/tegra: fix device leak on probe_device() > > drivers/iommu/apple-dart.c | 2 ++ > drivers/iommu/arm/arm-smmu/qcom_iommu.c | 10 +++----- > drivers/iommu/exynos-iommu.c | 9 +++---- > drivers/iommu/ipmmu-vmsa.c | 2 ++ > drivers/iommu/mtk_iommu.c | 33 +++++++++++++++++-------- > drivers/iommu/mtk_iommu_v1.c | 28 +++++++++++++++++---- > drivers/iommu/omap-iommu.c | 32 +++++++++++++++--------- > drivers/iommu/sun50i-iommu.c | 2 ++ > drivers/iommu/tegra-smmu.c | 5 ++-- > 9 files changed, 81 insertions(+), 42 deletions(-) >
On Thu, Sep 25, 2025 at 02:27:42PM +0200, Johan Hovold wrote: > This series fixes device leaks in the iommu drivers, which pretty > consistently failed to drop the reference taken by > of_find_device_by_node() when looking up iommu platform devices. Yes, they are mis-designed in many ways :\ IDK if it is worth fixing like this, or if more effort should be put to make the drivers use of_xlate properly - the arm smmu drivers show the only way to use it.. But if staying like this then maybe add a little helper? void *iommu_xlate_to_iommu_drvdata(const struct of_phandle_args *args); Put the whole racy of_find_device_by_node / put_device / platform_get_drvdata sequence is in one tidy function.. With documentation it is not safe don't use it in new code? Jason
On Tue, Sep 30, 2025 at 03:21:58PM -0300, Jason Gunthorpe wrote: > On Thu, Sep 25, 2025 at 02:27:42PM +0200, Johan Hovold wrote: > > This series fixes device leaks in the iommu drivers, which pretty > > consistently failed to drop the reference taken by > > of_find_device_by_node() when looking up iommu platform devices. > > Yes, they are mis-designed in many ways :\ This seems to be more a case of developers not reading documentation and copying implementations from existing drivers. I amended the documentation for of_find_device_by_node() in 2016 and at least of some these drivers were merged later. Fixing up the existing uses will hopefully reduce the likelihood of further leaks being introduced (e.g. in places were it matters more). > IDK if it is worth fixing like this, or if more effort should be put > to make the drivers use of_xlate properly - the arm smmu drivers show > the only way to use it.. As Robin pointed out, those drivers just drop the reference as they should (even if I'd drop the reference after looking up the driver data). > But if staying like this then maybe add a little helper? > > void *iommu_xlate_to_iommu_drvdata(const struct of_phandle_args *args); > > Put the whole racy of_find_device_by_node / put_device / > platform_get_drvdata sequence is in one tidy function.. With > documentation it is not safe don't use it in new code? It's not racy in the context of iommu drivers as Robin also explained. Johan
On Wed, Oct 01, 2025 at 11:16:09AM +0200, Johan Hovold wrote: > This seems to be more a case of developers not reading documentation and > copying implementations from existing drivers. IMHO the drivers are mis-using of_xlate, it shouldn't be looking up drvdata at all. > > IDK if it is worth fixing like this, or if more effort should be put > > to make the drivers use of_xlate properly - the arm smmu drivers show > > the only way to use it.. > > As Robin pointed out, those drivers just drop the reference as they > should (even if I'd drop the reference after looking up the driver > data). So I wrote the series to clean this up and drop the calls to of_find_device_by_node() and so on. I left dart, exynos, msm and omap as-is, so I suggest you trim this series to only those drivers and rely on my version to fix the rest. Jason
On Wed, Oct 01, 2025 at 01:01:32PM -0300, Jason Gunthorpe wrote: > On Wed, Oct 01, 2025 at 11:16:09AM +0200, Johan Hovold wrote: > > > This seems to be more a case of developers not reading documentation and > > copying implementations from existing drivers. > > IMHO the drivers are mis-using of_xlate, it shouldn't be looking up > drvdata at all. Ok, but that would in any case be a separate issue. > > > IDK if it is worth fixing like this, or if more effort should be put > > > to make the drivers use of_xlate properly - the arm smmu drivers show > > > the only way to use it.. > > > > As Robin pointed out, those drivers just drop the reference as they > > should (even if I'd drop the reference after looking up the driver > > data). > > So I wrote the series to clean this up and drop the calls to > of_find_device_by_node() and so on. > > I left dart, exynos, msm and omap as-is, so I suggest you trim this > series to only those drivers and rely on my version to fix the rest. Looks like there's some room for unification and code reuse, but that can be done on top of these fixes. Johan
On 2025-09-30 7:21 pm, Jason Gunthorpe wrote: > On Thu, Sep 25, 2025 at 02:27:42PM +0200, Johan Hovold wrote: >> This series fixes device leaks in the iommu drivers, which pretty >> consistently failed to drop the reference taken by >> of_find_device_by_node() when looking up iommu platform devices. > > Yes, they are mis-designed in many ways :\ Historically they weren't really leaks either, just spare references on a device which at that point could definitely never go away. I suppose now that we finally have the .of_xlate calls in IOMMU registration, it would be possible for some error during probe to cause the IOMMU driver to fail to bind, at which point the references could rightly be considered leaked, however these are all embedded platforms with essentially zero chance of platform device hotplug, especially not of IOMMU devices, so realistically those references still don't matter to anything other than code checkers. In summary; meh. > IDK if it is worth fixing like this, or if more effort should be put > to make the drivers use of_xlate properly - the arm smmu drivers show > the only way to use it.. The SMMU drivers are really doing the same thing, they just defer that lookup operation to .probe_device time (largely for historical reasons, I think), and they use bus_find_device_by_node() rather than the specific of_ version since they support ACPI too. And they do happen to include the put_device(), since apparently I was paying full attention that day. > But if staying like this then maybe add a little helper? > > void *iommu_xlate_to_iommu_drvdata(const struct of_phandle_args *args); > > Put the whole racy of_find_device_by_node / put_device / > platform_get_drvdata sequence is in one tidy function.. With > documentation it is not safe don't use it in new code? It's not racy; if we're calling the .of_xlate op (or really any op for that matter), it's because an IOMMU driver has registered (or is registering) for the given fwnode, which means it is bound to the corresponding struct device. Thus as above, in that context said struct device, nor said IOMMU driver's drvdata, ain't goin' nowhere. Thanks, Robin.
On Tue, Sep 30, 2025 at 08:35:01PM +0100, Robin Murphy wrote:
> On 2025-09-30 7:21 pm, Jason Gunthorpe wrote:
> > On Thu, Sep 25, 2025 at 02:27:42PM +0200, Johan Hovold wrote:
> > > This series fixes device leaks in the iommu drivers, which pretty
> > > consistently failed to drop the reference taken by
> > > of_find_device_by_node() when looking up iommu platform devices.
> >
> > Yes, they are mis-designed in many ways :\
>
> Historically they weren't really leaks either, just spare references on a
> device which at that point could definitely never go away. I suppose now
> that we finally have the .of_xlate calls in IOMMU registration, it would be
> possible for some error during probe to cause the IOMMU driver to fail to
> bind, at which point the references could rightly be considered leaked,
> however these are all embedded platforms with essentially zero chance of
> platform device hotplug, especially not of IOMMU devices, so realistically
> those references still don't matter to anything other than code checkers.
>
> In summary; meh.
Yeah, it isn't a real practical bug, but it still ugly and no doubt
upsets static tools.
> > IDK if it is worth fixing like this, or if more effort should be put
> > to make the drivers use of_xlate properly - the arm smmu drivers show
> > the only way to use it..
>
> The SMMU drivers are really doing the same thing, they just defer that
> lookup operation to .probe_device time (largely for historical reasons, I
> think), and they use bus_find_device_by_node()
However the SMMU drivers are doing this under the
iommu_probe_device_lock and not stashing the pointer into a drvdata
where there is no locking protecting it.
> It's not racy; if we're calling the .of_xlate op (or really any op for that
> matter), it's because an IOMMU driver has registered (or is registering) for
> the given fwnode, which means it is bound to the corresponding struct
> device.
It is not racy if you make the very practical assumption there is no
iommu driver unplug.
Anyhow, I drafted a nice fix for all of this. After all the rework it
is trivial for the core code to pass in the struct iommu_device * to
probe and then most of the drivers just drop this ugly code
completely.
https://github.com/jgunthorpe/linux/commits/iommu-fwspec/
Jason
commit cca42a9b5325b96bfd3d74e24628511f537afbe9
Author: Jason Gunthorpe <jgg@ziepe.ca>
Date: Wed Oct 1 09:18:13 2025 -0300
iommu: Add a probe_device_fwspec() op
For fwspec using drivers the core code has already determined which struct
iommu_device instance the fwspec is linked to. It can trivially pass that
instance pointer into the driver.
This frees fwspec drivers from having to repeat the work of trying to find
the struct iommu_device for the fwspec.
Non-fwspec drivers (x86/etc) continue to use the old probe function which
is called on the first non-fwspec iommu driver registered.
This is only usable by drivers that support a single iommu instance per
device. There are some drivers (msm, exynos, dart) that do have an iommus
property that list multiple iommu_devices with multiple IDs. They cannot
use this simplified mechanism.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 060ebe330ee163..718a1da8f54710 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -142,6 +142,8 @@ static void __iommu_group_free_device(struct iommu_group *group,
struct group_device *grp_dev);
static void iommu_domain_init(struct iommu_domain *domain, unsigned int type,
const struct iommu_ops *ops);
+static struct iommu_device *
+iommu_from_fwnode(const struct fwnode_handle *fwnode);
#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \
struct iommu_group_attribute iommu_group_attr_##_name = \
@@ -406,13 +408,75 @@ void dev_iommu_priv_set(struct device *dev, void *priv)
}
EXPORT_SYMBOL_GPL(dev_iommu_priv_set);
+static int iommu_do_probe_device(struct device *dev)
+{
+ struct iommu_device *iommu;
+ int ret;
+
+ lockdep_assert_held(&iommu_probe_device_lock);
+
+ if (dev->iommu->fwspec) {
+ struct iommu_device *fwspec_iommu;
+
+ fwspec_iommu =
+ iommu_from_fwnode(dev->iommu->fwspec->iommu_fwnode);
+ if (!fwspec_iommu)
+ return -ENODEV;
+
+ if (fwspec_iommu->ops->probe_device_fwspec) {
+ ret = fwspec_iommu->ops->probe_device_fwspec(
+ fwspec_iommu, dev);
+ if (ret)
+ return ret;
+ iommu = fwspec_iommu;
+ } else {
+ iommu = fwspec_iommu->ops->probe_device(dev);
+ if (IS_ERR(iommu))
+ return PTR_ERR(iommu);
+ if (WARN_ON(iommu != fwspec_iommu)) {
+ ret = -EINVAL;
+ goto err_release;
+ }
+ }
+ } else {
+ /*
+ * At this point, relevant devices either now have a fwspec
+ * which will match ops registered with a non-NULL fwnode, or we
+ * can reasonably assume that only one of Intel, AMD, s390, PAMU
+ * or legacy SMMUv2 can be present, and that any of their
+ * registered instances has suitable ops for probing, and thus
+ * cheekily co-opt the same mechanism.
+ */
+ iommu = iommu_from_fwnode(NULL);
+ if (!iommu)
+ return -ENODEV;
+ /* Non fwspec drivers must identify their instance internally */
+ if (WARN_ON(!iommu->ops->probe_device))
+ return -EINVAL;
+ iommu = iommu->ops->probe_device(dev);
+ if (IS_ERR(iommu))
+ return PTR_ERR(iommu);
+ }
+
+ if (!try_module_get(iommu->ops->owner)) {
+ ret = -EINVAL;
+ goto err_release;
+ }
+
+ dev->iommu->iommu_dev = iommu;
+
+err_release:
+ if (iommu->ops->release_device)
+ iommu->ops->release_device(dev);
+ return ret;
+}
+
/*
* Init the dev->iommu and dev->iommu_group in the struct device and get the
* driver probed
*/
static int iommu_init_device(struct device *dev)
{
- const struct iommu_ops *ops;
struct iommu_device *iommu_dev;
struct iommu_group *group;
int ret;
@@ -434,36 +498,17 @@ static int iommu_init_device(struct device *dev)
if (!dev->iommu || dev->iommu_group)
return -ENODEV;
}
- /*
- * At this point, relevant devices either now have a fwspec which will
- * match ops registered with a non-NULL fwnode, or we can reasonably
- * assume that only one of Intel, AMD, s390, PAMU or legacy SMMUv2 can
- * be present, and that any of their registered instances has suitable
- * ops for probing, and thus cheekily co-opt the same mechanism.
- */
- ops = iommu_fwspec_ops(dev->iommu->fwspec);
- if (!ops) {
- ret = -ENODEV;
- goto err_free;
- }
- if (!try_module_get(ops->owner)) {
- ret = -EINVAL;
+ ret = iommu_do_probe_device(dev);
+ if (ret)
goto err_free;
- }
-
- iommu_dev = ops->probe_device(dev);
- if (IS_ERR(iommu_dev)) {
- ret = PTR_ERR(iommu_dev);
- goto err_module_put;
- }
- dev->iommu->iommu_dev = iommu_dev;
+ iommu_dev = dev->iommu->iommu_dev;
ret = iommu_device_link(iommu_dev, dev);
if (ret)
goto err_release;
- group = ops->device_group(dev);
+ group = iommu_dev->ops->device_group(dev);
if (WARN_ON_ONCE(group == NULL))
group = ERR_PTR(-EINVAL);
if (IS_ERR(group)) {
@@ -473,17 +518,17 @@ static int iommu_init_device(struct device *dev)
dev->iommu_group = group;
dev->iommu->max_pasids = dev_iommu_get_max_pasids(dev);
- if (ops->is_attach_deferred)
- dev->iommu->attach_deferred = ops->is_attach_deferred(dev);
+ if (iommu_dev->ops->is_attach_deferred)
+ dev->iommu->attach_deferred =
+ iommu_dev->ops->is_attach_deferred(dev);
return 0;
err_unlink:
iommu_device_unlink(iommu_dev, dev);
err_release:
- if (ops->release_device)
- ops->release_device(dev);
-err_module_put:
- module_put(ops->owner);
+ if (iommu_dev->ops->release_device)
+ iommu_dev->ops->release_device(dev);
+ module_put(iommu_dev->ops->owner);
err_free:
dev->iommu->iommu_dev = NULL;
dev_iommu_free(dev);
@@ -2855,9 +2900,10 @@ bool iommu_default_passthrough(void)
}
EXPORT_SYMBOL_GPL(iommu_default_passthrough);
-static const struct iommu_device *iommu_from_fwnode(const struct fwnode_handle *fwnode)
+static struct iommu_device *iommu_from_fwnode(
+ const struct fwnode_handle *fwnode)
{
- const struct iommu_device *iommu, *ret = NULL;
+ struct iommu_device *iommu, *ret = NULL;
spin_lock(&iommu_device_lock);
list_for_each_entry(iommu, &iommu_device_list, list)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index c30d12e16473df..52e74ccdb4dc79 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -48,6 +48,7 @@ struct iommufd_ctx;
struct iommufd_viommu;
struct msi_desc;
struct msi_msg;
+struct iommu_device;
#define IOMMU_FAULT_PERM_READ (1 << 0) /* read */
#define IOMMU_FAULT_PERM_WRITE (1 << 1) /* write */
@@ -680,6 +681,8 @@ struct iommu_ops {
struct device *dev, struct iommu_domain *parent, u32 flags,
const struct iommu_user_data *user_data);
+ int (*probe_device_fwspec)(struct iommu_device *iommu,
+ struct device *dev);
struct iommu_device *(*probe_device)(struct device *dev);
void (*release_device)(struct device *dev);
void (*probe_finalize)(struct device *dev);
On 2025-10-01 4:58 pm, Jason Gunthorpe wrote:
> On Tue, Sep 30, 2025 at 08:35:01PM +0100, Robin Murphy wrote:
>> On 2025-09-30 7:21 pm, Jason Gunthorpe wrote:
>>> On Thu, Sep 25, 2025 at 02:27:42PM +0200, Johan Hovold wrote:
>>>> This series fixes device leaks in the iommu drivers, which pretty
>>>> consistently failed to drop the reference taken by
>>>> of_find_device_by_node() when looking up iommu platform devices.
>>>
>>> Yes, they are mis-designed in many ways :\
>>
>> Historically they weren't really leaks either, just spare references on a
>> device which at that point could definitely never go away. I suppose now
>> that we finally have the .of_xlate calls in IOMMU registration, it would be
>> possible for some error during probe to cause the IOMMU driver to fail to
>> bind, at which point the references could rightly be considered leaked,
>> however these are all embedded platforms with essentially zero chance of
>> platform device hotplug, especially not of IOMMU devices, so realistically
>> those references still don't matter to anything other than code checkers.
>>
>> In summary; meh.
>
> Yeah, it isn't a real practical bug, but it still ugly and no doubt
> upsets static tools.
>
>>> IDK if it is worth fixing like this, or if more effort should be put
>>> to make the drivers use of_xlate properly - the arm smmu drivers show
>>> the only way to use it..
>>
>> The SMMU drivers are really doing the same thing, they just defer that
>> lookup operation to .probe_device time (largely for historical reasons, I
>> think), and they use bus_find_device_by_node()
>
> However the SMMU drivers are doing this under the
> iommu_probe_device_lock and not stashing the pointer into a drvdata
> where there is no locking protecting it.
Huh? Every .of_xlate call is under probe_device_lock just as much as
.probe_device calls are; they *have* to be, since they too are in the
position of working with dev->iommu before dev->iommu_group is set to
guarantee its stability.
>> It's not racy; if we're calling the .of_xlate op (or really any op for that
>> matter), it's because an IOMMU driver has registered (or is registering) for
>> the given fwnode, which means it is bound to the corresponding struct
>> device.
>
> It is not racy if you make the very practical assumption there is no
> iommu driver unplug.
If the IOMMU code allowed a driver to be removed while it's in the
middle of calling into that driver, that would hardly be the driver's
fault. And indeed the driver cannot be removed, because we hold a module
reference around the call (and if a buggy driver failed to suppress
manual sysfs unbinding, this case is frankly one of the smallest drops
in the ocean of catastrophic consequences there.)
> Anyhow, I drafted a nice fix for all of this. After all the rework it
> is trivial for the core code to pass in the struct iommu_device * to
> probe and then most of the drivers just drop this ugly code
> completely.
>
> https://github.com/jgunthorpe/linux/commits/iommu-fwspec/
Eww, that is neither nice nor a "fix". Once again it's just piling on a
load of extra complexity to have multiple
confusingly-overlapping-but-different ways of doing the same thing, one
of which is still the exact same one you've decided to object to because
you've failed to understand it (as demonstrated by the commit message
below, the obvious bug in the hideous mess below that, and at a glance
the other patches actively *breaking* at least one driver.)
Thanks,
Robin.
>
> Jason
>
> commit cca42a9b5325b96bfd3d74e24628511f537afbe9
> Author: Jason Gunthorpe <jgg@ziepe.ca>
> Date: Wed Oct 1 09:18:13 2025 -0300
>
> iommu: Add a probe_device_fwspec() op
>
> For fwspec using drivers the core code has already determined which struct
> iommu_device instance the fwspec is linked to. It can trivially pass that
> instance pointer into the driver.
>
> This frees fwspec drivers from having to repeat the work of trying to find
> the struct iommu_device for the fwspec.
>
> Non-fwspec drivers (x86/etc) continue to use the old probe function which
> is called on the first non-fwspec iommu driver registered.
>
> This is only usable by drivers that support a single iommu instance per
> device. There are some drivers (msm, exynos, dart) that do have an iommus
> property that list multiple iommu_devices with multiple IDs. They cannot
> use this simplified mechanism.
>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
>
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 060ebe330ee163..718a1da8f54710 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -142,6 +142,8 @@ static void __iommu_group_free_device(struct iommu_group *group,
> struct group_device *grp_dev);
> static void iommu_domain_init(struct iommu_domain *domain, unsigned int type,
> const struct iommu_ops *ops);
> +static struct iommu_device *
> +iommu_from_fwnode(const struct fwnode_handle *fwnode);
>
> #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \
> struct iommu_group_attribute iommu_group_attr_##_name = \
> @@ -406,13 +408,75 @@ void dev_iommu_priv_set(struct device *dev, void *priv)
> }
> EXPORT_SYMBOL_GPL(dev_iommu_priv_set);
>
> +static int iommu_do_probe_device(struct device *dev)
> +{
> + struct iommu_device *iommu;
> + int ret;
> +
> + lockdep_assert_held(&iommu_probe_device_lock);
> +
> + if (dev->iommu->fwspec) {
> + struct iommu_device *fwspec_iommu;
> +
> + fwspec_iommu =
> + iommu_from_fwnode(dev->iommu->fwspec->iommu_fwnode);
> + if (!fwspec_iommu)
> + return -ENODEV;
> +
> + if (fwspec_iommu->ops->probe_device_fwspec) {
> + ret = fwspec_iommu->ops->probe_device_fwspec(
> + fwspec_iommu, dev);
> + if (ret)
> + return ret;
> + iommu = fwspec_iommu;
> + } else {
> + iommu = fwspec_iommu->ops->probe_device(dev);
> + if (IS_ERR(iommu))
> + return PTR_ERR(iommu);
> + if (WARN_ON(iommu != fwspec_iommu)) {
> + ret = -EINVAL;
> + goto err_release;
> + }
> + }
> + } else {
> + /*
> + * At this point, relevant devices either now have a fwspec
> + * which will match ops registered with a non-NULL fwnode, or we
> + * can reasonably assume that only one of Intel, AMD, s390, PAMU
> + * or legacy SMMUv2 can be present, and that any of their
> + * registered instances has suitable ops for probing, and thus
> + * cheekily co-opt the same mechanism.
> + */
> + iommu = iommu_from_fwnode(NULL);
> + if (!iommu)
> + return -ENODEV;
> + /* Non fwspec drivers must identify their instance internally */
> + if (WARN_ON(!iommu->ops->probe_device))
> + return -EINVAL;
> + iommu = iommu->ops->probe_device(dev);
> + if (IS_ERR(iommu))
> + return PTR_ERR(iommu);
> + }
> +
> + if (!try_module_get(iommu->ops->owner)) {
> + ret = -EINVAL;
> + goto err_release;
> + }
> +
> + dev->iommu->iommu_dev = iommu;
> +
> +err_release:
> + if (iommu->ops->release_device)
> + iommu->ops->release_device(dev);
> + return ret;
> +}
> +
> /*
> * Init the dev->iommu and dev->iommu_group in the struct device and get the
> * driver probed
> */
> static int iommu_init_device(struct device *dev)
> {
> - const struct iommu_ops *ops;
> struct iommu_device *iommu_dev;
> struct iommu_group *group;
> int ret;
> @@ -434,36 +498,17 @@ static int iommu_init_device(struct device *dev)
> if (!dev->iommu || dev->iommu_group)
> return -ENODEV;
> }
> - /*
> - * At this point, relevant devices either now have a fwspec which will
> - * match ops registered with a non-NULL fwnode, or we can reasonably
> - * assume that only one of Intel, AMD, s390, PAMU or legacy SMMUv2 can
> - * be present, and that any of their registered instances has suitable
> - * ops for probing, and thus cheekily co-opt the same mechanism.
> - */
> - ops = iommu_fwspec_ops(dev->iommu->fwspec);
> - if (!ops) {
> - ret = -ENODEV;
> - goto err_free;
> - }
>
> - if (!try_module_get(ops->owner)) {
> - ret = -EINVAL;
> + ret = iommu_do_probe_device(dev);
> + if (ret)
> goto err_free;
> - }
> -
> - iommu_dev = ops->probe_device(dev);
> - if (IS_ERR(iommu_dev)) {
> - ret = PTR_ERR(iommu_dev);
> - goto err_module_put;
> - }
> - dev->iommu->iommu_dev = iommu_dev;
> + iommu_dev = dev->iommu->iommu_dev;
>
> ret = iommu_device_link(iommu_dev, dev);
> if (ret)
> goto err_release;
>
> - group = ops->device_group(dev);
> + group = iommu_dev->ops->device_group(dev);
> if (WARN_ON_ONCE(group == NULL))
> group = ERR_PTR(-EINVAL);
> if (IS_ERR(group)) {
> @@ -473,17 +518,17 @@ static int iommu_init_device(struct device *dev)
> dev->iommu_group = group;
>
> dev->iommu->max_pasids = dev_iommu_get_max_pasids(dev);
> - if (ops->is_attach_deferred)
> - dev->iommu->attach_deferred = ops->is_attach_deferred(dev);
> + if (iommu_dev->ops->is_attach_deferred)
> + dev->iommu->attach_deferred =
> + iommu_dev->ops->is_attach_deferred(dev);
> return 0;
>
> err_unlink:
> iommu_device_unlink(iommu_dev, dev);
> err_release:
> - if (ops->release_device)
> - ops->release_device(dev);
> -err_module_put:
> - module_put(ops->owner);
> + if (iommu_dev->ops->release_device)
> + iommu_dev->ops->release_device(dev);
> + module_put(iommu_dev->ops->owner);
> err_free:
> dev->iommu->iommu_dev = NULL;
> dev_iommu_free(dev);
> @@ -2855,9 +2900,10 @@ bool iommu_default_passthrough(void)
> }
> EXPORT_SYMBOL_GPL(iommu_default_passthrough);
>
> -static const struct iommu_device *iommu_from_fwnode(const struct fwnode_handle *fwnode)
> +static struct iommu_device *iommu_from_fwnode(
> + const struct fwnode_handle *fwnode)
> {
> - const struct iommu_device *iommu, *ret = NULL;
> + struct iommu_device *iommu, *ret = NULL;
>
> spin_lock(&iommu_device_lock);
> list_for_each_entry(iommu, &iommu_device_list, list)
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index c30d12e16473df..52e74ccdb4dc79 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -48,6 +48,7 @@ struct iommufd_ctx;
> struct iommufd_viommu;
> struct msi_desc;
> struct msi_msg;
> +struct iommu_device;
>
> #define IOMMU_FAULT_PERM_READ (1 << 0) /* read */
> #define IOMMU_FAULT_PERM_WRITE (1 << 1) /* write */
> @@ -680,6 +681,8 @@ struct iommu_ops {
> struct device *dev, struct iommu_domain *parent, u32 flags,
> const struct iommu_user_data *user_data);
>
> + int (*probe_device_fwspec)(struct iommu_device *iommu,
> + struct device *dev);
> struct iommu_device *(*probe_device)(struct device *dev);
> void (*release_device)(struct device *dev);
> void (*probe_finalize)(struct device *dev);
On Thu, Oct 02, 2025 at 12:48:35PM +0100, Robin Murphy wrote:
> > However the SMMU drivers are doing this under the
> > iommu_probe_device_lock and not stashing the pointer into a drvdata
> > where there is no locking protecting it.
>
> Huh? Every .of_xlate call is under probe_device_lock just as much as
> .probe_device calls are; they *have* to be, since they too are in the
> position of working with dev->iommu before dev->iommu_group is set to
> guarantee its stability.
Yes, of_xlate is under the lock, but IIRC there are still cases where
probe gets deferred, the probe_device_lock is unlocked, and the
drvdata continues to exist.
> indeed the driver cannot be removed, because we hold a module reference
> around the call
That's not how module reference counts work. Drivers can be unbound
through sysfs at any time.
> > Anyhow, I drafted a nice fix for all of this. After all the rework it
> > is trivial for the core code to pass in the struct iommu_device * to
> > probe and then most of the drivers just drop this ugly code
> > completely.
> >
> > https://github.com/jgunthorpe/linux/commits/iommu-fwspec/
>
> Eww, that is neither nice nor a "fix". Once again it's just piling on a load
> of extra complexity to have multiple confusingly-overlapping-but-different
> ways of doing the same thing, one of which is still the exact same one
> you've decided to object to because you've failed to understand it (as
> demonstrated by the commit message below, the obvious bug in the hideous
> mess below that, and at a glance the other patches actively *breaking* at
> least one driver.)
It is hard to take you seriously with such vauge objections
Robin. Please try to be constructive. If you are specific I'll go fix
the things and maybe other people besides you can understand this
stuff.
I'm shocked you disagree with the core code helping the drivers find
their iommu_driver. This seems like very basic obvious good stuff. We
don't need all sorts of different open coded ugly ways for drivers to
do this. It removes 200 lines of junk for drivers :\
> > + iommu = fwspec_iommu->ops->probe_device(dev);
> > + if (IS_ERR(iommu))
> > + return PTR_ERR(iommu);
> > + if (WARN_ON(iommu != fwspec_iommu)) {
This is at least one typo.
Jason
© 2016 - 2026 Red Hat, Inc.