iommu.lists.linux-foundation.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 00/17] Consolidate the error handling around device attachment
@ 2023-05-11  4:41 Jason Gunthorpe
  2023-05-11  4:41 ` [PATCH v5 01/17] iommu: Replace iommu_group_device_count() with list_count_nodes() Jason Gunthorpe
                   ` (17 more replies)
  0 siblings, 18 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:41 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

Device attachment has a bunch of different flows open coded in different
ways throughout the code.

One of the things that became apparently recently is that error handling
is important and we do need to consistently treat errors during attach and
have some strategy to unwind back to a safe state.

Implement a single algorithm for this in one function. It will call each
device's attach, if it fails it will try to go back to the prior domain or
as a contingency against a UAF crash try to go to a blocking domain.

As part of this we consolidate how the default domain is created and
attached as well into one place with a consistent flow.

The new worker functions are called __iommu_device_set_domain() and
__iommu_group_set_domain_internal(), each has sensible error handling
internally. At the end __iommu_group_set_domain_internal() is the only
function that stores to group->domain, and must be called to change this
value.

Some flags tell the intent of the caller, if the caller cannot accept a
failure, or if the caller is a first attach and wants to do the deferred
logic.

Several of the confusing workflows where we store things in group->domain
or group->default_domain before they are fully setup are removed.

This has a followup series that does a similar de-duplication to the probe
path:

https://github.com/jgunthorpe/linux/commits/iommu_err_unwind

v5:
 - Print a warning if iommu_create_device_direct_mappings() fails the
   first time. Fail probe() if it fails the second time
 - Update comments
 - Rebase to v6.4-rc1
 - Tested-by's for ARM32, ARM64, S390
v4: https://lore.kernel.org/r/0-v4-79d0c229580a+650-iommu_err_unwind_jgg@nvidia.com
 - Update comments and commit messages
 - New patch "Remove iommu_group_do_dma_first_attach() from iommu_group_add_device()"
 - Redo "Replace __iommu_group_dma_first_attach() with set_domain"
   to avoid the flag
 - Drop "Make iommu_group_do_dma_first_attach() work with owned groups"
   since the fix happens implicitly now
 - Use __iommu_group_set_domain() instead of
   __iommu_group_set_domain_internal() in most places
 - Make sure iommu_create_device_direct_mappings() is always called to
   update the default domain, even if the current attached domain is not
   the default domain
 - Make the error case for inconsistent iommu_get_def_domain_type()'s
   always use iommu_def_domain_type
 - Handle errrors for the first default domain attach more cleanly
v3: https://lore.kernel.org/r/0-v3-e89a9bb522f5+8c87-iommu_err_unwind_jgg@nvidia.com
 - New patch to do iommu_group_create_direct_mappings() before
   attach on the hotplug path based on Lu and Robin's remarks
 - Fix to return 0 if the group has conflicting default domain types like
   the original code
 - Put iommu_group_create_direct_mappings() before attach in setup_domains
 - Split up the alloc changes from the setup_domain patch to their own
   patch, implement Robin's point about how the iommu_def_domain_type should
   work
 - New patch to optionally do iommu_group_create_direct_mappings() after
   attach
 - Reword the setup_domain patch's commit message
v2: https://lore.kernel.org/r/0-v2-cd32667d2ba6+70bd1-iommu_err_unwind_jgg@nvidia.com
 - New patch to remove iommu_group_device_count()
 - New patch to add a for_each helper: for_each_group_device()
 - Rebase on Joerg's tree
 - IOMMU_SET_DOMAIN_MUST_SUCCEED instead of true
 - Split patch to fix owned groups during first attach
 - Change iommu_create_device_direct_mappings to accept a domain not a
   group
 - Significantly revise the "iommu: Consolidate the default_domain setup to
   one function" patch to de-duplicate the domain type calculation logic
   too
 - New patch to clean the flow inside iommu_group_store_type()
v1: https://lore.kernel.org/r/0-v1-20507a7e6b7e+2d6-iommu_err_unwind_jgg@nvidia.com

Jason Gunthorpe (17):
  iommu: Replace iommu_group_device_count() with list_count_nodes()
  iommu: Add for_each_group_device()
  iommu: Make __iommu_group_set_domain() handle error unwind
  iommu: Use __iommu_group_set_domain() for __iommu_attach_group()
  iommu: Use __iommu_group_set_domain() in iommu_change_dev_def_domain()
  iommu: Replace __iommu_group_dma_first_attach() with set_domain
  iommu: Remove iommu_group_do_dma_first_attach() from
    iommu_group_add_device()
  iommu: Replace iommu_group_do_dma_first_attach with
    __iommu_device_set_domain
  iommu: Fix iommu_probe_device() to attach the right domain
  iommu: Do iommu_group_create_direct_mappings() before attach
  iommu: Remove the assignment of group->domain during default domain
    alloc
  iommu: Consolidate the code to calculate the target default domain
    type
  iommu: Revise iommu_group_alloc_default_domain()
  iommu: Consolidate the default_domain setup to one function
  iommu: Allow IOMMU_RESV_DIRECT to work on ARM
  iommu: Remove __iommu_group_for_each_dev()
  iommu: Tidy the control flow in iommu_group_store_type()

 .clang-format         |   1 +
 drivers/iommu/iommu.c | 683 +++++++++++++++++++++---------------------
 2 files changed, 345 insertions(+), 339 deletions(-)


base-commit: ac9a78681b921877518763ba0e89202254349d1b
-- 
2.40.1


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

* [PATCH v5 01/17] iommu: Replace iommu_group_device_count() with list_count_nodes()
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
@ 2023-05-11  4:41 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 02/17] iommu: Add for_each_group_device() Jason Gunthorpe
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:41 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

No reason to wrapper a standard function, just call the library directly.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index f1dcfa3f1a1b48..f2c0c10af32c4c 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1125,17 +1125,6 @@ void iommu_group_remove_device(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(iommu_group_remove_device);
 
-static int iommu_group_device_count(struct iommu_group *group)
-{
-	struct group_device *entry;
-	int ret = 0;
-
-	list_for_each_entry(entry, &group->devices, list)
-		ret++;
-
-	return ret;
-}
-
 static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
 				      int (*fn)(struct device *, void *))
 {
@@ -2082,7 +2071,7 @@ int iommu_attach_device(struct iommu_domain *domain, struct device *dev)
 	 */
 	mutex_lock(&group->mutex);
 	ret = -EINVAL;
-	if (iommu_group_device_count(group) != 1)
+	if (list_count_nodes(&group->devices) != 1)
 		goto out_unlock;
 
 	ret = __iommu_attach_group(domain, group);
@@ -2113,7 +2102,7 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
 
 	mutex_lock(&group->mutex);
 	if (WARN_ON(domain != group->domain) ||
-	    WARN_ON(iommu_group_device_count(group) != 1))
+	    WARN_ON(list_count_nodes(&group->devices) != 1))
 		goto out_unlock;
 	__iommu_group_set_core_domain(group);
 
-- 
2.40.1


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

* [PATCH v5 02/17] iommu: Add for_each_group_device()
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
  2023-05-11  4:41 ` [PATCH v5 01/17] iommu: Replace iommu_group_device_count() with list_count_nodes() Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 03/17] iommu: Make __iommu_group_set_domain() handle error unwind Jason Gunthorpe
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

Convenience macro to iterate over every struct group_device in the group.

Replace all open coded list_for_each_entry's with this macro.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 .clang-format         |  1 +
 drivers/iommu/iommu.c | 16 ++++++++++------
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/.clang-format b/.clang-format
index 0d1ed87767337e..0bbb1991defead 100644
--- a/.clang-format
+++ b/.clang-format
@@ -254,6 +254,7 @@ ForEachMacros:
   - 'for_each_free_mem_range'
   - 'for_each_free_mem_range_reverse'
   - 'for_each_func_rsrc'
+  - 'for_each_group_device'
   - 'for_each_group_evsel'
   - 'for_each_group_member'
   - 'for_each_hstate'
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index f2c0c10af32c4c..b315cba0d4ed0f 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -68,6 +68,10 @@ struct group_device {
 	char *name;
 };
 
+/* Iterate over each struct group_device in a struct iommu_group */
+#define for_each_group_device(group, pos) \
+	list_for_each_entry(pos, &(group)->devices, list)
+
 struct iommu_group_attribute {
 	struct attribute attr;
 	ssize_t (*show)(struct iommu_group *group, char *buf);
@@ -468,7 +472,7 @@ __iommu_group_remove_device(struct iommu_group *group, struct device *dev)
 	struct group_device *device;
 
 	lockdep_assert_held(&group->mutex);
-	list_for_each_entry(device, &group->devices, list) {
+	for_each_group_device(group, device) {
 		if (device->dev == dev) {
 			list_del(&device->list);
 			return device;
@@ -707,7 +711,7 @@ int iommu_get_group_resv_regions(struct iommu_group *group,
 	int ret = 0;
 
 	mutex_lock(&group->mutex);
-	list_for_each_entry(device, &group->devices, list) {
+	for_each_group_device(group, device) {
 		struct list_head dev_resv_regions;
 
 		/*
@@ -1131,7 +1135,7 @@ static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
 	struct group_device *device;
 	int ret = 0;
 
-	list_for_each_entry(device, &group->devices, list) {
+	for_each_group_device(group, device) {
 		ret = fn(device->dev, data);
 		if (ret)
 			break;
@@ -1935,7 +1939,7 @@ bool iommu_group_has_isolated_msi(struct iommu_group *group)
 	bool ret = true;
 
 	mutex_lock(&group->mutex);
-	list_for_each_entry(group_dev, &group->devices, list)
+	for_each_group_device(group, group_dev)
 		ret &= msi_device_has_isolated_msi(group_dev->dev);
 	mutex_unlock(&group->mutex);
 	return ret;
@@ -3242,7 +3246,7 @@ static int __iommu_set_group_pasid(struct iommu_domain *domain,
 	struct group_device *device;
 	int ret = 0;
 
-	list_for_each_entry(device, &group->devices, list) {
+	for_each_group_device(group, device) {
 		ret = domain->ops->set_dev_pasid(domain, device->dev, pasid);
 		if (ret)
 			break;
@@ -3257,7 +3261,7 @@ static void __iommu_remove_group_pasid(struct iommu_group *group,
 	struct group_device *device;
 	const struct iommu_ops *ops;
 
-	list_for_each_entry(device, &group->devices, list) {
+	for_each_group_device(group, device) {
 		ops = dev_iommu_ops(device->dev);
 		ops->remove_dev_pasid(device->dev, pasid);
 	}
-- 
2.40.1


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

* [PATCH v5 03/17] iommu: Make __iommu_group_set_domain() handle error unwind
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
  2023-05-11  4:41 ` [PATCH v5 01/17] iommu: Replace iommu_group_device_count() with list_count_nodes() Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 02/17] iommu: Add for_each_group_device() Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 04/17] iommu: Use __iommu_group_set_domain() for __iommu_attach_group() Jason Gunthorpe
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

Let's try to have a consistent and clear strategy for error handling
during domain attach failures.

There are two broad categories, the first is callers doing destruction and
trying to set the domain back to a previously good domain. These cases
cannot handle failure during destruction flows and must succeed, or at
least avoid a UAF on the current group->domain which is likely about to be
freed.

Many of the drivers are well behaved here and will not hit the WARN_ON's
or a UAF, but some are doing hypercalls/etc that can fail unpredictably
and don't meet the expectations.

The second case is attaching a domain for the first time in a failable
context, failure should restore the attachment back to group->domain using
the above unfailable operation.

Have __iommu_group_set_domain_internal() execute a common algorithm that
tries to achieve this, and in the worst case, would leave a device
"detached" or assigned to a global blocking domain. This relies on some
existing common driver behaviors where attach failure will also do detatch
and true IOMMU_DOMAIN_BLOCK implementations that are not allowed to ever
fail.

Name the first case with __iommu_group_set_domain_nofail() to make it
clear.

Pull all the error handling and WARN_ON generation into
__iommu_group_set_domain_internal().

Avoid the obfuscating use of __iommu_group_for_each_dev() and be more
careful about what should happen during failures by only touching devices
we've already touched.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 137 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 112 insertions(+), 25 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index b315cba0d4ed0f..df7fda7ce8a592 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -101,8 +101,26 @@ static int __iommu_attach_device(struct iommu_domain *domain,
 				 struct device *dev);
 static int __iommu_attach_group(struct iommu_domain *domain,
 				struct iommu_group *group);
+
+enum {
+	IOMMU_SET_DOMAIN_MUST_SUCCEED = 1 << 0,
+};
+
+static int __iommu_group_set_domain_internal(struct iommu_group *group,
+					     struct iommu_domain *new_domain,
+					     unsigned int flags);
 static int __iommu_group_set_domain(struct iommu_group *group,
-				    struct iommu_domain *new_domain);
+				    struct iommu_domain *new_domain)
+{
+	return __iommu_group_set_domain_internal(group, new_domain, 0);
+}
+static void __iommu_group_set_domain_nofail(struct iommu_group *group,
+					    struct iommu_domain *new_domain)
+{
+	WARN_ON(__iommu_group_set_domain_internal(
+		group, new_domain, IOMMU_SET_DOMAIN_MUST_SUCCEED));
+}
+
 static int iommu_create_device_direct_mappings(struct iommu_group *group,
 					       struct device *dev);
 static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
@@ -2021,15 +2039,13 @@ EXPORT_SYMBOL_GPL(iommu_domain_free);
 static void __iommu_group_set_core_domain(struct iommu_group *group)
 {
 	struct iommu_domain *new_domain;
-	int ret;
 
 	if (group->owner)
 		new_domain = group->blocking_domain;
 	else
 		new_domain = group->default_domain;
 
-	ret = __iommu_group_set_domain(group, new_domain);
-	WARN(ret, "iommu driver failed to attach the default/blocking domain");
+	__iommu_group_set_domain_nofail(group, new_domain);
 }
 
 static int __iommu_attach_device(struct iommu_domain *domain,
@@ -2214,21 +2230,55 @@ int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group)
 }
 EXPORT_SYMBOL_GPL(iommu_attach_group);
 
-static int iommu_group_do_set_platform_dma(struct device *dev, void *data)
+static int __iommu_device_set_domain(struct iommu_group *group,
+				     struct device *dev,
+				     struct iommu_domain *new_domain,
+				     unsigned int flags)
 {
-	const struct iommu_ops *ops = dev_iommu_ops(dev);
-
-	if (!WARN_ON(!ops->set_platform_dma_ops))
-		ops->set_platform_dma_ops(dev);
+	int ret;
 
+	ret = __iommu_attach_device(new_domain, dev);
+	if (ret) {
+		/*
+		 * If we have a blocking domain then try to attach that in hopes
+		 * of avoiding a UAF. Modern drivers should implement blocking
+		 * domains as global statics that cannot fail.
+		 */
+		if ((flags & IOMMU_SET_DOMAIN_MUST_SUCCEED) &&
+		    group->blocking_domain &&
+		    group->blocking_domain != new_domain)
+			__iommu_attach_device(group->blocking_domain, dev);
+		return ret;
+	}
 	return 0;
 }
 
-static int __iommu_group_set_domain(struct iommu_group *group,
-				    struct iommu_domain *new_domain)
+/*
+ * If 0 is returned the group's domain is new_domain. If an error is returned
+ * then the group's domain will be set back to the existing domain unless
+ * IOMMU_SET_DOMAIN_MUST_SUCCEED, otherwise an error is returned and the group's
+ * domains is left inconsistent. This is a driver bug to fail attach with a
+ * previously good domain. We try to avoid a kernel UAF because of this.
+ *
+ * IOMMU groups are really the natural working unit of the IOMMU, but the IOMMU
+ * API works on domains and devices.  Bridge that gap by iterating over the
+ * devices in a group.  Ideally we'd have a single device which represents the
+ * requestor ID of the group, but we also allow IOMMU drivers to create policy
+ * defined minimum sets, where the physical hardware may be able to distiguish
+ * members, but we wish to group them at a higher level (ex. untrusted
+ * multi-function PCI devices).  Thus we attach each device.
+ */
+static int __iommu_group_set_domain_internal(struct iommu_group *group,
+					     struct iommu_domain *new_domain,
+					     unsigned int flags)
 {
+	struct group_device *last_gdev;
+	struct group_device *gdev;
+	int result;
 	int ret;
 
+	lockdep_assert_held(&group->mutex);
+
 	if (group->domain == new_domain)
 		return 0;
 
@@ -2238,8 +2288,12 @@ static int __iommu_group_set_domain(struct iommu_group *group,
 	 * platform specific behavior.
 	 */
 	if (!new_domain) {
-		__iommu_group_for_each_dev(group, NULL,
-					   iommu_group_do_set_platform_dma);
+		for_each_group_device(group, gdev) {
+			const struct iommu_ops *ops = dev_iommu_ops(gdev->dev);
+
+			if (!WARN_ON(!ops->set_platform_dma_ops))
+				ops->set_platform_dma_ops(gdev->dev);
+		}
 		group->domain = NULL;
 		return 0;
 	}
@@ -2249,16 +2303,52 @@ static int __iommu_group_set_domain(struct iommu_group *group,
 	 * domain. This switch does not have to be atomic and DMA can be
 	 * discarded during the transition. DMA must only be able to access
 	 * either new_domain or group->domain, never something else.
-	 *
-	 * Note that this is called in error unwind paths, attaching to a
-	 * domain that has already been attached cannot fail.
 	 */
-	ret = __iommu_group_for_each_dev(group, new_domain,
-					 iommu_group_do_attach_device);
-	if (ret)
-		return ret;
+	result = 0;
+	for_each_group_device(group, gdev) {
+		ret = __iommu_device_set_domain(group, gdev->dev, new_domain,
+						flags);
+		if (ret) {
+			result = ret;
+			/*
+			 * Keep trying the other devices in the group. If a
+			 * driver fails attach to an otherwise good domain, and
+			 * does not support blocking domains, it should at least
+			 * drop its reference on the current domain so we don't
+			 * UAF.
+			 */
+			if (flags & IOMMU_SET_DOMAIN_MUST_SUCCEED)
+				continue;
+			goto err_revert;
+		}
+	}
 	group->domain = new_domain;
-	return 0;
+	return result;
+
+err_revert:
+	/*
+	 * This is called in error unwind paths. A well behaved driver should
+	 * always allow us to attach to a domain that was already attached.
+	 */
+	last_gdev = gdev;
+	for_each_group_device(group, gdev) {
+		const struct iommu_ops *ops = dev_iommu_ops(gdev->dev);
+
+		/*
+		 * If set_platform_dma_ops is not present a NULL domain can
+		 * happen only for first probe, in which case we leave
+		 * group->domain as NULL and let release clean everything up.
+		 */
+		if (group->domain)
+			WARN_ON(__iommu_device_set_domain(
+				group, gdev->dev, group->domain,
+				IOMMU_SET_DOMAIN_MUST_SUCCEED));
+		else if (ops->set_platform_dma_ops)
+			ops->set_platform_dma_ops(gdev->dev);
+		if (gdev == last_gdev)
+			break;
+	}
+	return ret;
 }
 
 void iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group)
@@ -3175,16 +3265,13 @@ EXPORT_SYMBOL_GPL(iommu_device_claim_dma_owner);
 
 static void __iommu_release_dma_ownership(struct iommu_group *group)
 {
-	int ret;
-
 	if (WARN_ON(!group->owner_cnt || !group->owner ||
 		    !xa_empty(&group->pasid_array)))
 		return;
 
 	group->owner_cnt = 0;
 	group->owner = NULL;
-	ret = __iommu_group_set_domain(group, group->default_domain);
-	WARN(ret, "iommu driver failed to attach the default domain");
+	__iommu_group_set_domain_nofail(group, group->default_domain);
 }
 
 /**
-- 
2.40.1


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

* [PATCH v5 04/17] iommu: Use __iommu_group_set_domain() for __iommu_attach_group()
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (2 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 03/17] iommu: Make __iommu_group_set_domain() handle error unwind Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 05/17] iommu: Use __iommu_group_set_domain() in iommu_change_dev_def_domain() Jason Gunthorpe
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

The error recovery here matches the recovery inside
__iommu_group_set_domain(), so just use it directly.

Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 40 +---------------------------------------
 1 file changed, 1 insertion(+), 39 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index df7fda7ce8a592..f99c000118e2e1 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2158,52 +2158,14 @@ struct iommu_domain *iommu_get_dma_domain(struct device *dev)
 	return dev->iommu_group->default_domain;
 }
 
-/*
- * IOMMU groups are really the natural working unit of the IOMMU, but
- * the IOMMU API works on domains and devices.  Bridge that gap by
- * iterating over the devices in a group.  Ideally we'd have a single
- * device which represents the requestor ID of the group, but we also
- * allow IOMMU drivers to create policy defined minimum sets, where
- * the physical hardware may be able to distiguish members, but we
- * wish to group them at a higher level (ex. untrusted multi-function
- * PCI devices).  Thus we attach each device.
- */
-static int iommu_group_do_attach_device(struct device *dev, void *data)
-{
-	struct iommu_domain *domain = data;
-
-	return __iommu_attach_device(domain, dev);
-}
-
 static int __iommu_attach_group(struct iommu_domain *domain,
 				struct iommu_group *group)
 {
-	int ret;
-
 	if (group->domain && group->domain != group->default_domain &&
 	    group->domain != group->blocking_domain)
 		return -EBUSY;
 
-	ret = __iommu_group_for_each_dev(group, domain,
-					 iommu_group_do_attach_device);
-	if (ret == 0) {
-		group->domain = domain;
-	} else {
-		/*
-		 * To recover from the case when certain device within the
-		 * group fails to attach to the new domain, we need force
-		 * attaching all devices back to the old domain. The old
-		 * domain is compatible for all devices in the group,
-		 * hence the iommu driver should always return success.
-		 */
-		struct iommu_domain *old_domain = group->domain;
-
-		group->domain = NULL;
-		WARN(__iommu_group_set_domain(group, old_domain),
-		     "iommu driver failed to attach a compatible domain");
-	}
-
-	return ret;
+	return __iommu_group_set_domain(group, domain);
 }
 
 /**
-- 
2.40.1


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

* [PATCH v5 05/17] iommu: Use __iommu_group_set_domain() in iommu_change_dev_def_domain()
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (3 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 04/17] iommu: Use __iommu_group_set_domain() for __iommu_attach_group() Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 06/17] iommu: Replace __iommu_group_dma_first_attach() with set_domain Jason Gunthorpe
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

This is missing re-attach error handling if the attach fails, use the
common code.

The ugly "group->domain = prev_domain" will be cleaned in a later patch.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index f99c000118e2e1..46000ed5d19317 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2945,11 +2945,12 @@ static int iommu_change_dev_def_domain(struct iommu_group *group,
 	if (ret)
 		goto restore_old_domain;
 
-	ret = iommu_group_create_direct_mappings(group);
+	group->domain = prev_dom;
+	ret = iommu_create_device_direct_mappings(group, dev);
 	if (ret)
 		goto free_new_domain;
 
-	ret = __iommu_attach_group(group->default_domain, group);
+	ret = __iommu_group_set_domain(group, group->default_domain);
 	if (ret)
 		goto free_new_domain;
 
@@ -2961,7 +2962,6 @@ static int iommu_change_dev_def_domain(struct iommu_group *group,
 	iommu_domain_free(group->default_domain);
 restore_old_domain:
 	group->default_domain = prev_dom;
-	group->domain = prev_dom;
 
 	return ret;
 }
-- 
2.40.1


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

* [PATCH v5 06/17] iommu: Replace __iommu_group_dma_first_attach() with set_domain
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (4 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 05/17] iommu: Use __iommu_group_set_domain() in iommu_change_dev_def_domain() Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 07/17] iommu: Remove iommu_group_do_dma_first_attach() from iommu_group_add_device() Jason Gunthorpe
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

Reorganize the attach_deferred logic to set dev->iommu->attach_deferred
immediately during probe and then have __iommu_device_set_domain() check
it and not attach the default_domain.

This is to prepare for removing the group->domain set from
iommu_group_alloc_default_domain() by calling __iommu_group_set_domain()
to set the group->domain.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 32 +++++++++++---------------------
 1 file changed, 11 insertions(+), 21 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 46000ed5d19317..44b74850f7f442 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -365,6 +365,8 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
 
 	dev->iommu->iommu_dev = iommu_dev;
 	dev->iommu->max_pasids = dev_iommu_get_max_pasids(dev);
+	if (ops->is_attach_deferred)
+		dev->iommu->attach_deferred = ops->is_attach_deferred(dev);
 
 	group = iommu_group_get_for_dev(dev);
 	if (IS_ERR(group)) {
@@ -399,27 +401,14 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
 	return ret;
 }
 
-static bool iommu_is_attach_deferred(struct device *dev)
-{
-	const struct iommu_ops *ops = dev_iommu_ops(dev);
-
-	if (ops->is_attach_deferred)
-		return ops->is_attach_deferred(dev);
-
-	return false;
-}
-
 static int iommu_group_do_dma_first_attach(struct device *dev, void *data)
 {
 	struct iommu_domain *domain = data;
 
 	lockdep_assert_held(&dev->iommu_group->mutex);
 
-	if (iommu_is_attach_deferred(dev)) {
-		dev->iommu->attach_deferred = 1;
+	if (dev->iommu->attach_deferred)
 		return 0;
-	}
-
 	return __iommu_attach_device(domain, dev);
 }
 
@@ -1831,12 +1820,6 @@ static void probe_alloc_default_domain(const struct bus_type *bus,
 
 }
 
-static int __iommu_group_dma_first_attach(struct iommu_group *group)
-{
-	return __iommu_group_for_each_dev(group, group->default_domain,
-					  iommu_group_do_dma_first_attach);
-}
-
 static int iommu_group_do_probe_finalize(struct device *dev, void *data)
 {
 	const struct iommu_ops *ops = dev_iommu_ops(dev);
@@ -1899,7 +1882,8 @@ int bus_iommu_probe(const struct bus_type *bus)
 
 		iommu_group_create_direct_mappings(group);
 
-		ret = __iommu_group_dma_first_attach(group);
+		group->domain = NULL;
+		ret = __iommu_group_set_domain(group, group->default_domain);
 
 		mutex_unlock(&group->mutex);
 
@@ -2199,6 +2183,12 @@ static int __iommu_device_set_domain(struct iommu_group *group,
 {
 	int ret;
 
+	if (dev->iommu->attach_deferred) {
+		if (new_domain == group->default_domain)
+			return 0;
+		dev->iommu->attach_deferred = 0;
+	}
+
 	ret = __iommu_attach_device(new_domain, dev);
 	if (ret) {
 		/*
-- 
2.40.1


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

* [PATCH v5 07/17] iommu: Remove iommu_group_do_dma_first_attach() from iommu_group_add_device()
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (5 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 06/17] iommu: Replace __iommu_group_dma_first_attach() with set_domain Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 08/17] iommu: Replace iommu_group_do_dma_first_attach with __iommu_device_set_domain Jason Gunthorpe
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

This function is only used to construct the groups, it should not be
operating the iommu driver.

External callers in VFIO and POWER do not have any iommu drivers on the
devices so group->domain will be NULL.

The only internal caller is from iommu_probe_device() which already calls
iommu_group_do_dma_first_attach(), meaning we are calling it twice in the
only case it matters.

Since iommu_probe_device() is the logical place to sort out the group's
domain, remove the call from iommu_group_add_device().

Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 44b74850f7f442..5ca23efd2e048c 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1080,25 +1080,13 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
 
 	mutex_lock(&group->mutex);
 	list_add_tail(&device->list, &group->devices);
-	if (group->domain)
-		ret = iommu_group_do_dma_first_attach(dev, group->domain);
 	mutex_unlock(&group->mutex);
-	if (ret)
-		goto err_put_group;
-
 	trace_add_device_to_group(group->id, dev);
 
 	dev_info(dev, "Adding to iommu group %d\n", group->id);
 
 	return 0;
 
-err_put_group:
-	mutex_lock(&group->mutex);
-	list_del(&device->list);
-	mutex_unlock(&group->mutex);
-	dev->iommu_group = NULL;
-	kobject_put(group->devices_kobj);
-	sysfs_remove_link(group->devices_kobj, device->name);
 err_free_name:
 	kfree(device->name);
 err_remove_link:
-- 
2.40.1


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

* [PATCH v5 08/17] iommu: Replace iommu_group_do_dma_first_attach with __iommu_device_set_domain
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (6 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 07/17] iommu: Remove iommu_group_do_dma_first_attach() from iommu_group_add_device() Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 09/17] iommu: Fix iommu_probe_device() to attach the right domain Jason Gunthorpe
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

Since __iommu_device_set_domain() now knows how to handle deferred attach
we can just call it directly from the only call site.

Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 5ca23efd2e048c..8b9325565b3b48 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -106,6 +106,10 @@ enum {
 	IOMMU_SET_DOMAIN_MUST_SUCCEED = 1 << 0,
 };
 
+static int __iommu_device_set_domain(struct iommu_group *group,
+				     struct device *dev,
+				     struct iommu_domain *new_domain,
+				     unsigned int flags);
 static int __iommu_group_set_domain_internal(struct iommu_group *group,
 					     struct iommu_domain *new_domain,
 					     unsigned int flags);
@@ -401,17 +405,6 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
 	return ret;
 }
 
-static int iommu_group_do_dma_first_attach(struct device *dev, void *data)
-{
-	struct iommu_domain *domain = data;
-
-	lockdep_assert_held(&dev->iommu_group->mutex);
-
-	if (dev->iommu->attach_deferred)
-		return 0;
-	return __iommu_attach_device(domain, dev);
-}
-
 int iommu_probe_device(struct device *dev)
 {
 	const struct iommu_ops *ops;
@@ -442,7 +435,7 @@ int iommu_probe_device(struct device *dev)
 	 * attach the default domain.
 	 */
 	if (group->default_domain && !group->owner) {
-		ret = iommu_group_do_dma_first_attach(dev, group->default_domain);
+		ret = __iommu_device_set_domain(group, dev, group->domain, 0);
 		if (ret) {
 			mutex_unlock(&group->mutex);
 			iommu_group_put(group);
-- 
2.40.1


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

* [PATCH v5 09/17] iommu: Fix iommu_probe_device() to attach the right domain
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (7 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 08/17] iommu: Replace iommu_group_do_dma_first_attach with __iommu_device_set_domain Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 10/17] iommu: Do iommu_group_create_direct_mappings() before attach Jason Gunthorpe
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

The general invariant is that all devices in an iommu_group are attached
to group->domain. We missed some cases here where an owned group would not
get the device attached.

Rework this logic so it follows the default domain flow of the
bus_iommu_probe() - call iommu_alloc_default_domain(), then use
__iommu_group_set_domain_internal() to set up all the devices.

Finally always attach the device to the current domain if it is already
set.

This is an unlikely functional issue as iommufd uses iommu_attach_group().
It is possible to hot plug in a new group member, add a vfio driver to it
and then hot add it to an existing iommufd. In this case it is required
that the core code set the iommu_domain properly since iommufd won't call
iommu_attach_group() again.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 44 +++++++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 20 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 8b9325565b3b48..71ac5f7fe6bd09 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -421,27 +421,31 @@ int iommu_probe_device(struct device *dev)
 		goto err_release;
 	}
 
-	/*
-	 * Try to allocate a default domain - needs support from the
-	 * IOMMU driver. There are still some drivers which don't
-	 * support default domains, so the return value is not yet
-	 * checked.
-	 */
 	mutex_lock(&group->mutex);
-	iommu_alloc_default_domain(group, dev);
 
-	/*
-	 * If device joined an existing group which has been claimed, don't
-	 * attach the default domain.
-	 */
-	if (group->default_domain && !group->owner) {
+	if (group->domain) {
 		ret = __iommu_device_set_domain(group, dev, group->domain, 0);
-		if (ret) {
-			mutex_unlock(&group->mutex);
-			iommu_group_put(group);
-			goto err_release;
-		}
+	} else if (!group->default_domain) {
+		/*
+		 * Try to allocate a default domain - needs support from the
+		 * IOMMU driver. There are still some drivers which don't
+		 * support default domains, so the return value is not yet
+		 * checked.
+		 */
+		iommu_alloc_default_domain(group, dev);
+		group->domain = NULL;
+		if (group->default_domain)
+			ret = __iommu_group_set_domain(group,
+						       group->default_domain);
+
+		/*
+		 * We assume that the iommu driver starts up the device in
+		 * 'set_platform_dma_ops' mode if it does not support default
+		 * domains.
+		 */
 	}
+	if (ret)
+		goto err_unlock;
 
 	iommu_create_device_direct_mappings(group, dev);
 
@@ -454,6 +458,9 @@ int iommu_probe_device(struct device *dev)
 
 	return 0;
 
+err_unlock:
+	mutex_unlock(&group->mutex);
+	iommu_group_put(group);
 err_release:
 	iommu_release_device(dev);
 
@@ -1665,9 +1672,6 @@ static int iommu_alloc_default_domain(struct iommu_group *group,
 {
 	unsigned int type;
 
-	if (group->default_domain)
-		return 0;
-
 	type = iommu_get_def_domain_type(dev) ? : iommu_def_domain_type;
 
 	return iommu_group_alloc_default_domain(dev->bus, group, type);
-- 
2.40.1


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

* [PATCH v5 10/17] iommu: Do iommu_group_create_direct_mappings() before attach
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (8 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 09/17] iommu: Fix iommu_probe_device() to attach the right domain Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-06-05  7:09   ` Ricardo Cañuelo
  2023-05-11  4:42 ` [PATCH v5 11/17] iommu: Remove the assignment of group->domain during default domain alloc Jason Gunthorpe
                   ` (7 subsequent siblings)
  17 siblings, 1 reply; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

The iommu_probe_device() path calls iommu_create_device_direct_mappings()
after attaching the device.

IOMMU_RESV_DIRECT maps need to be continually in place, so if a hotplugged
device has new ranges the should have been mapped into the default domain
before it is attached.

Move the iommu_create_device_direct_mappings() call up.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 71ac5f7fe6bd09..690025e26413f1 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -423,6 +423,8 @@ int iommu_probe_device(struct device *dev)
 
 	mutex_lock(&group->mutex);
 
+	iommu_create_device_direct_mappings(group, dev);
+
 	if (group->domain) {
 		ret = __iommu_device_set_domain(group, dev, group->domain, 0);
 	} else if (!group->default_domain) {
@@ -434,9 +436,11 @@ int iommu_probe_device(struct device *dev)
 		 */
 		iommu_alloc_default_domain(group, dev);
 		group->domain = NULL;
-		if (group->default_domain)
+		if (group->default_domain) {
+			iommu_create_device_direct_mappings(group, dev);
 			ret = __iommu_group_set_domain(group,
 						       group->default_domain);
+		}
 
 		/*
 		 * We assume that the iommu driver starts up the device in
@@ -447,8 +451,6 @@ int iommu_probe_device(struct device *dev)
 	if (ret)
 		goto err_unlock;
 
-	iommu_create_device_direct_mappings(group, dev);
-
 	mutex_unlock(&group->mutex);
 	iommu_group_put(group);
 
-- 
2.40.1


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

* [PATCH v5 11/17] iommu: Remove the assignment of group->domain during default domain alloc
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (9 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 10/17] iommu: Do iommu_group_create_direct_mappings() before attach Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 12/17] iommu: Consolidate the code to calculate the target default domain type Jason Gunthorpe
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

group->domain should only be set once all the device's drivers have
had their ops->attach_dev() called. iommu_group_alloc_default_domain()
doesn't do this, so it shouldn't set the value.

The previous patches organized things so that each caller of
iommu_group_alloc_default_domain() follows up with calling
__iommu_group_set_domain_internal() that does set the group->domain.

Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 690025e26413f1..7cafd830d2067e 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -435,7 +435,6 @@ int iommu_probe_device(struct device *dev)
 		 * checked.
 		 */
 		iommu_alloc_default_domain(group, dev);
-		group->domain = NULL;
 		if (group->default_domain) {
 			iommu_create_device_direct_mappings(group, dev);
 			ret = __iommu_group_set_domain(group,
@@ -1664,8 +1663,6 @@ static int iommu_group_alloc_default_domain(const struct bus_type *bus,
 		return -ENOMEM;
 
 	group->default_domain = dom;
-	if (!group->domain)
-		group->domain = dom;
 	return 0;
 }
 
@@ -1869,7 +1866,6 @@ int bus_iommu_probe(const struct bus_type *bus)
 
 		iommu_group_create_direct_mappings(group);
 
-		group->domain = NULL;
 		ret = __iommu_group_set_domain(group, group->default_domain);
 
 		mutex_unlock(&group->mutex);
-- 
2.40.1


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

* [PATCH v5 12/17] iommu: Consolidate the code to calculate the target default domain type
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (10 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 11/17] iommu: Remove the assignment of group->domain during default domain alloc Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 13/17] iommu: Revise iommu_group_alloc_default_domain() Jason Gunthorpe
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

Put all the code to calculate the default domain type into one
function. Make the function able to handle the
iommu_change_dev_def_domain() by taking in the target domain type and
erroring out if the target type isn't reachable.

This makes it really clear that specifying a 0 type during
iommu_change_dev_def_domain() will have the same outcome as the normal
probe path.

Remove the obfuscating use of __iommu_group_for_each_dev() and related
struct __group_domain_type.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 88 +++++++++++++++++--------------------------
 1 file changed, 35 insertions(+), 53 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 7cafd830d2067e..8242ac609089ea 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1758,50 +1758,43 @@ static int iommu_bus_notifier(struct notifier_block *nb,
 	return 0;
 }
 
-struct __group_domain_type {
-	struct device *dev;
-	unsigned int type;
-};
-
-static int probe_get_default_domain_type(struct device *dev, void *data)
+/* A target_type of 0 will select the best domain type and cannot fail */
+static int iommu_get_default_domain_type(struct iommu_group *group,
+					 int target_type)
 {
-	struct __group_domain_type *gtype = data;
-	unsigned int type = iommu_get_def_domain_type(dev);
+	int best_type = target_type;
+	struct group_device *gdev;
+	struct device *last_dev;
 
-	if (type) {
-		if (gtype->type && gtype->type != type) {
-			dev_warn(dev, "Device needs domain type %s, but device %s in the same iommu group requires type %s - using default\n",
-				 iommu_domain_type_str(type),
-				 dev_name(gtype->dev),
-				 iommu_domain_type_str(gtype->type));
-			gtype->type = 0;
-		}
+	lockdep_assert_held(&group->mutex);
 
-		if (!gtype->dev) {
-			gtype->dev  = dev;
-			gtype->type = type;
+	for_each_group_device(group, gdev) {
+		unsigned int type = iommu_get_def_domain_type(gdev->dev);
+
+		if (best_type && type && best_type != type) {
+			if (target_type) {
+				dev_err_ratelimited(
+					gdev->dev,
+					"Device cannot be in %s domain\n",
+					iommu_domain_type_str(target_type));
+				return -1;
+			}
+
+			dev_warn(
+				gdev->dev,
+				"Device needs domain type %s, but device %s in the same iommu group requires type %s - using default\n",
+				iommu_domain_type_str(type), dev_name(last_dev),
+				iommu_domain_type_str(best_type));
+			return iommu_def_domain_type;
 		}
+		if (!best_type)
+			best_type = type;
+		last_dev = gdev->dev;
 	}
 
-	return 0;
-}
-
-static void probe_alloc_default_domain(const struct bus_type *bus,
-				       struct iommu_group *group)
-{
-	struct __group_domain_type gtype;
-
-	memset(&gtype, 0, sizeof(gtype));
-
-	/* Ask for default domain requirements of all devices in the group */
-	__iommu_group_for_each_dev(group, &gtype,
-				   probe_get_default_domain_type);
-
-	if (!gtype.type)
-		gtype.type = iommu_def_domain_type;
-
-	iommu_group_alloc_default_domain(bus, group, gtype.type);
-
+	if (!best_type)
+		return iommu_def_domain_type;
+	return best_type;
 }
 
 static int iommu_group_do_probe_finalize(struct device *dev, void *data)
@@ -1857,7 +1850,8 @@ int bus_iommu_probe(const struct bus_type *bus)
 		list_del_init(&group->entry);
 
 		/* Try to allocate default domain */
-		probe_alloc_default_domain(bus, group);
+		iommu_group_alloc_default_domain(
+			bus, group, iommu_get_default_domain_type(group, 0));
 
 		if (!group->default_domain) {
 			mutex_unlock(&group->mutex);
@@ -2881,27 +2875,15 @@ EXPORT_SYMBOL_GPL(iommu_dev_disable_feature);
 static int iommu_change_dev_def_domain(struct iommu_group *group,
 				       struct device *dev, int type)
 {
-	struct __group_domain_type gtype = {NULL, 0};
 	struct iommu_domain *prev_dom;
 	int ret;
 
 	lockdep_assert_held(&group->mutex);
 
 	prev_dom = group->default_domain;
-	__iommu_group_for_each_dev(group, &gtype,
-				   probe_get_default_domain_type);
-	if (!type) {
-		/*
-		 * If the user hasn't requested any specific type of domain and
-		 * if the device supports both the domains, then default to the
-		 * domain the device was booted with
-		 */
-		type = gtype.type ? : iommu_def_domain_type;
-	} else if (gtype.type && type != gtype.type) {
-		dev_err_ratelimited(dev, "Device cannot be in %s domain\n",
-				    iommu_domain_type_str(type));
+	type = iommu_get_default_domain_type(group, type);
+	if (type < 0)
 		return -EINVAL;
-	}
 
 	/*
 	 * Switch to a new domain only if the requested domain type is different
-- 
2.40.1


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

* [PATCH v5 13/17] iommu: Revise iommu_group_alloc_default_domain()
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (11 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 12/17] iommu: Consolidate the code to calculate the target default domain type Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 14/17] iommu: Consolidate the default_domain setup to one function Jason Gunthorpe
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

Robin points out that the fallback to guessing what domains the driver
supports should only happen if the driver doesn't return a preference from
its ops->def_domain_type().

Re-organize iommu_group_alloc_default_domain() so it internally uses
iommu_def_domain_type only during the fallback and makes it clearer how
the fallback sequence works.

Make iommu_group_alloc_default_domain() return the domain so the return
based logic is cleaner and to prepare for the next patch.

Remove the iommu_alloc_default_domain() function as it is now trivially
just calling iommu_group_alloc_default_domain().

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 71 ++++++++++++++++++++++---------------------
 1 file changed, 37 insertions(+), 34 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 8242ac609089ea..b1dc5e203eca0b 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -93,8 +93,9 @@ static const char * const iommu_group_resv_type_string[] = {
 static int iommu_bus_notifier(struct notifier_block *nb,
 			      unsigned long action, void *data);
 static void iommu_release_device(struct device *dev);
-static int iommu_alloc_default_domain(struct iommu_group *group,
-				      struct device *dev);
+static struct iommu_domain *
+iommu_group_alloc_default_domain(struct iommu_group *group, int req_type);
+static int iommu_get_def_domain_type(struct device *dev);
 static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus,
 						 unsigned type);
 static int __iommu_attach_device(struct iommu_domain *domain,
@@ -434,7 +435,8 @@ int iommu_probe_device(struct device *dev)
 		 * support default domains, so the return value is not yet
 		 * checked.
 		 */
-		iommu_alloc_default_domain(group, dev);
+		group->default_domain = iommu_group_alloc_default_domain(
+			group, iommu_get_def_domain_type(dev));
 		if (group->default_domain) {
 			iommu_create_device_direct_mappings(group, dev);
 			ret = __iommu_group_set_domain(group,
@@ -1645,35 +1647,38 @@ static int iommu_get_def_domain_type(struct device *dev)
 	return 0;
 }
 
-static int iommu_group_alloc_default_domain(const struct bus_type *bus,
-					    struct iommu_group *group,
-					    unsigned int type)
+/*
+ * req_type of 0 means "auto" which means to select a domain based on
+ * iommu_def_domain_type or what the driver actually supports.
+ */
+static struct iommu_domain *
+iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
 {
+	const struct bus_type *bus =
+		list_first_entry(&group->devices, struct group_device, list)
+			->dev->bus;
 	struct iommu_domain *dom;
 
-	dom = __iommu_domain_alloc(bus, type);
-	if (!dom && type != IOMMU_DOMAIN_DMA) {
-		dom = __iommu_domain_alloc(bus, IOMMU_DOMAIN_DMA);
-		if (dom)
-			pr_warn("Failed to allocate default IOMMU domain of type %u for group %s - Falling back to IOMMU_DOMAIN_DMA",
-				type, group->name);
-	}
-
-	if (!dom)
-		return -ENOMEM;
+	lockdep_assert_held(&group->mutex);
 
-	group->default_domain = dom;
-	return 0;
-}
+	if (req_type)
+		return __iommu_domain_alloc(bus, req_type);
 
-static int iommu_alloc_default_domain(struct iommu_group *group,
-				      struct device *dev)
-{
-	unsigned int type;
+	/* The driver gave no guidance on what type to use, try the default */
+	dom = __iommu_domain_alloc(bus, iommu_def_domain_type);
+	if (dom)
+		return dom;
 
-	type = iommu_get_def_domain_type(dev) ? : iommu_def_domain_type;
+	/* Otherwise IDENTITY and DMA_FQ defaults will try DMA */
+	if (iommu_def_domain_type == IOMMU_DOMAIN_DMA)
+		return NULL;
+	dom = __iommu_domain_alloc(bus, IOMMU_DOMAIN_DMA);
+	if (!dom)
+		return NULL;
 
-	return iommu_group_alloc_default_domain(dev->bus, group, type);
+	pr_warn("Failed to allocate default IOMMU domain of type %u for group %s - Falling back to IOMMU_DOMAIN_DMA",
+		iommu_def_domain_type, group->name);
+	return dom;
 }
 
 /**
@@ -1785,15 +1790,12 @@ static int iommu_get_default_domain_type(struct iommu_group *group,
 				"Device needs domain type %s, but device %s in the same iommu group requires type %s - using default\n",
 				iommu_domain_type_str(type), dev_name(last_dev),
 				iommu_domain_type_str(best_type));
-			return iommu_def_domain_type;
+			return 0;
 		}
 		if (!best_type)
 			best_type = type;
 		last_dev = gdev->dev;
 	}
-
-	if (!best_type)
-		return iommu_def_domain_type;
 	return best_type;
 }
 
@@ -1850,9 +1852,8 @@ int bus_iommu_probe(const struct bus_type *bus)
 		list_del_init(&group->entry);
 
 		/* Try to allocate default domain */
-		iommu_group_alloc_default_domain(
-			bus, group, iommu_get_default_domain_type(group, 0));
-
+		group->default_domain = iommu_group_alloc_default_domain(
+			group, iommu_get_default_domain_type(group, 0));
 		if (!group->default_domain) {
 			mutex_unlock(&group->mutex);
 			continue;
@@ -2896,9 +2897,11 @@ static int iommu_change_dev_def_domain(struct iommu_group *group,
 	group->domain = NULL;
 
 	/* Sets group->default_domain to the newly allocated domain */
-	ret = iommu_group_alloc_default_domain(dev->bus, group, type);
-	if (ret)
+	group->default_domain = iommu_group_alloc_default_domain(group, type);
+	if (!group->default_domain) {
+		ret = -EINVAL;
 		goto restore_old_domain;
+	}
 
 	group->domain = prev_dom;
 	ret = iommu_create_device_direct_mappings(group, dev);
-- 
2.40.1


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

* [PATCH v5 14/17] iommu: Consolidate the default_domain setup to one function
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (12 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 13/17] iommu: Revise iommu_group_alloc_default_domain() Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 15/17] iommu: Allow IOMMU_RESV_DIRECT to work on ARM Jason Gunthorpe
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

Make iommu_change_dev_def_domain() general enough to setup the initial
default_domain or replace it with a new default_domain. Call the new
function iommu_setup_default_domain() and make it the only place in the
code that stores to group->default_domain.

Consolidate the three copies of the default_domain setup sequence. The flow
flow requires:

 - Determining the domain type to use
 - Checking if the current default domain is the same type
 - Allocating a domain
 - Doing iommu_create_device_direct_mappings()
 - Attaching it to devices
 - Store group->default_domain

This adjusts the domain allocation from the prior patch to be able to
detect if each of the allocation steps is already the domain we already
have, which is a more robust version of what change default domain was
already doing.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 202 +++++++++++++++++++-----------------------
 1 file changed, 89 insertions(+), 113 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index b1dc5e203eca0b..cb1287d4d5dec7 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -93,9 +93,6 @@ static const char * const iommu_group_resv_type_string[] = {
 static int iommu_bus_notifier(struct notifier_block *nb,
 			      unsigned long action, void *data);
 static void iommu_release_device(struct device *dev);
-static struct iommu_domain *
-iommu_group_alloc_default_domain(struct iommu_group *group, int req_type);
-static int iommu_get_def_domain_type(struct device *dev);
 static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus,
 						 unsigned type);
 static int __iommu_attach_device(struct iommu_domain *domain,
@@ -126,7 +123,9 @@ static void __iommu_group_set_domain_nofail(struct iommu_group *group,
 		group, new_domain, IOMMU_SET_DOMAIN_MUST_SUCCEED));
 }
 
-static int iommu_create_device_direct_mappings(struct iommu_group *group,
+static int iommu_setup_default_domain(struct iommu_group *group,
+				      int target_type);
+static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
 					       struct device *dev);
 static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
 static ssize_t iommu_group_store_type(struct iommu_group *group,
@@ -424,33 +423,18 @@ int iommu_probe_device(struct device *dev)
 
 	mutex_lock(&group->mutex);
 
-	iommu_create_device_direct_mappings(group, dev);
+	if (group->default_domain)
+		iommu_create_device_direct_mappings(group->default_domain, dev);
 
 	if (group->domain) {
 		ret = __iommu_device_set_domain(group, dev, group->domain, 0);
+		if (ret)
+			goto err_unlock;
 	} else if (!group->default_domain) {
-		/*
-		 * Try to allocate a default domain - needs support from the
-		 * IOMMU driver. There are still some drivers which don't
-		 * support default domains, so the return value is not yet
-		 * checked.
-		 */
-		group->default_domain = iommu_group_alloc_default_domain(
-			group, iommu_get_def_domain_type(dev));
-		if (group->default_domain) {
-			iommu_create_device_direct_mappings(group, dev);
-			ret = __iommu_group_set_domain(group,
-						       group->default_domain);
-		}
-
-		/*
-		 * We assume that the iommu driver starts up the device in
-		 * 'set_platform_dma_ops' mode if it does not support default
-		 * domains.
-		 */
+		ret = iommu_setup_default_domain(group, 0);
+		if (ret)
+			goto err_unlock;
 	}
-	if (ret)
-		goto err_unlock;
 
 	mutex_unlock(&group->mutex);
 	iommu_group_put(group);
@@ -967,16 +951,15 @@ int iommu_group_set_name(struct iommu_group *group, const char *name)
 }
 EXPORT_SYMBOL_GPL(iommu_group_set_name);
 
-static int iommu_create_device_direct_mappings(struct iommu_group *group,
+static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
 					       struct device *dev)
 {
-	struct iommu_domain *domain = group->default_domain;
 	struct iommu_resv_region *entry;
 	struct list_head mappings;
 	unsigned long pg_size;
 	int ret = 0;
 
-	if (!domain || !iommu_is_dma_domain(domain))
+	if (!iommu_is_dma_domain(domain))
 		return 0;
 
 	BUG_ON(!domain->pgsize_bitmap);
@@ -1647,6 +1630,15 @@ static int iommu_get_def_domain_type(struct device *dev)
 	return 0;
 }
 
+static struct iommu_domain *
+__iommu_group_alloc_default_domain(const struct bus_type *bus,
+				   struct iommu_group *group, int req_type)
+{
+	if (group->default_domain && group->default_domain->type == req_type)
+		return group->default_domain;
+	return __iommu_domain_alloc(bus, req_type);
+}
+
 /*
  * req_type of 0 means "auto" which means to select a domain based on
  * iommu_def_domain_type or what the driver actually supports.
@@ -1662,17 +1654,17 @@ iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
 	lockdep_assert_held(&group->mutex);
 
 	if (req_type)
-		return __iommu_domain_alloc(bus, req_type);
+		return __iommu_group_alloc_default_domain(bus, group, req_type);
 
 	/* The driver gave no guidance on what type to use, try the default */
-	dom = __iommu_domain_alloc(bus, iommu_def_domain_type);
+	dom = __iommu_group_alloc_default_domain(bus, group, iommu_def_domain_type);
 	if (dom)
 		return dom;
 
 	/* Otherwise IDENTITY and DMA_FQ defaults will try DMA */
 	if (iommu_def_domain_type == IOMMU_DOMAIN_DMA)
 		return NULL;
-	dom = __iommu_domain_alloc(bus, IOMMU_DOMAIN_DMA);
+	dom = __iommu_group_alloc_default_domain(bus, group, IOMMU_DOMAIN_DMA);
 	if (!dom)
 		return NULL;
 
@@ -1815,21 +1807,6 @@ static void __iommu_group_dma_finalize(struct iommu_group *group)
 				   iommu_group_do_probe_finalize);
 }
 
-static int iommu_do_create_direct_mappings(struct device *dev, void *data)
-{
-	struct iommu_group *group = data;
-
-	iommu_create_device_direct_mappings(group, dev);
-
-	return 0;
-}
-
-static int iommu_group_create_direct_mappings(struct iommu_group *group)
-{
-	return __iommu_group_for_each_dev(group, group,
-					  iommu_do_create_direct_mappings);
-}
-
 int bus_iommu_probe(const struct bus_type *bus)
 {
 	struct iommu_group *group, *next;
@@ -1851,27 +1828,16 @@ int bus_iommu_probe(const struct bus_type *bus)
 		/* Remove item from the list */
 		list_del_init(&group->entry);
 
-		/* Try to allocate default domain */
-		group->default_domain = iommu_group_alloc_default_domain(
-			group, iommu_get_default_domain_type(group, 0));
-		if (!group->default_domain) {
+		ret = iommu_setup_default_domain(group, 0);
+		if (ret) {
 			mutex_unlock(&group->mutex);
-			continue;
+			return ret;
 		}
-
-		iommu_group_create_direct_mappings(group);
-
-		ret = __iommu_group_set_domain(group, group->default_domain);
-
 		mutex_unlock(&group->mutex);
-
-		if (ret)
-			break;
-
 		__iommu_group_dma_finalize(group);
 	}
 
-	return ret;
+	return 0;
 }
 
 bool iommu_present(const struct bus_type *bus)
@@ -2859,68 +2825,83 @@ int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
 }
 EXPORT_SYMBOL_GPL(iommu_dev_disable_feature);
 
-/*
- * Changes the default domain of an iommu group
- *
- * @group: The group for which the default domain should be changed
- * @dev: The first device in the group
- * @type: The type of the new default domain that gets associated with the group
- *
- * Returns 0 on success and error code on failure
+/**
+ * iommu_setup_default_domain - Set the default_domain for the group
+ * @group: Group to change
+ * @target_type: Domain type to set as the default_domain
  *
- * Note:
- * 1. Presently, this function is called only when user requests to change the
- *    group's default domain type through /sys/kernel/iommu_groups/<grp_id>/type
- *    Please take a closer look if intended to use for other purposes.
+ * Allocate a default domain and set it as the current domain on the group. If
+ * the group already has a default domain it will be changed to the target_type.
+ * When target_type is 0 the default domain is selected based on driver and
+ * system preferences.
  */
-static int iommu_change_dev_def_domain(struct iommu_group *group,
-				       struct device *dev, int type)
+static int iommu_setup_default_domain(struct iommu_group *group,
+				      int target_type)
 {
-	struct iommu_domain *prev_dom;
+	struct iommu_domain *old_dom = group->default_domain;
+	struct group_device *gdev;
+	struct iommu_domain *dom;
+	int req_type;
 	int ret;
 
 	lockdep_assert_held(&group->mutex);
 
-	prev_dom = group->default_domain;
-	type = iommu_get_default_domain_type(group, type);
-	if (type < 0)
+	req_type = iommu_get_default_domain_type(group, target_type);
+	if (req_type < 0)
 		return -EINVAL;
 
 	/*
-	 * Switch to a new domain only if the requested domain type is different
-	 * from the existing default domain type
+	 * There are still some drivers which don't support default domains, so
+	 * we ignore the failure and leave group->default_domain NULL.
+	 *
+	 * We assume that the iommu driver starts up the device in
+	 * 'set_platform_dma_ops' mode if it does not support default domains.
 	 */
-	if (prev_dom->type == type)
+	dom = iommu_group_alloc_default_domain(group, req_type);
+	if (!dom) {
+		/* Once in default_domain mode we never leave */
+		if (group->default_domain)
+			return -ENODEV;
+		group->default_domain = NULL;
 		return 0;
-
-	group->default_domain = NULL;
-	group->domain = NULL;
-
-	/* Sets group->default_domain to the newly allocated domain */
-	group->default_domain = iommu_group_alloc_default_domain(group, type);
-	if (!group->default_domain) {
-		ret = -EINVAL;
-		goto restore_old_domain;
 	}
 
-	group->domain = prev_dom;
-	ret = iommu_create_device_direct_mappings(group, dev);
-	if (ret)
-		goto free_new_domain;
-
-	ret = __iommu_group_set_domain(group, group->default_domain);
-	if (ret)
-		goto free_new_domain;
-
-	iommu_domain_free(prev_dom);
+	if (group->default_domain == dom)
+		return 0;
 
-	return 0;
+	/*
+	 * IOMMU_RESV_DIRECT and IOMMU_RESV_DIRECT_RELAXABLE regions must be
+	 * mapped before their device is attached, in order to guarantee
+	 * continuity with any FW activity
+	 */
+	for_each_group_device(group, gdev)
+		iommu_create_device_direct_mappings(dom, gdev->dev);
 
-free_new_domain:
-	iommu_domain_free(group->default_domain);
-restore_old_domain:
-	group->default_domain = prev_dom;
+	/* We must set default_domain early for __iommu_device_set_domain */
+	group->default_domain = dom;
+	if (!group->domain) {
+		/*
+		 * Drivers are not allowed to fail the first domain attach.
+		 * The only way to recover from this is to fail attaching the
+		 * iommu driver and call ops->release_device. Put the domain
+		 * in group->default_domain so it is freed after.
+		 */
+		ret = __iommu_group_set_domain_internal(
+			group, dom, IOMMU_SET_DOMAIN_MUST_SUCCEED);
+		if (WARN_ON(ret))
+			goto out_free;
+	} else {
+		ret = __iommu_group_set_domain(group, dom);
+		if (ret) {
+			iommu_domain_free(dom);
+			group->default_domain = old_dom;
+			return ret;
+		}
+	}
 
+out_free:
+	if (old_dom)
+		iommu_domain_free(old_dom);
 	return ret;
 }
 
@@ -2936,8 +2917,6 @@ static int iommu_change_dev_def_domain(struct iommu_group *group,
 static ssize_t iommu_group_store_type(struct iommu_group *group,
 				      const char *buf, size_t count)
 {
-	struct group_device *grp_dev;
-	struct device *dev;
 	int ret, req_type;
 
 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -2975,10 +2954,7 @@ static ssize_t iommu_group_store_type(struct iommu_group *group,
 		return -EPERM;
 	}
 
-	grp_dev = list_first_entry(&group->devices, struct group_device, list);
-	dev = grp_dev->dev;
-
-	ret = iommu_change_dev_def_domain(group, dev, req_type);
+	ret = iommu_setup_default_domain(group, req_type);
 
 	/*
 	 * Release the mutex here because ops->probe_finalize() call-back of
-- 
2.40.1


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

* [PATCH v5 15/17] iommu: Allow IOMMU_RESV_DIRECT to work on ARM
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (13 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 14/17] iommu: Consolidate the default_domain setup to one function Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 16/17] iommu: Remove __iommu_group_for_each_dev() Jason Gunthorpe
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

For now several ARM drivers do not allow mappings to be created until a
domain is attached. This means they do not technically support
IOMMU_RESV_DIRECT as it requires the 1:1 maps to work continuously.

Currently if the platform requests these maps on ARM systems they are
silently ignored.

Work around this by trying again to establish the direct mappings after
the domain is attached if the pre-attach attempt failed.

In the long run the drivers will be fixed to fully setup domains when they
are created without waiting for attachment.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index cb1287d4d5dec7..a710e3b5d1e6ba 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2841,6 +2841,7 @@ static int iommu_setup_default_domain(struct iommu_group *group,
 	struct iommu_domain *old_dom = group->default_domain;
 	struct group_device *gdev;
 	struct iommu_domain *dom;
+	bool direct_failed;
 	int req_type;
 	int ret;
 
@@ -2874,8 +2875,15 @@ static int iommu_setup_default_domain(struct iommu_group *group,
 	 * mapped before their device is attached, in order to guarantee
 	 * continuity with any FW activity
 	 */
-	for_each_group_device(group, gdev)
-		iommu_create_device_direct_mappings(dom, gdev->dev);
+	direct_failed = false;
+	for_each_group_device(group, gdev) {
+		if (iommu_create_device_direct_mappings(dom, gdev->dev)) {
+			direct_failed = true;
+			dev_warn_once(
+				gdev->dev->iommu->iommu_dev->dev,
+				"IOMMU driver was not able to establish FW requested direct mapping.");
+		}
+	}
 
 	/* We must set default_domain early for __iommu_device_set_domain */
 	group->default_domain = dom;
@@ -2899,6 +2907,27 @@ static int iommu_setup_default_domain(struct iommu_group *group,
 		}
 	}
 
+	/*
+	 * Drivers are supposed to allow mappings to be installed in a domain
+	 * before device attachment, but some don't. Hack around this defect by
+	 * trying again after attaching. If this happens it means the device
+	 * will not continuously have the IOMMU_RESV_DIRECT map.
+	 */
+	if (direct_failed) {
+		for_each_group_device(group, gdev) {
+			ret = iommu_create_device_direct_mappings(dom, gdev->dev);
+			if (ret)
+				goto err_restore;
+		}
+	}
+
+err_restore:
+	if (old_dom) {
+		__iommu_group_set_domain_internal(
+			group, old_dom, IOMMU_SET_DOMAIN_MUST_SUCCEED);
+		iommu_domain_free(dom);
+		old_dom = NULL;
+	}
 out_free:
 	if (old_dom)
 		iommu_domain_free(old_dom);
-- 
2.40.1


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

* [PATCH v5 16/17] iommu: Remove __iommu_group_for_each_dev()
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (14 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 15/17] iommu: Allow IOMMU_RESV_DIRECT to work on ARM Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-11  4:42 ` [PATCH v5 17/17] iommu: Tidy the control flow in iommu_group_store_type() Jason Gunthorpe
  2023-05-23  6:16 ` [PATCH v5 00/17] Consolidate the error handling around device attachment Joerg Roedel
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

The last two users of it are quite trivial, just open code the one line
loop.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 53 ++++++++++++++++++++-----------------------
 1 file changed, 25 insertions(+), 28 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index a710e3b5d1e6ba..7d2fdd2a11cca1 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1110,20 +1110,6 @@ void iommu_group_remove_device(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(iommu_group_remove_device);
 
-static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
-				      int (*fn)(struct device *, void *))
-{
-	struct group_device *device;
-	int ret = 0;
-
-	for_each_group_device(group, device) {
-		ret = fn(device->dev, data);
-		if (ret)
-			break;
-	}
-	return ret;
-}
-
 /**
  * iommu_group_for_each_dev - iterate over each device in the group
  * @group: the group
@@ -1138,10 +1124,15 @@ static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
 int iommu_group_for_each_dev(struct iommu_group *group, void *data,
 			     int (*fn)(struct device *, void *))
 {
-	int ret;
+	struct group_device *device;
+	int ret = 0;
 
 	mutex_lock(&group->mutex);
-	ret = __iommu_group_for_each_dev(group, data, fn);
+	for_each_group_device(group, device) {
+		ret = fn(device->dev, data);
+		if (ret)
+			break;
+	}
 	mutex_unlock(&group->mutex);
 
 	return ret;
@@ -1791,20 +1782,12 @@ static int iommu_get_default_domain_type(struct iommu_group *group,
 	return best_type;
 }
 
-static int iommu_group_do_probe_finalize(struct device *dev, void *data)
+static void iommu_group_do_probe_finalize(struct device *dev)
 {
 	const struct iommu_ops *ops = dev_iommu_ops(dev);
 
 	if (ops->probe_finalize)
 		ops->probe_finalize(dev);
-
-	return 0;
-}
-
-static void __iommu_group_dma_finalize(struct iommu_group *group)
-{
-	__iommu_group_for_each_dev(group, group->default_domain,
-				   iommu_group_do_probe_finalize);
 }
 
 int bus_iommu_probe(const struct bus_type *bus)
@@ -1823,6 +1806,8 @@ int bus_iommu_probe(const struct bus_type *bus)
 		return ret;
 
 	list_for_each_entry_safe(group, next, &group_list, entry) {
+		struct group_device *gdev;
+
 		mutex_lock(&group->mutex);
 
 		/* Remove item from the list */
@@ -1834,7 +1819,15 @@ int bus_iommu_probe(const struct bus_type *bus)
 			return ret;
 		}
 		mutex_unlock(&group->mutex);
-		__iommu_group_dma_finalize(group);
+
+		/*
+		 * FIXME: Mis-locked because the ops->probe_finalize() call-back
+		 * of some IOMMU drivers calls arm_iommu_attach_device() which
+		 * in-turn might call back into IOMMU core code, where it tries
+		 * to take group->mutex, resulting in a deadlock.
+		 */
+		for_each_group_device(group, gdev)
+			iommu_group_do_probe_finalize(gdev->dev);
 	}
 
 	return 0;
@@ -2994,8 +2987,12 @@ static ssize_t iommu_group_store_type(struct iommu_group *group,
 	mutex_unlock(&group->mutex);
 
 	/* Make sure dma_ops is appropriatley set */
-	if (!ret)
-		__iommu_group_dma_finalize(group);
+	if (!ret) {
+		struct group_device *gdev;
+
+		for_each_group_device(group, gdev)
+			iommu_group_do_probe_finalize(gdev->dev);
+	}
 
 	return ret ?: count;
 }
-- 
2.40.1


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

* [PATCH v5 17/17] iommu: Tidy the control flow in iommu_group_store_type()
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (15 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 16/17] iommu: Remove __iommu_group_for_each_dev() Jason Gunthorpe
@ 2023-05-11  4:42 ` Jason Gunthorpe
  2023-05-23  6:16 ` [PATCH v5 00/17] Consolidate the error handling around device attachment Joerg Roedel
  17 siblings, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-05-11  4:42 UTC (permalink / raw)
  To: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon
  Cc: Lu Baolu, Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

Use a normal "goto unwind" instead of trying to be clever with checking
!ret and manually managing the unlock.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 7d2fdd2a11cca1..4d7010f2b260a7 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2939,6 +2939,7 @@ static int iommu_setup_default_domain(struct iommu_group *group,
 static ssize_t iommu_group_store_type(struct iommu_group *group,
 				      const char *buf, size_t count)
 {
+	struct group_device *gdev;
 	int ret, req_type;
 
 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -2963,20 +2964,23 @@ static ssize_t iommu_group_store_type(struct iommu_group *group,
 	if (req_type == IOMMU_DOMAIN_DMA_FQ &&
 	    group->default_domain->type == IOMMU_DOMAIN_DMA) {
 		ret = iommu_dma_init_fq(group->default_domain);
-		if (!ret)
-			group->default_domain->type = IOMMU_DOMAIN_DMA_FQ;
-		mutex_unlock(&group->mutex);
+		if (ret)
+			goto out_unlock;
 
-		return ret ?: count;
+		group->default_domain->type = IOMMU_DOMAIN_DMA_FQ;
+		ret = count;
+		goto out_unlock;
 	}
 
 	/* Otherwise, ensure that device exists and no driver is bound. */
 	if (list_empty(&group->devices) || group->owner_cnt) {
-		mutex_unlock(&group->mutex);
-		return -EPERM;
+		ret = -EPERM;
+		goto out_unlock;
 	}
 
 	ret = iommu_setup_default_domain(group, req_type);
+	if (ret)
+		goto out_unlock;
 
 	/*
 	 * Release the mutex here because ops->probe_finalize() call-back of
@@ -2987,13 +2991,12 @@ static ssize_t iommu_group_store_type(struct iommu_group *group,
 	mutex_unlock(&group->mutex);
 
 	/* Make sure dma_ops is appropriatley set */
-	if (!ret) {
-		struct group_device *gdev;
-
-		for_each_group_device(group, gdev)
-			iommu_group_do_probe_finalize(gdev->dev);
-	}
+	for_each_group_device(group, gdev)
+		iommu_group_do_probe_finalize(gdev->dev);
+	return count;
 
+out_unlock:
+	mutex_unlock(&group->mutex);
 	return ret ?: count;
 }
 
-- 
2.40.1


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

* Re: [PATCH v5 00/17] Consolidate the error handling around device attachment
  2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
                   ` (16 preceding siblings ...)
  2023-05-11  4:42 ` [PATCH v5 17/17] iommu: Tidy the control flow in iommu_group_store_type() Jason Gunthorpe
@ 2023-05-23  6:16 ` Joerg Roedel
  17 siblings, 0 replies; 24+ messages in thread
From: Joerg Roedel @ 2023-05-23  6:16 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: iommu, llvm, Nathan Chancellor, Nick Desaulniers, Miguel Ojeda,
	Robin Murphy, Tom Rix, Will Deacon, Lu Baolu, Heiko Stuebner,
	Kevin Tian, Nicolin Chen, Niklas Schnelle

On Thu, May 11, 2023 at 01:41:58AM -0300, Jason Gunthorpe wrote:
> Jason Gunthorpe (17):
>   iommu: Replace iommu_group_device_count() with list_count_nodes()
>   iommu: Add for_each_group_device()
>   iommu: Make __iommu_group_set_domain() handle error unwind
>   iommu: Use __iommu_group_set_domain() for __iommu_attach_group()
>   iommu: Use __iommu_group_set_domain() in iommu_change_dev_def_domain()
>   iommu: Replace __iommu_group_dma_first_attach() with set_domain
>   iommu: Remove iommu_group_do_dma_first_attach() from
>     iommu_group_add_device()
>   iommu: Replace iommu_group_do_dma_first_attach with
>     __iommu_device_set_domain
>   iommu: Fix iommu_probe_device() to attach the right domain
>   iommu: Do iommu_group_create_direct_mappings() before attach
>   iommu: Remove the assignment of group->domain during default domain
>     alloc
>   iommu: Consolidate the code to calculate the target default domain
>     type
>   iommu: Revise iommu_group_alloc_default_domain()
>   iommu: Consolidate the default_domain setup to one function
>   iommu: Allow IOMMU_RESV_DIRECT to work on ARM
>   iommu: Remove __iommu_group_for_each_dev()
>   iommu: Tidy the control flow in iommu_group_store_type()
> 
>  .clang-format         |   1 +
>  drivers/iommu/iommu.c | 683 +++++++++++++++++++++---------------------
>  2 files changed, 345 insertions(+), 339 deletions(-)

Applied, thanks Jason.

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

* Re: [PATCH v5 10/17] iommu: Do iommu_group_create_direct_mappings() before attach
  2023-05-11  4:42 ` [PATCH v5 10/17] iommu: Do iommu_group_create_direct_mappings() before attach Jason Gunthorpe
@ 2023-06-05  7:09   ` Ricardo Cañuelo
  2023-06-05 13:47     ` Jason Gunthorpe
  0 siblings, 1 reply; 24+ messages in thread
From: Ricardo Cañuelo @ 2023-06-05  7:09 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon, Lu Baolu,
	Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

Hi Jason,

On jue 11-05-2023 01:42:08, Jason Gunthorpe wrote:
> The iommu_probe_device() path calls iommu_create_device_direct_mappings()
> after attaching the device.
> 
> IOMMU_RESV_DIRECT maps need to be continually in place, so if a hotplugged
> device has new ranges the should have been mapped into the default domain
> before it is attached.

This patch seems to introduce a regression in `hana` Chromebooks
(MT8173), this was detected by the KernelCI bot [1].

This is an excerpt of the kernel log when the failure happens:

============================================================
[   16.051893] mediatek-disp-rdma 14010000.rdma: Adding to iommu group 0
[   16.092921] Bluetooth: vendor=0x2df, device=0x912e, class=255, fn=2
[   16.094140] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000018
[   16.098392] usbcore: registered new interface driver uvcvideo
[   16.120447] mwifiex_sdio mmc2:0001:1: Direct firmware load for mrvl/sd8897_uapsta.bin failed with error -2
[   16.126182] Mem abort info:
[   16.126185]   ESR = 0x0000000096000006
[   16.126187]   EC = 0x25: DABT (current EL), IL = 32 bits
[   16.126189]   SET = 0, FnV = 0
[   16.126191]   EA = 0, S1PTW = 0
[   16.126193]   FSC = 0x06: level 2 translation fault
[   16.126196] Data abort info:
[   16.126197]   ISV = 0, ISS = 0x00000006, ISS2 = 0x00000000
[   16.126208]   CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[   16.126210]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[   16.126213] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000107b6f000
[   16.126238] [0000000000000018] pgd=0800000107bac003, p4d=0800000107bac003, pud=0800000107bad003, pmd=0000000000000000
[   16.126248] Internal error: Oops: 0000000096000006 [#1] PREEMPT SMP
[   16.126251] Modules linked in: mwifiex_sdio(+) uvcvideo mtk_mdp uvc videobuf2_vmalloc v4l2_mem2mem videobuf2_dma_contig mwifiex videobuf2_memops btmrvl_sdio(+) mediatek_drm(+) videobuf2_v4l2 btmrvl r8152(+) mtk_mutex hid_multitouch mtk_mmsys cfg80211 videodev videobuf2_common bluetooth mc ecdh_generic ecc rfkill sbs_battery elan_i2c elants_i2c cros_ec_sensors cros_ec_sensors_core industrialio_triggered_buffer kfifo_buf cros_ec_chardev auxadc_thermal mediatek_drm_hdmi
[   16.136728] mwifiex_sdio mmc2:0001:1: Failed to get firmware mrvl/sd8897_uapsta.bin
[   16.141848]  mt6577_auxadc mtk_vpu phy_mtk_hdmi_drv phy_mtk_mipi_dsi_drv display_connector
[   16.141859] CPU: 2 PID: 126 Comm: udevd Not tainted 6.4.0-rc4-next-20230530-dirty #1
[   16.141863] Hardware name: Google Hana (DT)
[   16.141865] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[   16.141869] pc : mtk_iommu_flush_iotlb_all+0x18/0x70
[   16.141881] lr : iommu_create_device_direct_mappings.part.0+0x13c/0x21c
[   16.141886] sp : ffff80000b4e3640
[   16.141888] x29: ffff80000b4e3640 x28: ffff80000b4e36d8 x27: 0000000000001000
[   16.141894] x26: ffff0000c966e268 x25: ffff80000aa0d874 x24: 0000000000000000
[   16.141900] x23: ffff0000c08c5c10 x22: ffff80000b4e36d8
[   16.155999] mwifiex_sdio mmc2:0001:1: info: _mwifiex_fw_dpc: unregister device
[   16.157791]  x21: 0000000000000000
[   16.157795] x20: ffff0000c966e148 x19: ffff0000c966e268 x18: 00000000fffffffe
[   16.157800] x17: 5f6272616c5f696d x16: 735f6b746d207370 x15: 0000000000000020
[   16.157806] x14: 00000000000002f3 x13: 0000000000000001 x12: 0000000000000000
[   16.157812] x11: 0000000000000000 x10: ffff0000c08c5c10
[   16.168820] r8152 2-1.1:1.0: Direct firmware load for rtl_nic/rtl8153b-2.fw failed with error -2
[   16.170416]  x9 : 0000000000000000
[   16.173730] r8152 2-1.1:1.0: unable to load firmware patch rtl_nic/rtl8153b-2.fw (-2)
[   16.177107] x8 : ffff0000c084f400 x7 : ffff80000957b028 x6 : ffff0000c966cc00
[   16.177113] x5 : 0000000000000040 x4 : ffff80000957b4a8 x3 : ffff80000957b4a8
[   16.228229] btmrvl_sdio mmc2:0001:2: Direct firmware load for mrvl/sd8897_uapsta.bin failed with error -2
[   16.267586] 
[   16.267588] x2 : 0000000000000000 x1 : ffff800008883548 x0 : 0000000000000000
[   16.267594] Call trace:
[   16.267597]  mtk_iommu_flush_iotlb_all+0x18/0x70
[   16.267603]  iommu_create_device_direct_mappings.part.0+0x13c/0x21c
[   16.267608]  iommu_setup_default_domain+0x27c/0x430
[   16.267611]  iommu_probe_device+0x7c/0x144
[   16.267615]  of_iommu_configure+0x114/0x200
[   16.267619]  of_dma_configure_id+0x1e0/0x3b4
[   16.275567] Bluetooth: request_firmware(firmware) failed, error code = -2
[   16.275604] r8152 2-1.1:1.0 eth0: v1.12.13
[   16.276104] usbcore: registered new interface driver r8152
[   16.284034]  platform_dma_configure+0x30/0xc0
[   16.284039]  really_probe+0x70/0x2b4
[   16.284044]  __driver_probe_device+0x78/0x12c
[   16.284049]  driver_probe_device+0xd8/0x15c
[   16.284054]  __driver_attach+0x94/0x19c
[   16.292076] Bluetooth: Failed to download firmware!
[   16.296474]  bus_for_each_dev+0x74/0xd4
[   16.296479]  driver_attach+0x24/0x30
[   16.296483]  bus_add_driver+0xe4/0x1e8
[   16.296488]  driver_register+0x60/0x128
[   16.296490]  __platform_register_drivers+0x64/0xe8
[   16.296494]  mtk_drm_init+0x24/0x1000 [mediatek_drm]
[   16.303720] Bluetooth: Downloading firmware failed!
[   16.308914]  do_one_initcall+0x6c/0x1b0
[   16.308919]  do_init_module+0x58/0x1e4
[   16.308924]  load_module+0x18f4/0x1a98
[   16.552552]  __do_sys_finit_module+0xb8/0x10c
[   16.557162]  __arm64_sys_finit_module+0x20/0x2c
[   16.561945]  invoke_syscall+0x48/0x114
[   16.565947]  el0_svc_common.constprop.0+0x44/0xec
[   16.570902]  do_el0_svc+0x38/0xa4
[   16.574469]  el0_svc+0x2c/0x84
[   16.577777]  el0t_64_sync_handler+0xb8/0xbc
[   16.582211]  el0t_64_sync+0x190/0x194
[   16.586126] Code: 910003fd a90153f3 f90013f5 f85f8000 (f9400c15) 
[   16.592470] ---[ end trace 0000000000000000 ]---
============================================================

I reproduced the bug running the same test with a kernel containing the
patch: https://lava.collabora.dev/scheduler/job/10563738

and I checked that reverting the patch fixes the problem:
https://lava.collabora.dev/scheduler/job/10564507

In order to run these tests I used kci_build [2] to build the kernels,
dtbs and modules, and ran the same LAVA jobs definitions than the
original test run using the generated kernels.

This doesn't seem to be affecting other targets supported by KernelCI.

[1] https://groups.io/g/kernelci-results/message/42976
[2] https://github.com/kernelci/kernelci-core/blob/main/doc/kci_build.md

#regzbot introduced 152431e4fe7f
#regzbot title iommu: NULL pointer dereference in Hana Chromebook

Cheers,
Ricardo

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

* Re: [PATCH v5 10/17] iommu: Do iommu_group_create_direct_mappings() before attach
  2023-06-05  7:09   ` Ricardo Cañuelo
@ 2023-06-05 13:47     ` Jason Gunthorpe
  2023-06-05 14:00       ` Robin Murphy
  0 siblings, 1 reply; 24+ messages in thread
From: Jason Gunthorpe @ 2023-06-05 13:47 UTC (permalink / raw)
  To: Ricardo Cañuelo, Yong Wu, linux-mediatek
  Cc: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Robin Murphy, Tom Rix, Will Deacon, Lu Baolu,
	Heiko Stuebner, Kevin Tian, Nicolin Chen, Niklas Schnelle

On Mon, Jun 05, 2023 at 09:09:59AM +0200, Ricardo Cañuelo wrote:
> [   16.267594] Call trace:
> [   16.267597]  mtk_iommu_flush_iotlb_all+0x18/0x70
> [   16.267603]  iommu_create_device_direct_mappings.part.0+0x13c/0x21c
> [   16.267608]  iommu_setup_default_domain+0x27c/0x430
> [   16.267611]  iommu_probe_device+0x7c/0x144
> [   16.267615]  of_iommu_configure+0x114/0x200
> [   16.267619]  of_dma_configure_id+0x1e0/0x3b4

This is definitely some problem in the mtk driver.. But I can't guess
what is wrong:

static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain)
{
	struct mtk_iommu_domain *dom = to_mtk_domain(domain);

	if (dom->bank)
		mtk_iommu_tlb_flush_all(dom->bank->parent_data);
}

We know domain != NULL since the caller checked (and de-ref'd)
it.

dom->bank should either be NULL (if pre-finalize) or a devm tracked
pointer.

parent_data is always valid if bank is valid.

So I'm at a loss.. Can you debug a bit more and find out where mtk is
crashing?

Thanks,
Jason

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

* Re: [PATCH v5 10/17] iommu: Do iommu_group_create_direct_mappings() before attach
  2023-06-05 13:47     ` Jason Gunthorpe
@ 2023-06-05 14:00       ` Robin Murphy
  2023-06-05 14:11         ` Jason Gunthorpe
  2023-06-06  5:33         ` Ricardo Cañuelo
  0 siblings, 2 replies; 24+ messages in thread
From: Robin Murphy @ 2023-06-05 14:00 UTC (permalink / raw)
  To: Jason Gunthorpe, Ricardo Cañuelo, Yong Wu, linux-mediatek
  Cc: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Tom Rix, Will Deacon, Lu Baolu, Heiko Stuebner,
	Kevin Tian, Nicolin Chen, Niklas Schnelle

On 2023-06-05 14:47, Jason Gunthorpe wrote:
> On Mon, Jun 05, 2023 at 09:09:59AM +0200, Ricardo Cañuelo wrote:
>> [   16.267594] Call trace:
>> [   16.267597]  mtk_iommu_flush_iotlb_all+0x18/0x70
>> [   16.267603]  iommu_create_device_direct_mappings.part.0+0x13c/0x21c
>> [   16.267608]  iommu_setup_default_domain+0x27c/0x430
>> [   16.267611]  iommu_probe_device+0x7c/0x144
>> [   16.267615]  of_iommu_configure+0x114/0x200
>> [   16.267619]  of_dma_configure_id+0x1e0/0x3b4
> 
> This is definitely some problem in the mtk driver.. But I can't guess
> what is wrong:
> 
> static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain)
> {
> 	struct mtk_iommu_domain *dom = to_mtk_domain(domain);
> 
> 	if (dom->bank)
> 		mtk_iommu_tlb_flush_all(dom->bank->parent_data);
> }
> 
> We know domain != NULL since the caller checked (and de-ref'd)
> it.
> 
> dom->bank should either be NULL (if pre-finalize) or a devm tracked
> pointer.
> 
> parent_data is always valid if bank is valid.
> 
> So I'm at a loss.. Can you debug a bit more and find out where mtk is
> crashing?

The log says it's next-20230530 - the fix you're seeing there from 
commit b3fc95709c54 landed 2 days later :)

Robin.

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

* Re: [PATCH v5 10/17] iommu: Do iommu_group_create_direct_mappings() before attach
  2023-06-05 14:00       ` Robin Murphy
@ 2023-06-05 14:11         ` Jason Gunthorpe
  2023-06-06  5:33         ` Ricardo Cañuelo
  1 sibling, 0 replies; 24+ messages in thread
From: Jason Gunthorpe @ 2023-06-05 14:11 UTC (permalink / raw)
  To: Robin Murphy
  Cc: Ricardo Cañuelo, Yong Wu, linux-mediatek, iommu,
	Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Tom Rix, Will Deacon, Lu Baolu, Heiko Stuebner,
	Kevin Tian, Nicolin Chen, Niklas Schnelle

On Mon, Jun 05, 2023 at 03:00:24PM +0100, Robin Murphy wrote:
> On 2023-06-05 14:47, Jason Gunthorpe wrote:
> > On Mon, Jun 05, 2023 at 09:09:59AM +0200, Ricardo Cañuelo wrote:
> > > [   16.267594] Call trace:
> > > [   16.267597]  mtk_iommu_flush_iotlb_all+0x18/0x70
> > > [   16.267603]  iommu_create_device_direct_mappings.part.0+0x13c/0x21c
> > > [   16.267608]  iommu_setup_default_domain+0x27c/0x430
> > > [   16.267611]  iommu_probe_device+0x7c/0x144
> > > [   16.267615]  of_iommu_configure+0x114/0x200
> > > [   16.267619]  of_dma_configure_id+0x1e0/0x3b4
> > 
> > This is definitely some problem in the mtk driver.. But I can't guess
> > what is wrong:
> > 
> > static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain)
> > {
> > 	struct mtk_iommu_domain *dom = to_mtk_domain(domain);
> > 
> > 	if (dom->bank)
> > 		mtk_iommu_tlb_flush_all(dom->bank->parent_data);
> > }
> > 
> > We know domain != NULL since the caller checked (and de-ref'd)
> > it.
> > 
> > dom->bank should either be NULL (if pre-finalize) or a devm tracked
> > pointer.
> > 
> > parent_data is always valid if bank is valid.
> > 
> > So I'm at a loss.. Can you debug a bit more and find out where mtk is
> > crashing?
> 
> The log says it's next-20230530 - the fix you're seeing there from commit
> b3fc95709c54 landed 2 days later :)

Ah, I was looking at Joerg's tree, mystery solved then :)

Thanks,
Jason

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

* Re: [PATCH v5 10/17] iommu: Do iommu_group_create_direct_mappings() before attach
  2023-06-05 14:00       ` Robin Murphy
  2023-06-05 14:11         ` Jason Gunthorpe
@ 2023-06-06  5:33         ` Ricardo Cañuelo
  1 sibling, 0 replies; 24+ messages in thread
From: Ricardo Cañuelo @ 2023-06-06  5:33 UTC (permalink / raw)
  To: Robin Murphy, Jason Gunthorpe, Yong Wu, linux-mediatek
  Cc: iommu, Joerg Roedel, llvm, Nathan Chancellor, Nick Desaulniers,
	Miguel Ojeda, Tom Rix, Will Deacon, Lu Baolu, Heiko Stuebner,
	Kevin Tian, Nicolin Chen, Niklas Schnelle

Hi all,

On 5/6/23 16:00, Robin Murphy wrote:
> The log says it's next-20230530 - the fix you're seeing there from commit b3fc95709c54 landed 2 days later :)

Thanks for checking that out Robin, KernelCI still hasn't run
that build but I tested it manually and the issue is not there
anymore.

#regzbot fix: b3fc95709c54

Cheers,
Ricardo

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

end of thread, other threads:[~2023-06-06  5:33 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-11  4:41 [PATCH v5 00/17] Consolidate the error handling around device attachment Jason Gunthorpe
2023-05-11  4:41 ` [PATCH v5 01/17] iommu: Replace iommu_group_device_count() with list_count_nodes() Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 02/17] iommu: Add for_each_group_device() Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 03/17] iommu: Make __iommu_group_set_domain() handle error unwind Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 04/17] iommu: Use __iommu_group_set_domain() for __iommu_attach_group() Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 05/17] iommu: Use __iommu_group_set_domain() in iommu_change_dev_def_domain() Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 06/17] iommu: Replace __iommu_group_dma_first_attach() with set_domain Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 07/17] iommu: Remove iommu_group_do_dma_first_attach() from iommu_group_add_device() Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 08/17] iommu: Replace iommu_group_do_dma_first_attach with __iommu_device_set_domain Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 09/17] iommu: Fix iommu_probe_device() to attach the right domain Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 10/17] iommu: Do iommu_group_create_direct_mappings() before attach Jason Gunthorpe
2023-06-05  7:09   ` Ricardo Cañuelo
2023-06-05 13:47     ` Jason Gunthorpe
2023-06-05 14:00       ` Robin Murphy
2023-06-05 14:11         ` Jason Gunthorpe
2023-06-06  5:33         ` Ricardo Cañuelo
2023-05-11  4:42 ` [PATCH v5 11/17] iommu: Remove the assignment of group->domain during default domain alloc Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 12/17] iommu: Consolidate the code to calculate the target default domain type Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 13/17] iommu: Revise iommu_group_alloc_default_domain() Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 14/17] iommu: Consolidate the default_domain setup to one function Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 15/17] iommu: Allow IOMMU_RESV_DIRECT to work on ARM Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 16/17] iommu: Remove __iommu_group_for_each_dev() Jason Gunthorpe
2023-05-11  4:42 ` [PATCH v5 17/17] iommu: Tidy the control flow in iommu_group_store_type() Jason Gunthorpe
2023-05-23  6:16 ` [PATCH v5 00/17] Consolidate the error handling around device attachment Joerg Roedel

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).