iommufd: Make attach_handle generic than fault specific
authorNicolin Chen <nicolinc@nvidia.com>
Tue, 4 Feb 2025 05:00:54 +0000 (21:00 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 20 Apr 2025 08:16:00 +0000 (10:16 +0200)
commit fb21b1568adaa76af7a8c853f37c60fba8b28661 upstream.

"attach_handle" was added exclusively for the iommufd_fault_iopf_handler()
used by IOPF/PRI use cases. Now, both the MSI and PASID series require to
reuse the attach_handle for non-fault cases.

Add a set of new attach/detach/replace helpers that does the attach_handle
allocation/releasing/replacement in the common path and also handles those
fault specific routines such as iopf enabling/disabling and auto response.

This covers both non-fault and fault cases in a clean way, replacing those
inline helpers in the header. The following patch will clean up those old
helpers in the fault.c file.

Link: https://patch.msgid.link/r/32687df01c02291d89986a9fca897bbbe2b10987.1738645017.git.nicolinc@nvidia.com
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Yi Liu <yi.l.liu@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/iommu/iommufd/device.c
drivers/iommu/iommufd/fault.c
drivers/iommu/iommufd/iommufd_private.h

index 19a94999708b0824da275c49db99e5eff46ea154..a8ab0688d67d526a48d60f55e0ab1961365e3569 100644 (file)
@@ -352,6 +352,111 @@ iommufd_device_attach_reserved_iova(struct iommufd_device *idev,
        return 0;
 }
 
+/* The device attach/detach/replace helpers for attach_handle */
+
+static int iommufd_hwpt_attach_device(struct iommufd_hw_pagetable *hwpt,
+                                     struct iommufd_device *idev)
+{
+       struct iommufd_attach_handle *handle;
+       int rc;
+
+       lockdep_assert_held(&idev->igroup->lock);
+
+       handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       if (hwpt->fault) {
+               rc = iommufd_fault_iopf_enable(idev);
+               if (rc)
+                       goto out_free_handle;
+       }
+
+       handle->idev = idev;
+       rc = iommu_attach_group_handle(hwpt->domain, idev->igroup->group,
+                                      &handle->handle);
+       if (rc)
+               goto out_disable_iopf;
+
+       return 0;
+
+out_disable_iopf:
+       if (hwpt->fault)
+               iommufd_fault_iopf_disable(idev);
+out_free_handle:
+       kfree(handle);
+       return rc;
+}
+
+static struct iommufd_attach_handle *
+iommufd_device_get_attach_handle(struct iommufd_device *idev)
+{
+       struct iommu_attach_handle *handle;
+
+       lockdep_assert_held(&idev->igroup->lock);
+
+       handle =
+               iommu_attach_handle_get(idev->igroup->group, IOMMU_NO_PASID, 0);
+       if (IS_ERR(handle))
+               return NULL;
+       return to_iommufd_handle(handle);
+}
+
+static void iommufd_hwpt_detach_device(struct iommufd_hw_pagetable *hwpt,
+                                      struct iommufd_device *idev)
+{
+       struct iommufd_attach_handle *handle;
+
+       handle = iommufd_device_get_attach_handle(idev);
+       iommu_detach_group_handle(hwpt->domain, idev->igroup->group);
+       if (hwpt->fault) {
+               iommufd_auto_response_faults(hwpt, handle);
+               iommufd_fault_iopf_disable(idev);
+       }
+       kfree(handle);
+}
+
+static int iommufd_hwpt_replace_device(struct iommufd_device *idev,
+                                      struct iommufd_hw_pagetable *hwpt,
+                                      struct iommufd_hw_pagetable *old)
+{
+       struct iommufd_attach_handle *handle, *old_handle =
+               iommufd_device_get_attach_handle(idev);
+       int rc;
+
+       handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       if (hwpt->fault && !old->fault) {
+               rc = iommufd_fault_iopf_enable(idev);
+               if (rc)
+                       goto out_free_handle;
+       }
+
+       handle->idev = idev;
+       rc = iommu_replace_group_handle(idev->igroup->group, hwpt->domain,
+                                       &handle->handle);
+       if (rc)
+               goto out_disable_iopf;
+
+       if (old->fault) {
+               iommufd_auto_response_faults(hwpt, old_handle);
+               if (!hwpt->fault)
+                       iommufd_fault_iopf_disable(idev);
+       }
+       kfree(old_handle);
+
+       return 0;
+
+out_disable_iopf:
+       if (hwpt->fault && !old->fault)
+               iommufd_fault_iopf_disable(idev);
+out_free_handle:
+       kfree(handle);
+       return rc;
+}
+
 int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
                                struct iommufd_device *idev)
 {
index 95e2e99ab272417f5075d54781c237e4070752ff..1b0812f8bf840a7fb6fe38a2f3a927ab70d20970 100644 (file)
@@ -16,7 +16,7 @@
 #include "../iommu-priv.h"
 #include "iommufd_private.h"
 
-static int iommufd_fault_iopf_enable(struct iommufd_device *idev)
+int iommufd_fault_iopf_enable(struct iommufd_device *idev)
 {
        struct device *dev = idev->dev;
        int ret;
@@ -45,7 +45,7 @@ static int iommufd_fault_iopf_enable(struct iommufd_device *idev)
        return ret;
 }
 
-static void iommufd_fault_iopf_disable(struct iommufd_device *idev)
+void iommufd_fault_iopf_disable(struct iommufd_device *idev)
 {
        mutex_lock(&idev->iopf_lock);
        if (!WARN_ON(idev->iopf_enabled == 0)) {
@@ -93,8 +93,8 @@ int iommufd_fault_domain_attach_dev(struct iommufd_hw_pagetable *hwpt,
        return ret;
 }
 
-static void iommufd_auto_response_faults(struct iommufd_hw_pagetable *hwpt,
-                                        struct iommufd_attach_handle *handle)
+void iommufd_auto_response_faults(struct iommufd_hw_pagetable *hwpt,
+                                 struct iommufd_attach_handle *handle)
 {
        struct iommufd_fault *fault = hwpt->fault;
        struct iopf_group *group, *next;
index c1f82cb682425691f180a5817ebfe7b2ece10dc2..18cdf1391a03487744fb828e1bf5394f4d68c385 100644 (file)
@@ -523,35 +523,10 @@ int iommufd_fault_domain_replace_dev(struct iommufd_device *idev,
                                     struct iommufd_hw_pagetable *hwpt,
                                     struct iommufd_hw_pagetable *old);
 
-static inline int iommufd_hwpt_attach_device(struct iommufd_hw_pagetable *hwpt,
-                                            struct iommufd_device *idev)
-{
-       if (hwpt->fault)
-               return iommufd_fault_domain_attach_dev(hwpt, idev);
-
-       return iommu_attach_group(hwpt->domain, idev->igroup->group);
-}
-
-static inline void iommufd_hwpt_detach_device(struct iommufd_hw_pagetable *hwpt,
-                                             struct iommufd_device *idev)
-{
-       if (hwpt->fault) {
-               iommufd_fault_domain_detach_dev(hwpt, idev);
-               return;
-       }
-
-       iommu_detach_group(hwpt->domain, idev->igroup->group);
-}
-
-static inline int iommufd_hwpt_replace_device(struct iommufd_device *idev,
-                                             struct iommufd_hw_pagetable *hwpt,
-                                             struct iommufd_hw_pagetable *old)
-{
-       if (old->fault || hwpt->fault)
-               return iommufd_fault_domain_replace_dev(idev, hwpt, old);
-
-       return iommu_group_replace_domain(idev->igroup->group, hwpt->domain);
-}
+int iommufd_fault_iopf_enable(struct iommufd_device *idev);
+void iommufd_fault_iopf_disable(struct iommufd_device *idev);
+void iommufd_auto_response_faults(struct iommufd_hw_pagetable *hwpt,
+                                 struct iommufd_attach_handle *handle);
 
 #ifdef CONFIG_IOMMUFD_TEST
 int iommufd_test(struct iommufd_ucmd *ucmd);