iommu/arm-smmu: Defer TLB maintenance until after a buffer is unmapped
TLB maintenance is currently performed while a buffer is being unmapped. For large buffers, doing so is suboptimal, as opposed to invalidating the entire TLB for a particular context after the buffer has been unmapped. Thus, defer TLB maintenance until a buffer is unmapped, and iommu_iotlb_sync() is invoked. This shows a significant amount of improvement in the latency incurred by unmapping a buffer. Without this patch, we observe the following latencies: (average over 10 iterations) size iommu_map iommu_unmap 4K 1.265 us 651.619 us 64K 7.666 us 678.968 us 1M 90.979 us 1152.072 us 2M 179.885 us 2303.020 us 12M 1082.140 us 5537.349 us 24M 2159.463 us 9415.588 us 32M 2878.609 us 12001.406 us size iommu_map_sg iommu_unmap 4K 1.088 us 647.921 us 64K 7.208 us 680.312 us 1M 103.505 us 1153.520 us 2M 200.885 us 2302.593 us 12M 1159.146 us 5534.989 us 24M 2300.744 us 9411.614 us 32M 3057.343 us 12000.468 us While applying this patch yields the following latencies: (average over 10 iterations) size iommu_map iommu_unmap 4K 1.172 us 5.218 us 64K 6.229 us 9.338 us 1M 91.812 us 77.828 us 2M 179.500 us 154.156 us 12M 1077.927 us 154.572 us 24M 2159.630 us 157.453 us 32M 2883.953 us 157.921 us size iommu_map_sg iommu_unmap 4K 1.041 us 5.005 us 64K 6.781 us 9.364 us 1M 102.390 us 79.515 us 2M 200.328 us 152.270 us 12M 1161.000 us 154.515 us 24M 2304.369 us 157.822 us 32M 3059.416 us 160.734 us. Change-Id: I7aecf559746eb65d2543ce9b16ad12492eb70fa1 Signed-off-by: Isaac J. Manjarres <isaacm@codeaurora.org>
This commit is contained in:
@@ -2423,7 +2423,7 @@ static void arm_smmu_iotlb_sync(struct iommu_domain *domain,
|
||||
arm_smmu_rpm_get(smmu);
|
||||
if (smmu->version == ARM_SMMU_V2 ||
|
||||
smmu_domain->stage == ARM_SMMU_DOMAIN_S1)
|
||||
arm_smmu_tlb_sync_context(smmu_domain);
|
||||
arm_smmu_tlb_inv_context_s1(smmu_domain);
|
||||
else
|
||||
arm_smmu_tlb_sync_global(smmu);
|
||||
arm_smmu_rpm_put(smmu);
|
||||
|
@@ -624,7 +624,6 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
|
||||
|
||||
tablep = iopte_deref(pte, data);
|
||||
} else if (unmap_idx >= 0) {
|
||||
io_pgtable_tlb_add_page(&data->iop, gather, iova, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -653,9 +652,6 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
|
||||
__arm_lpae_set_pte(ptep, 0, &iop->cfg);
|
||||
|
||||
if (!iopte_leaf(pte, lvl, iop->fmt)) {
|
||||
/* Also flush any partial walks */
|
||||
io_pgtable_tlb_flush_walk(iop, iova, size,
|
||||
ARM_LPAE_GRANULE(data));
|
||||
ptep = iopte_deref(pte, data);
|
||||
__arm_lpae_free_pgtable(data, lvl + 1, ptep);
|
||||
} else if (iop->cfg.quirks & IO_PGTABLE_QUIRK_NON_STRICT) {
|
||||
@@ -665,8 +661,6 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
|
||||
* has observed it before the TLBIALL can be issued.
|
||||
*/
|
||||
smp_wmb();
|
||||
} else {
|
||||
io_pgtable_tlb_add_page(iop, gather, iova, size);
|
||||
}
|
||||
|
||||
return size;
|
||||
@@ -679,15 +673,9 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
|
||||
|
||||
iopte_tblcnt_sub(ptep, 1);
|
||||
if (!iopte_tblcnt(*ptep)) {
|
||||
size_t blk_size = ARM_LPAE_BLOCK_SIZE(lvl, data);
|
||||
|
||||
/* no valid mappings left under this table. free it. */
|
||||
__arm_lpae_set_pte(ptep, 0, &iop->cfg);
|
||||
io_pgtable_tlb_flush_walk(iop, ALIGN_DOWN(iova, blk_size),
|
||||
blk_size, ARM_LPAE_GRANULE(data));
|
||||
__arm_lpae_free_pgtable(data, lvl + 1, table);
|
||||
} else {
|
||||
io_pgtable_tlb_add_page(iop, gather, iova, size);
|
||||
}
|
||||
|
||||
return size;
|
||||
|
Reference in New Issue
Block a user