Commit 58d84f43 authored by Jason Gunthorpe's avatar Jason Gunthorpe

iommufd/device: Wrap IOMMUFD_OBJ_HWPT_PAGING-only configurations

Some of the configurations during the attach/replace() should only apply
to IOMMUFD_OBJ_HWPT_PAGING. Once IOMMUFD_OBJ_HWPT_NESTED gets introduced
in a following patch, keeping them unconditionally in the common routine
will not work.

Wrap all of those PAGING-only configurations together into helpers. Do a
hwpt_is_paging check whenever calling them or their fallback routines.

Link: https://lore.kernel.org/r/20231026043938.63898-4-yi.l.liu@intel.comSigned-off-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarYi Liu <yi.l.liu@intel.com>
Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 9744a7ab
...@@ -325,6 +325,28 @@ static int iommufd_group_setup_msi(struct iommufd_group *igroup, ...@@ -325,6 +325,28 @@ static int iommufd_group_setup_msi(struct iommufd_group *igroup,
return 0; return 0;
} }
static int iommufd_hwpt_paging_attach(struct iommufd_hw_pagetable *hwpt,
struct iommufd_device *idev)
{
int rc;
lockdep_assert_held(&idev->igroup->lock);
rc = iopt_table_enforce_dev_resv_regions(&hwpt->ioas->iopt, idev->dev,
&idev->igroup->sw_msi_start);
if (rc)
return rc;
if (list_empty(&idev->igroup->device_list)) {
rc = iommufd_group_setup_msi(idev->igroup, hwpt);
if (rc) {
iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
return rc;
}
}
return 0;
}
int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt, int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
struct iommufd_device *idev) struct iommufd_device *idev)
{ {
...@@ -337,10 +359,11 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt, ...@@ -337,10 +359,11 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
goto err_unlock; goto err_unlock;
} }
rc = iopt_table_enforce_dev_resv_regions(&hwpt->ioas->iopt, idev->dev, if (hwpt_is_paging(hwpt)) {
&idev->igroup->sw_msi_start); rc = iommufd_hwpt_paging_attach(hwpt, idev);
if (rc) if (rc)
goto err_unlock; goto err_unlock;
}
/* /*
* Only attach to the group once for the first device that is in the * Only attach to the group once for the first device that is in the
...@@ -350,10 +373,6 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt, ...@@ -350,10 +373,6 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
* attachment. * attachment.
*/ */
if (list_empty(&idev->igroup->device_list)) { if (list_empty(&idev->igroup->device_list)) {
rc = iommufd_group_setup_msi(idev->igroup, hwpt);
if (rc)
goto err_unresv;
rc = iommu_attach_group(hwpt->domain, idev->igroup->group); rc = iommu_attach_group(hwpt->domain, idev->igroup->group);
if (rc) if (rc)
goto err_unresv; goto err_unresv;
...@@ -364,7 +383,8 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt, ...@@ -364,7 +383,8 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
mutex_unlock(&idev->igroup->lock); mutex_unlock(&idev->igroup->lock);
return 0; return 0;
err_unresv: err_unresv:
iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev); if (hwpt_is_paging(hwpt))
iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
err_unlock: err_unlock:
mutex_unlock(&idev->igroup->lock); mutex_unlock(&idev->igroup->lock);
return rc; return rc;
...@@ -381,7 +401,8 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev) ...@@ -381,7 +401,8 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev)
iommu_detach_group(hwpt->domain, idev->igroup->group); iommu_detach_group(hwpt->domain, idev->igroup->group);
idev->igroup->hwpt = NULL; idev->igroup->hwpt = NULL;
} }
iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev); if (hwpt_is_paging(hwpt))
iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
mutex_unlock(&idev->igroup->lock); mutex_unlock(&idev->igroup->lock);
/* Caller must destroy hwpt */ /* Caller must destroy hwpt */
...@@ -400,13 +421,52 @@ iommufd_device_do_attach(struct iommufd_device *idev, ...@@ -400,13 +421,52 @@ iommufd_device_do_attach(struct iommufd_device *idev,
return NULL; return NULL;
} }
static void
iommufd_group_remove_reserved_iova(struct iommufd_group *igroup,
struct iommufd_hw_pagetable *hwpt)
{
struct iommufd_device *cur;
lockdep_assert_held(&igroup->lock);
list_for_each_entry(cur, &igroup->device_list, group_item)
iopt_remove_reserved_iova(&hwpt->ioas->iopt, cur->dev);
}
static int iommufd_group_do_replace_paging(struct iommufd_group *igroup,
struct iommufd_hw_pagetable *hwpt)
{
struct iommufd_hw_pagetable *old_hwpt = igroup->hwpt;
struct iommufd_device *cur;
int rc;
lockdep_assert_held(&igroup->lock);
if (!hwpt_is_paging(old_hwpt) || hwpt->ioas != old_hwpt->ioas) {
list_for_each_entry(cur, &igroup->device_list, group_item) {
rc = iopt_table_enforce_dev_resv_regions(
&hwpt->ioas->iopt, cur->dev, NULL);
if (rc)
goto err_unresv;
}
}
rc = iommufd_group_setup_msi(igroup, hwpt);
if (rc)
goto err_unresv;
return 0;
err_unresv:
iommufd_group_remove_reserved_iova(igroup, hwpt);
return rc;
}
static struct iommufd_hw_pagetable * static struct iommufd_hw_pagetable *
iommufd_device_do_replace(struct iommufd_device *idev, iommufd_device_do_replace(struct iommufd_device *idev,
struct iommufd_hw_pagetable *hwpt) struct iommufd_hw_pagetable *hwpt)
{ {
struct iommufd_group *igroup = idev->igroup; struct iommufd_group *igroup = idev->igroup;
struct iommufd_hw_pagetable *old_hwpt; struct iommufd_hw_pagetable *old_hwpt;
struct iommufd_device *cur;
unsigned int num_devices; unsigned int num_devices;
int rc; int rc;
...@@ -422,29 +482,20 @@ iommufd_device_do_replace(struct iommufd_device *idev, ...@@ -422,29 +482,20 @@ iommufd_device_do_replace(struct iommufd_device *idev,
return NULL; return NULL;
} }
old_hwpt = igroup->hwpt; if (hwpt_is_paging(hwpt)) {
if (hwpt->ioas != old_hwpt->ioas) { rc = iommufd_group_do_replace_paging(igroup, hwpt);
list_for_each_entry(cur, &igroup->device_list, group_item) { if (rc)
rc = iopt_table_enforce_dev_resv_regions( goto err_unlock;
&hwpt->ioas->iopt, cur->dev, NULL);
if (rc)
goto err_unresv;
}
} }
rc = iommufd_group_setup_msi(idev->igroup, hwpt);
if (rc)
goto err_unresv;
rc = iommu_group_replace_domain(igroup->group, hwpt->domain); rc = iommu_group_replace_domain(igroup->group, hwpt->domain);
if (rc) if (rc)
goto err_unresv; goto err_unresv;
if (hwpt->ioas != old_hwpt->ioas) { old_hwpt = igroup->hwpt;
list_for_each_entry(cur, &igroup->device_list, group_item) if (hwpt_is_paging(old_hwpt) &&
iopt_remove_reserved_iova(&old_hwpt->ioas->iopt, (!hwpt_is_paging(hwpt) || hwpt->ioas != old_hwpt->ioas))
cur->dev); iommufd_group_remove_reserved_iova(igroup, old_hwpt);
}
igroup->hwpt = hwpt; igroup->hwpt = hwpt;
...@@ -462,8 +513,8 @@ iommufd_device_do_replace(struct iommufd_device *idev, ...@@ -462,8 +513,8 @@ iommufd_device_do_replace(struct iommufd_device *idev,
/* Caller must destroy old_hwpt */ /* Caller must destroy old_hwpt */
return old_hwpt; return old_hwpt;
err_unresv: err_unresv:
list_for_each_entry(cur, &igroup->device_list, group_item) if (hwpt_is_paging(hwpt))
iopt_remove_reserved_iova(&hwpt->ioas->iopt, cur->dev); iommufd_group_remove_reserved_iova(igroup, hwpt);
err_unlock: err_unlock:
mutex_unlock(&idev->igroup->lock); mutex_unlock(&idev->igroup->lock);
return ERR_PTR(rc); return ERR_PTR(rc);
......
...@@ -252,6 +252,11 @@ struct iommufd_hw_pagetable { ...@@ -252,6 +252,11 @@ struct iommufd_hw_pagetable {
struct list_head hwpt_item; struct list_head hwpt_item;
}; };
static inline bool hwpt_is_paging(struct iommufd_hw_pagetable *hwpt)
{
return hwpt->obj.type == IOMMUFD_OBJ_HWPT_PAGING;
}
static inline struct iommufd_hw_pagetable * static inline struct iommufd_hw_pagetable *
iommufd_get_hwpt(struct iommufd_ucmd *ucmd, u32 id) iommufd_get_hwpt(struct iommufd_ucmd *ucmd, u32 id)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment