Skip to content

Commit 7d0c9da

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Add set_dev_pasid callback for dma domain
This allows the upper layers to set a domain to a PASID of a device if the PASID feature is supported by the IOMMU hardware. The typical use cases are, for example, kernel DMA with PASID and hardware assisted mediated device drivers. The attaching device and pasid information is tracked in a per-domain list and is used for IOTLB and devTLB invalidation. Signed-off-by: Lu Baolu <[email protected]> Signed-off-by: Jacob Pan <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 37f900e commit 7d0c9da

File tree

2 files changed

+106
-5
lines changed

2 files changed

+106
-5
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,7 @@ domain_lookup_dev_info(struct dmar_domain *domain,
13591359

13601360
static void domain_update_iotlb(struct dmar_domain *domain)
13611361
{
1362+
struct dev_pasid_info *dev_pasid;
13621363
struct device_domain_info *info;
13631364
bool has_iotlb_device = false;
13641365
unsigned long flags;
@@ -1370,6 +1371,14 @@ static void domain_update_iotlb(struct dmar_domain *domain)
13701371
break;
13711372
}
13721373
}
1374+
1375+
list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) {
1376+
info = dev_iommu_priv_get(dev_pasid->dev);
1377+
if (info->ats_enabled) {
1378+
has_iotlb_device = true;
1379+
break;
1380+
}
1381+
}
13731382
domain->has_iotlb_device = has_iotlb_device;
13741383
spin_unlock_irqrestore(&domain->lock, flags);
13751384
}
@@ -1455,6 +1464,7 @@ static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
14551464
static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
14561465
u64 addr, unsigned mask)
14571466
{
1467+
struct dev_pasid_info *dev_pasid;
14581468
struct device_domain_info *info;
14591469
unsigned long flags;
14601470

@@ -1464,6 +1474,19 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
14641474
spin_lock_irqsave(&domain->lock, flags);
14651475
list_for_each_entry(info, &domain->devices, link)
14661476
__iommu_flush_dev_iotlb(info, addr, mask);
1477+
1478+
list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) {
1479+
info = dev_iommu_priv_get(dev_pasid->dev);
1480+
1481+
if (!info->ats_enabled)
1482+
continue;
1483+
1484+
qi_flush_dev_iotlb_pasid(info->iommu,
1485+
PCI_DEVID(info->bus, info->devfn),
1486+
info->pfsid, dev_pasid->pasid,
1487+
info->ats_qdep, addr,
1488+
mask);
1489+
}
14671490
spin_unlock_irqrestore(&domain->lock, flags);
14681491
}
14691492

@@ -1472,9 +1495,13 @@ static void domain_flush_pasid_iotlb(struct intel_iommu *iommu,
14721495
unsigned long npages, bool ih)
14731496
{
14741497
u16 did = domain_id_iommu(domain, iommu);
1498+
struct dev_pasid_info *dev_pasid;
14751499
unsigned long flags;
14761500

14771501
spin_lock_irqsave(&domain->lock, flags);
1502+
list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain)
1503+
qi_flush_piotlb(iommu, did, dev_pasid->pasid, addr, npages, ih);
1504+
14781505
if (!list_empty(&domain->devices))
14791506
qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, npages, ih);
14801507
spin_unlock_irqrestore(&domain->lock, flags);
@@ -1739,6 +1766,7 @@ static struct dmar_domain *alloc_domain(unsigned int type)
17391766
domain->use_first_level = true;
17401767
domain->has_iotlb_device = false;
17411768
INIT_LIST_HEAD(&domain->devices);
1769+
INIT_LIST_HEAD(&domain->dev_pasids);
17421770
spin_lock_init(&domain->lock);
17431771
xa_init(&domain->iommu_array);
17441772

@@ -4726,7 +4754,10 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain,
47264754
static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
47274755
{
47284756
struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
4757+
struct dev_pasid_info *curr, *dev_pasid = NULL;
4758+
struct dmar_domain *dmar_domain;
47294759
struct iommu_domain *domain;
4760+
unsigned long flags;
47304761

47314762
domain = iommu_get_domain_for_dev_pasid(dev, pasid, 0);
47324763
if (WARN_ON_ONCE(!domain))
@@ -4742,17 +4773,79 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
47424773
goto out_tear_down;
47434774
}
47444775

4745-
/*
4746-
* Should never reach here until we add support for attaching
4747-
* non-SVA domain to a pasid.
4748-
*/
4749-
WARN_ON(1);
4776+
dmar_domain = to_dmar_domain(domain);
4777+
spin_lock_irqsave(&dmar_domain->lock, flags);
4778+
list_for_each_entry(curr, &dmar_domain->dev_pasids, link_domain) {
4779+
if (curr->dev == dev && curr->pasid == pasid) {
4780+
list_del(&curr->link_domain);
4781+
dev_pasid = curr;
4782+
break;
4783+
}
4784+
}
4785+
WARN_ON_ONCE(!dev_pasid);
4786+
spin_unlock_irqrestore(&dmar_domain->lock, flags);
47504787

4788+
domain_detach_iommu(dmar_domain, iommu);
4789+
kfree(dev_pasid);
47514790
out_tear_down:
47524791
intel_pasid_tear_down_entry(iommu, dev, pasid, false);
47534792
intel_drain_pasid_prq(dev, pasid);
47544793
}
47554794

4795+
static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
4796+
struct device *dev, ioasid_t pasid)
4797+
{
4798+
struct device_domain_info *info = dev_iommu_priv_get(dev);
4799+
struct dmar_domain *dmar_domain = to_dmar_domain(domain);
4800+
struct intel_iommu *iommu = info->iommu;
4801+
struct dev_pasid_info *dev_pasid;
4802+
unsigned long flags;
4803+
int ret;
4804+
4805+
if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
4806+
return -EOPNOTSUPP;
4807+
4808+
if (context_copied(iommu, info->bus, info->devfn))
4809+
return -EBUSY;
4810+
4811+
ret = prepare_domain_attach_device(domain, dev);
4812+
if (ret)
4813+
return ret;
4814+
4815+
dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL);
4816+
if (!dev_pasid)
4817+
return -ENOMEM;
4818+
4819+
ret = domain_attach_iommu(dmar_domain, iommu);
4820+
if (ret)
4821+
goto out_free;
4822+
4823+
if (domain_type_is_si(dmar_domain))
4824+
ret = intel_pasid_setup_pass_through(iommu, dmar_domain,
4825+
dev, pasid);
4826+
else if (dmar_domain->use_first_level)
4827+
ret = domain_setup_first_level(iommu, dmar_domain,
4828+
dev, pasid);
4829+
else
4830+
ret = intel_pasid_setup_second_level(iommu, dmar_domain,
4831+
dev, pasid);
4832+
if (ret)
4833+
goto out_detach_iommu;
4834+
4835+
dev_pasid->dev = dev;
4836+
dev_pasid->pasid = pasid;
4837+
spin_lock_irqsave(&dmar_domain->lock, flags);
4838+
list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids);
4839+
spin_unlock_irqrestore(&dmar_domain->lock, flags);
4840+
4841+
return 0;
4842+
out_detach_iommu:
4843+
domain_detach_iommu(dmar_domain, iommu);
4844+
out_free:
4845+
kfree(dev_pasid);
4846+
return ret;
4847+
}
4848+
47564849
const struct iommu_ops intel_iommu_ops = {
47574850
.capable = intel_iommu_capable,
47584851
.domain_alloc = intel_iommu_domain_alloc,
@@ -4772,6 +4865,7 @@ const struct iommu_ops intel_iommu_ops = {
47724865
#endif
47734866
.default_domain_ops = &(const struct iommu_domain_ops) {
47744867
.attach_dev = intel_iommu_attach_device,
4868+
.set_dev_pasid = intel_iommu_set_dev_pasid,
47754869
.map_pages = intel_iommu_map_pages,
47764870
.unmap_pages = intel_iommu_unmap_pages,
47774871
.iotlb_sync_map = intel_iommu_iotlb_sync_map,

drivers/iommu/intel/iommu.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ struct dmar_domain {
595595

596596
spinlock_t lock; /* Protect device tracking lists */
597597
struct list_head devices; /* all devices' list */
598+
struct list_head dev_pasids; /* all attached pasids */
598599

599600
struct dma_pte *pgd; /* virtual address */
600601
int gaw; /* max guest address width */
@@ -717,6 +718,12 @@ struct device_domain_info {
717718
struct pasid_table *pasid_table; /* pasid table */
718719
};
719720

721+
struct dev_pasid_info {
722+
struct list_head link_domain; /* link to domain siblings */
723+
struct device *dev;
724+
ioasid_t pasid;
725+
};
726+
720727
static inline void __iommu_flush_cache(
721728
struct intel_iommu *iommu, void *addr, int size)
722729
{

0 commit comments

Comments
 (0)