mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-15 23:25:07 +00:00
iommufd: Add IOMMU_HWPT_ALLOC
This allows userspace to manually create HWPTs on IOAS's and then use those HWPTs as inputs to iommufd_device_attach/replace(). Following series will extend this to allow creating iommu_domains with driver specific parameters. Link: https://lore.kernel.org/r/17-v8-6659224517ea+532-iommufd_alloc_jgg@nvidia.com Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Tested-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
parent
fa1ffdb9e2
commit
7074d7bd67
4 changed files with 84 additions and 0 deletions
|
@ -3,6 +3,7 @@
|
||||||
* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
|
* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
|
||||||
*/
|
*/
|
||||||
#include <linux/iommu.h>
|
#include <linux/iommu.h>
|
||||||
|
#include <uapi/linux/iommufd.h>
|
||||||
|
|
||||||
#include "iommufd_private.h"
|
#include "iommufd_private.h"
|
||||||
|
|
||||||
|
@ -131,3 +132,48 @@ iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
|
||||||
iommufd_object_abort_and_destroy(ictx, &hwpt->obj);
|
iommufd_object_abort_and_destroy(ictx, &hwpt->obj);
|
||||||
return ERR_PTR(rc);
|
return ERR_PTR(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
|
||||||
|
{
|
||||||
|
struct iommu_hwpt_alloc *cmd = ucmd->cmd;
|
||||||
|
struct iommufd_hw_pagetable *hwpt;
|
||||||
|
struct iommufd_device *idev;
|
||||||
|
struct iommufd_ioas *ioas;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (cmd->flags || cmd->__reserved)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
idev = iommufd_get_device(ucmd, cmd->dev_id);
|
||||||
|
if (IS_ERR(idev))
|
||||||
|
return PTR_ERR(idev);
|
||||||
|
|
||||||
|
ioas = iommufd_get_ioas(ucmd->ictx, cmd->pt_id);
|
||||||
|
if (IS_ERR(ioas)) {
|
||||||
|
rc = PTR_ERR(ioas);
|
||||||
|
goto out_put_idev;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&ioas->mutex);
|
||||||
|
hwpt = iommufd_hw_pagetable_alloc(ucmd->ictx, ioas, idev, false);
|
||||||
|
if (IS_ERR(hwpt)) {
|
||||||
|
rc = PTR_ERR(hwpt);
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd->out_hwpt_id = hwpt->obj.id;
|
||||||
|
rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
|
||||||
|
if (rc)
|
||||||
|
goto out_hwpt;
|
||||||
|
iommufd_object_finalize(ucmd->ictx, &hwpt->obj);
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
out_hwpt:
|
||||||
|
iommufd_object_abort_and_destroy(ucmd->ictx, &hwpt->obj);
|
||||||
|
out_unlock:
|
||||||
|
mutex_unlock(&ioas->mutex);
|
||||||
|
iommufd_put_object(&ioas->obj);
|
||||||
|
out_put_idev:
|
||||||
|
iommufd_put_object(&idev->obj);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
|
@ -262,6 +262,7 @@ struct iommufd_hw_pagetable *
|
||||||
iommufd_hw_pagetable_detach(struct iommufd_device *idev);
|
iommufd_hw_pagetable_detach(struct iommufd_device *idev);
|
||||||
void iommufd_hw_pagetable_destroy(struct iommufd_object *obj);
|
void iommufd_hw_pagetable_destroy(struct iommufd_object *obj);
|
||||||
void iommufd_hw_pagetable_abort(struct iommufd_object *obj);
|
void iommufd_hw_pagetable_abort(struct iommufd_object *obj);
|
||||||
|
int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd);
|
||||||
|
|
||||||
static inline void iommufd_hw_pagetable_put(struct iommufd_ctx *ictx,
|
static inline void iommufd_hw_pagetable_put(struct iommufd_ctx *ictx,
|
||||||
struct iommufd_hw_pagetable *hwpt)
|
struct iommufd_hw_pagetable *hwpt)
|
||||||
|
@ -298,6 +299,14 @@ struct iommufd_device {
|
||||||
bool enforce_cache_coherency;
|
bool enforce_cache_coherency;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline struct iommufd_device *
|
||||||
|
iommufd_get_device(struct iommufd_ucmd *ucmd, u32 id)
|
||||||
|
{
|
||||||
|
return container_of(iommufd_get_object(ucmd->ictx, id,
|
||||||
|
IOMMUFD_OBJ_DEVICE),
|
||||||
|
struct iommufd_device, obj);
|
||||||
|
}
|
||||||
|
|
||||||
void iommufd_device_destroy(struct iommufd_object *obj);
|
void iommufd_device_destroy(struct iommufd_object *obj);
|
||||||
|
|
||||||
struct iommufd_access {
|
struct iommufd_access {
|
||||||
|
|
|
@ -265,6 +265,7 @@ static int iommufd_option(struct iommufd_ucmd *ucmd)
|
||||||
|
|
||||||
union ucmd_buffer {
|
union ucmd_buffer {
|
||||||
struct iommu_destroy destroy;
|
struct iommu_destroy destroy;
|
||||||
|
struct iommu_hwpt_alloc hwpt;
|
||||||
struct iommu_ioas_alloc alloc;
|
struct iommu_ioas_alloc alloc;
|
||||||
struct iommu_ioas_allow_iovas allow_iovas;
|
struct iommu_ioas_allow_iovas allow_iovas;
|
||||||
struct iommu_ioas_copy ioas_copy;
|
struct iommu_ioas_copy ioas_copy;
|
||||||
|
@ -296,6 +297,8 @@ struct iommufd_ioctl_op {
|
||||||
}
|
}
|
||||||
static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = {
|
static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = {
|
||||||
IOCTL_OP(IOMMU_DESTROY, iommufd_destroy, struct iommu_destroy, id),
|
IOCTL_OP(IOMMU_DESTROY, iommufd_destroy, struct iommu_destroy, id),
|
||||||
|
IOCTL_OP(IOMMU_HWPT_ALLOC, iommufd_hwpt_alloc, struct iommu_hwpt_alloc,
|
||||||
|
__reserved),
|
||||||
IOCTL_OP(IOMMU_IOAS_ALLOC, iommufd_ioas_alloc_ioctl,
|
IOCTL_OP(IOMMU_IOAS_ALLOC, iommufd_ioas_alloc_ioctl,
|
||||||
struct iommu_ioas_alloc, out_ioas_id),
|
struct iommu_ioas_alloc, out_ioas_id),
|
||||||
IOCTL_OP(IOMMU_IOAS_ALLOW_IOVAS, iommufd_ioas_allow_iovas,
|
IOCTL_OP(IOMMU_IOAS_ALLOW_IOVAS, iommufd_ioas_allow_iovas,
|
||||||
|
|
|
@ -45,6 +45,7 @@ enum {
|
||||||
IOMMUFD_CMD_IOAS_UNMAP,
|
IOMMUFD_CMD_IOAS_UNMAP,
|
||||||
IOMMUFD_CMD_OPTION,
|
IOMMUFD_CMD_OPTION,
|
||||||
IOMMUFD_CMD_VFIO_IOAS,
|
IOMMUFD_CMD_VFIO_IOAS,
|
||||||
|
IOMMUFD_CMD_HWPT_ALLOC,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -344,4 +345,29 @@ struct iommu_vfio_ioas {
|
||||||
__u16 __reserved;
|
__u16 __reserved;
|
||||||
};
|
};
|
||||||
#define IOMMU_VFIO_IOAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VFIO_IOAS)
|
#define IOMMU_VFIO_IOAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VFIO_IOAS)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct iommu_hwpt_alloc - ioctl(IOMMU_HWPT_ALLOC)
|
||||||
|
* @size: sizeof(struct iommu_hwpt_alloc)
|
||||||
|
* @flags: Must be 0
|
||||||
|
* @dev_id: The device to allocate this HWPT for
|
||||||
|
* @pt_id: The IOAS to connect this HWPT to
|
||||||
|
* @out_hwpt_id: The ID of the new HWPT
|
||||||
|
* @__reserved: Must be 0
|
||||||
|
*
|
||||||
|
* Explicitly allocate a hardware page table object. This is the same object
|
||||||
|
* type that is returned by iommufd_device_attach() and represents the
|
||||||
|
* underlying iommu driver's iommu_domain kernel object.
|
||||||
|
*
|
||||||
|
* A HWPT will be created with the IOVA mappings from the given IOAS.
|
||||||
|
*/
|
||||||
|
struct iommu_hwpt_alloc {
|
||||||
|
__u32 size;
|
||||||
|
__u32 flags;
|
||||||
|
__u32 dev_id;
|
||||||
|
__u32 pt_id;
|
||||||
|
__u32 out_hwpt_id;
|
||||||
|
__u32 __reserved;
|
||||||
|
};
|
||||||
|
#define IOMMU_HWPT_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_ALLOC)
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue