[PATCH 04/14] iommufd: Use the iommufd_group to avoid duplicate reserved groups and msi setup

Jason Gunthorpe
2023-02-25T00:28:07Z

These items only needs to be done once per group, not once per device. The
once per device was a way to make the device list work. Since we are
abandoning this we can optimize things a bit.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommufd/device.c | 38 ++++++++++++++-----------
drivers/iommu/iommufd/io_pagetable.c | 5 ++--
drivers/iommu/iommufd/iommufd_private.h | 1 -
3 files changed, 23 insertions(+), 21 deletions(-)

diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index 264bfa2212481f..75e8d79678736f 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -298,9 +298,20 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
}
}

- rc = iopt_table_enforce_group_resv_regions(&hwpt->ioas->iopt, idev->dev,
- idev->igroup->group,
- &sw_msi_start);
+ /*
+ * The first device in the group to be attached will do all the work
+ * to setup the hwpt and ioas. Every other device re-uses it through
+ * the shared group attachment. Users are allowed/expected to attach
+ * every device in the group to the same hwpt, that just turns into
+ * a NOP.
+ */
+ if (idev->igroup->devices) {
+ idev->igroup->devices++;
+ return 0;
+ }
+
+ rc = iopt_table_enforce_group_resv_regions(
+ &hwpt->ioas->iopt, idev->igroup->group, &sw_msi_start);
if (rc)
return rc;

@@ -308,22 +319,15 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
if (rc)
goto err_unresv;

- /*
- * Only attach to the group once for the first device that is in the
- * group. All the other devices will follow this attachment.
- * The user can attach every device individually as well.
- */
- if (!idev->igroup->devices) {
- rc = iommu_attach_group(hwpt->domain, idev->igroup->group);
- if (rc)
- goto err_unresv;
- idev->igroup->hwpt = hwpt;
- refcount_inc(&hwpt->obj.users);
- }
+ rc = iommu_attach_group(hwpt->domain, idev->igroup->group);
+ if (rc)
+ goto err_unresv;
+ idev->igroup->hwpt = hwpt;
+ refcount_inc(&hwpt->obj.users);
idev->igroup->devices++;
return 0;
err_unresv:
- iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
+ iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->igroup->group);
return rc;
}

@@ -339,7 +343,7 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev)
iommu_detach_group(hwpt->domain, idev->igroup->group);
idev->igroup->hwpt = NULL;
}
- iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
+ iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->igroup->group);
return hwpt;
}

diff --git a/drivers/iommu/iommufd/io_pagetable.c b/drivers/iommu/iommufd/io_pagetable.c
index e0ae72b9e67f86..096491bbb5acf5 100644
--- a/drivers/iommu/iommufd/io_pagetable.c
+++ b/drivers/iommu/iommufd/io_pagetable.c
@@ -1163,7 +1163,6 @@ void iopt_remove_access(struct io_pagetable *iopt,

/* Narrow the valid_iova_itree to include reserved ranges from a group. */
int iopt_table_enforce_group_resv_regions(struct io_pagetable *iopt,
- struct device *device,
struct iommu_group *group,
phys_addr_t *sw_msi_start)
{
@@ -1191,7 +1190,7 @@ int iopt_table_enforce_group_resv_regions(struct io_pagetable *iopt,
}

rc = iopt_reserve_iova(iopt, resv->start,
- resv->length - 1 + resv->start, device);
+ resv->length - 1 + resv->start, group);
if (rc)
goto out_reserved;
}
@@ -1206,7 +1205,7 @@ int iopt_table_enforce_group_resv_regions(struct io_pagetable *iopt,
goto out_free_resv;

out_reserved:
- __iopt_remove_reserved_iova(iopt, device);
+ __iopt_remove_reserved_iova(iopt, group);
out_free_resv:
list_for_each_entry_safe(resv, tmp, &group_resv_regions, list)
kfree(resv);
diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index 5f3ad16da819e7..dbecdff013d082 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -77,7 +77,6 @@ int iopt_table_add_domain(struct io_pagetable *iopt,
void iopt_table_remove_domain(struct io_pagetable *iopt,
struct iommu_domain *domain);
int iopt_table_enforce_group_resv_regions(struct io_pagetable *iopt,
- struct device *device,
struct iommu_group *group,
phys_addr_t *sw_msi_start);
int iopt_set_allow_iova(struct io_pagetable *iopt,
--
2.39.1