Messages in this thread Patch in this message | | | From | Nicolin Chen <> | Subject | [PATCH v2] iommu/arm-smmu-v3: Allow default substream bypass with a pasid support | Date | Wed, 16 Aug 2023 21:21:35 -0700 |
| |
When an iommu_domain is set to IOMMU_DOMAIN_IDENTITY, the driver sets the arm_smmu_domain->stage to ARM_SMMU_DOMAIN_BYPASS and skips the allocation of a CD table, and then sets STRTAB_STE_0_CFG_BYPASS to the CONFIG field of the STE. This works well for devices that only have one substream, i.e. pasid disabled.
With a pasid-capable device, however, there could be a use case where it allows an IDENTITY domain attachment without disabling its pasid feature. This requires the driver to allocate a multi-entry CD table to attach the IDENTITY domain to its default substream and to configure the S1DSS filed of the STE to STRTAB_STE_1_S1DSS_BYPASS. So, there is a missing link here between the STE setup and an IDENTITY domain attachment.
Add a new stage ARM_SMMU_DOMAIN_BYPASS_S1DSS to tag this configuration by overriding the ARM_SMMU_DOMAIN_BYPASS if the device has pasid capability. This new tag will allow the driver allocating a CD table yet skipping an CD insertion from the IDENTITY domain, and setting up the STE accordingly.
In a use case of ARM_SMMU_DOMAIN_BYPASS_S1DSS, the SHCFG field of the STE should be set to STRTAB_STE_1_SHCFG_INCOMING. In other cases of having a CD table, the shareability comes from a CD, not the SHCFG field: according to "13.5 Summary of attribute/permission configuration fields" in the spec the SHCFG field value is irrelevant. So, always configure the SHCFG field of the STE to STRTAB_STE_1_SHCFG_INCOMING when a CD table is present, for simplification.
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> ---
Changelog v2: * Rebased on top of Michael's series reworking CD table ownership: https://lore.kernel.org/all/20230816131925.2521220-1-mshavit@google.com/ * Added a new ARM_SMMU_DOMAIN_BYPASS_S1DSS stage to tag the use case v1: https://lore.kernel.org/all/20230627033326.5236-1-nicolinc@nvidia.com/
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 22 +++++++++++++++++++-- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 1 + 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index b27011b2bec9..860db4fbb995 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1271,6 +1271,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid, * 3. Update Config, sync */ u64 val = le64_to_cpu(dst[0]); + u8 s1dss = STRTAB_STE_1_S1DSS_SSID0; bool ste_live = false; struct arm_smmu_device *smmu = NULL; struct arm_smmu_ctx_desc_cfg *cd_table = NULL; @@ -1290,6 +1291,9 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid, if (smmu_domain) { switch (smmu_domain->stage) { + case ARM_SMMU_DOMAIN_BYPASS_S1DSS: + s1dss = STRTAB_STE_1_S1DSS_BYPASS; + fallthrough; case ARM_SMMU_DOMAIN_S1: cd_table = &master->cd_table; break; @@ -1348,7 +1352,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid, BUG_ON(ste_live); dst[1] = cpu_to_le64( - FIELD_PREP(STRTAB_STE_1_S1DSS, STRTAB_STE_1_S1DSS_SSID0) | + FIELD_PREP(STRTAB_STE_1_S1DSS, s1dss) | + FIELD_PREP(STRTAB_STE_1_SHCFG, STRTAB_STE_1_SHCFG_INCOMING) | FIELD_PREP(STRTAB_STE_1_S1CIR, STRTAB_STE_1_S1C_CACHE_WBRA) | FIELD_PREP(STRTAB_STE_1_S1COR, STRTAB_STE_1_S1C_CACHE_WBRA) | FIELD_PREP(STRTAB_STE_1_S1CSH, ARM_SMMU_SH_ISH) | @@ -2435,6 +2440,16 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) } else if (smmu_domain->smmu != smmu) ret = -EINVAL; + /* + * When attaching an IDENTITY domain to a master with pasid capability, + * the master can still enable SVA feature by allocating a multi-entry + * CD table and attaching the IDENTITY domain to its default substream + * that alone can be byassed using the S1DSS field of the STE. + */ + if (smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS && master->ssid_bits && + smmu->features & ARM_SMMU_FEAT_TRANS_S1) + smmu_domain->stage = ARM_SMMU_DOMAIN_BYPASS_S1DSS; + mutex_unlock(&smmu_domain->init_mutex); if (ret) return ret; @@ -2456,7 +2471,8 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) list_add(&master->domain_head, &smmu_domain->devices); spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); - if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { + if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 || + smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS_S1DSS) { if (!master->cd_table.cdtab) { ret = arm_smmu_alloc_cd_tables(master); if (ret) { @@ -2464,7 +2480,9 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) goto out_list_del; } } + } + if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { /* * Prevent SVA from concurrently modifying the CD or writing to * the CD entry diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index b7a91c8e9b52..e9361f85c91c 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -714,6 +714,7 @@ enum arm_smmu_domain_stage { ARM_SMMU_DOMAIN_S2, ARM_SMMU_DOMAIN_NESTED, ARM_SMMU_DOMAIN_BYPASS, + ARM_SMMU_DOMAIN_BYPASS_S1DSS, /* Bypass S1 default substream only */ }; struct arm_smmu_domain { base-commit: aed5d77d0c3d55d1949db89f27cf7a3981261ef4 -- 2.41.0
| |