Skip to content

Commit

Permalink
iommufd/device: Enforce reserved IOVA also when attached to hwpt_nested
Browse files Browse the repository at this point in the history
Currently, device reserved regions are only enforced when the device is
attached to an hwpt_paging. In other words, if the device gets attached to
an hwpt_nested directly, the parent hwpt_paging of the hwpt_nested's would
not enforce those reserved IOVAs. This works for most of reserved region
types, but not for IOMMU_RESV_SW_MSI, which is a unique software defined
window, required by a nesting case too to setup an MSI doorbell on the
parent stage-2 hwpt/domain.

Kevin pointed out in 1 that:
1) there is no usage using up closely the entire IOVA space yet,

2) guest may change the viommu mode to switch between nested and paging
   then VMM has to take all devices' reserved regions into consideration
   anyway, when composing the GPA space.

So it would be actually convenient for us to also enforce reserved IOVA
onto the parent hwpt_paging, when attaching a device to an hwpt_nested.

Repurpose the existing attach/replace_paging helpers to attach device's
reserved IOVAs exclusively.

Add a new find_hwpt_paging helper, which is only used by these reserved
IOVA functions, to allow an IOMMUFD_OBJ_HWPT_NESTED hwpt to redirect to
its parent hwpt_paging. Return a NULL in these two helpers for any new
HWPT type in the future.

Link: https://patch.msgid.link/r/[email protected]
Link: https://lore.kernel.org/all/BN9PR11MB5276497781C96415272E6FED8CB12@BN9PR11MB5276.namprd11.prod.outlook.com/ #1
Suggested-by: Kevin Tian <[email protected]>
Signed-off-by: Nicolin Chen <[email protected]>
Reviewed-by: Kevin Tian <[email protected]>
Signed-off-by: Jason Gunthorpe <[email protected]>
  • Loading branch information
nicolinc authored and jgunthorpe committed Aug 27, 2024
1 parent 5be63fc commit b2f4481
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 26 deletions.
52 changes: 26 additions & 26 deletions drivers/iommu/iommufd/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,9 @@ static int iommufd_group_setup_msi(struct iommufd_group *igroup,
return 0;
}

static int iommufd_hwpt_paging_attach(struct iommufd_hwpt_paging *hwpt_paging,
struct iommufd_device *idev)
static int
iommufd_device_attach_reserved_iova(struct iommufd_device *idev,
struct iommufd_hwpt_paging *hwpt_paging)
{
int rc;

Expand All @@ -354,6 +355,7 @@ static int iommufd_hwpt_paging_attach(struct iommufd_hwpt_paging *hwpt_paging,
int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
struct iommufd_device *idev)
{
struct iommufd_hwpt_paging *hwpt_paging = find_hwpt_paging(hwpt);
int rc;

mutex_lock(&idev->igroup->lock);
Expand All @@ -363,8 +365,8 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
goto err_unlock;
}

if (hwpt_is_paging(hwpt)) {
rc = iommufd_hwpt_paging_attach(to_hwpt_paging(hwpt), idev);
if (hwpt_paging) {
rc = iommufd_device_attach_reserved_iova(idev, hwpt_paging);
if (rc)
goto err_unlock;
}
Expand All @@ -387,9 +389,8 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
mutex_unlock(&idev->igroup->lock);
return 0;
err_unresv:
if (hwpt_is_paging(hwpt))
iopt_remove_reserved_iova(&to_hwpt_paging(hwpt)->ioas->iopt,
idev->dev);
if (hwpt_paging)
iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, idev->dev);
err_unlock:
mutex_unlock(&idev->igroup->lock);
return rc;
Expand All @@ -399,16 +400,16 @@ struct iommufd_hw_pagetable *
iommufd_hw_pagetable_detach(struct iommufd_device *idev)
{
struct iommufd_hw_pagetable *hwpt = idev->igroup->hwpt;
struct iommufd_hwpt_paging *hwpt_paging = find_hwpt_paging(hwpt);

mutex_lock(&idev->igroup->lock);
list_del(&idev->group_item);
if (list_empty(&idev->igroup->device_list)) {
iommufd_hwpt_detach_device(hwpt, idev);
idev->igroup->hwpt = NULL;
}
if (hwpt_is_paging(hwpt))
iopt_remove_reserved_iova(&to_hwpt_paging(hwpt)->ioas->iopt,
idev->dev);
if (hwpt_paging)
iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, idev->dev);
mutex_unlock(&idev->igroup->lock);

/* Caller must destroy hwpt */
Expand Down Expand Up @@ -440,17 +441,17 @@ iommufd_group_remove_reserved_iova(struct iommufd_group *igroup,
}

static int
iommufd_group_do_replace_paging(struct iommufd_group *igroup,
struct iommufd_hwpt_paging *hwpt_paging)
iommufd_group_do_replace_reserved_iova(struct iommufd_group *igroup,
struct iommufd_hwpt_paging *hwpt_paging)
{
struct iommufd_hw_pagetable *old_hwpt = igroup->hwpt;
struct iommufd_hwpt_paging *old_hwpt_paging;
struct iommufd_device *cur;
int rc;

lockdep_assert_held(&igroup->lock);

if (!hwpt_is_paging(old_hwpt) ||
hwpt_paging->ioas != to_hwpt_paging(old_hwpt)->ioas) {
old_hwpt_paging = find_hwpt_paging(igroup->hwpt);
if (!old_hwpt_paging || hwpt_paging->ioas != old_hwpt_paging->ioas) {
list_for_each_entry(cur, &igroup->device_list, group_item) {
rc = iopt_table_enforce_dev_resv_regions(
&hwpt_paging->ioas->iopt, cur->dev, NULL);
Expand All @@ -473,6 +474,8 @@ static struct iommufd_hw_pagetable *
iommufd_device_do_replace(struct iommufd_device *idev,
struct iommufd_hw_pagetable *hwpt)
{
struct iommufd_hwpt_paging *hwpt_paging = find_hwpt_paging(hwpt);
struct iommufd_hwpt_paging *old_hwpt_paging;
struct iommufd_group *igroup = idev->igroup;
struct iommufd_hw_pagetable *old_hwpt;
unsigned int num_devices;
Expand All @@ -491,9 +494,8 @@ iommufd_device_do_replace(struct iommufd_device *idev,
}

old_hwpt = igroup->hwpt;
if (hwpt_is_paging(hwpt)) {
rc = iommufd_group_do_replace_paging(igroup,
to_hwpt_paging(hwpt));
if (hwpt_paging) {
rc = iommufd_group_do_replace_reserved_iova(igroup, hwpt_paging);
if (rc)
goto err_unlock;
}
Expand All @@ -502,11 +504,10 @@ iommufd_device_do_replace(struct iommufd_device *idev,
if (rc)
goto err_unresv;

if (hwpt_is_paging(old_hwpt) &&
(!hwpt_is_paging(hwpt) ||
to_hwpt_paging(hwpt)->ioas != to_hwpt_paging(old_hwpt)->ioas))
iommufd_group_remove_reserved_iova(igroup,
to_hwpt_paging(old_hwpt));
old_hwpt_paging = find_hwpt_paging(old_hwpt);
if (old_hwpt_paging &&
(!hwpt_paging || hwpt_paging->ioas != old_hwpt_paging->ioas))
iommufd_group_remove_reserved_iova(igroup, old_hwpt_paging);

igroup->hwpt = hwpt;

Expand All @@ -524,9 +525,8 @@ iommufd_device_do_replace(struct iommufd_device *idev,
/* Caller must destroy old_hwpt */
return old_hwpt;
err_unresv:
if (hwpt_is_paging(hwpt))
iommufd_group_remove_reserved_iova(igroup,
to_hwpt_paging(hwpt));
if (hwpt_paging)
iommufd_group_remove_reserved_iova(igroup, hwpt_paging);
err_unlock:
mutex_unlock(&idev->igroup->lock);
return ERR_PTR(rc);
Expand Down
19 changes: 19 additions & 0 deletions drivers/iommu/iommufd/iommufd_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,25 @@ to_hwpt_paging(struct iommufd_hw_pagetable *hwpt)
return container_of(hwpt, struct iommufd_hwpt_paging, common);
}

static inline struct iommufd_hwpt_nested *
to_hwpt_nested(struct iommufd_hw_pagetable *hwpt)
{
return container_of(hwpt, struct iommufd_hwpt_nested, common);
}

static inline struct iommufd_hwpt_paging *
find_hwpt_paging(struct iommufd_hw_pagetable *hwpt)
{
switch (hwpt->obj.type) {
case IOMMUFD_OBJ_HWPT_PAGING:
return to_hwpt_paging(hwpt);
case IOMMUFD_OBJ_HWPT_NESTED:
return to_hwpt_nested(hwpt)->parent;
default:
return NULL;
}
}

static inline struct iommufd_hwpt_paging *
iommufd_get_hwpt_paging(struct iommufd_ucmd *ucmd, u32 id)
{
Expand Down

0 comments on commit b2f4481

Please sign in to comment.