Skip to content

Commit f66f62f

Browse files
committed
Merge tag 'iommu-fixes-v6.1-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull iommu fixes from Joerg Roedel: "Intel VT-d fixes: - IO/TLB flush fix - Various pci_dev refcount fixes" * tag 'iommu-fixes-v6.1-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: iommu/vt-d: Fix PCI device refcount leak in dmar_dev_scope_init() iommu/vt-d: Fix PCI device refcount leak in has_external_pci() iommu/vt-d: Fix PCI device refcount leak in prq_event_thread() iommu/vt-d: Add a fix for devices need extra dtlb flush
2 parents 6606515 + 4bedbbd commit f66f62f

File tree

4 files changed

+88
-9
lines changed

4 files changed

+88
-9
lines changed

drivers/iommu/intel/dmar.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,7 @@ int __init dmar_dev_scope_init(void)
820820
info = dmar_alloc_pci_notify_info(dev,
821821
BUS_NOTIFY_ADD_DEVICE);
822822
if (!info) {
823+
pci_dev_put(dev);
823824
return dmar_dev_scope_status;
824825
} else {
825826
dmar_pci_bus_add_dev(info);

drivers/iommu/intel/iommu.c

Lines changed: 70 additions & 3 deletions
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,
@@ -3854,8 +3873,10 @@ static inline bool has_external_pci(void)
38543873
struct pci_dev *pdev = NULL;
38553874

38563875
for_each_pci_dev(pdev)
3857-
if (pdev->external_facing)
3876+
if (pdev->external_facing) {
3877+
pci_dev_put(pdev);
38583878
return true;
3879+
}
38593880

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

drivers/iommu/intel/iommu.h

Lines changed: 4 additions & 0 deletions
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

Lines changed: 13 additions & 6 deletions
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,
@@ -745,12 +748,16 @@ static irqreturn_t prq_event_thread(int irq, void *d)
745748
* If prq is to be handled outside iommu driver via receiver of
746749
* the fault notifiers, we skip the page response here.
747750
*/
748-
if (!pdev || intel_svm_prq_report(iommu, &pdev->dev, req))
749-
handle_bad_prq_event(iommu, req, QI_RESP_INVALID);
751+
if (!pdev)
752+
goto bad_req;
750753

751-
trace_prq_report(iommu, &pdev->dev, req->qw_0, req->qw_1,
752-
req->priv_data[0], req->priv_data[1],
753-
iommu->prq_seq_number++);
754+
if (intel_svm_prq_report(iommu, &pdev->dev, req))
755+
handle_bad_prq_event(iommu, req, QI_RESP_INVALID);
756+
else
757+
trace_prq_report(iommu, &pdev->dev, req->qw_0, req->qw_1,
758+
req->priv_data[0], req->priv_data[1],
759+
iommu->prq_seq_number++);
760+
pci_dev_put(pdev);
754761
prq_advance:
755762
head = (head + sizeof(*req)) & PRQ_RING_MASK;
756763
}

0 commit comments

Comments
 (0)