Skip to content

Commit 8219853

Browse files
yiliu1765joergroedel
authored andcommitted
iommu/vt-d: Add missing iotlb flush for parent domain
If a domain is used as the parent in nested translation its mappings might be cached using DID of the nested domain. But the existing code ignores this fact to only invalidate the iotlb entries tagged by the domain's own DID. Loop the s1_domains list, if any, to invalidate all iotlb entries related to the target s2 address range. According to VT-d spec there is no need for software to explicitly flush the affected s1 cache. It's implicitly done by HW when s2 cache is invalidated. Fixes: b41e38e ("iommu/vt-d: Add nested domain allocation") Signed-off-by: Yi Liu <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Lu Baolu <[email protected]> Signed-off-by: Joerg Roedel <[email protected]>
1 parent 0455d31 commit 8219853

File tree

1 file changed

+31
-0
lines changed

1 file changed

+31
-0
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,6 +1451,28 @@ static void __mapping_notify_one(struct intel_iommu *iommu, struct dmar_domain *
14511451
iommu_flush_write_buffer(iommu);
14521452
}
14531453

1454+
/*
1455+
* Flush the relevant caches in nested translation if the domain
1456+
* also serves as a parent
1457+
*/
1458+
static void parent_domain_flush(struct dmar_domain *domain,
1459+
unsigned long pfn,
1460+
unsigned long pages, int ih)
1461+
{
1462+
struct dmar_domain *s1_domain;
1463+
1464+
spin_lock(&domain->s1_lock);
1465+
list_for_each_entry(s1_domain, &domain->s1_domains, s2_link) {
1466+
struct iommu_domain_info *info;
1467+
unsigned long i;
1468+
1469+
xa_for_each(&s1_domain->iommu_array, i, info)
1470+
__iommu_flush_iotlb_psi(info->iommu, info->did,
1471+
pfn, pages, ih);
1472+
}
1473+
spin_unlock(&domain->s1_lock);
1474+
}
1475+
14541476
static void intel_flush_iotlb_all(struct iommu_domain *domain)
14551477
{
14561478
struct dmar_domain *dmar_domain = to_dmar_domain(domain);
@@ -1470,6 +1492,9 @@ static void intel_flush_iotlb_all(struct iommu_domain *domain)
14701492
if (!cap_caching_mode(iommu->cap))
14711493
iommu_flush_dev_iotlb(dmar_domain, 0, MAX_AGAW_PFN_WIDTH);
14721494
}
1495+
1496+
if (dmar_domain->nested_parent)
1497+
parent_domain_flush(dmar_domain, 0, -1, 0);
14731498
}
14741499

14751500
static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
@@ -1993,6 +2018,9 @@ static void switch_to_super_page(struct dmar_domain *domain,
19932018
iommu_flush_iotlb_psi(info->iommu, domain,
19942019
start_pfn, lvl_pages,
19952020
0, 0);
2021+
if (domain->nested_parent)
2022+
parent_domain_flush(domain, start_pfn,
2023+
lvl_pages, 0);
19962024
}
19972025

19982026
pte++;
@@ -4125,6 +4153,9 @@ static void intel_iommu_tlb_sync(struct iommu_domain *domain,
41254153
start_pfn, nrpages,
41264154
list_empty(&gather->freelist), 0);
41274155

4156+
if (dmar_domain->nested_parent)
4157+
parent_domain_flush(dmar_domain, start_pfn, nrpages,
4158+
list_empty(&gather->freelist));
41284159
put_pages_list(&gather->freelist);
41294160
}
41304161

0 commit comments

Comments
 (0)