Commit 3e7f57d1 authored by Lu Baolu's avatar Lu Baolu Committed by Will Deacon
Browse files

iommu: Remove sva handle list



The struct sva_iommu represents an association between an SVA domain and
a PASID of a device. It's stored in the iommu group's pasid array and also
tracked by a list in the per-mm data structure. Removes duplicate tracking
of sva_iommu by eliminating the list.

Signed-off-by: default avatarLu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20240702063444.105814-3-baolu.lu@linux.intel.com


Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 14678219
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -28,4 +28,7 @@ void iommu_device_unregister_bus(struct iommu_device *iommu,
				 const struct bus_type *bus,
				 struct notifier_block *nb);

struct iommu_attach_handle *iommu_attach_handle_get(struct iommu_group *group,
						    ioasid_t pasid,
						    unsigned int type);
#endif /* __LINUX_IOMMU_PRIV_H */
+20 −10
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@ static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct de
	}
	iommu_mm->pasid = pasid;
	INIT_LIST_HEAD(&iommu_mm->sva_domains);
	INIT_LIST_HEAD(&iommu_mm->sva_handles);
	/*
	 * Make sure the write to mm->iommu_mm is not reordered in front of
	 * initialization to iommu_mm fields. If it does, readers may see a
@@ -69,11 +68,16 @@ static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct de
 */
struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
{
	struct iommu_group *group = dev->iommu_group;
	struct iommu_attach_handle *attach_handle;
	struct iommu_mm_data *iommu_mm;
	struct iommu_domain *domain;
	struct iommu_sva *handle;
	int ret;

	if (!group)
		return ERR_PTR(-ENODEV);

	mutex_lock(&iommu_sva_lock);

	/* Allocate mm->pasid if necessary. */
@@ -83,12 +87,22 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
		goto out_unlock;
	}

	list_for_each_entry(handle, &mm->iommu_mm->sva_handles, handle_item) {
		if (handle->dev == dev) {
	/* A bond already exists, just take a reference`. */
	attach_handle = iommu_attach_handle_get(group, iommu_mm->pasid, IOMMU_DOMAIN_SVA);
	if (!IS_ERR(attach_handle)) {
		handle = container_of(attach_handle, struct iommu_sva, handle);
		if (attach_handle->domain->mm != mm) {
			ret = -EBUSY;
			goto out_unlock;
		}
		refcount_inc(&handle->users);
		mutex_unlock(&iommu_sva_lock);
		return handle;
	}

	if (PTR_ERR(attach_handle) != -ENOENT) {
		ret = PTR_ERR(attach_handle);
		goto out_unlock;
	}

	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
@@ -99,7 +113,6 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm

	/* Search for an existing domain. */
	list_for_each_entry(domain, &mm->iommu_mm->sva_domains, next) {
		handle->handle.domain = domain;
		ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid,
						&handle->handle);
		if (!ret) {
@@ -115,7 +128,6 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
		goto out_free_handle;
	}

	handle->handle.domain = domain;
	ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid,
					&handle->handle);
	if (ret)
@@ -125,7 +137,6 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm

out:
	refcount_set(&handle->users, 1);
	list_add(&handle->handle_item, &mm->iommu_mm->sva_handles);
	mutex_unlock(&iommu_sva_lock);
	handle->dev = dev;
	return handle;
@@ -159,7 +170,6 @@ void iommu_sva_unbind_device(struct iommu_sva *handle)
		mutex_unlock(&iommu_sva_lock);
		return;
	}
	list_del(&handle->handle_item);

	iommu_detach_device_pasid(domain, dev, iommu_mm->pasid);
	if (--domain->users == 0) {
+31 −0
Original line number Diff line number Diff line
@@ -3486,3 +3486,34 @@ void iommu_free_global_pasid(ioasid_t pasid)
	ida_free(&iommu_global_pasid_ida, pasid);
}
EXPORT_SYMBOL_GPL(iommu_free_global_pasid);

/**
 * iommu_attach_handle_get - Return the attach handle
 * @group: the iommu group that domain was attached to
 * @pasid: the pasid within the group
 * @type: matched domain type, 0 for any match
 *
 * Return handle or ERR_PTR(-ENOENT) on none, ERR_PTR(-EBUSY) on mismatch.
 *
 * Return the attach handle to the caller. The life cycle of an iommu attach
 * handle is from the time when the domain is attached to the time when the
 * domain is detached. Callers are required to synchronize the call of
 * iommu_attach_handle_get() with domain attachment and detachment. The attach
 * handle can only be used during its life cycle.
 */
struct iommu_attach_handle *
iommu_attach_handle_get(struct iommu_group *group, ioasid_t pasid, unsigned int type)
{
	struct iommu_attach_handle *handle;

	xa_lock(&group->pasid_array);
	handle = xa_load(&group->pasid_array, pasid);
	if (!handle)
		handle = ERR_PTR(-ENOENT);
	else if (type && handle->domain->type != type)
		handle = ERR_PTR(-EBUSY);
	xa_unlock(&group->pasid_array);

	return handle;
}
EXPORT_SYMBOL_NS_GPL(iommu_attach_handle_get, IOMMUFD_INTERNAL);
+0 −2
Original line number Diff line number Diff line
@@ -1005,14 +1005,12 @@ struct iommu_attach_handle {
struct iommu_sva {
	struct iommu_attach_handle	handle;
	struct device			*dev;
	struct list_head		handle_item;
	refcount_t			users;
};

struct iommu_mm_data {
	u32			pasid;
	struct list_head	sva_domains;
	struct list_head	sva_handles;
};

int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,