mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-08 11:41:37 -04:00
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: Kevin Tian <kevin.tian@intel.com> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
committed by
Jason Gunthorpe
parent
69d2689e57
commit
13a750180f
@@ -57,7 +57,10 @@ void iommufd_hwpt_nested_destroy(struct iommufd_object *obj)
|
||||
container_of(obj, struct iommufd_hwpt_nested, common.obj);
|
||||
|
||||
__iommufd_hwpt_destroy(&hwpt_nested->common);
|
||||
refcount_dec(&hwpt_nested->parent->common.obj.users);
|
||||
if (hwpt_nested->viommu)
|
||||
refcount_dec(&hwpt_nested->viommu->obj.users);
|
||||
else
|
||||
refcount_dec(&hwpt_nested->parent->common.obj.users);
|
||||
}
|
||||
|
||||
void iommufd_hwpt_nested_abort(struct iommufd_object *obj)
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user