diff mbox series

[12/14] iommufd: Add IOMMU_HWPT_ALLOC

Message ID 12-v1-7612f88c19f5+2f21-iommufd_alloc_jgg@nvidia.com (mailing list archive)
State New
Headers show
Series Add iommufd physical device operations for replace and alloc hwpt | expand

Commit Message

Jason Gunthorpe Feb. 25, 2023, 12:27 a.m. UTC
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.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommufd/hw_pagetable.c    | 46 +++++++++++++++++++++++++
 drivers/iommu/iommufd/iommufd_private.h |  9 +++++
 drivers/iommu/iommufd/main.c            |  3 ++
 include/uapi/linux/iommufd.h            | 26 ++++++++++++++
 4 files changed, 84 insertions(+)

Comments

Nicolin Chen March 6, 2023, 1:42 a.m. UTC | #1
On Fri, Feb 24, 2023 at 08:27:57PM -0400, Jason Gunthorpe wrote:

> +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)
> +		return -EOPNOTSUPP;
> +
> +	idev = iommufd_get_device(ucmd, cmd->dev_id);
> +	if (IS_ERR(idev))
> +		return PTR_ERR(idev);
> +
> +	ioas = iommufd_get_ioas(ucmd, cmd->pt_id);
> +	if (IS_ERR(ioas)) {
> +		rc = PTR_ERR(idev);

PTR_ERR(ioas)

> +		goto out_put_idev;
> +	}
> +
> +	mutex_lock(&ioas->mutex);
> +	hwpt = iommufd_hw_pagetable_alloc(ucmd->ictx, ioas, idev, false);
> +	mutex_unlock(&ioas->mutex);
> +	if (IS_ERR(hwpt)) {
> +		rc = PTR_ERR(idev);
 
PTR_ERR(hwpt)

Thanks
Nic
Jason Gunthorpe March 6, 2023, 8:31 p.m. UTC | #2
On Sun, Mar 05, 2023 at 05:42:56PM -0800, Nicolin Chen wrote:
> On Fri, Feb 24, 2023 at 08:27:57PM -0400, Jason Gunthorpe wrote:
> 
> > +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)
> > +		return -EOPNOTSUPP;
> > +
> > +	idev = iommufd_get_device(ucmd, cmd->dev_id);
> > +	if (IS_ERR(idev))
> > +		return PTR_ERR(idev);
> > +
> > +	ioas = iommufd_get_ioas(ucmd, cmd->pt_id);
> > +	if (IS_ERR(ioas)) {
> > +		rc = PTR_ERR(idev);
> 
> PTR_ERR(ioas)
> 
> > +		goto out_put_idev;
> > +	}
> > +
> > +	mutex_lock(&ioas->mutex);
> > +	hwpt = iommufd_hw_pagetable_alloc(ucmd->ictx, ioas, idev, false);
> > +	mutex_unlock(&ioas->mutex);
> > +	if (IS_ERR(hwpt)) {
> > +		rc = PTR_ERR(idev);
>  
> PTR_ERR(hwpt)

Oops, yep

Thanks,
Jason
Tian, Kevin March 17, 2023, 3:02 a.m. UTC | #3
> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Saturday, February 25, 2023 8:28 AM
> +
> +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)
> +		return -EOPNOTSUPP;

miss a check on the __reserved field.

> +/**
> + * 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 normal HWPT will be created with the mappings from the given IOAS.
> + */

'normal' is a confusing word in this context.
Nicolin Chen March 17, 2023, 4:02 a.m. UTC | #4
On Fri, Mar 17, 2023 at 03:02:26AM +0000, Tian, Kevin wrote:

> > +/**
> > + * 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 normal HWPT will be created with the mappings from the given IOAS.
> > + */
> 
> 'normal' is a confusing word in this context.

Yea, Eric was asking about a related question in another thread,
because he couldn't get this part. I think we could replace this
"normal" with just "kernel-managed", so eventually it would look
like the following narrative after adding user_data and nesting:

 * A kernel-managed HWPT will be created with the mappings from the given IOAS.
 * The @data_type for its allocation can be set to IOMMU_HWPT_TYPE_DEFAULT, or
 * another type (being listed below) to customize the allocation.
 *
 * A user-managed 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. The @data_type must not be set to IOMMU_HWPT_TYPE_DEFAULT but a
 * pre-defined type corresponding to the underlying IOMMU hardware.

Thanks
Nic
Tian, Kevin March 17, 2023, 10:20 a.m. UTC | #5
> From: Nicolin Chen <nicolinc@nvidia.com>
> Sent: Friday, March 17, 2023 12:02 PM
> 
> On Fri, Mar 17, 2023 at 03:02:26AM +0000, Tian, Kevin wrote:
> 
> > > +/**
> > > + * 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 normal HWPT will be created with the mappings from the given
> IOAS.
> > > + */
> >
> > 'normal' is a confusing word in this context.
> 
> Yea, Eric was asking about a related question in another thread,
> because he couldn't get this part. I think we could replace this
> "normal" with just "kernel-managed", so eventually it would look
> like the following narrative after adding user_data and nesting:
> 
>  * A kernel-managed HWPT will be created with the mappings from the given
> IOAS.
>  * The @data_type for its allocation can be set to
> IOMMU_HWPT_TYPE_DEFAULT, or
>  * another type (being listed below) to customize the allocation.
>  *
>  * A user-managed 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. The @data_type must not be set to
> IOMMU_HWPT_TYPE_DEFAULT but a
>  * pre-defined type corresponding to the underlying IOMMU hardware.

that is fine. But at this point it's clearer to simply remove 'normal'. 
Jason Gunthorpe March 21, 2023, 5:16 p.m. UTC | #6
On Fri, Mar 17, 2023 at 03:02:26AM +0000, Tian, Kevin wrote:
> > From: Jason Gunthorpe <jgg@nvidia.com>
> > Sent: Saturday, February 25, 2023 8:28 AM
> > +
> > +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)
> > +		return -EOPNOTSUPP;
> 
> miss a check on the __reserved field.
> 
> > +/**
> > + * 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 normal HWPT will be created with the mappings from the given IOAS.
> > + */
> 
> 'normal' is a confusing word in this context.

Got it, thanks

Jason
diff mbox series

Patch

diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c
index 2584f9038b29a2..a1f87193057385 100644
--- a/drivers/iommu/iommufd/hw_pagetable.c
+++ b/drivers/iommu/iommufd/hw_pagetable.c
@@ -3,6 +3,7 @@ 
  * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
  */
 #include <linux/iommu.h>
+#include <uapi/linux/iommufd.h>
 
 #include "iommufd_private.h"
 
@@ -121,3 +122,48 @@  iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
 	iommufd_object_abort_and_destroy(ictx, &hwpt->obj);
 	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)
+		return -EOPNOTSUPP;
+
+	idev = iommufd_get_device(ucmd, cmd->dev_id);
+	if (IS_ERR(idev))
+		return PTR_ERR(idev);
+
+	ioas = iommufd_get_ioas(ucmd, cmd->pt_id);
+	if (IS_ERR(ioas)) {
+		rc = PTR_ERR(idev);
+		goto out_put_idev;
+	}
+
+	mutex_lock(&ioas->mutex);
+	hwpt = iommufd_hw_pagetable_alloc(ucmd->ictx, ioas, idev, false);
+	mutex_unlock(&ioas->mutex);
+	if (IS_ERR(hwpt)) {
+		rc = PTR_ERR(idev);
+		goto out_put_ioas;
+	}
+
+	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_put_ioas;
+
+out_hwpt:
+	iommufd_object_abort_and_destroy(ucmd->ictx, &hwpt->obj);
+out_put_ioas:
+	iommufd_put_object(&ioas->obj);
+out_put_idev:
+	iommufd_put_object(&idev->obj);
+	return rc;
+}
diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index cfcda73942b533..c9acc70d84f794 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -261,6 +261,7 @@  int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
 struct iommufd_hw_pagetable *
 iommufd_hw_pagetable_detach(struct iommufd_device *idev);
 void iommufd_hw_pagetable_destroy(struct iommufd_object *obj);
+int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd);
 
 static inline void iommufd_hw_pagetable_put(struct iommufd_ctx *ictx,
 					    struct iommufd_hw_pagetable *hwpt)
@@ -296,6 +297,14 @@  struct iommufd_device {
 	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);
 
 struct iommufd_access {
diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
index 9cba592d0482e7..694da191e4b155 100644
--- a/drivers/iommu/iommufd/main.c
+++ b/drivers/iommu/iommufd/main.c
@@ -261,6 +261,7 @@  static int iommufd_option(struct iommufd_ucmd *ucmd)
 
 union ucmd_buffer {
 	struct iommu_destroy destroy;
+	struct iommu_hwpt_alloc hwpt;
 	struct iommu_ioas_alloc alloc;
 	struct iommu_ioas_allow_iovas allow_iovas;
 	struct iommu_ioas_copy ioas_copy;
@@ -292,6 +293,8 @@  struct iommufd_ioctl_op {
 	}
 static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = {
 	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,
 		 struct iommu_ioas_alloc, out_ioas_id),
 	IOCTL_OP(IOMMU_IOAS_ALLOW_IOVAS, iommufd_ioas_allow_iovas,
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 98ebba80cfa1fc..ccd36acad36a3f 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -45,6 +45,7 @@  enum {
 	IOMMUFD_CMD_IOAS_UNMAP,
 	IOMMUFD_CMD_OPTION,
 	IOMMUFD_CMD_VFIO_IOAS,
+	IOMMUFD_CMD_HWPT_ALLOC,
 };
 
 /**
@@ -344,4 +345,29 @@  struct iommu_vfio_ioas {
 	__u16 __reserved;
 };
 #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 normal HWPT will be created with the 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