Commit 03c9b102 authored by Yi Liu's avatar Yi Liu Committed by Jason Gunthorpe
Browse files

iommufd: Pass @pasid through the device attach/replace path

Most of the core logic before conducting the actual device attach/
replace operation can be shared with pasid attach/replace. So pass
@pasid through the device attach/replace helpers to prepare adding
pasid attach/replace.

So far the @pasid should only be IOMMU_NO_PASID. No functional change.

Link: https://patch.msgid.link/r/20250321171940.7213-4-yi.l.liu@intel.com


Signed-off-by: default avatarKevin Tian <kevin.tian@intel.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Reviewed-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Reviewed-by: default avatarLu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: default avatarYi Liu <yi.l.liu@intel.com>
Tested-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 8a9e1e77
Loading
Loading
Loading
Loading
+41 −29
Original line number Diff line number Diff line
@@ -368,7 +368,8 @@ static bool iommufd_device_is_attached(struct iommufd_device *idev)
}

static int iommufd_hwpt_attach_device(struct iommufd_hw_pagetable *hwpt,
				      struct iommufd_device *idev)
				      struct iommufd_device *idev,
				      ioasid_t pasid)
{
	struct iommufd_attach_handle *handle;
	int rc;
@@ -386,6 +387,7 @@ static int iommufd_hwpt_attach_device(struct iommufd_hw_pagetable *hwpt,
	}

	handle->idev = idev;
	WARN_ON(pasid != IOMMU_NO_PASID);
	rc = iommu_attach_group_handle(hwpt->domain, idev->igroup->group,
				       &handle->handle);
	if (rc)
@@ -402,25 +404,28 @@ static int iommufd_hwpt_attach_device(struct iommufd_hw_pagetable *hwpt,
}

static struct iommufd_attach_handle *
iommufd_device_get_attach_handle(struct iommufd_device *idev)
iommufd_device_get_attach_handle(struct iommufd_device *idev, ioasid_t pasid)
{
	struct iommu_attach_handle *handle;

	lockdep_assert_held(&idev->igroup->lock);

	handle =
		iommu_attach_handle_get(idev->igroup->group, IOMMU_NO_PASID, 0);
		iommu_attach_handle_get(idev->igroup->group, pasid, 0);
	if (IS_ERR(handle))
		return NULL;
	return to_iommufd_handle(handle);
}

static void iommufd_hwpt_detach_device(struct iommufd_hw_pagetable *hwpt,
				       struct iommufd_device *idev)
				       struct iommufd_device *idev,
				       ioasid_t pasid)
{
	struct iommufd_attach_handle *handle;

	handle = iommufd_device_get_attach_handle(idev);
	WARN_ON(pasid != IOMMU_NO_PASID);

	handle = iommufd_device_get_attach_handle(idev, pasid);
	iommu_detach_group_handle(hwpt->domain, idev->igroup->group);
	if (hwpt->fault) {
		iommufd_auto_response_faults(hwpt, handle);
@@ -430,13 +435,17 @@ static void iommufd_hwpt_detach_device(struct iommufd_hw_pagetable *hwpt,
}

static int iommufd_hwpt_replace_device(struct iommufd_device *idev,
				       ioasid_t pasid,
				       struct iommufd_hw_pagetable *hwpt,
				       struct iommufd_hw_pagetable *old)
{
	struct iommufd_attach_handle *handle, *old_handle =
		iommufd_device_get_attach_handle(idev);
	struct iommufd_attach_handle *handle, *old_handle;
	int rc;

	WARN_ON(pasid != IOMMU_NO_PASID);

	old_handle = iommufd_device_get_attach_handle(idev, pasid);

	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
	if (!handle)
		return -ENOMEM;
@@ -471,7 +480,7 @@ static int iommufd_hwpt_replace_device(struct iommufd_device *idev,
}

int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
				struct iommufd_device *idev)
				struct iommufd_device *idev, ioasid_t pasid)
{
	struct iommufd_hwpt_paging *hwpt_paging = find_hwpt_paging(hwpt);
	int rc;
@@ -497,7 +506,7 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
	 * attachment.
	 */
	if (list_empty(&idev->igroup->device_list)) {
		rc = iommufd_hwpt_attach_device(hwpt, idev);
		rc = iommufd_hwpt_attach_device(hwpt, idev, pasid);
		if (rc)
			goto err_unresv;
		idev->igroup->hwpt = hwpt;
@@ -515,7 +524,7 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
}

struct iommufd_hw_pagetable *
iommufd_hw_pagetable_detach(struct iommufd_device *idev)
iommufd_hw_pagetable_detach(struct iommufd_device *idev, ioasid_t pasid)
{
	struct iommufd_hw_pagetable *hwpt = idev->igroup->hwpt;
	struct iommufd_hwpt_paging *hwpt_paging = find_hwpt_paging(hwpt);
@@ -523,7 +532,7 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev)
	mutex_lock(&idev->igroup->lock);
	list_del(&idev->group_item);
	if (list_empty(&idev->igroup->device_list)) {
		iommufd_hwpt_detach_device(hwpt, idev);
		iommufd_hwpt_detach_device(hwpt, idev, pasid);
		idev->igroup->hwpt = NULL;
	}
	if (hwpt_paging)
@@ -535,12 +544,12 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev)
}

static struct iommufd_hw_pagetable *
iommufd_device_do_attach(struct iommufd_device *idev,
iommufd_device_do_attach(struct iommufd_device *idev, ioasid_t pasid,
			 struct iommufd_hw_pagetable *hwpt)
{
	int rc;

	rc = iommufd_hw_pagetable_attach(hwpt, idev);
	rc = iommufd_hw_pagetable_attach(hwpt, idev, pasid);
	if (rc)
		return ERR_PTR(rc);
	return NULL;
@@ -589,7 +598,7 @@ iommufd_group_do_replace_reserved_iova(struct iommufd_group *igroup,
}

static struct iommufd_hw_pagetable *
iommufd_device_do_replace(struct iommufd_device *idev,
iommufd_device_do_replace(struct iommufd_device *idev, ioasid_t pasid,
			  struct iommufd_hw_pagetable *hwpt)
{
	struct iommufd_hwpt_paging *hwpt_paging = find_hwpt_paging(hwpt);
@@ -623,7 +632,7 @@ iommufd_device_do_replace(struct iommufd_device *idev,
			goto err_unlock;
	}

	rc = iommufd_hwpt_replace_device(idev, hwpt, old_hwpt);
	rc = iommufd_hwpt_replace_device(idev, pasid, hwpt, old_hwpt);
	if (rc)
		goto err_unresv;

@@ -656,7 +665,8 @@ iommufd_device_do_replace(struct iommufd_device *idev,
}

typedef struct iommufd_hw_pagetable *(*attach_fn)(
	struct iommufd_device *idev, struct iommufd_hw_pagetable *hwpt);
	struct iommufd_device *idev, ioasid_t pasid,
	struct iommufd_hw_pagetable *hwpt);

/*
 * When automatically managing the domains we search for a compatible domain in
@@ -664,7 +674,7 @@ typedef struct iommufd_hw_pagetable *(*attach_fn)(
 * Automatic domain selection will never pick a manually created domain.
 */
static struct iommufd_hw_pagetable *
iommufd_device_auto_get_domain(struct iommufd_device *idev,
iommufd_device_auto_get_domain(struct iommufd_device *idev, ioasid_t pasid,
			       struct iommufd_ioas *ioas, u32 *pt_id,
			       attach_fn do_attach)
{
@@ -693,7 +703,7 @@ iommufd_device_auto_get_domain(struct iommufd_device *idev,
		hwpt = &hwpt_paging->common;
		if (!iommufd_lock_obj(&hwpt->obj))
			continue;
		destroy_hwpt = (*do_attach)(idev, hwpt);
		destroy_hwpt = (*do_attach)(idev, pasid, hwpt);
		if (IS_ERR(destroy_hwpt)) {
			iommufd_put_object(idev->ictx, &hwpt->obj);
			/*
@@ -711,8 +721,8 @@ iommufd_device_auto_get_domain(struct iommufd_device *idev,
		goto out_unlock;
	}

	hwpt_paging = iommufd_hwpt_paging_alloc(idev->ictx, ioas, idev, 0,
						immediate_attach, NULL);
	hwpt_paging = iommufd_hwpt_paging_alloc(idev->ictx, ioas, idev, pasid,
						0, immediate_attach, NULL);
	if (IS_ERR(hwpt_paging)) {
		destroy_hwpt = ERR_CAST(hwpt_paging);
		goto out_unlock;
@@ -720,7 +730,7 @@ iommufd_device_auto_get_domain(struct iommufd_device *idev,
	hwpt = &hwpt_paging->common;

	if (!immediate_attach) {
		destroy_hwpt = (*do_attach)(idev, hwpt);
		destroy_hwpt = (*do_attach)(idev, pasid, hwpt);
		if (IS_ERR(destroy_hwpt))
			goto out_abort;
	} else {
@@ -741,8 +751,9 @@ iommufd_device_auto_get_domain(struct iommufd_device *idev,
	return destroy_hwpt;
}

static int iommufd_device_change_pt(struct iommufd_device *idev, u32 *pt_id,
				    attach_fn do_attach)
static int iommufd_device_change_pt(struct iommufd_device *idev,
				    ioasid_t pasid,
				    u32 *pt_id, attach_fn do_attach)
{
	struct iommufd_hw_pagetable *destroy_hwpt;
	struct iommufd_object *pt_obj;
@@ -757,7 +768,7 @@ static int iommufd_device_change_pt(struct iommufd_device *idev, u32 *pt_id,
		struct iommufd_hw_pagetable *hwpt =
			container_of(pt_obj, struct iommufd_hw_pagetable, obj);

		destroy_hwpt = (*do_attach)(idev, hwpt);
		destroy_hwpt = (*do_attach)(idev, pasid, hwpt);
		if (IS_ERR(destroy_hwpt))
			goto out_put_pt_obj;
		break;
@@ -766,8 +777,8 @@ static int iommufd_device_change_pt(struct iommufd_device *idev, u32 *pt_id,
		struct iommufd_ioas *ioas =
			container_of(pt_obj, struct iommufd_ioas, obj);

		destroy_hwpt = iommufd_device_auto_get_domain(idev, ioas, pt_id,
							      do_attach);
		destroy_hwpt = iommufd_device_auto_get_domain(idev, pasid, ioas,
							      pt_id, do_attach);
		if (IS_ERR(destroy_hwpt))
			goto out_put_pt_obj;
		break;
@@ -804,7 +815,8 @@ int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id)
{
	int rc;

	rc = iommufd_device_change_pt(idev, pt_id, &iommufd_device_do_attach);
	rc = iommufd_device_change_pt(idev, IOMMU_NO_PASID, pt_id,
				      &iommufd_device_do_attach);
	if (rc)
		return rc;

@@ -834,7 +846,7 @@ EXPORT_SYMBOL_NS_GPL(iommufd_device_attach, "IOMMUFD");
 */
int iommufd_device_replace(struct iommufd_device *idev, u32 *pt_id)
{
	return iommufd_device_change_pt(idev, pt_id,
	return iommufd_device_change_pt(idev, IOMMU_NO_PASID, pt_id,
					&iommufd_device_do_replace);
}
EXPORT_SYMBOL_NS_GPL(iommufd_device_replace, "IOMMUFD");
@@ -850,7 +862,7 @@ void iommufd_device_detach(struct iommufd_device *idev)
{
	struct iommufd_hw_pagetable *hwpt;

	hwpt = iommufd_hw_pagetable_detach(idev);
	hwpt = iommufd_hw_pagetable_detach(idev, IOMMU_NO_PASID);
	iommufd_hw_pagetable_put(idev->ictx, hwpt);
	refcount_dec(&idev->obj.users);
}
+7 −6
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ iommufd_hwpt_paging_enforce_cc(struct iommufd_hwpt_paging *hwpt_paging)
 * @ictx: iommufd context
 * @ioas: IOAS to associate the domain with
 * @idev: Device to get an iommu_domain for
 * @pasid: PASID to get an iommu_domain for
 * @flags: Flags from userspace
 * @immediate_attach: True if idev should be attached to the hwpt
 * @user_data: The user provided driver specific data describing the domain to
@@ -105,8 +106,8 @@ iommufd_hwpt_paging_enforce_cc(struct iommufd_hwpt_paging *hwpt_paging)
 */
struct iommufd_hwpt_paging *
iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
			  struct iommufd_device *idev, u32 flags,
			  bool immediate_attach,
			  struct iommufd_device *idev, ioasid_t pasid,
			  u32 flags, bool immediate_attach,
			  const struct iommu_user_data *user_data)
{
	const u32 valid_flags = IOMMU_HWPT_ALLOC_NEST_PARENT |
@@ -189,7 +190,7 @@ iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
	 * sequence. Once those drivers are fixed this should be removed.
	 */
	if (immediate_attach) {
		rc = iommufd_hw_pagetable_attach(hwpt, idev);
		rc = iommufd_hw_pagetable_attach(hwpt, idev, pasid);
		if (rc)
			goto out_abort;
	}
@@ -202,7 +203,7 @@ iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,

out_detach:
	if (immediate_attach)
		iommufd_hw_pagetable_detach(idev);
		iommufd_hw_pagetable_detach(idev, pasid);
out_abort:
	iommufd_object_abort_and_destroy(ictx, &hwpt->obj);
	return ERR_PTR(rc);
@@ -364,8 +365,8 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
		ioas = container_of(pt_obj, struct iommufd_ioas, obj);
		mutex_lock(&ioas->mutex);
		hwpt_paging = iommufd_hwpt_paging_alloc(
			ucmd->ictx, ioas, idev, cmd->flags, false,
			user_data.len ? &user_data : NULL);
			ucmd->ictx, ioas, idev, IOMMU_NO_PASID, cmd->flags,
			false, user_data.len ? &user_data : NULL);
		if (IS_ERR(hwpt_paging)) {
			rc = PTR_ERR(hwpt_paging);
			goto out_unlock;
+4 −4
Original line number Diff line number Diff line
@@ -369,13 +369,13 @@ int iommufd_hwpt_get_dirty_bitmap(struct iommufd_ucmd *ucmd);

struct iommufd_hwpt_paging *
iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
			  struct iommufd_device *idev, u32 flags,
			  bool immediate_attach,
			  struct iommufd_device *idev, ioasid_t pasid,
			  u32 flags, bool immediate_attach,
			  const struct iommu_user_data *user_data);
int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
				struct iommufd_device *idev);
				struct iommufd_device *idev, ioasid_t pasid);
struct iommufd_hw_pagetable *
iommufd_hw_pagetable_detach(struct iommufd_device *idev);
iommufd_hw_pagetable_detach(struct iommufd_device *idev, ioasid_t pasid);
void iommufd_hwpt_paging_destroy(struct iommufd_object *obj);
void iommufd_hwpt_paging_abort(struct iommufd_object *obj);
void iommufd_hwpt_nested_destroy(struct iommufd_object *obj);