Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iommu: Keep dev->iommu state consistent

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>

authored by

Robin Murphy and committed by
Joerg Roedel
3832862e fd598f71

+8 -2
+2
drivers/iommu/iommu-priv.h
··· 17 17 return dev->iommu->iommu_dev->ops; 18 18 } 19 19 20 + void dev_iommu_free(struct device *dev); 21 + 20 22 const struct iommu_ops *iommu_ops_from_fwnode(const struct fwnode_handle *fwnode); 21 23 22 24 static inline const struct iommu_ops *iommu_fwspec_ops(struct iommu_fwspec *fwspec)
+1 -1
drivers/iommu/iommu.c
··· 355 355 return param; 356 356 } 357 357 358 - static void dev_iommu_free(struct device *dev) 358 + void dev_iommu_free(struct device *dev) 359 359 { 360 360 struct dev_iommu *param = dev->iommu; 361 361
+5 -1
drivers/iommu/of_iommu.c
··· 116 116 int of_iommu_configure(struct device *dev, struct device_node *master_np, 117 117 const u32 *id) 118 118 { 119 + bool dev_iommu_present; 119 120 int err; 120 121 121 122 if (!master_np) ··· 128 127 mutex_unlock(&iommu_probe_device_lock); 129 128 return 0; 130 129 } 130 + dev_iommu_present = dev->iommu; 131 131 132 132 /* 133 133 * We don't currently walk up the tree looking for a parent IOMMU. ··· 149 147 err = of_iommu_configure_device(master_np, dev, id); 150 148 } 151 149 152 - if (err) 150 + if (err && dev_iommu_present) 153 151 iommu_fwspec_free(dev); 152 + else if (err && dev->iommu) 153 + dev_iommu_free(dev); 154 154 mutex_unlock(&iommu_probe_device_lock); 155 155 156 156 if (!err && dev->bus)