iommufd: Add enforced_cache_coherency to iommufd_hw_pagetable_alloc()
authorJason Gunthorpe <jgg@nvidia.com>
Mon, 17 Jul 2023 18:12:05 +0000 (15:12 -0300)
committerJason Gunthorpe <jgg@nvidia.com>
Wed, 26 Jul 2023 13:19:52 +0000 (10:19 -0300)
Logically the HWPT should have the coherency set properly for the device
that it is being created for when it is created.

This was happening implicitly if the immediate_attach was set because
iommufd_hw_pagetable_attach() does it as the first thing.

Do it unconditionally so !immediate_attach works properly.

Link: https://lore.kernel.org/r/9-v8-6659224517ea+532-iommufd_alloc_jgg@nvidia.com
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/iommu/iommufd/device.c
drivers/iommu/iommufd/hw_pagetable.c
drivers/iommu/iommufd/iommufd_private.h

index 89cef2d..08bba99 100644 (file)
@@ -338,22 +338,11 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
                goto err_unlock;
        }
 
-       /*
-        * Try to upgrade the domain we have, it is an iommu driver bug to
-        * report IOMMU_CAP_ENFORCE_CACHE_COHERENCY but fail
-        * enforce_cache_coherency when there are no devices attached to the
-        * domain.
-        */
-       if (idev->enforce_cache_coherency && !hwpt->enforce_cache_coherency) {
-               if (hwpt->domain->ops->enforce_cache_coherency)
-                       hwpt->enforce_cache_coherency =
-                               hwpt->domain->ops->enforce_cache_coherency(
-                                       hwpt->domain);
-               if (!hwpt->enforce_cache_coherency) {
-                       WARN_ON(list_empty(&idev->igroup->device_list));
-                       rc = -EINVAL;
+       /* Try to upgrade the domain we have */
+       if (idev->enforce_cache_coherency) {
+               rc = iommufd_hw_pagetable_enforce_cc(hwpt);
+               if (rc)
                        goto err_unlock;
-               }
        }
 
        rc = iopt_table_enforce_dev_resv_regions(&hwpt->ioas->iopt, idev->dev,
index bdb76cd..e0699d7 100644 (file)
@@ -25,6 +25,20 @@ void iommufd_hw_pagetable_destroy(struct iommufd_object *obj)
        refcount_dec(&hwpt->ioas->obj.users);
 }
 
+int iommufd_hw_pagetable_enforce_cc(struct iommufd_hw_pagetable *hwpt)
+{
+       if (hwpt->enforce_cache_coherency)
+               return 0;
+
+       if (hwpt->domain->ops->enforce_cache_coherency)
+               hwpt->enforce_cache_coherency =
+                       hwpt->domain->ops->enforce_cache_coherency(
+                               hwpt->domain);
+       if (!hwpt->enforce_cache_coherency)
+               return -EINVAL;
+       return 0;
+}
+
 /**
  * iommufd_hw_pagetable_alloc() - Get an iommu_domain for a device
  * @ictx: iommufd context
@@ -61,6 +75,19 @@ iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
        }
 
        /*
+        * Set the coherency mode before we do iopt_table_add_domain() as some
+        * iommus have a per-PTE bit that controls it and need to decide before
+        * doing any maps. It is an iommu driver bug to report
+        * IOMMU_CAP_ENFORCE_CACHE_COHERENCY but fail enforce_cache_coherency on
+        * a new domain.
+        */
+       if (idev->enforce_cache_coherency) {
+               rc = iommufd_hw_pagetable_enforce_cc(hwpt);
+               if (WARN_ON(rc))
+                       goto out_abort;
+       }
+
+       /*
         * immediate_attach exists only to accommodate iommu drivers that cannot
         * directly allocate a domain. These drivers do not finish creating the
         * domain until attach is completed. Thus we must have this call
index 8bdbef8..a6210f5 100644 (file)
@@ -254,6 +254,7 @@ struct iommufd_hw_pagetable {
 struct iommufd_hw_pagetable *
 iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
                           struct iommufd_device *idev, bool immediate_attach);
+int iommufd_hw_pagetable_enforce_cc(struct iommufd_hw_pagetable *hwpt);
 int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
                                struct iommufd_device *idev);
 struct iommufd_hw_pagetable *