Skip to content

Commit 2f26e0a

Browse files
David WoodhouseDavid Woodhouse
authored andcommitted
iommu/vt-d: Add basic SVM PASID support
This provides basic PASID support for endpoint devices, tested with a version of the i915 driver. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
1 parent b16d0cb commit 2f26e0a

File tree

6 files changed

+548
-5
lines changed

6 files changed

+548
-5
lines changed

drivers/iommu/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ config INTEL_IOMMU_SVM
139139
bool "Support for Shared Virtual Memory with Intel IOMMU"
140140
depends on INTEL_IOMMU && X86
141141
select PCI_PASID
142+
select MMU_NOTIFIER
142143
help
143144
Shared Virtual Memory (SVM) provides a facility for devices
144145
to access DMA resources through process address space by

drivers/iommu/intel-iommu.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4929,6 +4929,110 @@ static void intel_iommu_remove_device(struct device *dev)
49294929
iommu_device_unlink(iommu->iommu_dev, dev);
49304930
}
49314931

4932+
#ifdef CONFIG_INTEL_IOMMU_SVM
4933+
int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev)
4934+
{
4935+
struct device_domain_info *info;
4936+
struct context_entry *context;
4937+
struct dmar_domain *domain;
4938+
unsigned long flags;
4939+
u64 ctx_lo;
4940+
int ret;
4941+
4942+
domain = get_valid_domain_for_dev(sdev->dev);
4943+
if (!domain)
4944+
return -EINVAL;
4945+
4946+
spin_lock_irqsave(&device_domain_lock, flags);
4947+
spin_lock(&iommu->lock);
4948+
4949+
ret = -EINVAL;
4950+
info = sdev->dev->archdata.iommu;
4951+
if (!info || !info->pasid_supported)
4952+
goto out;
4953+
4954+
context = iommu_context_addr(iommu, info->bus, info->devfn, 0);
4955+
if (WARN_ON(!context))
4956+
goto out;
4957+
4958+
ctx_lo = context[0].lo;
4959+
4960+
sdev->did = domain->iommu_did[iommu->seq_id];
4961+
sdev->sid = PCI_DEVID(info->bus, info->devfn);
4962+
4963+
if (!(ctx_lo & CONTEXT_PASIDE)) {
4964+
context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table);
4965+
context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | ecap_pss(iommu->ecap);
4966+
wmb();
4967+
/* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both
4968+
* extended to permit requests-with-PASID if the PASIDE bit
4969+
* is set. which makes sense. For CONTEXT_TT_PASS_THROUGH,
4970+
* however, the PASIDE bit is ignored and requests-with-PASID
4971+
* are unconditionally blocked. Which makes less sense.
4972+
* So convert from CONTEXT_TT_PASS_THROUGH to one of the new
4973+
* "guest mode" translation types depending on whether ATS
4974+
* is available or not. Annoyingly, we can't use the new
4975+
* modes *unless* PASIDE is set. */
4976+
if ((ctx_lo & CONTEXT_TT_MASK) == (CONTEXT_TT_PASS_THROUGH << 2)) {
4977+
ctx_lo &= ~CONTEXT_TT_MASK;
4978+
if (info->ats_supported)
4979+
ctx_lo |= CONTEXT_TT_PT_PASID_DEV_IOTLB << 2;
4980+
else
4981+
ctx_lo |= CONTEXT_TT_PT_PASID << 2;
4982+
}
4983+
ctx_lo |= CONTEXT_PASIDE;
4984+
context[0].lo = ctx_lo;
4985+
wmb();
4986+
iommu->flush.flush_context(iommu, sdev->did, sdev->sid,
4987+
DMA_CCMD_MASK_NOBIT,
4988+
DMA_CCMD_DEVICE_INVL);
4989+
}
4990+
4991+
/* Enable PASID support in the device, if it wasn't already */
4992+
if (!info->pasid_enabled)
4993+
iommu_enable_dev_iotlb(info);
4994+
4995+
if (info->ats_enabled) {
4996+
sdev->dev_iotlb = 1;
4997+
sdev->qdep = info->ats_qdep;
4998+
if (sdev->qdep >= QI_DEV_EIOTLB_MAX_INVS)
4999+
sdev->qdep = 0;
5000+
}
5001+
ret = 0;
5002+
5003+
out:
5004+
spin_unlock(&iommu->lock);
5005+
spin_unlock_irqrestore(&device_domain_lock, flags);
5006+
5007+
return ret;
5008+
}
5009+
5010+
struct intel_iommu *intel_svm_device_to_iommu(struct device *dev)
5011+
{
5012+
struct intel_iommu *iommu;
5013+
u8 bus, devfn;
5014+
5015+
if (iommu_dummy(dev)) {
5016+
dev_warn(dev,
5017+
"No IOMMU translation for device; cannot enable SVM\n");
5018+
return NULL;
5019+
}
5020+
5021+
iommu = device_to_iommu(dev, &bus, &devfn);
5022+
if ((!iommu)) {
5023+
dev_dbg(dev, "No IOMMU for device; cannot enable SVM\n");
5024+
return NULL;
5025+
}
5026+
5027+
if (!iommu->pasid_table) {
5028+
dev_dbg(dev, "PASID not enabled on IOMMU; cannot enable SVM\n");
5029+
return NULL;
5030+
}
5031+
5032+
return iommu;
5033+
}
5034+
#endif /* CONFIG_INTEL_IOMMU_SVM */
5035+
49325036
static const struct iommu_ops intel_iommu_ops = {
49335037
.capable = intel_iommu_capable,
49345038
.domain_alloc = intel_iommu_domain_alloc,

0 commit comments

Comments
 (0)