]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu: Add new flag to explictly request PASID capable domain
authorJason Gunthorpe <jgg@ziepe.ca>
Mon, 28 Oct 2024 09:38:01 +0000 (09:38 +0000)
committerJoerg Roedel <jroedel@suse.de>
Tue, 29 Oct 2024 09:08:18 +0000 (10:08 +0100)
Introduce new flag (IOMMU_HWPT_ALLOC_PASID) to domain_alloc_users() ops.
If IOMMU supports PASID it will allocate domain. Otherwise return error.
In error path check for -EOPNOTSUPP and try to allocate non-PASID
domain so that DMA-API mode work fine for drivers which does not support
PASID as well.

Also modify __iommu_group_alloc_default_domain() to call
iommu_paging_domain_alloc_flags() with appropriate flag when allocating
paging domain.

Signed-off-by: Jason Gunthorpe <jgg@ziepe.ca>
Co-developed-by: Vasant Hegde <vasant.hegde@amd.com>
Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20241028093810.5901-4-vasant.hegde@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/iommu.c
include/uapi/linux/iommufd.h

index d82aa6563d84618131c4f7e7dbfc66bf7e1269b7..97ad431447363031140239e9e38ca9e2e0cd49a5 100644 (file)
@@ -32,6 +32,7 @@
 #include <trace/events/iommu.h>
 #include <linux/sched/mm.h>
 #include <linux/msi.h>
+#include <uapi/linux/iommufd.h>
 
 #include "dma-iommu.h"
 #include "iommu-priv.h"
@@ -99,6 +100,9 @@ static int __iommu_attach_device(struct iommu_domain *domain,
                                 struct device *dev);
 static int __iommu_attach_group(struct iommu_domain *domain,
                                struct iommu_group *group);
+static struct iommu_domain *__iommu_paging_domain_alloc_flags(struct device *dev,
+                                                      unsigned int type,
+                                                      unsigned int flags);
 
 enum {
        IOMMU_SET_DOMAIN_MUST_SUCCEED = 1 << 0,
@@ -1585,8 +1589,30 @@ EXPORT_SYMBOL_GPL(fsl_mc_device_group);
 static struct iommu_domain *
 __iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
 {
+       struct device *dev = iommu_group_first_dev(group);
+       struct iommu_domain *dom;
+
        if (group->default_domain && group->default_domain->type == req_type)
                return group->default_domain;
+
+       /*
+        * When allocating the DMA API domain assume that the driver is going to
+        * use PASID and make sure the RID's domain is PASID compatible.
+        */
+       if (req_type & __IOMMU_DOMAIN_PAGING) {
+               dom = __iommu_paging_domain_alloc_flags(dev, req_type,
+                          dev->iommu->max_pasids ? IOMMU_HWPT_ALLOC_PASID : 0);
+
+               /*
+                * If driver does not support PASID feature then
+                * try to allocate non-PASID domain
+                */
+               if (PTR_ERR(dom) == -EOPNOTSUPP)
+                       dom = __iommu_paging_domain_alloc_flags(dev, req_type, 0);
+
+               return dom;
+       }
+
        return __iommu_group_domain_alloc(group, req_type);
 }
 
@@ -1961,16 +1987,9 @@ __iommu_group_domain_alloc(struct iommu_group *group, unsigned int type)
        return __iommu_domain_alloc(dev_iommu_ops(dev), dev, type);
 }
 
-/**
- * iommu_paging_domain_alloc_flags() - Allocate a paging domain
- * @dev: device for which the domain is allocated
- * @flags: Enum of iommufd_hwpt_alloc_flags
- *
- * Allocate a paging domain which will be managed by a kernel driver. Return
- * allocated domain if successful, or an ERR pointer for failure.
- */
-struct iommu_domain *iommu_paging_domain_alloc_flags(struct device *dev,
-                                                    unsigned int flags)
+static struct iommu_domain *
+__iommu_paging_domain_alloc_flags(struct device *dev, unsigned int type,
+                                 unsigned int flags)
 {
        const struct iommu_ops *ops;
        struct iommu_domain *domain;
@@ -1994,9 +2013,24 @@ struct iommu_domain *iommu_paging_domain_alloc_flags(struct device *dev,
        if (!domain)
                return ERR_PTR(-ENOMEM);
 
-       iommu_domain_init(domain, IOMMU_DOMAIN_UNMANAGED, ops);
+       iommu_domain_init(domain, type, ops);
        return domain;
 }
+
+/**
+ * iommu_paging_domain_alloc_flags() - Allocate a paging domain
+ * @dev: device for which the domain is allocated
+ * @flags: Bitmap of iommufd_hwpt_alloc_flags
+ *
+ * Allocate a paging domain which will be managed by a kernel driver. Return
+ * allocated domain if successful, or an ERR pointer for failure.
+ */
+struct iommu_domain *iommu_paging_domain_alloc_flags(struct device *dev,
+                                                    unsigned int flags)
+{
+       return __iommu_paging_domain_alloc_flags(dev,
+                                        IOMMU_DOMAIN_UNMANAGED, flags);
+}
 EXPORT_SYMBOL_GPL(iommu_paging_domain_alloc_flags);
 
 void iommu_domain_free(struct iommu_domain *domain)
index 72010f71c5e479e26be02435fdc45e990832b687..0c0ed28ee11377e1c1d1896670507ed73d1789c4 100644 (file)
@@ -359,11 +359,19 @@ struct iommu_vfio_ioas {
  *                                   enforced on device attachment
  * @IOMMU_HWPT_FAULT_ID_VALID: The fault_id field of hwpt allocation data is
  *                             valid.
+ * @IOMMU_HWPT_ALLOC_PASID: Requests a domain that can be used with PASID. The
+ *                          domain can be attached to any PASID on the device.
+ *                          Any domain attached to the non-PASID part of the
+ *                          device must also be flaged, otherwise attaching a
+ *                          PASID will blocked.
+ *                          If IOMMU does not support PASID it will return
+ *                          error (-EOPNOTSUPP).
  */
 enum iommufd_hwpt_alloc_flags {
        IOMMU_HWPT_ALLOC_NEST_PARENT = 1 << 0,
        IOMMU_HWPT_ALLOC_DIRTY_TRACKING = 1 << 1,
        IOMMU_HWPT_FAULT_ID_VALID = 1 << 2,
+       IOMMU_HWPT_ALLOC_PASID = 1 << 3,
 };
 
 /**