summaryrefslogtreecommitdiff
path: root/drivers/iommu/iommufd/hw_pagetable.c
diff options
context:
space:
mode:
authorJason Gunthorpe <jgg@nvidia.com>2023-03-01 22:30:23 +0300
committerJason Gunthorpe <jgg@nvidia.com>2023-03-06 17:51:57 +0300
commit339fbf3ae144263725ccb7694cd2366d5e0c6ebf (patch)
treee09e6620947c64bf7b7fa43278346ecc388ebd15 /drivers/iommu/iommufd/hw_pagetable.c
parent7e7ec8a5692105450bbfde8c310af606e216add0 (diff)
downloadlinux-339fbf3ae144263725ccb7694cd2366d5e0c6ebf.tar.xz
iommufd: Make iommufd_hw_pagetable_alloc() do iopt_table_add_domain()
The HWPT is always linked to an IOAS and once a HWPT exists its domain should be fully mapped. This ended up being split up into device.c during a two phase creation that was a bit confusing. Move the iopt_table_add_domain() into iommufd_hw_pagetable_alloc() by having it call back to device.c to complete the domain attach in the required order. Calling iommufd_hw_pagetable_alloc() with immediate_attach = false will work on most drivers, but notably the SMMU drivers will fail because they can't decide what kind of domain to create until they are attached. This will be fixed when the domain_alloc function can take in a struct device. Link: https://lore.kernel.org/r/6-v3-ae9c2975a131+2e1e8-iommufd_hwpt_jgg@nvidia.com Reviewed-by: Kevin Tian <kevin.tian@intel.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Diffstat (limited to 'drivers/iommu/iommufd/hw_pagetable.c')
-rw-r--r--drivers/iommu/iommufd/hw_pagetable.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c
index 10db1359c067..6cdb6749d359 100644
--- a/drivers/iommu/iommufd/hw_pagetable.c
+++ b/drivers/iommu/iommufd/hw_pagetable.c
@@ -32,17 +32,22 @@ void iommufd_hw_pagetable_destroy(struct iommufd_object *obj)
* iommufd_hw_pagetable_alloc() - Get an iommu_domain for a device
* @ictx: iommufd context
* @ioas: IOAS to associate the domain with
- * @dev: Device to get an iommu_domain for
+ * @idev: Device to get an iommu_domain for
+ * @immediate_attach: True if idev should be attached to the hwpt
*
- * Allocate a new iommu_domain and return it as a hw_pagetable.
+ * Allocate a new iommu_domain and return it as a hw_pagetable. The HWPT
+ * will be linked to the given ioas and upon return the underlying iommu_domain
+ * is fully popoulated.
*/
struct iommufd_hw_pagetable *
iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
- struct device *dev)
+ struct iommufd_device *idev, bool immediate_attach)
{
struct iommufd_hw_pagetable *hwpt;
int rc;
+ lockdep_assert_held(&ioas->mutex);
+
hwpt = iommufd_object_alloc(ictx, hwpt, IOMMUFD_OBJ_HW_PAGETABLE);
if (IS_ERR(hwpt))
return hwpt;
@@ -54,14 +59,46 @@ iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
refcount_inc(&ioas->obj.users);
hwpt->ioas = ioas;
- hwpt->domain = iommu_domain_alloc(dev->bus);
+ hwpt->domain = iommu_domain_alloc(idev->dev->bus);
if (!hwpt->domain) {
rc = -ENOMEM;
goto out_abort;
}
+ mutex_lock(&hwpt->devices_lock);
+
+ /*
+ * 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
+ * sequence. Once those drivers are fixed this should be removed.
+ */
+ if (immediate_attach) {
+ rc = iommufd_hw_pagetable_attach(hwpt, idev);
+ if (rc)
+ goto out_unlock;
+ }
+
+ rc = iopt_table_add_domain(&hwpt->ioas->iopt, hwpt->domain);
+ if (rc)
+ goto out_detach;
+ list_add_tail(&hwpt->hwpt_item, &hwpt->ioas->hwpt_list);
+
+ if (immediate_attach) {
+ /* See iommufd_device_do_attach() */
+ refcount_inc(&hwpt->obj.users);
+ idev->hwpt = hwpt;
+ list_add(&idev->devices_item, &hwpt->devices);
+ }
+
+ mutex_unlock(&hwpt->devices_lock);
return hwpt;
+out_detach:
+ if (immediate_attach)
+ iommufd_hw_pagetable_detach(hwpt, idev);
+out_unlock:
+ mutex_unlock(&hwpt->devices_lock);
out_abort:
iommufd_object_abort_and_destroy(ictx, &hwpt->obj);
return ERR_PTR(rc);