From 95d4782c34a60800ccf91d9f0703137d4367a2fc Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 19 Apr 2022 14:01:58 -0700 Subject: [PATCH 01/12] iommu/arm-smmu-v3: Fix size calculation in arm_smmu_mm_invalidate_range() The arm_smmu_mm_invalidate_range function is designed to be called by mm core for Shared Virtual Addressing purpose between IOMMU and CPU MMU. However, the ways of two subsystems defining their "end" addresses are slightly different. IOMMU defines its "end" address using the last address of an address range, while mm core defines that using the following address of an address range: include/linux/mm_types.h: unsigned long vm_end; /* The first byte after our end address ... This mismatch resulted in an incorrect calculation for size so it failed to be page-size aligned. Further, it caused a dead loop at "while (iova < end)" check in __arm_smmu_tlb_inv_range function. This patch fixes the issue by doing the calculation correctly. Fixes: 2f7e8c553e98 ("iommu/arm-smmu-v3: Hook up ATC invalidation to mm ops") Cc: stable@vger.kernel.org Signed-off-by: Nicolin Chen Reviewed-by: Jason Gunthorpe Reviewed-by: Robin Murphy Reviewed-by: Jean-Philippe Brucker Link: https://lore.kernel.org/r/20220419210158.21320-1-nicolinc@nvidia.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c index 22ddd05bbdcd0..c623dae1e1154 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c @@ -183,7 +183,14 @@ static void arm_smmu_mm_invalidate_range(struct mmu_notifier *mn, { struct arm_smmu_mmu_notifier *smmu_mn = mn_to_smmu(mn); struct arm_smmu_domain *smmu_domain = smmu_mn->domain; - size_t size = end - start + 1; + size_t size; + + /* + * The mm_types defines vm_end as the first byte after the end address, + * different from IOMMU subsystem using the last address of an address + * range. So do a simple translation here by calculating size correctly. + */ + size = end - start; if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_BTM)) arm_smmu_tlb_inv_range_asid(start, size, smmu_mn->cd->asid, From 4a25f2ea0e030b2fc852c4059a50181bfc5b2f57 Mon Sep 17 00:00:00 2001 From: Ashish Mhetre Date: Thu, 21 Apr 2022 13:45:04 +0530 Subject: [PATCH 02/12] iommu: arm-smmu: disable large page mappings for Nvidia arm-smmu Tegra194 and Tegra234 SoCs have the erratum that causes walk cache entries to not be invalidated correctly. The problem is that the walk cache index generated for IOVA is not same across translation and invalidation requests. This is leading to page faults when PMD entry is released during unmap and populated with new PTE table during subsequent map request. Disabling large page mappings avoids the release of PMD entry and avoid translations seeing stale PMD entry in walk cache. Fix this by limiting the page mappings to PAGE_SIZE for Tegra194 and Tegra234 devices. This is recommended fix from Tegra hardware design team. Acked-by: Robin Murphy Reviewed-by: Krishna Reddy Co-developed-by: Pritesh Raithatha Signed-off-by: Pritesh Raithatha Signed-off-by: Ashish Mhetre Link: https://lore.kernel.org/r/20220421081504.24678-1-amhetre@nvidia.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c b/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c index 01e9b50b10a18..87bf522b9d2ee 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c @@ -258,6 +258,34 @@ static void nvidia_smmu_probe_finalize(struct arm_smmu_device *smmu, struct devi dev_name(dev), err); } +static int nvidia_smmu_init_context(struct arm_smmu_domain *smmu_domain, + struct io_pgtable_cfg *pgtbl_cfg, + struct device *dev) +{ + struct arm_smmu_device *smmu = smmu_domain->smmu; + const struct device_node *np = smmu->dev->of_node; + + /* + * Tegra194 and Tegra234 SoCs have the erratum that causes walk cache + * entries to not be invalidated correctly. The problem is that the walk + * cache index generated for IOVA is not same across translation and + * invalidation requests. This is leading to page faults when PMD entry + * is released during unmap and populated with new PTE table during + * subsequent map request. Disabling large page mappings avoids the + * release of PMD entry and avoid translations seeing stale PMD entry in + * walk cache. + * Fix this by limiting the page mappings to PAGE_SIZE on Tegra194 and + * Tegra234. + */ + if (of_device_is_compatible(np, "nvidia,tegra234-smmu") || + of_device_is_compatible(np, "nvidia,tegra194-smmu")) { + smmu->pgsize_bitmap = PAGE_SIZE; + pgtbl_cfg->pgsize_bitmap = smmu->pgsize_bitmap; + } + + return 0; +} + static const struct arm_smmu_impl nvidia_smmu_impl = { .read_reg = nvidia_smmu_read_reg, .write_reg = nvidia_smmu_write_reg, @@ -268,10 +296,12 @@ static const struct arm_smmu_impl nvidia_smmu_impl = { .global_fault = nvidia_smmu_global_fault, .context_fault = nvidia_smmu_context_fault, .probe_finalize = nvidia_smmu_probe_finalize, + .init_context = nvidia_smmu_init_context, }; static const struct arm_smmu_impl nvidia_smmu_single_impl = { .probe_finalize = nvidia_smmu_probe_finalize, + .init_context = nvidia_smmu_init_context, }; struct arm_smmu_device *nvidia_smmu_impl_init(struct arm_smmu_device *smmu) From 5a4eb91634711aa6278d0f5b3d33c3ea63397639 Mon Sep 17 00:00:00 2001 From: Rohit Agarwal Date: Mon, 11 Apr 2022 15:20:12 +0530 Subject: [PATCH 03/12] dt-bindings: arm-smmu: Add binding for SDX65 SMMU Add devicetree binding for Qualcomm SDX65 SMMU. Signed-off-by: Rohit Agarwal Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/1649670615-21268-5-git-send-email-quic_rohiagar@quicinc.com Signed-off-by: Will Deacon --- Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index da5381c8ee11c..1f99bffea537d 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -39,6 +39,7 @@ properties: - qcom,sc8180x-smmu-500 - qcom,sdm845-smmu-500 - qcom,sdx55-smmu-500 + - qcom,sdx65-smmu-500 - qcom,sm6350-smmu-500 - qcom,sm8150-smmu-500 - qcom,sm8250-smmu-500 From d9ed8af1dee37f181096631fb03729ece98ba816 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 25 Apr 2022 19:41:36 +0800 Subject: [PATCH 04/12] iommu/arm-smmu: fix possible null-ptr-deref in arm_smmu_device_probe() It will cause null-ptr-deref when using 'res', if platform_get_resource() returns NULL, so move using 'res' after devm_ioremap_resource() that will check it to avoid null-ptr-deref. And use devm_platform_get_and_ioremap_resource() to simplify code. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220425114136.2649310-1-yangyingliang@huawei.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c index 568cce590ccc1..52b71f6aee3fe 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c @@ -2092,11 +2092,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev) if (err) return err; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ioaddr = res->start; - smmu->base = devm_ioremap_resource(dev, res); + smmu->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(smmu->base)) return PTR_ERR(smmu->base); + ioaddr = res->start; /* * The resource size should effectively match the value of SMMU_TOP; * stash that temporarily until we know PAGESIZE to validate it with. From b131fa8c1d2afd05d0b7598621114674289c2fbb Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 25 Apr 2022 19:45:25 +0800 Subject: [PATCH 05/12] iommu/arm-smmu-v3: check return value after calling platform_get_resource() It will cause null-ptr-deref if platform_get_resource() returns NULL, we need check the return value. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220425114525.2651143-1-yangyingliang@huawei.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 2 ++ 1 file changed, 2 insertions(+) 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 627a3ed5ee8fd..88817a3376ef0 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -3770,6 +3770,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev) /* Base address */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; if (resource_size(res) < arm_smmu_resource_size(smmu)) { dev_err(dev, "MMIO region too small (%pr)\n", res); return -EINVAL; From cbd23144f7662b00bcde32a938c4a4057e476d68 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brucker Date: Tue, 26 Apr 2022 14:04:45 +0100 Subject: [PATCH 06/12] iommu/arm-smmu-v3-sva: Fix mm use-after-free We currently call arm64_mm_context_put() without holding a reference to the mm, which can result in use-after-free. Call mmgrab()/mmdrop() to ensure the mm only gets freed after we unpinned the ASID. Fixes: 32784a9562fb ("iommu/arm-smmu-v3: Implement iommu_sva_bind/unbind()") Signed-off-by: Jean-Philippe Brucker Tested-by: Zhangfei Gao Link: https://lore.kernel.org/r/20220426130444.300556-1-jean-philippe@linaro.org Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c index c623dae1e1154..1ef7bbb4acf30 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "arm-smmu-v3.h" @@ -96,9 +97,14 @@ static struct arm_smmu_ctx_desc *arm_smmu_alloc_shared_cd(struct mm_struct *mm) struct arm_smmu_ctx_desc *cd; struct arm_smmu_ctx_desc *ret = NULL; + /* Don't free the mm until we release the ASID */ + mmgrab(mm); + asid = arm64_mm_context_get(mm); - if (!asid) - return ERR_PTR(-ESRCH); + if (!asid) { + err = -ESRCH; + goto out_drop_mm; + } cd = kzalloc(sizeof(*cd), GFP_KERNEL); if (!cd) { @@ -165,6 +171,8 @@ static struct arm_smmu_ctx_desc *arm_smmu_alloc_shared_cd(struct mm_struct *mm) kfree(cd); out_put_context: arm64_mm_context_put(mm); +out_drop_mm: + mmdrop(mm); return err < 0 ? ERR_PTR(err) : ret; } @@ -173,6 +181,7 @@ static void arm_smmu_free_shared_cd(struct arm_smmu_ctx_desc *cd) if (arm_smmu_free_asid(cd)) { /* Unpin ASID */ arm64_mm_context_put(cd->mm); + mmdrop(cd->mm); kfree(cd); } } From 38db6b41b2f499c3a6e068f7796a2dd050b24166 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 3 May 2022 09:34:28 -0700 Subject: [PATCH 07/12] dt-bindings: arm-smmu: Add compatible for Qualcomm SC8280XP Add compatible for the Qualcomm SC8280XP platform to the ARM SMMU DeviceTree binding. Signed-off-by: Bjorn Andersson Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220503163429.960998-2-bjorn.andersson@linaro.org Signed-off-by: Will Deacon --- Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index 1f99bffea537d..96891576a575e 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -37,6 +37,7 @@ properties: - qcom,sc7180-smmu-500 - qcom,sc7280-smmu-500 - qcom,sc8180x-smmu-500 + - qcom,sc8280xp-smmu-500 - qcom,sdm845-smmu-500 - qcom,sdx55-smmu-500 - qcom,sdx65-smmu-500 From d044023e219d415d2af87e5e48e9e03488ad145c Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 3 May 2022 09:34:29 -0700 Subject: [PATCH 08/12] iommu/arm-smmu-qcom: Add SC8280XP support Add the Qualcomm SC8280XP platform to the list of compatible for which the Qualcomm-impl of the ARM SMMU should apply. Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220503163429.960998-3-bjorn.andersson@linaro.org Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index ba6298c7140ee..7820711c45608 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -408,6 +408,7 @@ static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = { { .compatible = "qcom,sc7180-smmu-500" }, { .compatible = "qcom,sc7280-smmu-500" }, { .compatible = "qcom,sc8180x-smmu-500" }, + { .compatible = "qcom,sc8280xp-smmu-500" }, { .compatible = "qcom,sdm630-smmu-v2" }, { .compatible = "qcom,sdm845-smmu-500" }, { .compatible = "qcom,sm6125-smmu-500" }, From c02bda09f91a340bc9fae4e236ce3e3ec6b1c9ff Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 29 Apr 2022 10:22:41 +0200 Subject: [PATCH 09/12] dt-bindings: arm-smmu: Document nvidia,memory-controller property On NVIDIA SoC's the ARM SMMU needs to interact with the memory controller in order to map memory clients to the corresponding stream IDs. Document how the nvidia,memory-controller property can be used to achieve this. Note that this is a backwards-incompatible change that is, however, necessary to ensure correctness. Without the new property, most of the devices would still work but it is not guaranteed that all will. Reviewed-by: Rob Herring Acked-by: Will Deacon Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20220429082243.496000-2-thierry.reding@gmail.com Signed-off-by: Will Deacon --- .../devicetree/bindings/iommu/arm,smmu.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index 96891576a575e..ffd537a94a150 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -159,6 +159,17 @@ properties: power-domains: maxItems: 1 + nvidia,memory-controller: + description: | + A phandle to the memory controller on NVIDIA Tegra186 and later SoCs. + The memory controller needs to be programmed with a mapping of memory + client IDs to ARM SMMU stream IDs. + + If this property is absent, the mapping programmed by early firmware + will be used and it is not guaranteed that IOMMU translations will be + enabled for any given device. + $ref: /schemas/types.yaml#/definitions/phandle + required: - compatible - reg @@ -181,6 +192,12 @@ allOf: reg: minItems: 1 maxItems: 2 + + # The reference to the memory controller is required to ensure that the + # memory client to stream ID mapping can be done synchronously with the + # IOMMU attachment. + required: + - nvidia,memory-controller else: properties: reg: From 95d5aeabda00baaccb2be262511adac74255dd7c Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 29 Apr 2022 10:22:42 +0200 Subject: [PATCH 10/12] dt-bindings: arm-smmu: Add compatible for Tegra234 SOC The NVIDIA Tegra234 SoC comes with one single-instance ARM SMMU used by isochronous memory clients and two dual-instance ARM SMMUs used by non- isochronous memory clients. Reviewed-by: Rob Herring Acked-by: Will Deacon Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20220429082243.496000-3-thierry.reding@gmail.com Signed-off-by: Will Deacon --- Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index ffd537a94a150..76fc2c0f4d549 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -64,8 +64,9 @@ properties: for improved performance. items: - enum: - - nvidia,tegra194-smmu - nvidia,tegra186-smmu + - nvidia,tegra194-smmu + - nvidia,tegra234-smmu - const: nvidia,smmu-500 - items: - const: arm,mmu-500 @@ -185,8 +186,9 @@ allOf: compatible: contains: enum: - - nvidia,tegra194-smmu - nvidia,tegra186-smmu + - nvidia,tegra194-smmu + - nvidia,tegra234-smmu then: properties: reg: From 5ca216155b5ead6e2d64738644afed9ac17f1fe3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 29 Apr 2022 10:22:43 +0200 Subject: [PATCH 11/12] iommu/arm-smmu: Support Tegra234 SMMU Allow the NVIDIA-specific ARM SMMU implementation to bind to the SMMU instances found on Tegra234. Acked-by: Robin Murphy Acked-by: Will Deacon Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20220429082243.496000-4-thierry.reding@gmail.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu-impl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c index 2c25cce380603..658f3cc832781 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c @@ -211,7 +211,8 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu) if (of_property_read_bool(np, "calxeda,smmu-secure-config-access")) smmu->impl = &calxeda_impl; - if (of_device_is_compatible(np, "nvidia,tegra194-smmu") || + if (of_device_is_compatible(np, "nvidia,tegra234-smmu") || + of_device_is_compatible(np, "nvidia,tegra194-smmu") || of_device_is_compatible(np, "nvidia,tegra186-smmu")) return nvidia_smmu_impl_init(smmu); From 628bf55b620497a105f4963ee8fb84769f7e6bb4 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 10 May 2022 09:38:58 +0100 Subject: [PATCH 12/12] iommu/arm-smmu: Force identity domains for legacy binding When using the legacy "mmu-masters" DT binding, we reject DMA domains since we have no guarantee of driver probe order and thus can't rely on client drivers getting the correct DMA ops. However, we can do better than fall back to the old no-default-domain behaviour now, by forcing an identity default domain instead. This also means that detaching from a VFIO domain can actually work - that looks to have been broken for over 6 years, so clearly isn't something that legacy binding users care about, but we may as well make the driver code make sense anyway. Suggested-by: Jason Gunthorpe Signed-off-by: Robin Murphy Link: https://lore.kernel.org/r/9805e4c492cb972bdcdd57999d2d001a2d8b5aab.1652171938.git.robin.murphy@arm.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c index 52b71f6aee3fe..2ed3594f384ef 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c @@ -1574,6 +1574,9 @@ static int arm_smmu_def_domain_type(struct device *dev) struct arm_smmu_master_cfg *cfg = dev_iommu_priv_get(dev); const struct arm_smmu_impl *impl = cfg->smmu->impl; + if (using_legacy_binding) + return IOMMU_DOMAIN_IDENTITY; + if (impl && impl->def_domain_type) return impl->def_domain_type(dev);