Skip to content

Commit e65a689

Browse files
Jacob Panjoergroedel
Jacob Pan
authored andcommitted
iommu/vt-d: Add a fix for devices need extra dtlb flush
QAT devices on Intel Sapphire Rapids and Emerald Rapids have a defect in address translation service (ATS). These devices may inadvertently issue ATS invalidation completion before posted writes initiated with translated address that utilized translations matching the invalidation address range, violating the invalidation completion ordering. This patch adds an extra device TLB invalidation for the affected devices, it is needed to ensure no more posted writes with translated address following the invalidation completion. Therefore, the ordering is preserved and data-corruption is prevented. Device TLBs are invalidated under the following six conditions: 1. Device driver does DMA API unmap IOVA 2. Device driver unbind a PASID from a process, sva_unbind_device() 3. PASID is torn down, after PASID cache is flushed. e.g. process exit_mmap() due to crash 4. Under SVA usage, called by mmu_notifier.invalidate_range() where VM has to free pages that were unmapped 5. userspace driver unmaps a DMA buffer 6. Cache invalidation in vSVA usage (upcoming) For #1 and #2, device drivers are responsible for stopping DMA traffic before unmap/unbind. For #3, iommu driver gets mmu_notifier to invalidate TLB the same way as normal user unmap which will do an extra invalidation. The dTLB invalidation after PASID cache flush does not need an extra invalidation. Therefore, we only need to deal with #4 and #5 in this patch. #1 is also covered by this patch due to common code path with #5. Tested-by: Yuzhang Luo <[email protected]> Reviewed-by: Ashok Raj <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Signed-off-by: Jacob Pan <[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 b7b275e commit e65a689

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

drivers/iommu/intel/iommu.c

+67-2
Original file line numberDiff line numberDiff line change
@@ -1396,6 +1396,24 @@ static void domain_update_iotlb(struct dmar_domain *domain)
13961396
spin_unlock_irqrestore(&domain->lock, flags);
13971397
}
13981398

1399+
/*
1400+
* The extra devTLB flush quirk impacts those QAT devices with PCI device
1401+
* IDs ranging from 0x4940 to 0x4943. It is exempted from risky_device()
1402+
* check because it applies only to the built-in QAT devices and it doesn't
1403+
* grant additional privileges.
1404+
*/
1405+
#define BUGGY_QAT_DEVID_MASK 0x494c
1406+
static bool dev_needs_extra_dtlb_flush(struct pci_dev *pdev)
1407+
{
1408+
if (pdev->vendor != PCI_VENDOR_ID_INTEL)
1409+
return false;
1410+
1411+
if ((pdev->device & 0xfffc) != BUGGY_QAT_DEVID_MASK)
1412+
return false;
1413+
1414+
return true;
1415+
}
1416+
13991417
static void iommu_enable_pci_caps(struct device_domain_info *info)
14001418
{
14011419
struct pci_dev *pdev;
@@ -1478,6 +1496,7 @@ static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
14781496
qdep = info->ats_qdep;
14791497
qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
14801498
qdep, addr, mask);
1499+
quirk_extra_dev_tlb_flush(info, addr, mask, PASID_RID2PASID, qdep);
14811500
}
14821501

14831502
static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
@@ -4490,9 +4509,10 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
44904509
if (dev_is_pci(dev)) {
44914510
if (ecap_dev_iotlb_support(iommu->ecap) &&
44924511
pci_ats_supported(pdev) &&
4493-
dmar_ats_supported(pdev, iommu))
4512+
dmar_ats_supported(pdev, iommu)) {
44944513
info->ats_supported = 1;
4495-
4514+
info->dtlb_extra_inval = dev_needs_extra_dtlb_flush(pdev);
4515+
}
44964516
if (sm_supported(iommu)) {
44974517
if (pasid_supported(iommu)) {
44984518
int features = pci_pasid_features(pdev);
@@ -4931,3 +4951,48 @@ static void __init check_tylersburg_isoch(void)
49314951
pr_warn("Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
49324952
vtisochctrl);
49334953
}
4954+
4955+
/*
4956+
* Here we deal with a device TLB defect where device may inadvertently issue ATS
4957+
* invalidation completion before posted writes initiated with translated address
4958+
* that utilized translations matching the invalidation address range, violating
4959+
* the invalidation completion ordering.
4960+
* Therefore, any use cases that cannot guarantee DMA is stopped before unmap is
4961+
* vulnerable to this defect. In other words, any dTLB invalidation initiated not
4962+
* under the control of the trusted/privileged host device driver must use this
4963+
* quirk.
4964+
* Device TLBs are invalidated under the following six conditions:
4965+
* 1. Device driver does DMA API unmap IOVA
4966+
* 2. Device driver unbind a PASID from a process, sva_unbind_device()
4967+
* 3. PASID is torn down, after PASID cache is flushed. e.g. process
4968+
* exit_mmap() due to crash
4969+
* 4. Under SVA usage, called by mmu_notifier.invalidate_range() where
4970+
* VM has to free pages that were unmapped
4971+
* 5. Userspace driver unmaps a DMA buffer
4972+
* 6. Cache invalidation in vSVA usage (upcoming)
4973+
*
4974+
* For #1 and #2, device drivers are responsible for stopping DMA traffic
4975+
* before unmap/unbind. For #3, iommu driver gets mmu_notifier to
4976+
* invalidate TLB the same way as normal user unmap which will use this quirk.
4977+
* The dTLB invalidation after PASID cache flush does not need this quirk.
4978+
*
4979+
* As a reminder, #6 will *NEED* this quirk as we enable nested translation.
4980+
*/
4981+
void quirk_extra_dev_tlb_flush(struct device_domain_info *info,
4982+
unsigned long address, unsigned long mask,
4983+
u32 pasid, u16 qdep)
4984+
{
4985+
u16 sid;
4986+
4987+
if (likely(!info->dtlb_extra_inval))
4988+
return;
4989+
4990+
sid = PCI_DEVID(info->bus, info->devfn);
4991+
if (pasid == PASID_RID2PASID) {
4992+
qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
4993+
qdep, address, mask);
4994+
} else {
4995+
qi_flush_dev_iotlb_pasid(info->iommu, sid, info->pfsid,
4996+
pasid, qdep, address, mask);
4997+
}
4998+
}

drivers/iommu/intel/iommu.h

+4
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ struct device_domain_info {
623623
u8 pri_enabled:1;
624624
u8 ats_supported:1;
625625
u8 ats_enabled:1;
626+
u8 dtlb_extra_inval:1; /* Quirk for devices need extra flush */
626627
u8 ats_qdep;
627628
struct device *dev; /* it's NULL for PCIe-to-PCI bridge */
628629
struct intel_iommu *iommu; /* IOMMU used by this device */
@@ -728,6 +729,9 @@ void qi_flush_piotlb(struct intel_iommu *iommu, u16 did, u32 pasid, u64 addr,
728729
void qi_flush_dev_iotlb_pasid(struct intel_iommu *iommu, u16 sid, u16 pfsid,
729730
u32 pasid, u16 qdep, u64 addr,
730731
unsigned int size_order);
732+
void quirk_extra_dev_tlb_flush(struct device_domain_info *info,
733+
unsigned long address, unsigned long pages,
734+
u32 pasid, u16 qdep);
731735
void qi_flush_pasid_cache(struct intel_iommu *iommu, u16 did, u64 granu,
732736
u32 pasid);
733737

drivers/iommu/intel/svm.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,13 @@ static void __flush_svm_range_dev(struct intel_svm *svm,
184184
return;
185185

186186
qi_flush_piotlb(sdev->iommu, sdev->did, svm->pasid, address, pages, ih);
187-
if (info->ats_enabled)
187+
if (info->ats_enabled) {
188188
qi_flush_dev_iotlb_pasid(sdev->iommu, sdev->sid, info->pfsid,
189189
svm->pasid, sdev->qdep, address,
190190
order_base_2(pages));
191+
quirk_extra_dev_tlb_flush(info, address, order_base_2(pages),
192+
svm->pasid, sdev->qdep);
193+
}
191194
}
192195

193196
static void intel_flush_svm_range_dev(struct intel_svm *svm,

0 commit comments

Comments
 (0)