diff options
| -rw-r--r-- | drivers/iommu/intel/dmar.c | 1 | ||||
| -rw-r--r-- | drivers/iommu/intel/iommu.c | 73 | ||||
| -rw-r--r-- | drivers/iommu/intel/iommu.h | 4 | ||||
| -rw-r--r-- | drivers/iommu/intel/svm.c | 19 | 
4 files changed, 88 insertions, 9 deletions
| diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c index 5a8f780e7ffd..bc94059a5b87 100644 --- a/drivers/iommu/intel/dmar.c +++ b/drivers/iommu/intel/dmar.c @@ -820,6 +820,7 @@ int __init dmar_dev_scope_init(void)  			info = dmar_alloc_pci_notify_info(dev,  					BUS_NOTIFY_ADD_DEVICE);  			if (!info) { +				pci_dev_put(dev);  				return dmar_dev_scope_status;  			} else {  				dmar_pci_bus_add_dev(info); diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 996a8b5ee5ee..5287efe247b1 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -1396,6 +1396,24 @@ static void domain_update_iotlb(struct dmar_domain *domain)  	spin_unlock_irqrestore(&domain->lock, flags);  } +/* + * The extra devTLB flush quirk impacts those QAT devices with PCI device + * IDs ranging from 0x4940 to 0x4943. It is exempted from risky_device() + * check because it applies only to the built-in QAT devices and it doesn't + * grant additional privileges. + */ +#define BUGGY_QAT_DEVID_MASK 0x494c +static bool dev_needs_extra_dtlb_flush(struct pci_dev *pdev) +{ +	if (pdev->vendor != PCI_VENDOR_ID_INTEL) +		return false; + +	if ((pdev->device & 0xfffc) != BUGGY_QAT_DEVID_MASK) +		return false; + +	return true; +} +  static void iommu_enable_pci_caps(struct device_domain_info *info)  {  	struct pci_dev *pdev; @@ -1478,6 +1496,7 @@ static void __iommu_flush_dev_iotlb(struct device_domain_info *info,  	qdep = info->ats_qdep;  	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,  			   qdep, addr, mask); +	quirk_extra_dev_tlb_flush(info, addr, mask, PASID_RID2PASID, qdep);  }  static void iommu_flush_dev_iotlb(struct dmar_domain *domain, @@ -3854,8 +3873,10 @@ static inline bool has_external_pci(void)  	struct pci_dev *pdev = NULL;  	for_each_pci_dev(pdev) -		if (pdev->external_facing) +		if (pdev->external_facing) { +			pci_dev_put(pdev);  			return true; +		}  	return false;  } @@ -4490,9 +4511,10 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)  	if (dev_is_pci(dev)) {  		if (ecap_dev_iotlb_support(iommu->ecap) &&  		    pci_ats_supported(pdev) && -		    dmar_ats_supported(pdev, iommu)) +		    dmar_ats_supported(pdev, iommu)) {  			info->ats_supported = 1; - +			info->dtlb_extra_inval = dev_needs_extra_dtlb_flush(pdev); +		}  		if (sm_supported(iommu)) {  			if (pasid_supported(iommu)) {  				int features = pci_pasid_features(pdev); @@ -4931,3 +4953,48 @@ static void __init check_tylersburg_isoch(void)  	pr_warn("Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",  	       vtisochctrl);  } + +/* + * Here we deal with a device TLB defect where device 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. + * Therefore, any use cases that cannot guarantee DMA is stopped before unmap is + * vulnerable to this defect. In other words, any dTLB invalidation initiated not + * under the control of the trusted/privileged host device driver must use this + * quirk. + * 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 use this quirk. + * The dTLB invalidation after PASID cache flush does not need this quirk. + * + * As a reminder, #6 will *NEED* this quirk as we enable nested translation. + */ +void quirk_extra_dev_tlb_flush(struct device_domain_info *info, +			       unsigned long address, unsigned long mask, +			       u32 pasid, u16 qdep) +{ +	u16 sid; + +	if (likely(!info->dtlb_extra_inval)) +		return; + +	sid = PCI_DEVID(info->bus, info->devfn); +	if (pasid == PASID_RID2PASID) { +		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid, +				   qdep, address, mask); +	} else { +		qi_flush_dev_iotlb_pasid(info->iommu, sid, info->pfsid, +					 pasid, qdep, address, mask); +	} +} diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index 92023dff9513..db9df7c3790c 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -623,6 +623,7 @@ struct device_domain_info {  	u8 pri_enabled:1;  	u8 ats_supported:1;  	u8 ats_enabled:1; +	u8 dtlb_extra_inval:1;	/* Quirk for devices need extra flush */  	u8 ats_qdep;  	struct device *dev; /* it's NULL for PCIe-to-PCI bridge */  	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,  void qi_flush_dev_iotlb_pasid(struct intel_iommu *iommu, u16 sid, u16 pfsid,  			      u32 pasid, u16 qdep, u64 addr,  			      unsigned int size_order); +void quirk_extra_dev_tlb_flush(struct device_domain_info *info, +			       unsigned long address, unsigned long pages, +			       u32 pasid, u16 qdep);  void qi_flush_pasid_cache(struct intel_iommu *iommu, u16 did, u64 granu,  			  u32 pasid); diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 7d08eb034f2d..03b25358946c 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -184,10 +184,13 @@ static void __flush_svm_range_dev(struct intel_svm *svm,  		return;  	qi_flush_piotlb(sdev->iommu, sdev->did, svm->pasid, address, pages, ih); -	if (info->ats_enabled) +	if (info->ats_enabled) {  		qi_flush_dev_iotlb_pasid(sdev->iommu, sdev->sid, info->pfsid,  					 svm->pasid, sdev->qdep, address,  					 order_base_2(pages)); +		quirk_extra_dev_tlb_flush(info, address, order_base_2(pages), +					  svm->pasid, sdev->qdep); +	}  }  static void intel_flush_svm_range_dev(struct intel_svm *svm, @@ -745,12 +748,16 @@ bad_req:  		 * If prq is to be handled outside iommu driver via receiver of  		 * the fault notifiers, we skip the page response here.  		 */ -		if (!pdev || intel_svm_prq_report(iommu, &pdev->dev, req)) -			handle_bad_prq_event(iommu, req, QI_RESP_INVALID); +		if (!pdev) +			goto bad_req; -		trace_prq_report(iommu, &pdev->dev, req->qw_0, req->qw_1, -				 req->priv_data[0], req->priv_data[1], -				 iommu->prq_seq_number++); +		if (intel_svm_prq_report(iommu, &pdev->dev, req)) +			handle_bad_prq_event(iommu, req, QI_RESP_INVALID); +		else +			trace_prq_report(iommu, &pdev->dev, req->qw_0, req->qw_1, +					 req->priv_data[0], req->priv_data[1], +					 iommu->prq_seq_number++); +		pci_dev_put(pdev);  prq_advance:  		head = (head + sizeof(*req)) & PRQ_RING_MASK;  	} | 
