[PATCH 7/7] iommu: Restore SMMU "disable_bypass"

Jason Gunthorpe jgg at nvidia.com
Thu Oct 5 11:28:18 PDT 2023


The module parameter "disable_bypass" changes the IOMMU configuration when
using CONFIG_ARM_DMA_USE_IOMMU to establish a faulting/blocked domain when
the ARM DMA ops are not being used.

SMMU does this by defaulting the device configuration to faulting during
probe. This keeps things faulting up until the ARM DMA ops first attach,
then the faulting is lost.

Since we removed NULL domains and immediately attach an IDENTIY domain
during probe this now doesn't work properly on either driver.

Reflect the SMMU module option to the core code and have it request a
BLOCKED or IDENTITY domain directly, only for CONFIG_ARM_DMA_USE_IOMMU.

Fixes: 98ac73f99bc4 ("iommu: Require a default_domain for all iommu drivers")
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
---
 drivers/iommu/arm/arm-smmu/arm-smmu.c |  1 +
 drivers/iommu/iommu.c                 | 23 ++++++++++++++++++++++-
 include/linux/iommu.h                 |  2 ++
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 4d69bb63ba1a3e..e164477a224dac 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -2211,6 +2211,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 		return err;
 	}
 
+	iommu_arm_disable_bypass |= disable_bypass;
 	err = iommu_device_register(&smmu->iommu, &arm_smmu_ops, dev);
 	if (err) {
 		dev_err(dev, "Failed to register iommu\n");
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index efa65b3d1bd405..e2798d8318b7bb 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -46,6 +46,13 @@ static unsigned int iommu_def_domain_type __read_mostly;
 static bool iommu_dma_strict __read_mostly = IS_ENABLED(CONFIG_IOMMU_DEFAULT_DMA_STRICT);
 static u32 iommu_cmd_line __read_mostly;
 
+/*
+ * This supports the module option "disable_bypass" that ARM SMMU and SMMUv3
+ * drivers supported. It causes the default domain to be BLOCKED when
+ * CONFIG_ARM_DMA_USE_IOMMU.
+ */
+bool iommu_arm_disable_bypass = false;
+
 struct iommu_group {
 	struct kobject kobj;
 	struct kobject *devices_kobj;
@@ -1914,7 +1921,13 @@ static int iommu_get_default_domain_type(struct iommu_group *group,
 	if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
 		static_assert(!(IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) &&
 				IS_ENABLED(CONFIG_IOMMU_DMA)));
-		driver_type = IOMMU_DOMAIN_IDENTITY;
+		if (!iommu_arm_disable_bypass ||
+		    !group_iommu_ops(group)->blocked_domain)
+			driver_type = IOMMU_DOMAIN_IDENTITY;
+		else
+			for_each_group_device(group, gdev)
+				if (gdev->dev->iommu->require_direct)
+					driver_type = IOMMU_DOMAIN_IDENTITY;
 	}
 
 	for_each_group_device(group, gdev) {
@@ -1932,6 +1945,14 @@ static int iommu_get_default_domain_type(struct iommu_group *group,
 		}
 	}
 
+	/*
+	 * For iommu_arm_disable_bypass mode the driver is allowed to force
+	 * IDENTITY, otherwise returning 0 from def_domain_type will mean
+	 * BLOCKED.
+	 */
+	if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) && driver_type == 0)
+		driver_type = IOMMU_DOMAIN_BLOCKED;
+
 	if (untrusted) {
 		if (driver_type && driver_type != IOMMU_DOMAIN_DMA) {
 			dev_err_ratelimited(
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index e27d2e67e48ef7..c88150300bff71 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -42,6 +42,8 @@ struct iommu_sva;
 struct iommu_fault_event;
 struct iommu_dma_cookie;
 
+extern bool iommu_arm_disable_bypass;
+
 /* iommu fault flags */
 #define IOMMU_FAULT_READ	0x0
 #define IOMMU_FAULT_WRITE	0x1
-- 
2.42.0




More information about the linux-arm-kernel mailing list