Skip to content

Commit

Permalink
iommu/vt-d: Track nested domains in parent
Browse files Browse the repository at this point in the history
Today the parent domain (s2_domain) is unaware of which DID's are
used by and which devices are attached to nested domains (s1_domain)
nested on it. This leads to a problem that some operations (flush
iotlb/devtlb and enable dirty tracking) on parent domain only apply to
DID's and devices directly tracked in the parent domain hence are
incomplete.

This tracks the nested domains in list in parent domain. With this,
operations on parent domain can loop the nested domains and refer to
the devices and iommu_array to ensure the operations on parent domain
take effect on all the affected devices and iommus.

Signed-off-by: Yi Liu <yi.l.liu@intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20240208082307.15759-2-yi.l.liu@intel.com
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
  • Loading branch information
yiliu1765 authored and pull[bot] committed Feb 25, 2024
1 parent 688cebb commit 33059c6
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 5 deletions.
18 changes: 14 additions & 4 deletions drivers/iommu/intel/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3883,6 +3883,7 @@ intel_iommu_domain_alloc_user(struct device *dev, u32 flags,
bool dirty_tracking = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
bool nested_parent = flags & IOMMU_HWPT_ALLOC_NEST_PARENT;
struct intel_iommu *iommu = info->iommu;
struct dmar_domain *dmar_domain;
struct iommu_domain *domain;

/* Must be NESTING domain */
Expand All @@ -3908,11 +3909,16 @@ intel_iommu_domain_alloc_user(struct device *dev, u32 flags,
if (!domain)
return ERR_PTR(-ENOMEM);

if (nested_parent)
to_dmar_domain(domain)->nested_parent = true;
dmar_domain = to_dmar_domain(domain);

if (nested_parent) {
dmar_domain->nested_parent = true;
INIT_LIST_HEAD(&dmar_domain->s1_domains);
spin_lock_init(&dmar_domain->s1_lock);
}

if (dirty_tracking) {
if (to_dmar_domain(domain)->use_first_level) {
if (dmar_domain->use_first_level) {
iommu_domain_free(domain);
return ERR_PTR(-EOPNOTSUPP);
}
Expand All @@ -3924,8 +3930,12 @@ intel_iommu_domain_alloc_user(struct device *dev, u32 flags,

static void intel_iommu_domain_free(struct iommu_domain *domain)
{
struct dmar_domain *dmar_domain = to_dmar_domain(domain);

WARN_ON(dmar_domain->nested_parent &&
!list_empty(&dmar_domain->s1_domains));
if (domain != &si_domain->domain)
domain_exit(to_dmar_domain(domain));
domain_exit(dmar_domain);
}

int prepare_domain_attach_device(struct iommu_domain *domain,
Expand Down
6 changes: 6 additions & 0 deletions drivers/iommu/intel/iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,10 @@ struct dmar_domain {
int agaw;
/* maximum mapped address */
u64 max_addr;
/* Protect the s1_domains list */
spinlock_t s1_lock;
/* Track s1_domains nested on this domain */
struct list_head s1_domains;
};

/* Nested user domain */
Expand All @@ -637,6 +641,8 @@ struct dmar_domain {
unsigned long s1_pgtbl;
/* page table attributes */
struct iommu_hwpt_vtd_s1 s1_cfg;
/* link to parent domain siblings */
struct list_head s2_link;
};
};

Expand Down
12 changes: 11 additions & 1 deletion drivers/iommu/intel/nested.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,13 @@ static int intel_nested_attach_dev(struct iommu_domain *domain,

static void intel_nested_domain_free(struct iommu_domain *domain)
{
kfree(to_dmar_domain(domain));
struct dmar_domain *dmar_domain = to_dmar_domain(domain);
struct dmar_domain *s2_domain = dmar_domain->s2_domain;

spin_lock(&s2_domain->s1_lock);
list_del(&dmar_domain->s2_link);
spin_unlock(&s2_domain->s1_lock);
kfree(dmar_domain);
}

static void nested_flush_dev_iotlb(struct dmar_domain *domain, u64 addr,
Expand Down Expand Up @@ -201,5 +207,9 @@ struct iommu_domain *intel_nested_domain_alloc(struct iommu_domain *parent,
spin_lock_init(&domain->lock);
xa_init(&domain->iommu_array);

spin_lock(&s2_domain->s1_lock);
list_add(&domain->s2_link, &s2_domain->s1_domains);
spin_unlock(&s2_domain->s1_lock);

return &domain->domain;
}

0 comments on commit 33059c6

Please sign in to comment.