From 8a17ef3114451f36583f0928abd22a7ca9ccc518 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Mon, 3 Apr 2017 16:43:53 -0700 Subject: [PATCH] iommu/arm-smmu: add support to configure IOVA range For IOMMU clients the DMA layer only allocates IOVA addresses within the range specified by the qcom,iommu-dma-addr-pool DT property. The remaining IOVA addresses outside of this range, but limited to [0 - 4GB) for fastmap clients, can be used by calls such as iommu_map and iommu_map_sg. Fastmap pre-allocates the page tables for its fully supported IOVA range, which is [0 - 4GB), and this consumes 8MB of memory. Because clients often don't use most of the IOVA addresses outside of the DMA layer IOVA range allow fastmap clients to use the qcom,iommu-geometry DT property to specify only the IOVA range which needs to be supported in order to save memory. CRs-Fixed: 2035925 Change-Id: Ib389e019a022d98417884002de08115fb0fc9384 [lmark@codeaurora.org: removed support for DOMAIN_ATTR_GEOMETRY domain] Signed-off-by: Liam Mark [guptap@codeaurora.org: update geometry.aperture with mapping] Signed-off-by: Prakash Gupta --- drivers/iommu/arm-smmu.c | 42 ++++++++++++++++++++++++++++---- drivers/iommu/dma-mapping-fast.c | 2 +- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index ba978a627b95..9e09bbe00f18 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1834,25 +1834,55 @@ static int arm_smmu_get_domain_iova_range(struct device *dev, dma_addr_t *ret_end) { dma_addr_t iova_base, iova_end; + dma_addr_t dma_base, dma_end, geometry_start, geometry_end; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); dma_addr_t hw_base = 0; dma_addr_t hw_end = (1UL << ias) - 1; bool is_fast = test_bit(DOMAIN_ATTR_FAST, smmu_domain->attributes); + int ret; - if (is_fast) { + if (!is_fast) { + iova_base = hw_base; + iova_end = hw_end; + goto end; + } + + ret = arm_smmu_get_domain_dma_range(dev, domain, hw_base, hw_end, + &dma_base, &dma_end); + if (ret) + return ret; + + ret = get_range_prop(dev, "qcom,iommu-geometry", &geometry_start, + &geometry_end); + if (!ret) { + if (geometry_start >= SZ_1G * 4ULL || + geometry_end >= SZ_1G * 4ULL) { + pr_err("fastmap geometry does not support IOVAs >= 4GB\n"); + return -EINVAL; + } + + if (geometry_start < dma_base) + iova_base = geometry_start; + else + iova_base = dma_base; + + if (geometry_end > dma_end) + iova_end = geometry_end; + else + iova_end = dma_end; + } else if (ret == -ENOENT) { iova_base = 0; iova_end = SZ_4G - 1; } else { - iova_base = hw_base; - iova_end = hw_end; + return ret; } if (!((hw_base <= iova_base) && (iova_end <= hw_end))) return -EINVAL; +end: *ret_base = iova_base; *ret_end = iova_end; - return 0; } @@ -2131,8 +2161,10 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, ret = arm_smmu_get_domain_iova_range(dev, domain, ias, &ttbr0_pgtbl_info->iova_base, &ttbr0_pgtbl_info->iova_end); - if (ret) + if (ret) { + dev_err(dev, "Failed to get domain IOVA range\n"); goto out_clear_smmu; + } ttbr0_pgtbl_info->pgtbl_cfg = (struct io_pgtable_cfg) { .quirks = quirks, diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c index 93f0fa52b269..71de9ac0f3be 100644 --- a/drivers/iommu/dma-mapping-fast.c +++ b/drivers/iommu/dma-mapping-fast.c @@ -798,7 +798,7 @@ static const struct dma_map_ops fast_smmu_dma_ops = { * * Creates a mapping structure which holds information about used/unused IO * address ranges, which is required to perform mapping with IOMMU aware - * functions. The only VA range supported is [0, 4GB). + * functions. The only VA range supported is [0, 4GB). * * The client device need to be attached to the mapping with * fast_smmu_attach_device function.