iommu: Pass in parent domain with user_data to domain_alloc_user op
authorYi Liu <yi.l.liu@intel.com>
Thu, 26 Oct 2023 04:39:34 +0000 (21:39 -0700)
committerJason Gunthorpe <jgg@nvidia.com>
Thu, 26 Oct 2023 14:15:57 +0000 (11:15 -0300)
domain_alloc_user op already accepts user flags for domain allocation, add
a parent domain pointer and a driver specific user data support as well.
The user data would be tagged with a type for iommu drivers to add their
own driver specific user data per hw_pagetable.

Add a struct iommu_user_data as a bundle of data_ptr/data_len/type from an
iommufd core uAPI structure. Make the user data opaque to the core, since
a userspace driver must match the kernel driver. In the future, if drivers
share some common parameter, there would be a generic parameter as well.

Link: https://lore.kernel.org/r/20231026043938.63898-7-yi.l.liu@intel.com
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Co-developed-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/iommu/amd/iommu.c
drivers/iommu/intel/iommu.c
drivers/iommu/iommufd/hw_pagetable.c
drivers/iommu/iommufd/selftest.c
include/linux/iommu.h

index caad10f9cee3f903d38a30df988bd7fa78551655..b399c57413784688e69beaa54f2fed5b23d0462c 100644 (file)
@@ -2219,12 +2219,15 @@ static struct iommu_domain *amd_iommu_domain_alloc(unsigned int type)
        return domain;
 }
 
-static struct iommu_domain *amd_iommu_domain_alloc_user(struct device *dev,
-                                                       u32 flags)
+static struct iommu_domain *
+amd_iommu_domain_alloc_user(struct device *dev, u32 flags,
+                           struct iommu_domain *parent,
+                           const struct iommu_user_data *user_data)
+
 {
        unsigned int type = IOMMU_DOMAIN_UNMANAGED;
 
-       if (flags & ~IOMMU_HWPT_ALLOC_DIRTY_TRACKING)
+       if ((flags & ~IOMMU_HWPT_ALLOC_DIRTY_TRACKING) || parent || user_data)
                return ERR_PTR(-EOPNOTSUPP);
 
        return do_iommu_domain_alloc(type, dev, flags);
index eb92a201cc0b776d63ef0044514856b406085dc1..fe67f8d77b09eadbba6fd0ad2da84152f43eebc5 100644 (file)
@@ -4076,7 +4076,9 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
 }
 
 static struct iommu_domain *
-intel_iommu_domain_alloc_user(struct device *dev, u32 flags)
+intel_iommu_domain_alloc_user(struct device *dev, u32 flags,
+                             struct iommu_domain *parent,
+                             const struct iommu_user_data *user_data)
 {
        struct iommu_domain *domain;
        struct intel_iommu *iommu;
@@ -4086,6 +4088,9 @@ intel_iommu_domain_alloc_user(struct device *dev, u32 flags)
            (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING)))
                return ERR_PTR(-EOPNOTSUPP);
 
+       if (parent || user_data)
+               return ERR_PTR(-EOPNOTSUPP);
+
        iommu = device_to_iommu(dev, NULL, NULL);
        if (!iommu)
                return ERR_PTR(-ENODEV);
index 6bce9af0cb8d68ef6174c498921c481c5e2bd049..198ecbd536f7bc47478b6cdf793d96eacc73228b 100644 (file)
@@ -108,7 +108,8 @@ iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
        hwpt_paging->ioas = ioas;
 
        if (ops->domain_alloc_user) {
-               hwpt->domain = ops->domain_alloc_user(idev->dev, flags);
+               hwpt->domain =
+                       ops->domain_alloc_user(idev->dev, flags, NULL, NULL);
                if (IS_ERR(hwpt->domain)) {
                        rc = PTR_ERR(hwpt->domain);
                        hwpt->domain = NULL;
index 068928ba7950518b26204e80204e8a7dc084ebf4..d710072348960778a190cfce7f401a2a145bcb8a 100644 (file)
@@ -241,7 +241,9 @@ static struct iommu_domain *mock_domain_alloc(unsigned int iommu_domain_type)
 }
 
 static struct iommu_domain *
-mock_domain_alloc_user(struct device *dev, u32 flags)
+mock_domain_alloc_user(struct device *dev, u32 flags,
+                      struct iommu_domain *parent,
+                      const struct iommu_user_data *user_data)
 {
        struct mock_dev *mdev = container_of(dev, struct mock_dev, dev);
        struct iommu_domain *domain;
@@ -250,6 +252,9 @@ mock_domain_alloc_user(struct device *dev, u32 flags)
            (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING)))
                return ERR_PTR(-EOPNOTSUPP);
 
+       if (parent || user_data)
+               return ERR_PTR(-EOPNOTSUPP);
+
        if ((flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING) &&
            (mdev->flags & MOCK_FLAGS_DEVICE_NO_DIRTY))
                return ERR_PTR(-EOPNOTSUPP);
index bc303cb2af37acc8bc61fb93cbeaa8cf09d315fe..2ddd99f55471ba89fd2a0a605f48b4cdeda9cb61 100644 (file)
@@ -265,6 +265,21 @@ struct iommu_dirty_ops {
                                    struct iommu_dirty_bitmap *dirty);
 };
 
+/**
+ * struct iommu_user_data - iommu driver specific user space data info
+ * @type: The data type of the user buffer
+ * @uptr: Pointer to the user buffer for copy_from_user()
+ * @len: The length of the user buffer in bytes
+ *
+ * A user space data is an uAPI that is defined in include/uapi/linux/iommufd.h
+ * @type, @uptr and @len should be just copied from an iommufd core uAPI struct.
+ */
+struct iommu_user_data {
+       unsigned int type;
+       void __user *uptr;
+       size_t len;
+};
+
 /**
  * struct iommu_ops - iommu ops and capabilities
  * @capable: check capability
@@ -279,8 +294,12 @@ struct iommu_dirty_ops {
  *                     parameters as defined in include/uapi/linux/iommufd.h.
  *                     Unlike @domain_alloc, it is called only by IOMMUFD and
  *                     must fully initialize the new domain before return.
- *                     Upon success, a domain is returned. Upon failure,
- *                     ERR_PTR must be returned.
+ *                     Upon success, if the @user_data is valid and the @parent
+ *                     points to a kernel-managed domain, the new domain must be
+ *                     IOMMU_DOMAIN_NESTED type; otherwise, the @parent must be
+ *                     NULL while the @user_data can be optionally provided, the
+ *                     new domain must support __IOMMU_DOMAIN_PAGING.
+ *                     Upon failure, ERR_PTR must be returned.
  * @probe_device: Add device to iommu driver handling
  * @release_device: Remove device from iommu driver handling
  * @probe_finalize: Do final setup work after the device is added to an IOMMU
@@ -313,7 +332,9 @@ struct iommu_ops {
 
        /* Domain allocation and freeing by the iommu driver */
        struct iommu_domain *(*domain_alloc)(unsigned iommu_domain_type);
-       struct iommu_domain *(*domain_alloc_user)(struct device *dev, u32 flags);
+       struct iommu_domain *(*domain_alloc_user)(
+               struct device *dev, u32 flags, struct iommu_domain *parent,
+               const struct iommu_user_data *user_data);
 
        struct iommu_device *(*probe_device)(struct device *dev);
        void (*release_device)(struct device *dev);