linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/7] iommu: Retire bus ops
@ 2023-10-11 18:14 Robin Murphy
  2023-10-11 18:14 ` [PATCH v5 1/7] iommu: Factor out some helpers Robin Murphy
                   ` (6 more replies)
  0 siblings, 7 replies; 29+ messages in thread
From: Robin Murphy @ 2023-10-11 18:14 UTC (permalink / raw)
  To: joro, will; +Cc: iommu, jgg, baolu.lu, linux-kernel

v4: https://lore.kernel.org/linux-iommu/cover.1696253096.git.robin.murphy@arm.com/

Hi all,

Really really hoping this is done now... same as v4 except I've
rewritten patch #4 to be a lot less ambitious and not require any
troublesome new reasoning.

Cheers,
Robin.


Robin Murphy (7):
  iommu: Factor out some helpers
  iommu: Decouple iommu_present() from bus ops
  iommu: Validate that devices match domains
  iommu: Decouple iommu_domain_alloc() from bus ops
  iommu/arm-smmu: Don't register fwnode for legacy binding
  iommu: Retire bus ops
  iommu: Clean up open-coded ownership checks

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |   3 -
 drivers/iommu/arm/arm-smmu/arm-smmu.c       |  12 +-
 drivers/iommu/arm/arm-smmu/qcom_iommu.c     |  16 +--
 drivers/iommu/iommu.c                       | 143 +++++++++++++-------
 drivers/iommu/mtk_iommu.c                   |   7 +-
 drivers/iommu/mtk_iommu_v1.c                |   3 -
 drivers/iommu/sprd-iommu.c                  |   8 +-
 drivers/iommu/virtio-iommu.c                |   3 -
 include/acpi/acpi_bus.h                     |   2 +
 include/linux/device.h                      |   1 -
 include/linux/device/bus.h                  |   5 -
 include/linux/dma-map-ops.h                 |   1 +
 include/linux/iommu.h                       |   1 +
 13 files changed, 108 insertions(+), 97 deletions(-)

-- 
2.39.2.101.g768bb238c484.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v5 1/7] iommu: Factor out some helpers
  2023-10-11 18:14 [PATCH v5 0/7] iommu: Retire bus ops Robin Murphy
@ 2023-10-11 18:14 ` Robin Murphy
  2023-10-11 23:34   ` Jason Gunthorpe
  2023-10-18 23:04   ` Jerry Snitselaar
  2023-10-11 18:14 ` [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops Robin Murphy
                   ` (5 subsequent siblings)
  6 siblings, 2 replies; 29+ messages in thread
From: Robin Murphy @ 2023-10-11 18:14 UTC (permalink / raw)
  To: joro, will; +Cc: iommu, jgg, baolu.lu, linux-kernel

The pattern for picking the first device out of the group list is
repeated a few times now, so it's clearly worth factoring out, which
also helps hide the iommu_group_dev detail from places that don't need
to know. Similarly, the safety check for dev_iommu_ops() at certain
public interfaces starts looking a bit repetitive, and might not be
completely obvious at first glance, so let's factor that out for clarity
as well, in preparation for more uses of both.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>

---

v3: Rename dev_iommu_ops_valid() to reflect what it's actually checking,
    rather than an implied consequence.
v4: Rebase, also catch the sneaky one in iommu_get_group_resv_regions()
    which wasn't the full pattern (but really should be since it guards
    the dev_iommu_ops() invocation in iommu_get_resv_regions()).
---
 drivers/iommu/iommu.c | 56 ++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 30 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index f9f315d58a3a..5a3ce293a5de 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -368,6 +368,15 @@ static void dev_iommu_free(struct device *dev)
 	kfree(param);
 }
 
+/*
+ * Internal equivalent of device_iommu_mapped() for when we care that a device
+ * actually has API ops, and don't want false positives from VFIO-only groups.
+ */
+static bool dev_has_iommu(struct device *dev)
+{
+	return dev->iommu && dev->iommu->iommu_dev;
+}
+
 static u32 dev_iommu_get_max_pasids(struct device *dev)
 {
 	u32 max_pasids = 0, bits = 0;
@@ -620,7 +629,7 @@ static void __iommu_group_remove_device(struct device *dev)
 
 		list_del(&device->list);
 		__iommu_group_free_device(group, device);
-		if (dev->iommu && dev->iommu->iommu_dev)
+		if (dev_has_iommu(dev))
 			iommu_deinit_device(dev);
 		else
 			dev->iommu_group = NULL;
@@ -819,7 +828,7 @@ int iommu_get_group_resv_regions(struct iommu_group *group,
 		 * Non-API groups still expose reserved_regions in sysfs,
 		 * so filter out calls that get here that way.
 		 */
-		if (!device->dev->iommu)
+		if (!dev_has_iommu(device->dev))
 			break;
 
 		INIT_LIST_HEAD(&dev_resv_regions);
@@ -1224,6 +1233,12 @@ void iommu_group_remove_device(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(iommu_group_remove_device);
 
+static struct device *iommu_group_first_dev(struct iommu_group *group)
+{
+	lockdep_assert_held(&group->mutex);
+	return list_first_entry(&group->devices, struct group_device, list)->dev;
+}
+
 /**
  * iommu_group_for_each_dev - iterate over each device in the group
  * @group: the group
@@ -1751,23 +1766,6 @@ __iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
 	return __iommu_group_domain_alloc(group, req_type);
 }
 
-/*
- * Returns the iommu_ops for the devices in an iommu group.
- *
- * It is assumed that all devices in an iommu group are managed by a single
- * IOMMU unit. Therefore, this returns the dev_iommu_ops of the first device
- * in the group.
- */
-static const struct iommu_ops *group_iommu_ops(struct iommu_group *group)
-{
-	struct group_device *device =
-		list_first_entry(&group->devices, struct group_device, list);
-
-	lockdep_assert_held(&group->mutex);
-
-	return dev_iommu_ops(device->dev);
-}
-
 /*
  * req_type of 0 means "auto" which means to select a domain based on
  * iommu_def_domain_type or what the driver actually supports.
@@ -1775,7 +1773,7 @@ static const struct iommu_ops *group_iommu_ops(struct iommu_group *group)
 static struct iommu_domain *
 iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
 {
-	const struct iommu_ops *ops = group_iommu_ops(group);
+	const struct iommu_ops *ops = dev_iommu_ops(iommu_group_first_dev(group));
 	struct iommu_domain *dom;
 
 	lockdep_assert_held(&group->mutex);
@@ -1853,7 +1851,7 @@ static int iommu_bus_notifier(struct notifier_block *nb,
 static int iommu_get_def_domain_type(struct iommu_group *group,
 				     struct device *dev, int cur_type)
 {
-	const struct iommu_ops *ops = group_iommu_ops(group);
+	const struct iommu_ops *ops = dev_iommu_ops(dev);
 	int type;
 
 	if (!ops->def_domain_type)
@@ -2020,7 +2018,7 @@ bool device_iommu_capable(struct device *dev, enum iommu_cap cap)
 {
 	const struct iommu_ops *ops;
 
-	if (!dev->iommu || !dev->iommu->iommu_dev)
+	if (!dev_has_iommu(dev))
 		return false;
 
 	ops = dev_iommu_ops(dev);
@@ -2117,11 +2115,9 @@ static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops,
 static struct iommu_domain *
 __iommu_group_domain_alloc(struct iommu_group *group, unsigned int type)
 {
-	struct device *dev =
-		list_first_entry(&group->devices, struct group_device, list)
-			->dev;
+	struct device *dev = iommu_group_first_dev(group);
 
-	return __iommu_domain_alloc(group_iommu_ops(group), dev, type);
+	return __iommu_domain_alloc(dev_iommu_ops(dev), dev, type);
 }
 
 struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus)
@@ -2972,8 +2968,8 @@ EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);
  */
 int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features feat)
 {
-	if (dev->iommu && dev->iommu->iommu_dev) {
-		const struct iommu_ops *ops = dev->iommu->iommu_dev->ops;
+	if (dev_has_iommu(dev)) {
+		const struct iommu_ops *ops = dev_iommu_ops(dev);
 
 		if (ops->dev_enable_feat)
 			return ops->dev_enable_feat(dev, feat);
@@ -2988,8 +2984,8 @@ EXPORT_SYMBOL_GPL(iommu_dev_enable_feature);
  */
 int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
 {
-	if (dev->iommu && dev->iommu->iommu_dev) {
-		const struct iommu_ops *ops = dev->iommu->iommu_dev->ops;
+	if (dev_has_iommu(dev)) {
+		const struct iommu_ops *ops = dev_iommu_ops(dev);
 
 		if (ops->dev_disable_feat)
 			return ops->dev_disable_feat(dev, feat);
-- 
2.39.2.101.g768bb238c484.dirty


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops
  2023-10-11 18:14 [PATCH v5 0/7] iommu: Retire bus ops Robin Murphy
  2023-10-11 18:14 ` [PATCH v5 1/7] iommu: Factor out some helpers Robin Murphy
@ 2023-10-11 18:14 ` Robin Murphy
  2023-10-12  6:05   ` Baolu Lu
                     ` (2 more replies)
  2023-10-11 18:14 ` [PATCH v5 3/7] iommu: Validate that devices match domains Robin Murphy
                   ` (4 subsequent siblings)
  6 siblings, 3 replies; 29+ messages in thread
From: Robin Murphy @ 2023-10-11 18:14 UTC (permalink / raw)
  To: joro, will; +Cc: iommu, jgg, baolu.lu, linux-kernel

Much as I'd like to remove iommu_present(), the final remaining users
are proving stubbornly difficult to clean up, so kick that can down the
road and just rework it to preserve the current behaviour without
depending on bus ops. Since commit 57365a04c921 ("iommu: Move bus setup
to IOMMU device registration"), any registered IOMMU instance is already
considered "present" for every entry in iommu_buses, so it's simply a
case of validating the bus and checking we have at least once IOMMU.

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>

---

v3: Tweak to use the ops-based check rather than group-based, to
    properly match the existing behaviour
v4: Just look for IOMMU instances instead of managed devices
---
 drivers/iommu/iommu.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 5a3ce293a5de..7bb92e8b7a49 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2000,9 +2000,28 @@ int bus_iommu_probe(const struct bus_type *bus)
 	return 0;
 }
 
+/**
+ * iommu_present() - make platform-specific assumptions about an IOMMU
+ * @bus: bus to check
+ *
+ * Do not use this function. You want device_iommu_mapped() instead.
+ *
+ * Return: true if some IOMMU is present and aware of devices on the given bus;
+ * in general it may not be the only IOMMU, and it may not have anything to do
+ * with whatever device you are ultimately interested in.
+ */
 bool iommu_present(const struct bus_type *bus)
 {
-	return bus->iommu_ops != NULL;
+	bool ret = false;
+
+	for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
+		if (iommu_buses[i] == bus) {
+			spin_lock(&iommu_device_lock);
+			ret = !list_empty(&iommu_device_list);
+			spin_unlock(&iommu_device_lock);
+		}
+	}
+	return ret;
 }
 EXPORT_SYMBOL_GPL(iommu_present);
 
-- 
2.39.2.101.g768bb238c484.dirty


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 3/7] iommu: Validate that devices match domains
  2023-10-11 18:14 [PATCH v5 0/7] iommu: Retire bus ops Robin Murphy
  2023-10-11 18:14 ` [PATCH v5 1/7] iommu: Factor out some helpers Robin Murphy
  2023-10-11 18:14 ` [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops Robin Murphy
@ 2023-10-11 18:14 ` Robin Murphy
  2023-10-18 23:14   ` Jerry Snitselaar
  2023-10-24 18:52   ` Jason Gunthorpe
  2023-10-11 18:14 ` [PATCH v5 4/7] iommu: Decouple iommu_domain_alloc() from bus ops Robin Murphy
                   ` (3 subsequent siblings)
  6 siblings, 2 replies; 29+ messages in thread
From: Robin Murphy @ 2023-10-11 18:14 UTC (permalink / raw)
  To: joro, will; +Cc: iommu, jgg, baolu.lu, linux-kernel

Before we can allow drivers to coexist, we need to make sure that one
driver's domain ops can't misinterpret another driver's dev_iommu_priv
data. To that end, add a token to the domain so we can remember how it
was allocated - for now this may as well be the device ops, since they
still correlate 1:1 with drivers. We can trust ourselves for internal
default domain attachment, so add checks to cover all the public attach
interfaces.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>

---

v4: Cover iommu_attach_device_pasid() as well, and improve robustness
    against theoretical attempts to attach a noiommu group.
---
 drivers/iommu/iommu.c | 10 ++++++++++
 include/linux/iommu.h |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 7bb92e8b7a49..578292d3b152 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2114,6 +2114,7 @@ static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops,
 		return NULL;
 
 	domain->type = type;
+	domain->owner = ops;
 	/*
 	 * If not already set, assume all sizes by default; the driver
 	 * may override this later
@@ -2279,10 +2280,16 @@ struct iommu_domain *iommu_get_dma_domain(struct device *dev)
 static int __iommu_attach_group(struct iommu_domain *domain,
 				struct iommu_group *group)
 {
+	struct device *dev;
+
 	if (group->domain && group->domain != group->default_domain &&
 	    group->domain != group->blocking_domain)
 		return -EBUSY;
 
+	dev = iommu_group_first_dev(group);
+	if (!dev_has_iommu(dev) || dev_iommu_ops(dev) != domain->owner)
+		return -EINVAL;
+
 	return __iommu_group_set_domain(group, domain);
 }
 
@@ -3480,6 +3487,9 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
 	if (!group)
 		return -ENODEV;
 
+	if (!dev_has_iommu(dev) || dev_iommu_ops(dev) != domain->owner)
+		return -EINVAL;
+
 	mutex_lock(&group->mutex);
 	curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, domain, GFP_KERNEL);
 	if (curr) {
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 2d2802fb2c74..5c9560813d05 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -99,6 +99,7 @@ struct iommu_domain_geometry {
 struct iommu_domain {
 	unsigned type;
 	const struct iommu_domain_ops *ops;
+	const struct iommu_ops *owner; /* Whose domain_alloc we came from */
 	unsigned long pgsize_bitmap;	/* Bitmap of page sizes in use */
 	struct iommu_domain_geometry geometry;
 	struct iommu_dma_cookie *iova_cookie;
-- 
2.39.2.101.g768bb238c484.dirty


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 4/7] iommu: Decouple iommu_domain_alloc() from bus ops
  2023-10-11 18:14 [PATCH v5 0/7] iommu: Retire bus ops Robin Murphy
                   ` (2 preceding siblings ...)
  2023-10-11 18:14 ` [PATCH v5 3/7] iommu: Validate that devices match domains Robin Murphy
@ 2023-10-11 18:14 ` Robin Murphy
  2023-10-11 23:38   ` Jason Gunthorpe
  2023-10-18 23:15   ` Jerry Snitselaar
  2023-10-11 18:14 ` [PATCH v5 5/7] iommu/arm-smmu: Don't register fwnode for legacy binding Robin Murphy
                   ` (2 subsequent siblings)
  6 siblings, 2 replies; 29+ messages in thread
From: Robin Murphy @ 2023-10-11 18:14 UTC (permalink / raw)
  To: joro, will; +Cc: iommu, jgg, baolu.lu, linux-kernel

As the final remaining piece of bus-dependent API, iommu_domain_alloc()
can now take responsibility for the "one iommu_ops per bus" rule for
itself. It turns out we can't safely make the internal allocation call
any more group-based or device-based yet - that will have to wait until
the external callers can pass the right thing - but we can at least get
as far as deriving "bus ops" based on which driver is actually managing
devices on the given bus, rather than whichever driver won the race to
register first.

This will then leave us able to convert the last of the core internals
over to the IOMMU-instance model, allow multiple drivers to register and
actually coexist (modulo the above limitation for unmanaged domain users
in the short term), and start trying to solve the long-standing
iommu_probe_device() mess.

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

---

v5: Rewrite, de-scoping to just retrieve ops under the same assumptions
    as the existing code.
---
 drivers/iommu/iommu.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 578292d3b152..18667dc2ff86 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2140,12 +2140,31 @@ __iommu_group_domain_alloc(struct iommu_group *group, unsigned int type)
 	return __iommu_domain_alloc(dev_iommu_ops(dev), dev, type);
 }
 
+static int __iommu_domain_alloc_dev(struct device *dev, void *data)
+{
+	const struct iommu_ops **ops = data;
+
+	if (!dev_has_iommu(dev))
+		return 0;
+
+	if (WARN_ONCE(*ops && *ops != dev_iommu_ops(dev),
+		      "Multiple IOMMU drivers present for bus %s, which the public IOMMU API can't fully support yet. You will still need to disable one or more for this to work, sorry!\n",
+		      dev_bus_name(dev)))
+		return -EBUSY;
+
+	*ops = dev_iommu_ops(dev);
+	return 0;
+}
+
 struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus)
 {
-	if (bus == NULL || bus->iommu_ops == NULL)
+	const struct iommu_ops *ops = NULL;
+	int err = bus_for_each_dev(bus, NULL, &ops, __iommu_domain_alloc_dev);
+
+	if (err || !ops)
 		return NULL;
-	return __iommu_domain_alloc(bus->iommu_ops, NULL,
-				    IOMMU_DOMAIN_UNMANAGED);
+
+	return __iommu_domain_alloc(ops, NULL, IOMMU_DOMAIN_UNMANAGED);
 }
 EXPORT_SYMBOL_GPL(iommu_domain_alloc);
 
-- 
2.39.2.101.g768bb238c484.dirty


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 5/7] iommu/arm-smmu: Don't register fwnode for legacy binding
  2023-10-11 18:14 [PATCH v5 0/7] iommu: Retire bus ops Robin Murphy
                   ` (3 preceding siblings ...)
  2023-10-11 18:14 ` [PATCH v5 4/7] iommu: Decouple iommu_domain_alloc() from bus ops Robin Murphy
@ 2023-10-11 18:14 ` Robin Murphy
  2023-10-12 12:56   ` Will Deacon
  2023-10-18 23:29   ` Jerry Snitselaar
  2023-10-11 18:14 ` [PATCH v5 6/7] iommu: Retire bus ops Robin Murphy
  2023-10-11 18:14 ` [PATCH v5 7/7] iommu: Clean up open-coded ownership checks Robin Murphy
  6 siblings, 2 replies; 29+ messages in thread
From: Robin Murphy @ 2023-10-11 18:14 UTC (permalink / raw)
  To: joro, will; +Cc: iommu, jgg, baolu.lu, linux-kernel

When using the legacy binding we bypass the of_xlate mechanism, so avoid
registering the instance fwnodes which act as keys for that. This will
help __iommu_probe_device() to retrieve the registered ops the same way
as for x86 etc. when no fwspec has previously been set up by of_xlate.

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
 drivers/iommu/arm/arm-smmu/arm-smmu.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index d6d1a2a55cc0..4b83a3adacd6 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -2161,7 +2161,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	err = iommu_device_register(&smmu->iommu, &arm_smmu_ops, dev);
+	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);
-- 
2.39.2.101.g768bb238c484.dirty


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 6/7] iommu: Retire bus ops
  2023-10-11 18:14 [PATCH v5 0/7] iommu: Retire bus ops Robin Murphy
                   ` (4 preceding siblings ...)
  2023-10-11 18:14 ` [PATCH v5 5/7] iommu/arm-smmu: Don't register fwnode for legacy binding Robin Murphy
@ 2023-10-11 18:14 ` Robin Murphy
  2023-10-18 23:36   ` Jerry Snitselaar
  2023-10-11 18:14 ` [PATCH v5 7/7] iommu: Clean up open-coded ownership checks Robin Murphy
  6 siblings, 1 reply; 29+ messages in thread
From: Robin Murphy @ 2023-10-11 18:14 UTC (permalink / raw)
  To: joro, will
  Cc: iommu, jgg, baolu.lu, linux-kernel, Rafael J . Wysocki,
	Christoph Hellwig, Greg Kroah-Hartman

With the rest of the API internals converted, it's time to finally
tackle probe_device and how we bootstrap the per-device ops association
to begin with. This ends up being disappointingly straightforward, since
fwspec users are already doing it in order to find their of_xlate
callback, and it works out that we can easily do the equivalent for
other drivers too. Then shuffle the remaining awareness of iommu_ops
into the couple of core headers that still need it, and breathe a sigh
of relief.

Ding dong the bus ops are gone!

CC: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>

---

v4: Don't forget new reference in iommu_device_register_bus()
---
 drivers/iommu/iommu.c       | 31 ++++++++++++++++++-------------
 include/acpi/acpi_bus.h     |  2 ++
 include/linux/device.h      |  1 -
 include/linux/device/bus.h  |  5 -----
 include/linux/dma-map-ops.h |  1 +
 5 files changed, 21 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 18667dc2ff86..6962f2c99428 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -148,7 +148,7 @@ struct iommu_group_attribute iommu_group_attr_##_name =		\
 static LIST_HEAD(iommu_device_list);
 static DEFINE_SPINLOCK(iommu_device_lock);
 
-static struct bus_type * const iommu_buses[] = {
+static const struct bus_type * const iommu_buses[] = {
 	&platform_bus_type,
 #ifdef CONFIG_PCI
 	&pci_bus_type,
@@ -257,13 +257,6 @@ int iommu_device_register(struct iommu_device *iommu,
 	/* We need to be able to take module references appropriately */
 	if (WARN_ON(is_module_address((unsigned long)ops) && !ops->owner))
 		return -EINVAL;
-	/*
-	 * Temporarily enforce global restriction to a single driver. This was
-	 * already the de-facto behaviour, since any possible combination of
-	 * existing drivers would compete for at least the PCI or platform bus.
-	 */
-	if (iommu_buses[0]->iommu_ops && iommu_buses[0]->iommu_ops != ops)
-		return -EBUSY;
 
 	iommu->ops = ops;
 	if (hwdev)
@@ -273,10 +266,8 @@ int iommu_device_register(struct iommu_device *iommu,
 	list_add_tail(&iommu->list, &iommu_device_list);
 	spin_unlock(&iommu_device_lock);
 
-	for (int i = 0; i < ARRAY_SIZE(iommu_buses) && !err; i++) {
-		iommu_buses[i]->iommu_ops = ops;
+	for (int i = 0; i < ARRAY_SIZE(iommu_buses) && !err; i++)
 		err = bus_iommu_probe(iommu_buses[i]);
-	}
 	if (err)
 		iommu_device_unregister(iommu);
 	return err;
@@ -329,7 +320,6 @@ int iommu_device_register_bus(struct iommu_device *iommu,
 	list_add_tail(&iommu->list, &iommu_device_list);
 	spin_unlock(&iommu_device_lock);
 
-	bus->iommu_ops = ops;
 	err = bus_iommu_probe(bus);
 	if (err) {
 		iommu_device_unregister_bus(iommu, bus, nb);
@@ -496,12 +486,27 @@ static void iommu_deinit_device(struct device *dev)
 
 static int __iommu_probe_device(struct device *dev, struct list_head *group_list)
 {
-	const struct iommu_ops *ops = dev->bus->iommu_ops;
+	const struct iommu_ops *ops;
+	struct iommu_fwspec *fwspec;
 	struct iommu_group *group;
 	static DEFINE_MUTEX(iommu_probe_device_lock);
 	struct group_device *gdev;
 	int ret;
 
+	/*
+	 * For FDT-based systems and ACPI IORT/VIOT, drivers register IOMMU
+	 * instances with non-NULL fwnodes, and client devices should have been
+	 * identified with a fwspec by this point. Otherwise, we can currently
+	 * 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.
+	 */
+	fwspec = dev_iommu_fwspec_get(dev);
+	if (fwspec && fwspec->ops)
+		ops = fwspec->ops;
+	else
+		ops = iommu_ops_from_fwnode(NULL);
+
 	if (!ops)
 		return -ENODEV;
 	/*
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 254685085c82..13d959b3ba29 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -623,6 +623,8 @@ struct acpi_pci_root {
 
 /* helper */
 
+struct iommu_ops;
+
 bool acpi_dma_supported(const struct acpi_device *adev);
 enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
 int acpi_iommu_fwspec_init(struct device *dev, u32 id,
diff --git a/include/linux/device.h b/include/linux/device.h
index 56d93a1ffb7b..b78e66f3b34a 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -42,7 +42,6 @@ struct class;
 struct subsys_private;
 struct device_node;
 struct fwnode_handle;
-struct iommu_ops;
 struct iommu_group;
 struct dev_pin_info;
 struct dev_iommu;
diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h
index ae10c4322754..e25aab08f873 100644
--- a/include/linux/device/bus.h
+++ b/include/linux/device/bus.h
@@ -62,9 +62,6 @@ struct fwnode_handle;
  *			this bus.
  * @pm:		Power management operations of this bus, callback the specific
  *		device driver's pm-ops.
- * @iommu_ops:  IOMMU specific operations for this bus, used to attach IOMMU
- *              driver implementations to a bus and allow the driver to do
- *              bus-specific setup
  * @need_parent_lock:	When probing or removing a device on this bus, the
  *			device core should lock the device's parent.
  *
@@ -104,8 +101,6 @@ struct bus_type {
 
 	const struct dev_pm_ops *pm;
 
-	const struct iommu_ops *iommu_ops;
-
 	bool need_parent_lock;
 };
 
diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
index f2fc203fb8a1..a52e508d1869 100644
--- a/include/linux/dma-map-ops.h
+++ b/include/linux/dma-map-ops.h
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 
 struct cma;
+struct iommu_ops;
 
 /*
  * Values for struct dma_map_ops.flags:
-- 
2.39.2.101.g768bb238c484.dirty


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 7/7] iommu: Clean up open-coded ownership checks
  2023-10-11 18:14 [PATCH v5 0/7] iommu: Retire bus ops Robin Murphy
                   ` (5 preceding siblings ...)
  2023-10-11 18:14 ` [PATCH v5 6/7] iommu: Retire bus ops Robin Murphy
@ 2023-10-11 18:14 ` Robin Murphy
  2023-10-12 12:57   ` Will Deacon
  2023-10-18 23:40   ` Jerry Snitselaar
  6 siblings, 2 replies; 29+ messages in thread
From: Robin Murphy @ 2023-10-11 18:14 UTC (permalink / raw)
  To: joro, will; +Cc: iommu, jgg, baolu.lu, linux-kernel

Some drivers already implement their own defence against the possibility
of being given someone else's device. Since this is now taken care of by
the core code (and via a slightly different path from the original
fwspec-based idea), let's clean them up.

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  3 ---
 drivers/iommu/arm/arm-smmu/arm-smmu.c       |  9 +--------
 drivers/iommu/arm/arm-smmu/qcom_iommu.c     | 16 +++-------------
 drivers/iommu/mtk_iommu.c                   |  7 +------
 drivers/iommu/mtk_iommu_v1.c                |  3 ---
 drivers/iommu/sprd-iommu.c                  |  8 +-------
 drivers/iommu/virtio-iommu.c                |  3 ---
 7 files changed, 6 insertions(+), 43 deletions(-)

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 e82bf1c449a3..01ea307c7791 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2653,9 +2653,6 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
 	struct arm_smmu_master *master;
 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
 
-	if (!fwspec || fwspec->ops != &arm_smmu_ops)
-		return ERR_PTR(-ENODEV);
-
 	if (WARN_ON_ONCE(dev_iommu_priv_get(dev)))
 		return ERR_PTR(-EBUSY);
 
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 4b83a3adacd6..4d09c0047892 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -1116,11 +1116,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 	struct arm_smmu_device *smmu;
 	int ret;
 
-	if (!fwspec || fwspec->ops != &arm_smmu_ops) {
-		dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
-		return -ENXIO;
-	}
-
 	/*
 	 * FIXME: The arch/arm DMA API code tries to attach devices to its own
 	 * domains between of_xlate() and probe_device() - we have no way to cope
@@ -1357,10 +1352,8 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
 		fwspec = dev_iommu_fwspec_get(dev);
 		if (ret)
 			goto out_free;
-	} else if (fwspec && fwspec->ops == &arm_smmu_ops) {
-		smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
 	} else {
-		return ERR_PTR(-ENODEV);
+		smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
 	}
 
 	ret = -EINVAL;
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 97b2122032b2..33f3c870086c 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -79,16 +79,6 @@ static struct qcom_iommu_domain *to_qcom_iommu_domain(struct iommu_domain *dom)
 
 static const struct iommu_ops qcom_iommu_ops;
 
-static struct qcom_iommu_dev * to_iommu(struct device *dev)
-{
-	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-
-	if (!fwspec || fwspec->ops != &qcom_iommu_ops)
-		return NULL;
-
-	return dev_iommu_priv_get(dev);
-}
-
 static struct qcom_iommu_ctx * to_ctx(struct qcom_iommu_domain *d, unsigned asid)
 {
 	struct qcom_iommu_dev *qcom_iommu = d->iommu;
@@ -372,7 +362,7 @@ static void qcom_iommu_domain_free(struct iommu_domain *domain)
 
 static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
 {
-	struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
+	struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
 	struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
 	int ret;
 
@@ -404,7 +394,7 @@ static int qcom_iommu_identity_attach(struct iommu_domain *identity_domain,
 	struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
 	struct qcom_iommu_domain *qcom_domain;
 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-	struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
+	struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
 	unsigned int i;
 
 	if (domain == identity_domain || !domain)
@@ -535,7 +525,7 @@ static bool qcom_iommu_capable(struct device *dev, enum iommu_cap cap)
 
 static struct iommu_device *qcom_iommu_probe_device(struct device *dev)
 {
-	struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
+	struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
 	struct device_link *link;
 
 	if (!qcom_iommu)
diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 19ef50221c93..0a3698c33e19 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -863,16 +863,11 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
 static struct iommu_device *mtk_iommu_probe_device(struct device *dev)
 {
 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-	struct mtk_iommu_data *data;
+	struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
 	struct device_link *link;
 	struct device *larbdev;
 	unsigned int larbid, larbidx, i;
 
-	if (!fwspec || fwspec->ops != &mtk_iommu_ops)
-		return ERR_PTR(-ENODEV); /* Not a iommu client device */
-
-	data = dev_iommu_priv_get(dev);
-
 	if (!MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM))
 		return &data->iommu;
 
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 67e044c1a7d9..25b41222abae 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -481,9 +481,6 @@ static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev)
 		idx++;
 	}
 
-	if (!fwspec || fwspec->ops != &mtk_iommu_v1_ops)
-		return ERR_PTR(-ENODEV); /* Not a iommu client device */
-
 	data = dev_iommu_priv_get(dev);
 
 	/* Link the consumer device with the smi-larb device(supplier) */
diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c
index 9c33ea6903f6..b15a8fe7ae8a 100644
--- a/drivers/iommu/sprd-iommu.c
+++ b/drivers/iommu/sprd-iommu.c
@@ -384,13 +384,7 @@ static phys_addr_t sprd_iommu_iova_to_phys(struct iommu_domain *domain,
 
 static struct iommu_device *sprd_iommu_probe_device(struct device *dev)
 {
-	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-	struct sprd_iommu_device *sdev;
-
-	if (!fwspec || fwspec->ops != &sprd_iommu_ops)
-		return ERR_PTR(-ENODEV);
-
-	sdev = dev_iommu_priv_get(dev);
+	struct sprd_iommu_device *sdev = dev_iommu_priv_get(dev);
 
 	return &sdev->iommu;
 }
diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c
index 17dcd826f5c2..bb2e795a80d0 100644
--- a/drivers/iommu/virtio-iommu.c
+++ b/drivers/iommu/virtio-iommu.c
@@ -969,9 +969,6 @@ static struct iommu_device *viommu_probe_device(struct device *dev)
 	struct viommu_dev *viommu = NULL;
 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
 
-	if (!fwspec || fwspec->ops != &viommu_ops)
-		return ERR_PTR(-ENODEV);
-
 	viommu = viommu_get_by_fwnode(fwspec->iommu_fwnode);
 	if (!viommu)
 		return ERR_PTR(-ENODEV);
-- 
2.39.2.101.g768bb238c484.dirty


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 1/7] iommu: Factor out some helpers
  2023-10-11 18:14 ` [PATCH v5 1/7] iommu: Factor out some helpers Robin Murphy
@ 2023-10-11 23:34   ` Jason Gunthorpe
  2023-10-18 23:04   ` Jerry Snitselaar
  1 sibling, 0 replies; 29+ messages in thread
From: Jason Gunthorpe @ 2023-10-11 23:34 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:48PM +0100, Robin Murphy wrote:
> The pattern for picking the first device out of the group list is
> repeated a few times now, so it's clearly worth factoring out, which
> also helps hide the iommu_group_dev detail from places that don't need
> to know. Similarly, the safety check for dev_iommu_ops() at certain
> public interfaces starts looking a bit repetitive, and might not be
> completely obvious at first glance, so let's factor that out for clarity
> as well, in preparation for more uses of both.
> 
> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> 
> ---
> 
> v3: Rename dev_iommu_ops_valid() to reflect what it's actually checking,
>     rather than an implied consequence.
> v4: Rebase, also catch the sneaky one in iommu_get_group_resv_regions()
>     which wasn't the full pattern (but really should be since it guards
>     the dev_iommu_ops() invocation in iommu_get_resv_regions()).
> ---
>  drivers/iommu/iommu.c | 56 ++++++++++++++++++++-----------------------
>  1 file changed, 26 insertions(+), 30 deletions(-)

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>

Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 4/7] iommu: Decouple iommu_domain_alloc() from bus ops
  2023-10-11 18:14 ` [PATCH v5 4/7] iommu: Decouple iommu_domain_alloc() from bus ops Robin Murphy
@ 2023-10-11 23:38   ` Jason Gunthorpe
  2023-10-18 23:15   ` Jerry Snitselaar
  1 sibling, 0 replies; 29+ messages in thread
From: Jason Gunthorpe @ 2023-10-11 23:38 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:51PM +0100, Robin Murphy wrote:
> As the final remaining piece of bus-dependent API, iommu_domain_alloc()
> can now take responsibility for the "one iommu_ops per bus" rule for
> itself. It turns out we can't safely make the internal allocation call
> any more group-based or device-based yet - that will have to wait until
> the external callers can pass the right thing - but we can at least get
> as far as deriving "bus ops" based on which driver is actually managing
> devices on the given bus, rather than whichever driver won the race to
> register first.
> 
> This will then leave us able to convert the last of the core internals
> over to the IOMMU-instance model, allow multiple drivers to register and
> actually coexist (modulo the above limitation for unmanaged domain users
> in the short term), and start trying to solve the long-standing
> iommu_probe_device() mess.
> 
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> 
> ---
> 
> v5: Rewrite, de-scoping to just retrieve ops under the same assumptions
>     as the existing code.
> ---
>  drivers/iommu/iommu.c | 25 ++++++++++++++++++++++---
>  1 file changed, 22 insertions(+), 3 deletions(-)

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>

FWIW, I was thinking afterwords that domain_alloc_paging() probably
should have been:

(domain_alloc_paging *)(struct iommu_device *iommu, struct iommu_group *group)

Most drivers can use the iommu and ignore the group, a few special
ones can do the needed reduce operation across the group.

We can get to that later when we get deeper into the PASID troubles,
it also requires the deferal of the domain creation like the bus code
probe does but the fwnode path doesn't :\

Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops
  2023-10-11 18:14 ` [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops Robin Murphy
@ 2023-10-12  6:05   ` Baolu Lu
  2023-10-12 11:40     ` Robin Murphy
  2023-10-12 12:58   ` Baolu Lu
  2023-10-18 23:05   ` Jerry Snitselaar
  2 siblings, 1 reply; 29+ messages in thread
From: Baolu Lu @ 2023-10-12  6:05 UTC (permalink / raw)
  To: Robin Murphy, joro, will; +Cc: baolu.lu, iommu, jgg, linux-kernel

On 10/12/23 2:14 AM, Robin Murphy wrote:
> Much as I'd like to remove iommu_present(), the final remaining users
> are proving stubbornly difficult to clean up, so kick that can down the
> road and just rework it to preserve the current behaviour without
> depending on bus ops. Since commit 57365a04c921 ("iommu: Move bus setup

The iommu_present() is only used in below two drivers.

$ git grep iommu_present
drivers/gpu/drm/mediatek/mtk_drm_drv.c: if 
(!iommu_present(&platform_bus_type))
drivers/gpu/drm/tegra/drm.c:    if (host1x_drm_wants_iommu(dev) && 
iommu_present(&platform_bus_type)) {

Both are platform drivers and have the device pointer passed in. Just
out of curiosity, why not replacing them with device_iommu_mapped()
instead? Sorry if I overlooked previous discussion.

Best regards,
baolu

> to IOMMU device registration"), any registered IOMMU instance is already
> considered "present" for every entry in iommu_buses, so it's simply a
> case of validating the bus and checking we have at least once IOMMU.
> 
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> 
> ---
> 
> v3: Tweak to use the ops-based check rather than group-based, to
>      properly match the existing behaviour
> v4: Just look for IOMMU instances instead of managed devices
> ---
>   drivers/iommu/iommu.c | 21 ++++++++++++++++++++-
>   1 file changed, 20 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 5a3ce293a5de..7bb92e8b7a49 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -2000,9 +2000,28 @@ int bus_iommu_probe(const struct bus_type *bus)
>   	return 0;
>   }
>   
> +/**
> + * iommu_present() - make platform-specific assumptions about an IOMMU
> + * @bus: bus to check
> + *
> + * Do not use this function. You want device_iommu_mapped() instead.
> + *
> + * Return: true if some IOMMU is present and aware of devices on the given bus;
> + * in general it may not be the only IOMMU, and it may not have anything to do
> + * with whatever device you are ultimately interested in.
> + */
>   bool iommu_present(const struct bus_type *bus)
>   {
> -	return bus->iommu_ops != NULL;
> +	bool ret = false;
> +
> +	for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
> +		if (iommu_buses[i] == bus) {
> +			spin_lock(&iommu_device_lock);
> +			ret = !list_empty(&iommu_device_list);
> +			spin_unlock(&iommu_device_lock);
> +		}
> +	}
> +	return ret;
>   }
>   EXPORT_SYMBOL_GPL(iommu_present);
>   

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops
  2023-10-12  6:05   ` Baolu Lu
@ 2023-10-12 11:40     ` Robin Murphy
  2023-10-12 12:37       ` Jason Gunthorpe
  0 siblings, 1 reply; 29+ messages in thread
From: Robin Murphy @ 2023-10-12 11:40 UTC (permalink / raw)
  To: Baolu Lu, joro, will; +Cc: iommu, jgg, linux-kernel

On 2023-10-12 07:05, Baolu Lu wrote:
> On 10/12/23 2:14 AM, Robin Murphy wrote:
>> Much as I'd like to remove iommu_present(), the final remaining users
>> are proving stubbornly difficult to clean up, so kick that can down the
>> road and just rework it to preserve the current behaviour without
>> depending on bus ops. Since commit 57365a04c921 ("iommu: Move bus setup
> 
> The iommu_present() is only used in below two drivers.
> 
> $ git grep iommu_present
> drivers/gpu/drm/mediatek/mtk_drm_drv.c: if 
> (!iommu_present(&platform_bus_type))
> drivers/gpu/drm/tegra/drm.c:    if (host1x_drm_wants_iommu(dev) && 
> iommu_present(&platform_bus_type)) {
> 
> Both are platform drivers and have the device pointer passed in. Just
> out of curiosity, why not replacing them with device_iommu_mapped()
> instead? Sorry if I overlooked previous discussion.

Yes, we've already gone round in circles on this several times, that's 
why it's explicitly called out as "stubbornly difficult" in the commit 
message. The Mediatek one is entirely redundant, but it seems I have yet 
to figure out the right CC list to get anyone to care about that 
patch[1]. The Tegra one is making some non-obvious assumptions to 
actually check on behalf of some *other* devices, even when the one to 
hand may not be using the IOMMU itself[2]. That case is what the new 
kerneldoc alludes to.

My hope is to eventually punt this into the Tegra driver itself 
(probably at the point when it needs something similar for 
iommu_domain_alloc() as well), however previous experience has taught me 
that trying to coordinate cross-subsystem work with drm-misc is an 
ordeal best avoided until there is no possible alternative.

Thanks,
Robin.

[1] https://patchwork.freedesktop.org/patch/536273/
[2] 
https://lore.kernel.org/linux-iommu/a0c7e954-ee3f-74fd-cfea-9b6dbce924dc@collabora.com/

> 
> Best regards,
> baolu
> 
>> to IOMMU device registration"), any registered IOMMU instance is already
>> considered "present" for every entry in iommu_buses, so it's simply a
>> case of validating the bus and checking we have at least once IOMMU.
>>
>> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
>> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
>>
>> ---
>>
>> v3: Tweak to use the ops-based check rather than group-based, to
>>      properly match the existing behaviour
>> v4: Just look for IOMMU instances instead of managed devices
>> ---
>>   drivers/iommu/iommu.c | 21 ++++++++++++++++++++-
>>   1 file changed, 20 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>> index 5a3ce293a5de..7bb92e8b7a49 100644
>> --- a/drivers/iommu/iommu.c
>> +++ b/drivers/iommu/iommu.c
>> @@ -2000,9 +2000,28 @@ int bus_iommu_probe(const struct bus_type *bus)
>>       return 0;
>>   }
>> +/**
>> + * iommu_present() - make platform-specific assumptions about an IOMMU
>> + * @bus: bus to check
>> + *
>> + * Do not use this function. You want device_iommu_mapped() instead.
>> + *
>> + * Return: true if some IOMMU is present and aware of devices on the 
>> given bus;
>> + * in general it may not be the only IOMMU, and it may not have 
>> anything to do
>> + * with whatever device you are ultimately interested in.
>> + */
>>   bool iommu_present(const struct bus_type *bus)
>>   {
>> -    return bus->iommu_ops != NULL;
>> +    bool ret = false;
>> +
>> +    for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
>> +        if (iommu_buses[i] == bus) {
>> +            spin_lock(&iommu_device_lock);
>> +            ret = !list_empty(&iommu_device_list);
>> +            spin_unlock(&iommu_device_lock);
>> +        }
>> +    }
>> +    return ret;
>>   }
>>   EXPORT_SYMBOL_GPL(iommu_present);

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops
  2023-10-12 11:40     ` Robin Murphy
@ 2023-10-12 12:37       ` Jason Gunthorpe
  2023-10-12 12:57         ` Baolu Lu
  0 siblings, 1 reply; 29+ messages in thread
From: Jason Gunthorpe @ 2023-10-12 12:37 UTC (permalink / raw)
  To: Robin Murphy; +Cc: Baolu Lu, joro, will, iommu, linux-kernel

On Thu, Oct 12, 2023 at 12:40:01PM +0100, Robin Murphy wrote:
> On 2023-10-12 07:05, Baolu Lu wrote:
> > On 10/12/23 2:14 AM, Robin Murphy wrote:
> > > Much as I'd like to remove iommu_present(), the final remaining users
> > > are proving stubbornly difficult to clean up, so kick that can down the
> > > road and just rework it to preserve the current behaviour without
> > > depending on bus ops. Since commit 57365a04c921 ("iommu: Move bus setup
> > 
> > The iommu_present() is only used in below two drivers.
> > 
> > $ git grep iommu_present
> > drivers/gpu/drm/mediatek/mtk_drm_drv.c: if
> > (!iommu_present(&platform_bus_type))
> > drivers/gpu/drm/tegra/drm.c:    if (host1x_drm_wants_iommu(dev) &&
> > iommu_present(&platform_bus_type)) {
> > 
> > Both are platform drivers and have the device pointer passed in. Just
> > out of curiosity, why not replacing them with device_iommu_mapped()
> > instead? Sorry if I overlooked previous discussion.
> 
> Yes, we've already gone round in circles on this several times, that's why
> it's explicitly called out as "stubbornly difficult" in the commit message.
> The Mediatek one is entirely redundant, but it seems I have yet to figure
> out the right CC list to get anyone to care about that patch[1].

Please just have Joerg take such a trivial patch, there is no reason
we need to torture outselves because DRM side is not behaving well. :(

Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 5/7] iommu/arm-smmu: Don't register fwnode for legacy binding
  2023-10-11 18:14 ` [PATCH v5 5/7] iommu/arm-smmu: Don't register fwnode for legacy binding Robin Murphy
@ 2023-10-12 12:56   ` Will Deacon
  2023-10-18 23:29   ` Jerry Snitselaar
  1 sibling, 0 replies; 29+ messages in thread
From: Will Deacon @ 2023-10-12 12:56 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, iommu, jgg, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:52PM +0100, Robin Murphy wrote:
> When using the legacy binding we bypass the of_xlate mechanism, so avoid
> registering the instance fwnodes which act as keys for that. This will
> help __iommu_probe_device() to retrieve the registered ops the same way
> as for x86 etc. when no fwspec has previously been set up by of_xlate.
> 
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> ---
>  drivers/iommu/arm/arm-smmu/arm-smmu.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> index d6d1a2a55cc0..4b83a3adacd6 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> @@ -2161,7 +2161,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>  		return err;
>  	}
>  
> -	err = iommu_device_register(&smmu->iommu, &arm_smmu_ops, dev);
> +	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);
> -- 
> 2.39.2.101.g768bb238c484.dirty

Acked-by: Will Deacon <will@kernel.org>

Will

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops
  2023-10-12 12:37       ` Jason Gunthorpe
@ 2023-10-12 12:57         ` Baolu Lu
  0 siblings, 0 replies; 29+ messages in thread
From: Baolu Lu @ 2023-10-12 12:57 UTC (permalink / raw)
  To: Jason Gunthorpe, Robin Murphy; +Cc: baolu.lu, joro, will, iommu, linux-kernel

On 2023/10/12 20:37, Jason Gunthorpe wrote:
> On Thu, Oct 12, 2023 at 12:40:01PM +0100, Robin Murphy wrote:
>> On 2023-10-12 07:05, Baolu Lu wrote:
>>> On 10/12/23 2:14 AM, Robin Murphy wrote:
>>>> Much as I'd like to remove iommu_present(), the final remaining users
>>>> are proving stubbornly difficult to clean up, so kick that can down the
>>>> road and just rework it to preserve the current behaviour without
>>>> depending on bus ops. Since commit 57365a04c921 ("iommu: Move bus setup
>>>
>>> The iommu_present() is only used in below two drivers.
>>>
>>> $ git grep iommu_present
>>> drivers/gpu/drm/mediatek/mtk_drm_drv.c: if
>>> (!iommu_present(&platform_bus_type))
>>> drivers/gpu/drm/tegra/drm.c:    if (host1x_drm_wants_iommu(dev) &&
>>> iommu_present(&platform_bus_type)) {
>>>
>>> Both are platform drivers and have the device pointer passed in. Just
>>> out of curiosity, why not replacing them with device_iommu_mapped()
>>> instead? Sorry if I overlooked previous discussion.
>>
>> Yes, we've already gone round in circles on this several times, that's why
>> it's explicitly called out as "stubbornly difficult" in the commit message.
>> The Mediatek one is entirely redundant, but it seems I have yet to figure
>> out the right CC list to get anyone to care about that patch[1].

I see now. Thanks for the explanation.

> 
> Please just have Joerg take such a trivial patch, there is no reason
> we need to torture outselves because DRM side is not behaving well. :(

I was not object to the patch. Just want to make sure that I understand
the reason why device_iommu_mapped() can't be used in those two drivers.

It's fine to me. I will add my r-b.

Best regards,
baolu


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 7/7] iommu: Clean up open-coded ownership checks
  2023-10-11 18:14 ` [PATCH v5 7/7] iommu: Clean up open-coded ownership checks Robin Murphy
@ 2023-10-12 12:57   ` Will Deacon
  2023-10-18 23:40   ` Jerry Snitselaar
  1 sibling, 0 replies; 29+ messages in thread
From: Will Deacon @ 2023-10-12 12:57 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, iommu, jgg, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:54PM +0100, Robin Murphy wrote:
> Some drivers already implement their own defence against the possibility
> of being given someone else's device. Since this is now taken care of by
> the core code (and via a slightly different path from the original
> fwspec-based idea), let's clean them up.
> 
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  3 ---
>  drivers/iommu/arm/arm-smmu/arm-smmu.c       |  9 +--------
>  drivers/iommu/arm/arm-smmu/qcom_iommu.c     | 16 +++-------------
>  drivers/iommu/mtk_iommu.c                   |  7 +------
>  drivers/iommu/mtk_iommu_v1.c                |  3 ---
>  drivers/iommu/sprd-iommu.c                  |  8 +-------
>  drivers/iommu/virtio-iommu.c                |  3 ---
>  7 files changed, 6 insertions(+), 43 deletions(-)

Acked-by: Will Deacon <will@kernel.org>

Will

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops
  2023-10-11 18:14 ` [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops Robin Murphy
  2023-10-12  6:05   ` Baolu Lu
@ 2023-10-12 12:58   ` Baolu Lu
  2023-10-18 23:05   ` Jerry Snitselaar
  2 siblings, 0 replies; 29+ messages in thread
From: Baolu Lu @ 2023-10-12 12:58 UTC (permalink / raw)
  To: Robin Murphy, joro, will; +Cc: baolu.lu, iommu, jgg, linux-kernel

On 2023/10/12 2:14, Robin Murphy wrote:
> Much as I'd like to remove iommu_present(), the final remaining users
> are proving stubbornly difficult to clean up, so kick that can down the
> road and just rework it to preserve the current behaviour without
> depending on bus ops. Since commit 57365a04c921 ("iommu: Move bus setup
> to IOMMU device registration"), any registered IOMMU instance is already
> considered "present" for every entry in iommu_buses, so it's simply a
> case of validating the bus and checking we have at least once IOMMU.
> 
> Reviewed-by: Jason Gunthorpe<jgg@nvidia.com>
> Signed-off-by: Robin Murphy<robin.murphy@arm.com>

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>

Best regards,
baolu

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 1/7] iommu: Factor out some helpers
  2023-10-11 18:14 ` [PATCH v5 1/7] iommu: Factor out some helpers Robin Murphy
  2023-10-11 23:34   ` Jason Gunthorpe
@ 2023-10-18 23:04   ` Jerry Snitselaar
  1 sibling, 0 replies; 29+ messages in thread
From: Jerry Snitselaar @ 2023-10-18 23:04 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, jgg, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:48PM +0100, Robin Murphy wrote:
> The pattern for picking the first device out of the group list is
> repeated a few times now, so it's clearly worth factoring out, which
> also helps hide the iommu_group_dev detail from places that don't need
> to know. Similarly, the safety check for dev_iommu_ops() at certain
> public interfaces starts looking a bit repetitive, and might not be
> completely obvious at first glance, so let's factor that out for clarity
> as well, in preparation for more uses of both.
> 
> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> 
> ---
> 
> v3: Rename dev_iommu_ops_valid() to reflect what it's actually checking,
>     rather than an implied consequence.
> v4: Rebase, also catch the sneaky one in iommu_get_group_resv_regions()
>     which wasn't the full pattern (but really should be since it guards
>     the dev_iommu_ops() invocation in iommu_get_resv_regions()).
> ---


Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops
  2023-10-11 18:14 ` [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops Robin Murphy
  2023-10-12  6:05   ` Baolu Lu
  2023-10-12 12:58   ` Baolu Lu
@ 2023-10-18 23:05   ` Jerry Snitselaar
  2 siblings, 0 replies; 29+ messages in thread
From: Jerry Snitselaar @ 2023-10-18 23:05 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, jgg, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:49PM +0100, Robin Murphy wrote:
> Much as I'd like to remove iommu_present(), the final remaining users
> are proving stubbornly difficult to clean up, so kick that can down the
> road and just rework it to preserve the current behaviour without
> depending on bus ops. Since commit 57365a04c921 ("iommu: Move bus setup
> to IOMMU device registration"), any registered IOMMU instance is already
> considered "present" for every entry in iommu_buses, so it's simply a
> case of validating the bus and checking we have at least once IOMMU.
> 
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> 
> ---
> 
> v3: Tweak to use the ops-based check rather than group-based, to
>     properly match the existing behaviour
> v4: Just look for IOMMU instances instead of managed devices
> ---

Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 3/7] iommu: Validate that devices match domains
  2023-10-11 18:14 ` [PATCH v5 3/7] iommu: Validate that devices match domains Robin Murphy
@ 2023-10-18 23:14   ` Jerry Snitselaar
  2023-10-24 18:52   ` Jason Gunthorpe
  1 sibling, 0 replies; 29+ messages in thread
From: Jerry Snitselaar @ 2023-10-18 23:14 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, jgg, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:50PM +0100, Robin Murphy wrote:
> Before we can allow drivers to coexist, we need to make sure that one
> driver's domain ops can't misinterpret another driver's dev_iommu_priv
> data. To that end, add a token to the domain so we can remember how it
> was allocated - for now this may as well be the device ops, since they
> still correlate 1:1 with drivers. We can trust ourselves for internal
> default domain attachment, so add checks to cover all the public attach
> interfaces.
> 
> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> 
> ---
> 
> v4: Cover iommu_attach_device_pasid() as well, and improve robustness
>     against theoretical attempts to attach a noiommu group.
> ---

Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 4/7] iommu: Decouple iommu_domain_alloc() from bus ops
  2023-10-11 18:14 ` [PATCH v5 4/7] iommu: Decouple iommu_domain_alloc() from bus ops Robin Murphy
  2023-10-11 23:38   ` Jason Gunthorpe
@ 2023-10-18 23:15   ` Jerry Snitselaar
  1 sibling, 0 replies; 29+ messages in thread
From: Jerry Snitselaar @ 2023-10-18 23:15 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, jgg, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:51PM +0100, Robin Murphy wrote:
> As the final remaining piece of bus-dependent API, iommu_domain_alloc()
> can now take responsibility for the "one iommu_ops per bus" rule for
> itself. It turns out we can't safely make the internal allocation call
> any more group-based or device-based yet - that will have to wait until
> the external callers can pass the right thing - but we can at least get
> as far as deriving "bus ops" based on which driver is actually managing
> devices on the given bus, rather than whichever driver won the race to
> register first.
> 
> This will then leave us able to convert the last of the core internals
> over to the IOMMU-instance model, allow multiple drivers to register and
> actually coexist (modulo the above limitation for unmanaged domain users
> in the short term), and start trying to solve the long-standing
> iommu_probe_device() mess.
> 
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> 
> ---
> 
> v5: Rewrite, de-scoping to just retrieve ops under the same assumptions
>     as the existing code.
> ---

Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 5/7] iommu/arm-smmu: Don't register fwnode for legacy binding
  2023-10-11 18:14 ` [PATCH v5 5/7] iommu/arm-smmu: Don't register fwnode for legacy binding Robin Murphy
  2023-10-12 12:56   ` Will Deacon
@ 2023-10-18 23:29   ` Jerry Snitselaar
  1 sibling, 0 replies; 29+ messages in thread
From: Jerry Snitselaar @ 2023-10-18 23:29 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, jgg, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:52PM +0100, Robin Murphy wrote:
> When using the legacy binding we bypass the of_xlate mechanism, so avoid
> registering the instance fwnodes which act as keys for that. This will
> help __iommu_probe_device() to retrieve the registered ops the same way
> as for x86 etc. when no fwspec has previously been set up by of_xlate.
> 
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> ---
>  drivers/iommu/arm/arm-smmu/arm-smmu.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> index d6d1a2a55cc0..4b83a3adacd6 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> @@ -2161,7 +2161,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>  		return err;
>  	}
>  
> -	err = iommu_device_register(&smmu->iommu, &arm_smmu_ops, dev);
> +	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);
> -- 
> 2.39.2.101.g768bb238c484.dirty
> 

Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 6/7] iommu: Retire bus ops
  2023-10-11 18:14 ` [PATCH v5 6/7] iommu: Retire bus ops Robin Murphy
@ 2023-10-18 23:36   ` Jerry Snitselaar
  0 siblings, 0 replies; 29+ messages in thread
From: Jerry Snitselaar @ 2023-10-18 23:36 UTC (permalink / raw)
  To: Robin Murphy
  Cc: joro, will, iommu, jgg, baolu.lu, linux-kernel,
	Rafael J . Wysocki, Christoph Hellwig, Greg Kroah-Hartman

On Wed, Oct 11, 2023 at 07:14:53PM +0100, Robin Murphy wrote:
> With the rest of the API internals converted, it's time to finally
> tackle probe_device and how we bootstrap the per-device ops association
> to begin with. This ends up being disappointingly straightforward, since
> fwspec users are already doing it in order to find their of_xlate
> callback, and it works out that we can easily do the equivalent for
> other drivers too. Then shuffle the remaining awareness of iommu_ops
> into the couple of core headers that still need it, and breathe a sigh
> of relief.
> 
> Ding dong the bus ops are gone!
> 
> CC: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Acked-by: Christoph Hellwig <hch@lst.de>
> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> 
> ---
> 
> v4: Don't forget new reference in iommu_device_register_bus()
> ---
>  drivers/iommu/iommu.c       | 31 ++++++++++++++++++-------------
>  include/acpi/acpi_bus.h     |  2 ++
>  include/linux/device.h      |  1 -
>  include/linux/device/bus.h  |  5 -----
>  include/linux/dma-map-ops.h |  1 +
>  5 files changed, 21 insertions(+), 19 deletions(-)
> 

Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 7/7] iommu: Clean up open-coded ownership checks
  2023-10-11 18:14 ` [PATCH v5 7/7] iommu: Clean up open-coded ownership checks Robin Murphy
  2023-10-12 12:57   ` Will Deacon
@ 2023-10-18 23:40   ` Jerry Snitselaar
  1 sibling, 0 replies; 29+ messages in thread
From: Jerry Snitselaar @ 2023-10-18 23:40 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, jgg, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:54PM +0100, Robin Murphy wrote:
> Some drivers already implement their own defence against the possibility
> of being given someone else's device. Since this is now taken care of by
> the core code (and via a slightly different path from the original
> fwspec-based idea), let's clean them up.
> 
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  3 ---
>  drivers/iommu/arm/arm-smmu/arm-smmu.c       |  9 +--------
>  drivers/iommu/arm/arm-smmu/qcom_iommu.c     | 16 +++-------------
>  drivers/iommu/mtk_iommu.c                   |  7 +------
>  drivers/iommu/mtk_iommu_v1.c                |  3 ---
>  drivers/iommu/sprd-iommu.c                  |  8 +-------
>  drivers/iommu/virtio-iommu.c                |  3 ---
>  7 files changed, 6 insertions(+), 43 deletions(-)
> 

Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 3/7] iommu: Validate that devices match domains
  2023-10-11 18:14 ` [PATCH v5 3/7] iommu: Validate that devices match domains Robin Murphy
  2023-10-18 23:14   ` Jerry Snitselaar
@ 2023-10-24 18:52   ` Jason Gunthorpe
  2023-10-25 12:39     ` Robin Murphy
  1 sibling, 1 reply; 29+ messages in thread
From: Jason Gunthorpe @ 2023-10-24 18:52 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, baolu.lu, linux-kernel

On Wed, Oct 11, 2023 at 07:14:50PM +0100, Robin Murphy wrote:

> @@ -2279,10 +2280,16 @@ struct iommu_domain *iommu_get_dma_domain(struct device *dev)
>  static int __iommu_attach_group(struct iommu_domain *domain,
>  				struct iommu_group *group)
>  {
> +	struct device *dev;
> +
>  	if (group->domain && group->domain != group->default_domain &&
>  	    group->domain != group->blocking_domain)
>  		return -EBUSY;
>  
> +	dev = iommu_group_first_dev(group);
> +	if (!dev_has_iommu(dev) || dev_iommu_ops(dev) != domain->owner)
> +		return -EINVAL;

I was thinking about this later, how does this work for the global
static domains? domain->owner will not be set?

	if (alloc_type == IOMMU_DOMAIN_IDENTITY && ops->identity_domain)
		return ops->identity_domain;
	else if (alloc_type == IOMMU_DOMAIN_BLOCKED && ops->blocked_domain)
		return ops->blocked_domain;

Seems like it will break everything?

I suggest we just put a simple void * tag in the const domain->ops at
compile time to indicate the owning driver.

Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 3/7] iommu: Validate that devices match domains
  2023-10-24 18:52   ` Jason Gunthorpe
@ 2023-10-25 12:39     ` Robin Murphy
  2023-10-25 12:55       ` Jason Gunthorpe
  0 siblings, 1 reply; 29+ messages in thread
From: Robin Murphy @ 2023-10-25 12:39 UTC (permalink / raw)
  To: Jason Gunthorpe; +Cc: joro, will, iommu, baolu.lu, linux-kernel

On 24/10/2023 7:52 pm, Jason Gunthorpe wrote:
> On Wed, Oct 11, 2023 at 07:14:50PM +0100, Robin Murphy wrote:
> 
>> @@ -2279,10 +2280,16 @@ struct iommu_domain *iommu_get_dma_domain(struct device *dev)
>>   static int __iommu_attach_group(struct iommu_domain *domain,
>>   				struct iommu_group *group)
>>   {
>> +	struct device *dev;
>> +
>>   	if (group->domain && group->domain != group->default_domain &&
>>   	    group->domain != group->blocking_domain)
>>   		return -EBUSY;
>>   
>> +	dev = iommu_group_first_dev(group);
>> +	if (!dev_has_iommu(dev) || dev_iommu_ops(dev) != domain->owner)
>> +		return -EINVAL;
> 
> I was thinking about this later, how does this work for the global
> static domains? domain->owner will not be set?
> 
> 	if (alloc_type == IOMMU_DOMAIN_IDENTITY && ops->identity_domain)
> 		return ops->identity_domain;
> 	else if (alloc_type == IOMMU_DOMAIN_BLOCKED && ops->blocked_domain)
> 		return ops->blocked_domain;
> 
> Seems like it will break everything?

I don't believe it makes any significant difference - as the commit 
message points out, this validation is only applied at the public 
interface boundaries of iommu_attach_group(), iommu_attach_device(), and 
iommu_attach_device_pasid(), which are only expected to be operating on 
explicitly-allocated unmanaged domains. For internal default domain 
attachment, the domain is initially derived from the device/group itself 
so we know it's appropriate by construction.

I guess this *would* now prevent some external caller reaching in and 
trying to attach something to some other group's identity default 
domain, but frankly it feels like making that fail would be no bad thing 
anyway.

Thanks,
Robin.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 3/7] iommu: Validate that devices match domains
  2023-10-25 12:39     ` Robin Murphy
@ 2023-10-25 12:55       ` Jason Gunthorpe
  2023-10-25 16:05         ` Robin Murphy
  0 siblings, 1 reply; 29+ messages in thread
From: Jason Gunthorpe @ 2023-10-25 12:55 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, baolu.lu, linux-kernel

On Wed, Oct 25, 2023 at 01:39:56PM +0100, Robin Murphy wrote:
> On 24/10/2023 7:52 pm, Jason Gunthorpe wrote:
> > On Wed, Oct 11, 2023 at 07:14:50PM +0100, Robin Murphy wrote:
> > 
> > > @@ -2279,10 +2280,16 @@ struct iommu_domain *iommu_get_dma_domain(struct device *dev)
> > >   static int __iommu_attach_group(struct iommu_domain *domain,
> > >   				struct iommu_group *group)
> > >   {
> > > +	struct device *dev;
> > > +
> > >   	if (group->domain && group->domain != group->default_domain &&
> > >   	    group->domain != group->blocking_domain)
> > >   		return -EBUSY;
> > > +	dev = iommu_group_first_dev(group);
> > > +	if (!dev_has_iommu(dev) || dev_iommu_ops(dev) != domain->owner)
> > > +		return -EINVAL;
> > 
> > I was thinking about this later, how does this work for the global
> > static domains? domain->owner will not be set?
> > 
> > 	if (alloc_type == IOMMU_DOMAIN_IDENTITY && ops->identity_domain)
> > 		return ops->identity_domain;
> > 	else if (alloc_type == IOMMU_DOMAIN_BLOCKED && ops->blocked_domain)
> > 		return ops->blocked_domain;
> > 
> > Seems like it will break everything?
> 
> I don't believe it makes any significant difference - as the commit message
> points out, this validation is only applied at the public interface
> boundaries of iommu_attach_group(), iommu_attach_device(), 

Oh, making it only work for on domain type seems kind of hacky..

If that is the intention maybe the owner set should be moved into
iommu_domain_alloc() with a little comment noting that it is limited
to work in only a few cases?

I certainly didn't understand from the commit message to mean it was
only actually working for one domain type and this also blocks using
other types with the public interface.

> and iommu_attach_device_pasid(), which are only expected to be
> operating on explicitly-allocated unmanaged domains.

We have nesting now in the iommufd branch, and SVA will come soon for
these APIs.

Regardless this will clash with the iommufd branch for this reason so
I guess it needs to wait till rc1.

Thanks,
Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 3/7] iommu: Validate that devices match domains
  2023-10-25 12:55       ` Jason Gunthorpe
@ 2023-10-25 16:05         ` Robin Murphy
  2023-10-25 16:15           ` Jason Gunthorpe
  0 siblings, 1 reply; 29+ messages in thread
From: Robin Murphy @ 2023-10-25 16:05 UTC (permalink / raw)
  To: Jason Gunthorpe; +Cc: joro, will, iommu, baolu.lu, linux-kernel

On 25/10/2023 1:55 pm, Jason Gunthorpe wrote:
> On Wed, Oct 25, 2023 at 01:39:56PM +0100, Robin Murphy wrote:
>> On 24/10/2023 7:52 pm, Jason Gunthorpe wrote:
>>> On Wed, Oct 11, 2023 at 07:14:50PM +0100, Robin Murphy wrote:
>>>
>>>> @@ -2279,10 +2280,16 @@ struct iommu_domain *iommu_get_dma_domain(struct device *dev)
>>>>    static int __iommu_attach_group(struct iommu_domain *domain,
>>>>    				struct iommu_group *group)
>>>>    {
>>>> +	struct device *dev;
>>>> +
>>>>    	if (group->domain && group->domain != group->default_domain &&
>>>>    	    group->domain != group->blocking_domain)
>>>>    		return -EBUSY;
>>>> +	dev = iommu_group_first_dev(group);
>>>> +	if (!dev_has_iommu(dev) || dev_iommu_ops(dev) != domain->owner)
>>>> +		return -EINVAL;
>>>
>>> I was thinking about this later, how does this work for the global
>>> static domains? domain->owner will not be set?
>>>
>>> 	if (alloc_type == IOMMU_DOMAIN_IDENTITY && ops->identity_domain)
>>> 		return ops->identity_domain;
>>> 	else if (alloc_type == IOMMU_DOMAIN_BLOCKED && ops->blocked_domain)
>>> 		return ops->blocked_domain;
>>>
>>> Seems like it will break everything?
>>
>> I don't believe it makes any significant difference - as the commit message
>> points out, this validation is only applied at the public interface
>> boundaries of iommu_attach_group(), iommu_attach_device(),
> 
> Oh, making it only work for on domain type seems kind of hacky..
> 
> If that is the intention maybe the owner set should be moved into
> iommu_domain_alloc() with a little comment noting that it is limited
> to work in only a few cases?
> 
> I certainly didn't understand from the commit message to mean it was
> only actually working for one domain type and this also blocks using
> other types with the public interface.

It's not about one particular domain type, it's about the scope of what 
we consider valid usage. External API users should almost always be 
attaching to their own domain which they have allocated, however we also 
tolerate co-attaching additional groups to the same DMA domain in rare 
cases where it's reasonable. The fact is that those users cannot 
allocate blocking or identity domains, and I can't see that they would 
ever have any legitimate business trying to do anything with them 
anyway. So although yes, we technically lose some functionality once 
this intersects with the static domain optimisation, it's only 
questionable functionality which was never explicitly intended anyway.

I mean, what would be the valid purpose of trying to attach group A to 
group B's identity domain, even if they *were* backed by the same 
driver? At best it's pointless if group A also has its own identity 
domain already, otherwise at worst it's a deliberate attempt to 
circumvent a default domain policy imposed by the IOMMU core.

>> and iommu_attach_device_pasid(), which are only expected to be
>> operating on explicitly-allocated unmanaged domains.
> 
> We have nesting now in the iommufd branch, and SVA will come soon for
> these APIs.
> 
> Regardless this will clash with the iommufd branch for this reason so
> I guess it needs to wait till rc1.

Sigh, back on the shelf it goes then...

Thanks,
Robin.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 3/7] iommu: Validate that devices match domains
  2023-10-25 16:05         ` Robin Murphy
@ 2023-10-25 16:15           ` Jason Gunthorpe
  0 siblings, 0 replies; 29+ messages in thread
From: Jason Gunthorpe @ 2023-10-25 16:15 UTC (permalink / raw)
  To: Robin Murphy; +Cc: joro, will, iommu, baolu.lu, linux-kernel

On Wed, Oct 25, 2023 at 05:05:08PM +0100, Robin Murphy wrote:
> On 25/10/2023 1:55 pm, Jason Gunthorpe wrote:
> > On Wed, Oct 25, 2023 at 01:39:56PM +0100, Robin Murphy wrote:
> > > On 24/10/2023 7:52 pm, Jason Gunthorpe wrote:
> > > > On Wed, Oct 11, 2023 at 07:14:50PM +0100, Robin Murphy wrote:
> > > > 
> > > > > @@ -2279,10 +2280,16 @@ struct iommu_domain *iommu_get_dma_domain(struct device *dev)
> > > > >    static int __iommu_attach_group(struct iommu_domain *domain,
> > > > >    				struct iommu_group *group)
> > > > >    {
> > > > > +	struct device *dev;
> > > > > +
> > > > >    	if (group->domain && group->domain != group->default_domain &&
> > > > >    	    group->domain != group->blocking_domain)
> > > > >    		return -EBUSY;
> > > > > +	dev = iommu_group_first_dev(group);
> > > > > +	if (!dev_has_iommu(dev) || dev_iommu_ops(dev) != domain->owner)
> > > > > +		return -EINVAL;
> > > > 
> > > > I was thinking about this later, how does this work for the global
> > > > static domains? domain->owner will not be set?
> > > > 
> > > > 	if (alloc_type == IOMMU_DOMAIN_IDENTITY && ops->identity_domain)
> > > > 		return ops->identity_domain;
> > > > 	else if (alloc_type == IOMMU_DOMAIN_BLOCKED && ops->blocked_domain)
> > > > 		return ops->blocked_domain;
> > > > 
> > > > Seems like it will break everything?
> > > 
> > > I don't believe it makes any significant difference - as the commit message
> > > points out, this validation is only applied at the public interface
> > > boundaries of iommu_attach_group(), iommu_attach_device(),
> > 
> > Oh, making it only work for on domain type seems kind of hacky..
> > 
> > If that is the intention maybe the owner set should be moved into
> > iommu_domain_alloc() with a little comment noting that it is limited
> > to work in only a few cases?
> > 
> > I certainly didn't understand from the commit message to mean it was
> > only actually working for one domain type and this also blocks using
> > other types with the public interface.
> 
> It's not about one particular domain type, it's about the scope of what we
> consider valid usage. External API users should almost always be attaching
> to their own domain which they have allocated, however we also tolerate
> co-attaching additional groups to the same DMA domain in rare cases where
> it's reasonable. The fact is that those users cannot allocate blocking or
> identity domains, and I can't see that they would ever have any legitimate
> business trying to do anything with them anyway. So although yes, we
> technically lose some functionality once this intersects with the static
> domain optimisation, it's only questionable functionality which was never
> explicitly intended anyway.

I have no problem with that argument, I'm saying this is a subtle
emergent property. Lets document it, lets be more explicit. The owner
checks would do well to go along with specific domain type checks as
well to robustly enforce what you just explained.

Thanks,
Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2023-10-25 16:15 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-11 18:14 [PATCH v5 0/7] iommu: Retire bus ops Robin Murphy
2023-10-11 18:14 ` [PATCH v5 1/7] iommu: Factor out some helpers Robin Murphy
2023-10-11 23:34   ` Jason Gunthorpe
2023-10-18 23:04   ` Jerry Snitselaar
2023-10-11 18:14 ` [PATCH v5 2/7] iommu: Decouple iommu_present() from bus ops Robin Murphy
2023-10-12  6:05   ` Baolu Lu
2023-10-12 11:40     ` Robin Murphy
2023-10-12 12:37       ` Jason Gunthorpe
2023-10-12 12:57         ` Baolu Lu
2023-10-12 12:58   ` Baolu Lu
2023-10-18 23:05   ` Jerry Snitselaar
2023-10-11 18:14 ` [PATCH v5 3/7] iommu: Validate that devices match domains Robin Murphy
2023-10-18 23:14   ` Jerry Snitselaar
2023-10-24 18:52   ` Jason Gunthorpe
2023-10-25 12:39     ` Robin Murphy
2023-10-25 12:55       ` Jason Gunthorpe
2023-10-25 16:05         ` Robin Murphy
2023-10-25 16:15           ` Jason Gunthorpe
2023-10-11 18:14 ` [PATCH v5 4/7] iommu: Decouple iommu_domain_alloc() from bus ops Robin Murphy
2023-10-11 23:38   ` Jason Gunthorpe
2023-10-18 23:15   ` Jerry Snitselaar
2023-10-11 18:14 ` [PATCH v5 5/7] iommu/arm-smmu: Don't register fwnode for legacy binding Robin Murphy
2023-10-12 12:56   ` Will Deacon
2023-10-18 23:29   ` Jerry Snitselaar
2023-10-11 18:14 ` [PATCH v5 6/7] iommu: Retire bus ops Robin Murphy
2023-10-18 23:36   ` Jerry Snitselaar
2023-10-11 18:14 ` [PATCH v5 7/7] iommu: Clean up open-coded ownership checks Robin Murphy
2023-10-12 12:57   ` Will Deacon
2023-10-18 23:40   ` Jerry Snitselaar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).