[PATCH v4 3/9] iommu: Add attachment handle to struct iopf_group

Lu Baolu
2024-04-03T01:16:34Z

Previously, the domain that a page fault targets is stored in an
iopf_group, which represents a minimal set of page faults. With the
introduction of attachment handle, replace the domain with the handle
so that the fault handler can obtain more information as needed
when handling the faults.

iommu_report_device_fault() is currently used for SVA page faults,
which handles the page fault in an internal cycle. The domain is retrieved
with iommu_get_domain_for_dev_pasid() if the pasid in the fault message
is valid. This doesn't work in IOMMUFD case, where if the pasid table of
a device is wholly managed by user space, there is no domain attached to
the PASID of the device. Improve this code to try fetching the attachment
handle on a PASID if possible, otherwise try it on the RID.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
include/linux/iommu.h | 2 +-
drivers/iommu/io-pgfault.c | 37 +++++++++++++++++--------------------
drivers/iommu/iommu-sva.c | 3 ++-
3 files changed, 20 insertions(+), 22 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index be9c9a10169d..652a0bdd5074 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -127,7 +127,7 @@ struct iopf_group {
/* list node for iommu_fault_param::faults */
struct list_head pending_node;
struct work_struct work;
- struct iommu_domain *domain;
+ struct iommu_attach_handle *attach_handle;
/* The device's fault data parameter. */
struct iommu_fault_param *fault_param;
};
diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
index 06d78fcc79fd..32004976a6b7 100644
--- a/drivers/iommu/io-pgfault.c
+++ b/drivers/iommu/io-pgfault.c
@@ -50,6 +50,9 @@ static void __iopf_free_group(struct iopf_group *group)

/* Pair with iommu_report_device_fault(). */
iopf_put_dev_fault_param(group->fault_param);
+
+ /* Pair with get_attach_handle_for_iopf(). */
+ iommu_attach_handle_put(group->attach_handle);
}

void iopf_free_group(struct iopf_group *group)
@@ -59,28 +62,22 @@ void iopf_free_group(struct iopf_group *group)
}
EXPORT_SYMBOL_GPL(iopf_free_group);

-static struct iommu_domain *get_domain_for_iopf(struct device *dev,
- struct iommu_fault *fault)
+static struct iommu_attach_handle *
+get_attach_handle_for_iopf(struct device *dev, struct iommu_fault *fault)
{
- struct iommu_domain *domain;
+ struct iommu_group *group = dev->iommu_group;
+ struct iommu_attach_handle *handle;
+
+ if (!group)
+ return ERR_PTR(-ENODEV);

if (fault->prm.flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID) {
- domain = iommu_get_domain_for_dev_pasid(dev, fault->prm.pasid, 0);
- if (IS_ERR(domain))
- domain = NULL;
- } else {
- domain = iommu_get_domain_for_dev(dev);
+ handle = iommu_attach_handle_get(group, fault->prm.pasid);
+ if (handle)
+ return handle;
}

- if (!domain || !domain->iopf_handler) {
- dev_warn_ratelimited(dev,
- "iopf (pasid %d) without domain attached or handler installed\n",
- fault->prm.pasid);
-
- return NULL;
- }
-
- return domain;
+ return iommu_attach_handle_get(group, IOMMU_NO_PASID);
}

/* Non-last request of a group. Postpone until the last one. */
@@ -206,15 +203,15 @@ void iommu_report_device_fault(struct device *dev, struct iopf_fault *evt)
if (group == &abort_group)
goto err_abort;

- group->domain = get_domain_for_iopf(dev, fault);
- if (!group->domain)
+ group->attach_handle = get_attach_handle_for_iopf(dev, fault);
+ if (!group->attach_handle || !group->attach_handle->domain->iopf_handler)
goto err_abort;

/*
* On success iopf_handler must call iopf_group_response() and
* iopf_free_group()
*/
- if (group->domain->iopf_handler(group))
+ if (group->attach_handle->domain->iopf_handler(group))
goto err_abort;

return;
diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
index 35ac2e4836e9..c66cf26137bf 100644
--- a/drivers/iommu/iommu-sva.c
+++ b/drivers/iommu/iommu-sva.c
@@ -248,7 +248,8 @@ static void iommu_sva_handle_iopf(struct work_struct *work)
if (status != IOMMU_PAGE_RESP_SUCCESS)
break;

- status = iommu_sva_handle_mm(&iopf->fault, group->domain->mm);
+ status = iommu_sva_handle_mm(&iopf->fault,
+ group->attach_handle->domain->mm);
}

iopf_group_response(group, status);
--
2.34.1