[PATCH 7/7] iommu: Restore SMMU "disable_bypass"
Robin Murphy
robin.murphy at arm.com
Fri Oct 6 05:06:08 PDT 2023
On 2023-10-05 19:28, Jason Gunthorpe wrote:
> 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.
Nothing to do with ARM DMA ops, it is purely about the behaviour for
StreamIDs not attached to domains. This includes known StreamIDs during
the window between SMMU initialisation and those devices first being
probed and attached to something, but these days is mostly concerned
with unknown StreamIDs that would never be attached either way.
If the driver *has* knowingly and willingly attached a device to an
identity domain, that's fine.
Also we're now tantalisingly close to having ARM use regular default
domains anyway - the full conversion to iommu-dma still depends on
significant changes to the IOVA allocator, but I'm 99% sure I've got a
viable intermediate step which at least gets it out of the way from the
rest of the core API's PoV (probe/release shenanigans etc.).
Furthermore I'd imagine that frankly the number of users of arm-smmu
with 32-bit mainline kernels is, to within experimental error, 0, so
honestly it's not worth complicating core code with this.
Thanks,
Robin.
> 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
More information about the linux-arm-kernel
mailing list