Skip to content

Commit

Permalink
iommufd: Attach/detach hwpt to IOAS at alloc/destroy
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
  • Loading branch information
nicolinc committed Feb 1, 2023
1 parent 93c7547 commit 5ae54f3
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 48 deletions.
50 changes: 12 additions & 38 deletions drivers/iommu/iommufd/device.c
Expand Up @@ -329,13 +329,6 @@ static int iommufd_device_do_attach(struct iommufd_device *idev,
if (rc)
goto out_iova;

if (refcount_read(&hwpt->device_users) == 1) {
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 (cur_hwpt && hwpt) {
/* Replace the cur_hwpt */
refcount_dec(&cur_hwpt->obj.users);
Expand All @@ -347,11 +340,6 @@ static int iommufd_device_do_attach(struct iommufd_device *idev,
refcount_inc(&hwpt->device_users);
return 0;

out_detach:
if (cur_hwpt)
iommu_device_replace_domain(idev->dev, cur_hwpt->domain);
else
iommu_detach_group(hwpt->domain, idev->group);
out_iova:
iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
return rc;
Expand Down Expand Up @@ -401,10 +389,18 @@ static int iommufd_device_auto_get_domain(struct iommufd_device *idev,
if (rc)
goto out_abort;

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);
hwpt->iopt_attached = true;

mutex_unlock(&ioas->mutex);
iommufd_object_finalize(idev->ictx, &hwpt->obj);
return 0;

out_detach:
iommufd_device_detach(idev);
out_abort:
iommufd_object_abort_and_destroy(idev->ictx, &hwpt->obj);
out_unlock:
Expand Down Expand Up @@ -482,10 +478,6 @@ void iommufd_device_detach(struct iommufd_device *idev)

mutex_lock(&hwpt->ioas->mutex);
refcount_dec(&hwpt->device_users);
if (refcount_read(&hwpt->device_users) == 1) {
iopt_table_remove_domain(&hwpt->ioas->iopt, hwpt->domain);
list_del(&hwpt->hwpt_item);
}
iommu_detach_device(hwpt->domain, idev->dev);
iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
mutex_unlock(&hwpt->ioas->mutex);
Expand Down Expand Up @@ -902,35 +894,17 @@ EXPORT_SYMBOL_NS_GPL(iommufd_access_rw, IOMMUFD);
* Creating a real iommufd_device is too hard, bypass creating a iommufd_device
* and go directly to attaching a domain.
*/
struct iommufd_hw_pagetable *
iommufd_device_selftest_attach(struct iommufd_ctx *ictx,
struct iommufd_ioas *ioas,
struct device *mock_dev)
{
struct iommufd_hw_pagetable *hwpt;
int rc;

hwpt = iommufd_hw_pagetable_alloc(ictx, ioas, mock_dev);
if (IS_ERR(hwpt))
return hwpt;

rc = iopt_table_add_domain(&hwpt->ioas->iopt, hwpt->domain);
if (rc)
goto out_hwpt;

int iommufd_device_selftest_attach(struct iommufd_ctx *ictx,
struct iommufd_hw_pagetable *hwpt)
{
refcount_inc(&hwpt->obj.users);
iommufd_object_finalize(ictx, &hwpt->obj);
return hwpt;

out_hwpt:
iommufd_object_abort_and_destroy(ictx, &hwpt->obj);
return ERR_PTR(rc);
return 0;
}

void iommufd_device_selftest_detach(struct iommufd_ctx *ictx,
struct iommufd_hw_pagetable *hwpt)
{
iopt_table_remove_domain(&hwpt->ioas->iopt, hwpt->domain);
refcount_dec(&hwpt->obj.users);
}
#endif
17 changes: 15 additions & 2 deletions drivers/iommu/iommufd/hw_pagetable.c
Expand Up @@ -11,6 +11,11 @@ void iommufd_hw_pagetable_destroy(struct iommufd_object *obj)
struct iommufd_hw_pagetable *hwpt =
container_of(obj, struct iommufd_hw_pagetable, obj);

if (hwpt->iopt_attached) {
lockdep_assert_held(&hwpt->ioas->mutex);
iopt_table_remove_domain(&hwpt->ioas->iopt, hwpt->domain);
list_del(&hwpt->hwpt_item);
}
iommu_domain_free(hwpt->domain);
refcount_dec(&hwpt->ioas->obj.users);
WARN_ON(!refcount_dec_if_one(&hwpt->device_users));
Expand Down Expand Up @@ -166,12 +171,18 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)

mutex_lock(&ioas->mutex);
hwpt = __iommufd_hw_pagetable_alloc(ictx, ioas, dev, NULL, data);
mutex_unlock(&ioas->mutex);
if (IS_ERR(hwpt)) {
rc = PTR_ERR(hwpt);
goto out_free_data;
goto out_unlock;
}

rc = iopt_table_add_domain(&hwpt->ioas->iopt, hwpt->domain);
if (rc)
goto out_destroy_hwpt;
list_add_tail(&hwpt->hwpt_item, &hwpt->ioas->hwpt_list);
hwpt->iopt_attached = true;
mutex_unlock(&ioas->mutex);

cmd->out_hwpt_id = hwpt->obj.id;

rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
Expand All @@ -185,6 +196,8 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
return 0;
out_destroy_hwpt:
iommufd_object_abort_and_destroy(ucmd->ictx, &hwpt->obj);
out_unlock:
mutex_unlock(&ioas->mutex);
out_free_data:
kfree(data);
out_put_pt:
Expand Down
7 changes: 3 additions & 4 deletions drivers/iommu/iommufd/iommufd_private.h
Expand Up @@ -246,6 +246,7 @@ struct iommufd_hw_pagetable {
bool auto_domain : 1;
bool enforce_cache_coherency : 1;
bool msi_cookie : 1;
bool iopt_attached : 1;
/* Head at iommufd_ioas::hwpt_list */
struct list_head hwpt_item;
refcount_t device_users;
Expand Down Expand Up @@ -292,10 +293,8 @@ void iopt_remove_access(struct io_pagetable *iopt,
void iommufd_access_destroy_object(struct iommufd_object *obj);

#ifdef CONFIG_IOMMUFD_TEST
struct iommufd_hw_pagetable *
iommufd_device_selftest_attach(struct iommufd_ctx *ictx,
struct iommufd_ioas *ioas,
struct device *mock_dev);
int iommufd_device_selftest_attach(struct iommufd_ctx *ictx,
struct iommufd_hw_pagetable *hwpt);
void iommufd_device_selftest_detach(struct iommufd_ctx *ictx,
struct iommufd_hw_pagetable *hwpt);
struct device *iommufd_selftest_obj_to_dev(struct iommufd_object *obj);
Expand Down
26 changes: 22 additions & 4 deletions drivers/iommu/iommufd/selftest.c
Expand Up @@ -311,22 +311,40 @@ static int iommufd_test_mock_domain(struct iommufd_ucmd *ucmd,
sobj->idev.mock_dev.bus = &mock_bus;
sobj->idev.mock_dev.iommu = &iommu;

hwpt = iommufd_device_selftest_attach(ucmd->ictx, ioas,
&sobj->idev.mock_dev);
mutex_lock(&ioas->mutex);
hwpt = iommufd_hw_pagetable_alloc(ucmd->ictx, ioas,
&sobj->idev.mock_dev);
if (IS_ERR(hwpt)) {
rc = PTR_ERR(hwpt);
goto out_sobj;
goto out_unlock;
}
sobj->idev.hwpt = hwpt;

rc = iommufd_device_selftest_attach(ucmd->ictx, hwpt);
if (rc)
goto out_free_hwpt;

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);
hwpt->iopt_attached = true;
mutex_unlock(&ioas->mutex);

/* Userspace must destroy both of these IDs to destroy the object */
cmd->mock_domain.out_hwpt_id = hwpt->obj.id;
cmd->mock_domain.out_device_id = sobj->obj.id;
iommufd_object_finalize(ucmd->ictx, &sobj->obj);
iommufd_object_finalize(ucmd->ictx, &hwpt->obj);
iommufd_put_object(&ioas->obj);
return iommufd_ucmd_respond(ucmd, sizeof(*cmd));

out_sobj:
out_detach:
iommufd_device_selftest_detach(ucmd->ictx, hwpt);
out_free_hwpt:
iommufd_object_abort_and_destroy(ucmd->ictx, &hwpt->obj);
out_unlock:
mutex_unlock(&ioas->mutex);
iommufd_object_abort(ucmd->ictx, &sobj->obj);
out_ioas:
iommufd_put_object(&ioas->obj);
Expand Down

0 comments on commit 5ae54f3

Please sign in to comment.