Nested translation has stage-1 and stage-2 hw_pagetables, and both needs userspace to allocate. Stage-1 hw_pagetable needs to work with a stage-2 hw_pagetable. This adds a parent pointer in struct iommufd_hw_pagetable to link stage-1 hw_pagetable with a stage-2 hw_pagetable. Hence iommufd core can accept user-managed hw_pagetable allocation request. Signed-off-by: Nicolin Chen <nicolinc@xxxxxxxxxx> Signed-off-by: Yi Liu <yi.l.liu@xxxxxxxxx> --- drivers/iommu/iommufd/device.c | 5 +++++ drivers/iommu/iommufd/hw_pagetable.c | 21 +++++++++++++++------ drivers/iommu/iommufd/iommufd_private.h | 1 + 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c index cdc4ab36f52d..6d948fa418d5 100644 --- a/drivers/iommu/iommufd/device.c +++ b/drivers/iommu/iommufd/device.c @@ -301,6 +301,9 @@ static int iommufd_device_attach_ioas(struct iommufd_device *idev, struct io_pagetable *iopt; int rc; + if (hwpt->parent) + hwpt = hwpt->parent; + iopt = &hwpt->ioas->iopt; rc = iopt_table_enforce_group_resv_regions(iopt, idev->dev, @@ -321,6 +324,8 @@ static int iommufd_device_attach_ioas(struct iommufd_device *idev, static void iommufd_device_detach_ioas(struct iommufd_device *idev, struct iommufd_hw_pagetable *hwpt) { + if (hwpt->parent) + hwpt = hwpt->parent; iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev); } diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c index 998d01490a74..02dee8e8d958 100644 --- a/drivers/iommu/iommufd/hw_pagetable.c +++ b/drivers/iommu/iommufd/hw_pagetable.c @@ -15,8 +15,12 @@ void iommufd_hw_pagetable_destroy(struct iommufd_object *obj) WARN_ON(!list_empty(&hwpt->devices)); - iopt_table_remove_domain(&hwpt->ioas->iopt, hwpt->domain); - list_del(&hwpt->hwpt_item); + if (!hwpt->parent) { + iopt_table_remove_domain(&hwpt->ioas->iopt, hwpt->domain); + list_del(&hwpt->hwpt_item); + } else { + refcount_dec(&hwpt->parent->obj.users); + } iommu_domain_free(hwpt->domain); refcount_dec(&hwpt->ioas->obj.users); mutex_destroy(&hwpt->devices_lock); @@ -58,13 +62,18 @@ __iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, goto out_abort; } + hwpt->parent = parent; INIT_LIST_HEAD(&hwpt->devices); INIT_LIST_HEAD(&hwpt->hwpt_item); mutex_init(&hwpt->devices_lock); - rc = iopt_table_add_domain(&ioas->iopt, hwpt->domain); - if (rc) - goto out_free_domain; - list_add_tail(&hwpt->hwpt_item, &ioas->hwpt_list); + if (!parent) { + rc = iopt_table_add_domain(&ioas->iopt, hwpt->domain); + if (rc) + goto out_free_domain; + list_add_tail(&hwpt->hwpt_item, &ioas->hwpt_list); + } else { + refcount_inc(&parent->obj.users); + } /* Pairs with iommufd_hw_pagetable_destroy() */ refcount_inc(&ioas->obj.users); diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h index ee5344baf135..5ef034451f4b 100644 --- a/drivers/iommu/iommufd/iommufd_private.h +++ b/drivers/iommu/iommufd/iommufd_private.h @@ -241,6 +241,7 @@ int iommufd_vfio_ioas(struct iommufd_ucmd *ucmd); */ struct iommufd_hw_pagetable { struct iommufd_object obj; + struct iommufd_hw_pagetable *parent; struct iommufd_ioas *ioas; struct iommu_domain *domain; bool auto_domain : 1; -- 2.34.1