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 <lmark@codeaurora.org>
[guptap@codeaurora.org: update geometry.aperture with mapping]
Signed-off-by: Prakash Gupta <guptap@codeaurora.org>
This commit is contained in:
Liam Mark 2017-04-03 16:43:53 -07:00
parent 7416fc8014
commit 8a17ef3114
2 changed files with 38 additions and 6 deletions

View File

@ -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,

View File

@ -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.