]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommu: Keep dev->iommu state consistent
authorRobin Murphy <robin.murphy@arm.com>
Fri, 28 Feb 2025 15:46:32 +0000 (15:46 +0000)
committerJoerg Roedel <jroedel@suse.de>
Tue, 11 Mar 2025 13:05:42 +0000 (14:05 +0100)
At the moment, if of_iommu_configure() allocates dev->iommu itself via
iommu_fwspec_init(), then suffers a DT parsing failure, it cleans up the
fwspec but leaves the empty dev_iommu hanging around. So far this is
benign (if a tiny bit wasteful), but we'd like to be able to reason
about dev->iommu having a consistent and unambiguous lifecycle. Thus
make sure that the of_iommu cleanup undoes precisely whatever it did.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/d219663a3f23001f23d520a883ac622d70b4e642.1740753261.git.robin.murphy@arm.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/iommu-priv.h
drivers/iommu/iommu.c
drivers/iommu/of_iommu.c

index fed55fbfe99cb49d6ccffa71fa36632addc15bec..05fa6e682e88d7b38d03472f0cf263e8538f855e 100644 (file)
@@ -17,6 +17,8 @@ static inline const struct iommu_ops *dev_iommu_ops(struct device *dev)
        return dev->iommu->iommu_dev->ops;
 }
 
+void dev_iommu_free(struct device *dev);
+
 const struct iommu_ops *iommu_ops_from_fwnode(const struct fwnode_handle *fwnode);
 
 static inline const struct iommu_ops *iommu_fwspec_ops(struct iommu_fwspec *fwspec)
index d26a459f29c32864ab75c364e7de1f811c09126b..b0be5c168a435a612747a8db4f3e5fdf0724db50 100644 (file)
@@ -355,7 +355,7 @@ static struct dev_iommu *dev_iommu_get(struct device *dev)
        return param;
 }
 
-static void dev_iommu_free(struct device *dev)
+void dev_iommu_free(struct device *dev)
 {
        struct dev_iommu *param = dev->iommu;
 
index 97987cd78da9346ce820e7c47f749a50edfbb7de..e10a68b5ffde1359f948f755c79ad6d90b78d740 100644 (file)
@@ -116,6 +116,7 @@ static void of_pci_check_device_ats(struct device *dev, struct device_node *np)
 int of_iommu_configure(struct device *dev, struct device_node *master_np,
                       const u32 *id)
 {
+       bool dev_iommu_present;
        int err;
 
        if (!master_np)
@@ -127,6 +128,7 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np,
                mutex_unlock(&iommu_probe_device_lock);
                return 0;
        }
+       dev_iommu_present = dev->iommu;
 
        /*
         * We don't currently walk up the tree looking for a parent IOMMU.
@@ -147,8 +149,10 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np,
                err = of_iommu_configure_device(master_np, dev, id);
        }
 
-       if (err)
+       if (err && dev_iommu_present)
                iommu_fwspec_free(dev);
+       else if (err && dev->iommu)
+               dev_iommu_free(dev);
        mutex_unlock(&iommu_probe_device_lock);
 
        if (!err && dev->bus)