339fbf3ae1
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>
106 lines
2.8 KiB
C
106 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
|
|
*/
|
|
#include <linux/iommu.h>
|
|
|
|
#include "iommufd_private.h"
|
|
|
|
void iommufd_hw_pagetable_destroy(struct iommufd_object *obj)
|
|
{
|
|
struct iommufd_hw_pagetable *hwpt =
|
|
container_of(obj, struct iommufd_hw_pagetable, obj);
|
|
|
|
WARN_ON(!list_empty(&hwpt->devices));
|
|
|
|
if (!list_empty(&hwpt->hwpt_item)) {
|
|
mutex_lock(&hwpt->ioas->mutex);
|
|
list_del(&hwpt->hwpt_item);
|
|
mutex_unlock(&hwpt->ioas->mutex);
|
|
|
|
iopt_table_remove_domain(&hwpt->ioas->iopt, hwpt->domain);
|
|
}
|
|
|
|
if (hwpt->domain)
|
|
iommu_domain_free(hwpt->domain);
|
|
|
|
refcount_dec(&hwpt->ioas->obj.users);
|
|
mutex_destroy(&hwpt->devices_lock);
|
|
}
|
|
|
|
/**
|
|
* iommufd_hw_pagetable_alloc() - Get an iommu_domain for a device
|
|
* @ictx: iommufd context
|
|
* @ioas: IOAS to associate the domain with
|
|
* @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. 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 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;
|
|
|
|
INIT_LIST_HEAD(&hwpt->devices);
|
|
INIT_LIST_HEAD(&hwpt->hwpt_item);
|
|
mutex_init(&hwpt->devices_lock);
|
|
/* Pairs with iommufd_hw_pagetable_destroy() */
|
|
refcount_inc(&ioas->obj.users);
|
|
hwpt->ioas = ioas;
|
|
|
|
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);
|
|
}
|