Skip to content

Commit 353e3cf

Browse files
committed
iommu/arm-smmu-v3: Fix ATC invalidation ordering wrt main TLBs
When invalidating the ATC for an PCIe endpoint using ATS, we must take care to complete invalidation of the main SMMU TLBs beforehand, otherwise the device could immediately repopulate its ATC with stale translations. Hooking the ATC invalidation into ->unmap() as we currently do does the exact opposite: it ensures that the ATC is invalidated *before* the main TLBs, which is bogus. Move ATC invalidation into the actual (leaf) invalidation routines so that it is always called after completing main TLB invalidation. Reviewed-by: Robin Murphy <[email protected]> Signed-off-by: Will Deacon <[email protected]>
1 parent bfff88e commit 353e3cf

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

drivers/iommu/arm-smmu-v3.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
19611961
*/
19621962
arm_smmu_cmdq_issue_cmd(smmu, &cmd);
19631963
arm_smmu_cmdq_issue_sync(smmu);
1964+
arm_smmu_atc_inv_domain(smmu_domain, 0, 0, 0);
19641965
}
19651966

19661967
static void arm_smmu_tlb_inv_range(unsigned long iova, size_t size,
@@ -1969,7 +1970,7 @@ static void arm_smmu_tlb_inv_range(unsigned long iova, size_t size,
19691970
{
19701971
u64 cmds[CMDQ_BATCH_ENTRIES * CMDQ_ENT_DWORDS];
19711972
struct arm_smmu_device *smmu = smmu_domain->smmu;
1972-
unsigned long end = iova + size;
1973+
unsigned long start = iova, end = iova + size;
19731974
int i = 0;
19741975
struct arm_smmu_cmdq_ent cmd = {
19751976
.tlbi = {
@@ -2001,6 +2002,12 @@ static void arm_smmu_tlb_inv_range(unsigned long iova, size_t size,
20012002
}
20022003

20032004
arm_smmu_cmdq_issue_cmdlist(smmu, cmds, i, true);
2005+
2006+
/*
2007+
* Unfortunately, this can't be leaf-only since we may have
2008+
* zapped an entire table.
2009+
*/
2010+
arm_smmu_atc_inv_domain(smmu_domain, 0, start, size);
20042011
}
20052012

20062013
static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
@@ -2420,18 +2427,13 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
24202427
static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
24212428
size_t size, struct iommu_iotlb_gather *gather)
24222429
{
2423-
int ret;
24242430
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
24252431
struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
24262432

24272433
if (!ops)
24282434
return 0;
24292435

2430-
ret = ops->unmap(ops, iova, size, gather);
2431-
if (ret && arm_smmu_atc_inv_domain(smmu_domain, 0, iova, size))
2432-
return 0;
2433-
2434-
return ret;
2436+
return ops->unmap(ops, iova, size, gather);
24352437
}
24362438

24372439
static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain)

0 commit comments

Comments
 (0)