From c72b15c11e83771e9ad29c1ae02875774d371baa Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Wed, 4 Dec 2019 14:51:50 -0800 Subject: [PATCH 1/2] iommu/arm-smmu: Express fastmap domain geometries correctly Fastmap implicilty imposes a requirement on clients that the domain geometry must be within the range [0, SZ_4G). The domain geometry is only adjusted in the presence of the qcom,iommu-dma-addr-pool property. Otherwise, the SMMU HW's restrictions are imposed on the domain geometry. This is problematic for fastmap clients that don't explicilty express a domain geometry requirement, as the SMMU HW's geometry restrictions may not align with the fastmap geometry restrictions. Thus for fastmap clients that do not express domain geometry requirements, impose the default fastmap domain geometry requirement. This makes it so that the geometry does not need to be fixed up for the debug devices, so remove the handling for that as well. Change-Id: I66f5fc6e80de621ae80888333126c7bcd3c15775 Signed-off-by: Isaac J. Manjarres --- drivers/iommu/arm-smmu.c | 63 +++++++++++++++++++++++-------------- drivers/iommu/iommu-debug.c | 7 ----- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 825198404f1f..9c75eeb9ee10 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1702,17 +1702,20 @@ static void arm_smmu_free_asid(struct iommu_domain *domain) /* * Checks for "qcom,iommu-dma-addr-pool" property to specify the IOVA range - * for the domain. If not present, the domain geometry is unmodified. + * for the domain. If not present, and the domain doesn't use fastmap, + * the domain geometry is unmodified. */ static int arm_smmu_adjust_domain_geometry(struct device *dev, - struct iommu_domain_geometry *geometry) + struct iommu_domain *domain) { struct device_node *np; + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); int naddr, nsize, len; u64 dma_base, dma_size, dma_end; const __be32 *ranges; - dma_addr_t hw_base = geometry->aperture_start; - dma_addr_t hw_end = geometry->aperture_end; + dma_addr_t hw_base = domain->geometry.aperture_start; + dma_addr_t hw_end = domain->geometry.aperture_end; + bool is_fast = test_bit(DOMAIN_ATTR_FAST, smmu_domain->attributes); if (!dev->of_node) return 0; @@ -1722,26 +1725,38 @@ static int arm_smmu_adjust_domain_geometry(struct device *dev, np = dev->of_node; ranges = of_get_property(np, "qcom,iommu-dma-addr-pool", &len); - if (!ranges) + + if (!ranges && !is_fast) return 0; - len /= sizeof(u32); - naddr = of_n_addr_cells(np); - nsize = of_n_size_cells(np); - if (len < naddr + nsize) { - dev_err(dev, "Invalid length for qcom,iommu-dma-addr-pool, expected %d cells\n", - naddr + nsize); - return -EINVAL; - } - if (naddr == 0 || nsize == 0) { - dev_err(dev, "Invalid #address-cells %d or #size-cells %d\n", - naddr, nsize); - return -EINVAL; - } + if (ranges) { + len /= sizeof(u32); + naddr = of_n_addr_cells(np); + nsize = of_n_size_cells(np); + if (len < naddr + nsize) { + dev_err(dev, "Invalid length for qcom,iommu-dma-addr-pool, expected %d cells\n", + naddr + nsize); + return -EINVAL; + } + if (naddr == 0 || nsize == 0) { + dev_err(dev, "Invalid #address-cells %d or #size-cells %d\n", + naddr, nsize); + return -EINVAL; + } - dma_base = of_read_number(ranges, naddr); - dma_size = of_read_number(ranges + naddr, nsize); - dma_end = dma_base + dma_size - 1; + dma_base = of_read_number(ranges, naddr); + dma_size = of_read_number(ranges + naddr, nsize); + dma_end = dma_base + dma_size - 1; + } else { + /* + * This domain uses fastmap, but doesn't have any domain + * geometry limitations, as implied by the absence of the + * qcom,iommu-dma-addr-pool property, so impose the default + * fastmap geometry requirement. + */ + dma_base = 0; + dma_end = SZ_4G - 1; + } /* * The original geometry describes the IOVA limitations of the hardware, @@ -1751,8 +1766,8 @@ static int arm_smmu_adjust_domain_geometry(struct device *dev, if (!((hw_base <= dma_base) && (dma_end <= hw_end))) return -EINVAL; - geometry->aperture_start = dma_base; - geometry->aperture_end = dma_end; + domain->geometry.aperture_start = dma_base; + domain->geometry.aperture_end = dma_end; return 0; } @@ -2025,7 +2040,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, /* Update the domain's page sizes to reflect the page table format */ domain->pgsize_bitmap = pgtbl_info->pgtbl_cfg.pgsize_bitmap; domain->geometry.aperture_end = (1UL << ias) - 1; - ret = arm_smmu_adjust_domain_geometry(dev, &domain->geometry); + ret = arm_smmu_adjust_domain_geometry(dev, domain); if (ret) goto out_clear_smmu; domain->geometry.force_aperture = true; diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index f74614ff8f26..f4994c041b8b 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -352,13 +352,6 @@ static int iommu_debug_dma_reconfigure(struct iommu_debug_device *ddev, if (is_fast) { iommu_domain_get_attr(domain, DOMAIN_ATTR_PGTBL_INFO, &info); - /* - * Fix up the domain geometry, as the fastmap implementation - * uses it for determining the IOVA space parameters. Allow - * it to use the entire fastmap IOVA space [0, 4GB). - */ - domain->geometry.aperture_start = 0; - domain->geometry.aperture_end = SZ_4G - 1; if (fast_smmu_init_mapping(dev, domain, info.ops)) { dev_err_ratelimited(dev, "fastmap init failed\n"); goto out_detach_group; From 1a5f2f795418551e312413255b9cd82f9e74c33f Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Thu, 5 Dec 2019 08:00:21 -0800 Subject: [PATCH 2/2] iommu/arm-smmu: Reduce log spam from ECATS translation timeouts Avoid flooding the console logs when ECATS translations timeout. Change-Id: I6f6b0e277a53fd918c47576c1f680230f1611a24 Signed-off-by: Isaac J. Manjarres --- drivers/iommu/arm-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 9c75eeb9ee10..318be3f9f8bb 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -5235,7 +5235,7 @@ redo: if (val & FSR_FAULT) break; if (ktime_compare(ktime_get(), timeout) > 0) { - dev_err(tbu->dev, "ECATS translation timed out!\n"); + dev_err_ratelimited(tbu->dev, "ECATS translation timed out!\n"); ret = -ETIMEDOUT; break; }