[PATCH v4 4/8] iommufd/selftest: Put iopf enablement in domain attach path

Lu Baolu posted 8 patches 11 months ago
There is a newer version of this series
[PATCH v4 4/8] iommufd/selftest: Put iopf enablement in domain attach path
Posted by Lu Baolu 11 months ago
Update iopf enablement in the iommufd mock device driver to use the new
method, similar to the arm-smmu-v3 driver. Enable iopf support when any
domain with an iopf_handler is attached, and disable it when the domain
is removed.

Add a refcount in the mock device state structure to keep track of the
number of domains set to the device and PASIDs that require iopf.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org>
---
 drivers/iommu/iommufd/selftest.c | 64 ++++++++++++++++++++++++++------
 1 file changed, 53 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c
index d40deb0a4f06..471af81e2617 100644
--- a/drivers/iommu/iommufd/selftest.c
+++ b/drivers/iommu/iommufd/selftest.c
@@ -58,6 +58,9 @@ enum {
 	MOCK_PFN_HUGE_IOVA = _MOCK_PFN_START << 2,
 };
 
+static int mock_dev_enable_iopf(struct device *dev, struct iommu_domain *domain);
+static void mock_dev_disable_iopf(struct device *dev, struct iommu_domain *domain);
+
 /*
  * Syzkaller has trouble randomizing the correct iova to use since it is linked
  * to the map ioctl's output, and it has no ide about that. So, simplify things.
@@ -164,6 +167,8 @@ struct mock_dev {
 	unsigned long flags;
 	int id;
 	u32 cache[MOCK_DEV_CACHE_NUM];
+	unsigned int iopf_refcount;
+	struct iommu_domain *domain;
 };
 
 static inline struct mock_dev *to_mock_dev(struct device *dev)
@@ -193,15 +198,34 @@ static int mock_domain_nop_attach(struct iommu_domain *domain,
 				  struct device *dev)
 {
 	struct mock_dev *mdev = to_mock_dev(dev);
+	int ret;
 
 	if (domain->dirty_ops && (mdev->flags & MOCK_FLAGS_DEVICE_NO_DIRTY))
 		return -EINVAL;
 
+	ret = mock_dev_enable_iopf(dev, domain);
+	if (ret)
+		return ret;
+
+	mock_dev_disable_iopf(dev, mdev->domain);
+	mdev->domain = domain;
+
+	return 0;
+}
+
+static int mock_domain_blocking_attach(struct iommu_domain *domain,
+				       struct device *dev)
+{
+	struct mock_dev *mdev = to_mock_dev(dev);
+
+	mock_dev_disable_iopf(dev, mdev->domain);
+	mdev->domain = NULL;
+
 	return 0;
 }
 
 static const struct iommu_domain_ops mock_blocking_ops = {
-	.attach_dev = mock_domain_nop_attach,
+	.attach_dev = mock_domain_blocking_attach,
 };
 
 static struct iommu_domain mock_blocking_domain = {
@@ -549,22 +573,42 @@ static void mock_domain_page_response(struct device *dev, struct iopf_fault *evt
 {
 }
 
-static int mock_dev_enable_feat(struct device *dev, enum iommu_dev_features feat)
+static int mock_dev_enable_iopf(struct device *dev, struct iommu_domain *domain)
 {
-	if (feat != IOMMU_DEV_FEAT_IOPF || !mock_iommu_iopf_queue)
+	struct mock_dev *mdev = to_mock_dev(dev);
+	int ret;
+
+	if (!domain || !domain->iopf_handler)
+		return 0;
+
+	if (!mock_iommu_iopf_queue)
 		return -ENODEV;
 
-	return iopf_queue_add_device(mock_iommu_iopf_queue, dev);
+	if (mdev->iopf_refcount) {
+		mdev->iopf_refcount++;
+		return 0;
+	}
+
+	ret = iopf_queue_add_device(mock_iommu_iopf_queue, dev);
+	if (ret)
+		return ret;
+
+	mdev->iopf_refcount = 1;
+
+	return 0;
 }
 
-static int mock_dev_disable_feat(struct device *dev, enum iommu_dev_features feat)
+static void mock_dev_disable_iopf(struct device *dev, struct iommu_domain *domain)
 {
-	if (feat != IOMMU_DEV_FEAT_IOPF || !mock_iommu_iopf_queue)
-		return -ENODEV;
+	struct mock_dev *mdev = to_mock_dev(dev);
+
+	if (!domain || !domain->iopf_handler)
+		return;
+
+	if (--mdev->iopf_refcount)
+		return;
 
 	iopf_queue_remove_device(mock_iommu_iopf_queue, dev);
-
-	return 0;
 }
 
 static void mock_viommu_destroy(struct iommufd_viommu *viommu)
@@ -709,8 +753,6 @@ static const struct iommu_ops mock_ops = {
 	.device_group = generic_device_group,
 	.probe_device = mock_probe_device,
 	.page_response = mock_domain_page_response,
-	.dev_enable_feat = mock_dev_enable_feat,
-	.dev_disable_feat = mock_dev_disable_feat,
 	.user_pasid_table = true,
 	.viommu_alloc = mock_viommu_alloc,
 	.default_domain_ops =
-- 
2.43.0
Re: [PATCH v4 4/8] iommufd/selftest: Put iopf enablement in domain attach path
Posted by Nicolin Chen 10 months, 3 weeks ago
On Thu, Mar 13, 2025 at 01:19:49PM +0800, Lu Baolu wrote:
> @@ -164,6 +167,8 @@ struct mock_dev {
>  	unsigned long flags;
>  	int id;
>  	u32 cache[MOCK_DEV_CACHE_NUM];
> +	unsigned int iopf_refcount;
> +	struct iommu_domain *domain;

Assuming both are protected by the core group->mutex, maybe add
lockdep_assert_held() in mock_dev_enable/disable_iopf()?

> +static int mock_domain_blocking_attach(struct iommu_domain *domain,
> +				       struct device *dev)
> +{
> +	struct mock_dev *mdev = to_mock_dev(dev);
> +
> +	mock_dev_disable_iopf(dev, mdev->domain);
> +	mdev->domain = NULL;

The input domain is valid. Maybe better to rename mdev->domain
to mdev->iopf_domain?

With that,

Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Re: [PATCH v4 4/8] iommufd/selftest: Put iopf enablement in domain attach path
Posted by Yi Liu 10 months, 3 weeks ago
On 2025/3/13 13:19, Lu Baolu wrote:
> Update iopf enablement in the iommufd mock device driver to use the new
> method, similar to the arm-smmu-v3 driver. Enable iopf support when any
> domain with an iopf_handler is attached, and disable it when the domain
> is removed.
> 
> Add a refcount in the mock device state structure to keep track of the
> number of domains set to the device and PASIDs that require iopf.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
> Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org>
> ---
>   drivers/iommu/iommufd/selftest.c | 64 ++++++++++++++++++++++++++------
>   1 file changed, 53 insertions(+), 11 deletions(-)

Reviewed-by: Yi Liu <yi.l.liu@intel.com>

Regards,
Yi Liu