Commit 13a75018 authored by Nicolin Chen's avatar Nicolin Chen Committed by Jason Gunthorpe
Browse files

iommufd: Allow pt_id to carry viommu_id for IOMMU_HWPT_ALLOC

Now a vIOMMU holds a shareable nesting parent HWPT. So, it can act like
that nesting parent HWPT to allocate a nested HWPT.

Support that in the IOMMU_HWPT_ALLOC ioctl handler, and update its kdoc.

Also, add an iommufd_viommu_alloc_hwpt_nested helper to allocate a nested
HWPT for a vIOMMU object. Since a vIOMMU object holds the parent hwpt's
refcount already, increase the refcount of the vIOMMU only.

Link: https://patch.msgid.link/r/a0f24f32bfada8b448d17587adcaedeeb50a67ed.1730836219.git.nicolinc@nvidia.com


Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Signed-off-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 69d2689e
Loading
Loading
Loading
Loading
+72 −1
Original line number Diff line number Diff line
@@ -57,6 +57,9 @@ void iommufd_hwpt_nested_destroy(struct iommufd_object *obj)
		container_of(obj, struct iommufd_hwpt_nested, common.obj);

	__iommufd_hwpt_destroy(&hwpt_nested->common);
	if (hwpt_nested->viommu)
		refcount_dec(&hwpt_nested->viommu->obj.users);
	else
		refcount_dec(&hwpt_nested->parent->common.obj.users);
}

@@ -260,6 +263,58 @@ iommufd_hwpt_nested_alloc(struct iommufd_ctx *ictx,
	return ERR_PTR(rc);
}

/**
 * iommufd_viommu_alloc_hwpt_nested() - Get a hwpt_nested for a vIOMMU
 * @viommu: vIOMMU ojbect to associate the hwpt_nested/domain with
 * @flags: Flags from userspace
 * @user_data: user_data pointer. Must be valid
 *
 * Allocate a new IOMMU_DOMAIN_NESTED for a vIOMMU and return it as a NESTED
 * hw_pagetable.
 */
static struct iommufd_hwpt_nested *
iommufd_viommu_alloc_hwpt_nested(struct iommufd_viommu *viommu, u32 flags,
				 const struct iommu_user_data *user_data)
{
	struct iommufd_hwpt_nested *hwpt_nested;
	struct iommufd_hw_pagetable *hwpt;
	int rc;

	if (!user_data->len)
		return ERR_PTR(-EOPNOTSUPP);
	if (!viommu->ops || !viommu->ops->alloc_domain_nested)
		return ERR_PTR(-EOPNOTSUPP);

	hwpt_nested = __iommufd_object_alloc(
		viommu->ictx, hwpt_nested, IOMMUFD_OBJ_HWPT_NESTED, common.obj);
	if (IS_ERR(hwpt_nested))
		return ERR_CAST(hwpt_nested);
	hwpt = &hwpt_nested->common;

	hwpt_nested->viommu = viommu;
	refcount_inc(&viommu->obj.users);
	hwpt_nested->parent = viommu->hwpt;

	hwpt->domain =
		viommu->ops->alloc_domain_nested(viommu, flags, user_data);
	if (IS_ERR(hwpt->domain)) {
		rc = PTR_ERR(hwpt->domain);
		hwpt->domain = NULL;
		goto out_abort;
	}
	hwpt->domain->owner = viommu->iommu_dev->ops;

	if (WARN_ON_ONCE(hwpt->domain->type != IOMMU_DOMAIN_NESTED)) {
		rc = -EINVAL;
		goto out_abort;
	}
	return hwpt_nested;

out_abort:
	iommufd_object_abort_and_destroy(viommu->ictx, &hwpt->obj);
	return ERR_PTR(rc);
}

int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
{
	struct iommu_hwpt_alloc *cmd = ucmd->cmd;
@@ -316,6 +371,22 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
			goto out_unlock;
		}
		hwpt = &hwpt_nested->common;
	} else if (pt_obj->type == IOMMUFD_OBJ_VIOMMU) {
		struct iommufd_hwpt_nested *hwpt_nested;
		struct iommufd_viommu *viommu;

		viommu = container_of(pt_obj, struct iommufd_viommu, obj);
		if (viommu->iommu_dev != __iommu_get_iommu_dev(idev->dev)) {
			rc = -EINVAL;
			goto out_unlock;
		}
		hwpt_nested = iommufd_viommu_alloc_hwpt_nested(
			viommu, cmd->flags, &user_data);
		if (IS_ERR(hwpt_nested)) {
			rc = PTR_ERR(hwpt_nested);
			goto out_unlock;
		}
		hwpt = &hwpt_nested->common;
	} else {
		rc = -EINVAL;
		goto out_put_pt;
+1 −0
Original line number Diff line number Diff line
@@ -290,6 +290,7 @@ struct iommufd_hwpt_paging {
struct iommufd_hwpt_nested {
	struct iommufd_hw_pagetable common;
	struct iommufd_hwpt_paging *parent;
	struct iommufd_viommu *viommu;
};

static inline bool hwpt_is_paging(struct iommufd_hw_pagetable *hwpt)
+8 −6
Original line number Diff line number Diff line
@@ -435,7 +435,7 @@ enum iommu_hwpt_data_type {
 * @size: sizeof(struct iommu_hwpt_alloc)
 * @flags: Combination of enum iommufd_hwpt_alloc_flags
 * @dev_id: The device to allocate this HWPT for
 * @pt_id: The IOAS or HWPT to connect this HWPT to
 * @pt_id: The IOAS or HWPT or vIOMMU to connect this HWPT to
 * @out_hwpt_id: The ID of the new HWPT
 * @__reserved: Must be 0
 * @data_type: One of enum iommu_hwpt_data_type
@@ -454,11 +454,13 @@ enum iommu_hwpt_data_type {
 * IOMMU_HWPT_DATA_NONE. The HWPT can be allocated as a parent HWPT for a
 * nesting configuration by passing IOMMU_HWPT_ALLOC_NEST_PARENT via @flags.
 *
 * A user-managed nested HWPT will be created from a given parent HWPT via
 * @pt_id, in which the parent HWPT must be allocated previously via the
 * same ioctl from a given IOAS (@pt_id). In this case, the @data_type
 * must be set to a pre-defined type corresponding to an I/O page table
 * type supported by the underlying IOMMU hardware.
 * A user-managed nested HWPT will be created from a given vIOMMU (wrapping a
 * parent HWPT) or a parent HWPT via @pt_id, in which the parent HWPT must be
 * allocated previously via the same ioctl from a given IOAS (@pt_id). In this
 * case, the @data_type must be set to a pre-defined type corresponding to an
 * I/O page table type supported by the underlying IOMMU hardware. The device
 * via @dev_id and the vIOMMU via @pt_id must be associated to the same IOMMU
 * instance.
 *
 * If the @data_type is set to IOMMU_HWPT_DATA_NONE, @data_len and
 * @data_uptr should be zero. Otherwise, both @data_len and @data_uptr