mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 14:21:47 +00:00
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.com Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Yi Liu <yi.l.liu@intel.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
parent
9744a7ab62
commit
58d84f430d
@ -325,6 +325,28 @@ static int iommufd_group_setup_msi(struct iommufd_group *igroup,
|
||||
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,
|
||||
struct iommufd_device *idev)
|
||||
{
|
||||
@ -337,10 +359,11 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
rc = iopt_table_enforce_dev_resv_regions(&hwpt->ioas->iopt, idev->dev,
|
||||
&idev->igroup->sw_msi_start);
|
||||
if (rc)
|
||||
goto err_unlock;
|
||||
if (hwpt_is_paging(hwpt)) {
|
||||
rc = iommufd_hwpt_paging_attach(hwpt, idev);
|
||||
if (rc)
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
* attachment.
|
||||
*/
|
||||
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);
|
||||
if (rc)
|
||||
goto err_unresv;
|
||||
@ -364,7 +383,8 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
|
||||
mutex_unlock(&idev->igroup->lock);
|
||||
return 0;
|
||||
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:
|
||||
mutex_unlock(&idev->igroup->lock);
|
||||
return rc;
|
||||
@ -381,7 +401,8 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev)
|
||||
iommu_detach_group(hwpt->domain, idev->igroup->group);
|
||||
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);
|
||||
|
||||
/* Caller must destroy hwpt */
|
||||
@ -400,13 +421,52 @@ iommufd_device_do_attach(struct iommufd_device *idev,
|
||||
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 *
|
||||
iommufd_device_do_replace(struct iommufd_device *idev,
|
||||
struct iommufd_hw_pagetable *hwpt)
|
||||
{
|
||||
struct iommufd_group *igroup = idev->igroup;
|
||||
struct iommufd_hw_pagetable *old_hwpt;
|
||||
struct iommufd_device *cur;
|
||||
unsigned int num_devices;
|
||||
int rc;
|
||||
|
||||
@ -422,29 +482,20 @@ iommufd_device_do_replace(struct iommufd_device *idev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
old_hwpt = igroup->hwpt;
|
||||
if (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;
|
||||
}
|
||||
if (hwpt_is_paging(hwpt)) {
|
||||
rc = iommufd_group_do_replace_paging(igroup, hwpt);
|
||||
if (rc)
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
rc = iommufd_group_setup_msi(idev->igroup, hwpt);
|
||||
if (rc)
|
||||
goto err_unresv;
|
||||
|
||||
rc = iommu_group_replace_domain(igroup->group, hwpt->domain);
|
||||
if (rc)
|
||||
goto err_unresv;
|
||||
|
||||
if (hwpt->ioas != old_hwpt->ioas) {
|
||||
list_for_each_entry(cur, &igroup->device_list, group_item)
|
||||
iopt_remove_reserved_iova(&old_hwpt->ioas->iopt,
|
||||
cur->dev);
|
||||
}
|
||||
old_hwpt = igroup->hwpt;
|
||||
if (hwpt_is_paging(old_hwpt) &&
|
||||
(!hwpt_is_paging(hwpt) || hwpt->ioas != old_hwpt->ioas))
|
||||
iommufd_group_remove_reserved_iova(igroup, old_hwpt);
|
||||
|
||||
igroup->hwpt = hwpt;
|
||||
|
||||
@ -462,8 +513,8 @@ iommufd_device_do_replace(struct iommufd_device *idev,
|
||||
/* Caller must destroy old_hwpt */
|
||||
return old_hwpt;
|
||||
err_unresv:
|
||||
list_for_each_entry(cur, &igroup->device_list, group_item)
|
||||
iopt_remove_reserved_iova(&hwpt->ioas->iopt, cur->dev);
|
||||
if (hwpt_is_paging(hwpt))
|
||||
iommufd_group_remove_reserved_iova(igroup, hwpt);
|
||||
err_unlock:
|
||||
mutex_unlock(&idev->igroup->lock);
|
||||
return ERR_PTR(rc);
|
||||
|
@ -252,6 +252,11 @@ struct iommufd_hw_pagetable {
|
||||
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 *
|
||||
iommufd_get_hwpt(struct iommufd_ucmd *ucmd, u32 id)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user