Commit fb21b156 authored by Nicolin Chen's avatar Nicolin Chen Committed by Jason Gunthorpe
Browse files

iommufd: Make attach_handle generic than fault specific

"attach_handle" was added exclusively for the iommufd_fault_iopf_handler()
used by IOPF/PRI use cases. Now, both the MSI and PASID series require to
reuse the attach_handle for non-fault cases.

Add a set of new attach/detach/replace helpers that does the attach_handle
allocation/releasing/replacement in the common path and also handles those
fault specific routines such as iopf enabling/disabling and auto response.

This covers both non-fault and fault cases in a clean way, replacing those
inline helpers in the header. The following patch will clean up those old
helpers in the fault.c file.

Link: https://patch.msgid.link/r/32687df01c02291d89986a9fca897bbbe2b10987.1738645017.git.nicolinc@nvidia.com


Signed-off-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Reviewed-by: default avatarYi Liu <yi.l.liu@intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent a64dcfb4
Loading
Loading
Loading
Loading
+105 −0
Original line number Diff line number Diff line
@@ -352,6 +352,111 @@ iommufd_device_attach_reserved_iova(struct iommufd_device *idev,
	return 0;
}

/* The device attach/detach/replace helpers for attach_handle */

static int iommufd_hwpt_attach_device(struct iommufd_hw_pagetable *hwpt,
				      struct iommufd_device *idev)
{
	struct iommufd_attach_handle *handle;
	int rc;

	lockdep_assert_held(&idev->igroup->lock);

	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
	if (!handle)
		return -ENOMEM;

	if (hwpt->fault) {
		rc = iommufd_fault_iopf_enable(idev);
		if (rc)
			goto out_free_handle;
	}

	handle->idev = idev;
	rc = iommu_attach_group_handle(hwpt->domain, idev->igroup->group,
				       &handle->handle);
	if (rc)
		goto out_disable_iopf;

	return 0;

out_disable_iopf:
	if (hwpt->fault)
		iommufd_fault_iopf_disable(idev);
out_free_handle:
	kfree(handle);
	return rc;
}

static struct iommufd_attach_handle *
iommufd_device_get_attach_handle(struct iommufd_device *idev)
{
	struct iommu_attach_handle *handle;

	lockdep_assert_held(&idev->igroup->lock);

	handle =
		iommu_attach_handle_get(idev->igroup->group, IOMMU_NO_PASID, 0);
	if (IS_ERR(handle))
		return NULL;
	return to_iommufd_handle(handle);
}

static void iommufd_hwpt_detach_device(struct iommufd_hw_pagetable *hwpt,
				       struct iommufd_device *idev)
{
	struct iommufd_attach_handle *handle;

	handle = iommufd_device_get_attach_handle(idev);
	iommu_detach_group_handle(hwpt->domain, idev->igroup->group);
	if (hwpt->fault) {
		iommufd_auto_response_faults(hwpt, handle);
		iommufd_fault_iopf_disable(idev);
	}
	kfree(handle);
}

static int iommufd_hwpt_replace_device(struct iommufd_device *idev,
				       struct iommufd_hw_pagetable *hwpt,
				       struct iommufd_hw_pagetable *old)
{
	struct iommufd_attach_handle *handle, *old_handle =
		iommufd_device_get_attach_handle(idev);
	int rc;

	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
	if (!handle)
		return -ENOMEM;

	if (hwpt->fault && !old->fault) {
		rc = iommufd_fault_iopf_enable(idev);
		if (rc)
			goto out_free_handle;
	}

	handle->idev = idev;
	rc = iommu_replace_group_handle(idev->igroup->group, hwpt->domain,
					&handle->handle);
	if (rc)
		goto out_disable_iopf;

	if (old->fault) {
		iommufd_auto_response_faults(hwpt, old_handle);
		if (!hwpt->fault)
			iommufd_fault_iopf_disable(idev);
	}
	kfree(old_handle);

	return 0;

out_disable_iopf:
	if (hwpt->fault && !old->fault)
		iommufd_fault_iopf_disable(idev);
out_free_handle:
	kfree(handle);
	return rc;
}

int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
				struct iommufd_device *idev)
{
+4 −4
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
#include "../iommu-priv.h"
#include "iommufd_private.h"

static int iommufd_fault_iopf_enable(struct iommufd_device *idev)
int iommufd_fault_iopf_enable(struct iommufd_device *idev)
{
	struct device *dev = idev->dev;
	int ret;
@@ -50,7 +50,7 @@ static int iommufd_fault_iopf_enable(struct iommufd_device *idev)
	return ret;
}

static void iommufd_fault_iopf_disable(struct iommufd_device *idev)
void iommufd_fault_iopf_disable(struct iommufd_device *idev)
{
	mutex_lock(&idev->iopf_lock);
	if (!WARN_ON(idev->iopf_enabled == 0)) {
@@ -98,7 +98,7 @@ int iommufd_fault_domain_attach_dev(struct iommufd_hw_pagetable *hwpt,
	return ret;
}

static void iommufd_auto_response_faults(struct iommufd_hw_pagetable *hwpt,
void iommufd_auto_response_faults(struct iommufd_hw_pagetable *hwpt,
				  struct iommufd_attach_handle *handle)
{
	struct iommufd_fault *fault = hwpt->fault;
+4 −29
Original line number Diff line number Diff line
@@ -504,35 +504,10 @@ int iommufd_fault_domain_replace_dev(struct iommufd_device *idev,
				     struct iommufd_hw_pagetable *hwpt,
				     struct iommufd_hw_pagetable *old);

static inline int iommufd_hwpt_attach_device(struct iommufd_hw_pagetable *hwpt,
					     struct iommufd_device *idev)
{
	if (hwpt->fault)
		return iommufd_fault_domain_attach_dev(hwpt, idev);

	return iommu_attach_group(hwpt->domain, idev->igroup->group);
}

static inline void iommufd_hwpt_detach_device(struct iommufd_hw_pagetable *hwpt,
					      struct iommufd_device *idev)
{
	if (hwpt->fault) {
		iommufd_fault_domain_detach_dev(hwpt, idev);
		return;
	}

	iommu_detach_group(hwpt->domain, idev->igroup->group);
}

static inline int iommufd_hwpt_replace_device(struct iommufd_device *idev,
					      struct iommufd_hw_pagetable *hwpt,
					      struct iommufd_hw_pagetable *old)
{
	if (old->fault || hwpt->fault)
		return iommufd_fault_domain_replace_dev(idev, hwpt, old);

	return iommu_group_replace_domain(idev->igroup->group, hwpt->domain);
}
int iommufd_fault_iopf_enable(struct iommufd_device *idev);
void iommufd_fault_iopf_disable(struct iommufd_device *idev);
void iommufd_auto_response_faults(struct iommufd_hw_pagetable *hwpt,
				  struct iommufd_attach_handle *handle);

static inline struct iommufd_viommu *
iommufd_get_viommu(struct iommufd_ucmd *ucmd, u32 id)