Commit 58d84f43 authored by Jason Gunthorpe's avatar Jason Gunthorpe
Browse files

iommufd/device: Wrap IOMMUFD_OBJ_HWPT_PAGING-only configurations

Some of the configurations during the attach/replace() should only apply
to IOMMUFD_OBJ_HWPT_PAGING. Once IOMMUFD_OBJ_HWPT_NESTED gets introduced
in a following patch, keeping them unconditionally in the common routine
will not work.

Wrap all of those PAGING-only configurations together into helpers. Do a
hwpt_is_paging check whenever calling them or their fallback routines.

Link: https://lore.kernel.org/r/20231026043938.63898-4-yi.l.liu@intel.com


Signed-off-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarYi Liu <yi.l.liu@intel.com>
Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 9744a7ab
Loading
Loading
Loading
Loading
+81 −30
Original line number Diff line number Diff line
@@ -325,6 +325,28 @@ static int iommufd_group_setup_msi(struct iommufd_group *igroup,
	return 0;
}

static int iommufd_hwpt_paging_attach(struct iommufd_hw_pagetable *hwpt,
				      struct iommufd_device *idev)
{
	int rc;

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

	rc = iopt_table_enforce_dev_resv_regions(&hwpt->ioas->iopt, idev->dev,
						 &idev->igroup->sw_msi_start);
	if (rc)
		return rc;

	if (list_empty(&idev->igroup->device_list)) {
		rc = iommufd_group_setup_msi(idev->igroup, hwpt);
		if (rc) {
			iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
			return rc;
		}
	}
	return 0;
}

int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
				struct iommufd_device *idev)
{
@@ -337,10 +359,11 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
		goto err_unlock;
	}

	rc = iopt_table_enforce_dev_resv_regions(&hwpt->ioas->iopt, idev->dev,
						 &idev->igroup->sw_msi_start);
	if (hwpt_is_paging(hwpt)) {
		rc = iommufd_hwpt_paging_attach(hwpt, idev);
		if (rc)
			goto err_unlock;
	}

	/*
	 * Only attach to the group once for the first device that is in the
@@ -350,10 +373,6 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
	 * attachment.
	 */
	if (list_empty(&idev->igroup->device_list)) {
		rc = iommufd_group_setup_msi(idev->igroup, hwpt);
		if (rc)
			goto err_unresv;

		rc = iommu_attach_group(hwpt->domain, idev->igroup->group);
		if (rc)
			goto err_unresv;
@@ -364,6 +383,7 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
	mutex_unlock(&idev->igroup->lock);
	return 0;
err_unresv:
	if (hwpt_is_paging(hwpt))
		iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
err_unlock:
	mutex_unlock(&idev->igroup->lock);
@@ -381,6 +401,7 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev)
		iommu_detach_group(hwpt->domain, idev->igroup->group);
		idev->igroup->hwpt = NULL;
	}
	if (hwpt_is_paging(hwpt))
		iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
	mutex_unlock(&idev->igroup->lock);

@@ -400,13 +421,52 @@ iommufd_device_do_attach(struct iommufd_device *idev,
	return NULL;
}

static void
iommufd_group_remove_reserved_iova(struct iommufd_group *igroup,
				   struct iommufd_hw_pagetable *hwpt)
{
	struct iommufd_device *cur;

	lockdep_assert_held(&igroup->lock);

	list_for_each_entry(cur, &igroup->device_list, group_item)
		iopt_remove_reserved_iova(&hwpt->ioas->iopt, cur->dev);
}

static int iommufd_group_do_replace_paging(struct iommufd_group *igroup,
					   struct iommufd_hw_pagetable *hwpt)
{
	struct iommufd_hw_pagetable *old_hwpt = igroup->hwpt;
	struct iommufd_device *cur;
	int rc;

	lockdep_assert_held(&igroup->lock);

	if (!hwpt_is_paging(old_hwpt) || hwpt->ioas != old_hwpt->ioas) {
		list_for_each_entry(cur, &igroup->device_list, group_item) {
			rc = iopt_table_enforce_dev_resv_regions(
				&hwpt->ioas->iopt, cur->dev, NULL);
			if (rc)
				goto err_unresv;
		}
	}

	rc = iommufd_group_setup_msi(igroup, hwpt);
	if (rc)
		goto err_unresv;
	return 0;

err_unresv:
	iommufd_group_remove_reserved_iova(igroup, hwpt);
	return rc;
}

static struct iommufd_hw_pagetable *
iommufd_device_do_replace(struct iommufd_device *idev,
			  struct iommufd_hw_pagetable *hwpt)
{
	struct iommufd_group *igroup = idev->igroup;
	struct iommufd_hw_pagetable *old_hwpt;
	struct iommufd_device *cur;
	unsigned int num_devices;
	int rc;

@@ -422,29 +482,20 @@ iommufd_device_do_replace(struct iommufd_device *idev,
		return NULL;
	}

	old_hwpt = igroup->hwpt;
	if (hwpt->ioas != old_hwpt->ioas) {
		list_for_each_entry(cur, &igroup->device_list, group_item) {
			rc = iopt_table_enforce_dev_resv_regions(
				&hwpt->ioas->iopt, cur->dev, NULL);
	if (hwpt_is_paging(hwpt)) {
		rc = iommufd_group_do_replace_paging(igroup, hwpt);
		if (rc)
				goto err_unresv;
		}
			goto err_unlock;
	}

	rc = iommufd_group_setup_msi(idev->igroup, hwpt);
	if (rc)
		goto err_unresv;

	rc = iommu_group_replace_domain(igroup->group, hwpt->domain);
	if (rc)
		goto err_unresv;

	if (hwpt->ioas != old_hwpt->ioas) {
		list_for_each_entry(cur, &igroup->device_list, group_item)
			iopt_remove_reserved_iova(&old_hwpt->ioas->iopt,
						  cur->dev);
	}
	old_hwpt = igroup->hwpt;
	if (hwpt_is_paging(old_hwpt) &&
	    (!hwpt_is_paging(hwpt) || hwpt->ioas != old_hwpt->ioas))
		iommufd_group_remove_reserved_iova(igroup, old_hwpt);

	igroup->hwpt = hwpt;

@@ -462,8 +513,8 @@ iommufd_device_do_replace(struct iommufd_device *idev,
	/* Caller must destroy old_hwpt */
	return old_hwpt;
err_unresv:
	list_for_each_entry(cur, &igroup->device_list, group_item)
		iopt_remove_reserved_iova(&hwpt->ioas->iopt, cur->dev);
	if (hwpt_is_paging(hwpt))
		iommufd_group_remove_reserved_iova(igroup, hwpt);
err_unlock:
	mutex_unlock(&idev->igroup->lock);
	return ERR_PTR(rc);
+5 −0
Original line number Diff line number Diff line
@@ -252,6 +252,11 @@ struct iommufd_hw_pagetable {
	struct list_head hwpt_item;
};

static inline bool hwpt_is_paging(struct iommufd_hw_pagetable *hwpt)
{
	return hwpt->obj.type == IOMMUFD_OBJ_HWPT_PAGING;
}

static inline struct iommufd_hw_pagetable *
iommufd_get_hwpt(struct iommufd_ucmd *ucmd, u32 id)
{