Skip to content

Commit

Permalink
iommu: Pass domain to remove_dev_pasid() op
Browse files Browse the repository at this point in the history
Existing remove_dev_pasid() callbacks of underlying iommu drivers gets
the attached domain from the group->pasid_array. However, the domains
stored in group->pasid_array are not always correct. For example, in the
error handling of the set_dev_pasid() path, remove_dev_pasid() callbacks
would get a wrong domain. This is because of

The set_dev_pasid path updates group->pasid_array before calling into
set_dev_pasid() callbacks. So remove_dev_pasid() callbacks in the
set_dev_pasdid path may get an incorrect domain for a given device. To
avoid this, pass domain to remove_dev_pasid() is more reliable.

Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
  • Loading branch information
yiliu1765 committed Mar 21, 2024
1 parent bb83270 commit bd270b7
Show file tree
Hide file tree
Showing 4 changed files with 12 additions and 20 deletions.
9 changes: 2 additions & 7 deletions drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -3044,14 +3044,9 @@ static int arm_smmu_def_domain_type(struct device *dev)
return 0;
}

static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
struct iommu_domain *domain)
{
struct iommu_domain *domain;

domain = iommu_get_domain_for_dev_pasid(dev, pasid, IOMMU_DOMAIN_SVA);
if (WARN_ON(IS_ERR(domain)) || !domain)
return;

arm_smmu_sva_remove_dev_pasid(domain, dev, pasid);
}

Expand Down
11 changes: 3 additions & 8 deletions drivers/iommu/intel/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4707,19 +4707,15 @@ static int intel_iommu_iotlb_sync_map(struct iommu_domain *domain,
return 0;
}

static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
struct iommu_domain *domain)
{
struct device_domain_info *info = dev_iommu_priv_get(dev);
struct dmar_domain *dmar_domain = to_dmar_domain(domain);
struct dev_pasid_info *curr, *dev_pasid = NULL;
struct intel_iommu *iommu = info->iommu;
struct dmar_domain *dmar_domain;
struct iommu_domain *domain;
unsigned long flags;

domain = iommu_get_domain_for_dev_pasid(dev, pasid, 0);
if (WARN_ON_ONCE(!domain))
goto out_tear_down;

/*
* The SVA implementation needs to handle its own stuffs like the mm
* notification. Before consolidating that code into iommu core, let
Expand All @@ -4730,7 +4726,6 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
goto out_tear_down;
}

dmar_domain = to_dmar_domain(domain);
spin_lock_irqsave(&dmar_domain->lock, flags);
list_for_each_entry(curr, &dmar_domain->dev_pasids, link_domain) {
if (curr->dev == dev && curr->pasid == pasid) {
Expand Down
9 changes: 5 additions & 4 deletions drivers/iommu/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3323,20 +3323,21 @@ static int __iommu_set_group_pasid(struct iommu_domain *domain,
if (device == last_gdev)
break;
dev_iommu_ops(device->dev)->remove_dev_pasid(device->dev,
pasid);
pasid, domain);
}
return ret;
}

static void __iommu_remove_group_pasid(struct iommu_group *group,
ioasid_t pasid)
ioasid_t pasid,
struct iommu_domain *domain)
{
struct group_device *device;
const struct iommu_ops *ops;

for_each_group_device(group, device) {
ops = dev_iommu_ops(device->dev);
ops->remove_dev_pasid(device->dev, pasid);
ops->remove_dev_pasid(device->dev, pasid, domain);
}
}

Expand Down Expand Up @@ -3397,7 +3398,7 @@ void iommu_detach_device_pasid(struct iommu_domain *domain, struct device *dev,
struct iommu_group *group = dev->iommu_group;

mutex_lock(&group->mutex);
__iommu_remove_group_pasid(group, pasid);
__iommu_remove_group_pasid(group, pasid, domain);
WARN_ON(xa_erase(&group->pasid_array, pasid) != domain);
mutex_unlock(&group->mutex);
}
Expand Down
3 changes: 2 additions & 1 deletion include/linux/iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,8 @@ struct iommu_ops {
struct iommu_page_response *msg);

int (*def_domain_type)(struct device *dev);
void (*remove_dev_pasid)(struct device *dev, ioasid_t pasid);
void (*remove_dev_pasid)(struct device *dev, ioasid_t pasid,
struct iommu_domain *domain);

const struct iommu_domain_ops *default_domain_ops;
unsigned long pgsize_bitmap;
Expand Down

0 comments on commit bd270b7

Please sign in to comment.