From: Nicolin Chen nicolinc@nvidia.com
When using a 2-stage nested hw_pagetable (hwpt) setup, the IOVA mappings or SW MSI are at the stage-2 hwpt, while the device will be attached to a stage-1 hwpt. And then the current do_attach() flow will fail to set up MSI, since it always uses the attaching hwpt pointer (i.e. stage-1 in such case).
As a preparatory change for the following nesting support patch, move all related operations into a pair of separate functions, so we only need to redirect the hwpt pointer to its stage-2 hwpt, when using a nested setup.
Signed-off-by: Nicolin Chen nicolinc@nvidia.com Signed-off-by: Yi Liu yi.l.liu@intel.com --- drivers/iommu/iommufd/device.c | 40 +++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-)
diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c index dd7943ff02e4..cdc4ab36f52d 100644 --- a/drivers/iommu/iommufd/device.c +++ b/drivers/iommu/iommufd/device.c @@ -294,6 +294,36 @@ static bool iommufd_hw_pagetable_has_group(struct iommufd_hw_pagetable *hwpt, return false; }
+static int iommufd_device_attach_ioas(struct iommufd_device *idev, + struct iommufd_hw_pagetable *hwpt) +{ + phys_addr_t sw_msi_start = PHYS_ADDR_MAX; + struct io_pagetable *iopt; + int rc; + + iopt = &hwpt->ioas->iopt; + + rc = iopt_table_enforce_group_resv_regions(iopt, idev->dev, + idev->group, &sw_msi_start); + if (rc) + return rc; + + rc = iommufd_device_setup_msi(idev, hwpt, sw_msi_start); + if (rc) + goto out_iova; + + return 0; +out_iova: + iopt_remove_reserved_iova(iopt, idev->group); + return rc; +} + +static void iommufd_device_detach_ioas(struct iommufd_device *idev, + struct iommufd_hw_pagetable *hwpt) +{ + iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev); +} + /** * __iommmufd_device_detach - Detach a device from idev->hwpt to new_hwpt * @idev: device to detach @@ -323,7 +353,7 @@ static void __iommmufd_device_detach(struct iommufd_device *idev,
if (hwpt->ioas != new_ioas) { mutex_lock(&hwpt->ioas->mutex); - iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev); + iommufd_device_detach_ioas(idev, hwpt); mutex_unlock(&hwpt->ioas->mutex); } mutex_unlock(&hwpt->devices_lock); @@ -342,7 +372,6 @@ static int iommufd_device_do_attach(struct iommufd_device *idev, struct iommufd_hw_pagetable *hwpt) { struct iommufd_hw_pagetable *cur_hwpt = idev->hwpt; - phys_addr_t sw_msi_start = PHYS_ADDR_MAX; int rc;
lockdep_assert_held(&hwpt->ioas->mutex); @@ -367,15 +396,10 @@ static int iommufd_device_do_attach(struct iommufd_device *idev, } }
- rc = iopt_table_enforce_group_resv_regions(&hwpt->ioas->iopt, idev->dev, - idev->group, &sw_msi_start); + rc = iommufd_device_attach_ioas(idev, hwpt); if (rc) goto out_unlock;
- rc = iommufd_device_setup_msi(idev, hwpt, sw_msi_start); - if (rc) - goto out_iova; - /* * FIXME: Hack around missing a device-centric iommu api, only attach to * the group once for the first device that is in the group.