All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jacob Pan <jacob.pan@linux.microsoft.com>
To: iommu@lists.linux.dev
Cc: Jason Gunthorpe <jgg@ziepe.ca>,
	Nicolin Chen <nicolinc@nvidia.com>,
	Kevin Tian <kevin.tian@intel.com>, Will Deacon <will@kernel.org>,
	Robin Murphy <robin.murphy@arm.com>, Wei Liu <wei.liu@kernel.org>,
	"K . Y . Srinivasan" <kys@microsoft.com>,
	Haiyang Zhang <haiyangz@microsoft.com>,
	Dexuan Cui <decui@microsoft.com>, Long Li <longli@microsoft.com>,
	linux-hyperv@vger.kernel.org, Joerg Roedel <joro@8bytes.org>,
	Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>,
	Vasant Hegde <vasant.hegde@amd.com>,
	Arnd Bergmann <arnd@arndb.de>,
	linux-arch@vger.kernel.org, linux-kernel@vger.kernel.org,
	"Aneesh Kumar K . V" <aneesh.kumar@kernel.org>,
	Mukesh Rathor <mukeshrathor@microsoft.com>,
	John Starks <John.Starks@microsoft.com>,
	Souradeep Chakrabarti <schakrabarti@microsoft.com>,
	Yu Zhang <zhangyu1@linux.microsoft.com>,
	Easwar Hariharan <eahariha@linux.microsoft.com>,
	Alex Williamson <alex@shazbot.org>
Subject: [PATCH RFC 3/9] iommufd: Add external HWPT support
Date: Fri, 25 Sep 2026 12:07:36 -0700	[thread overview]
Message-ID: <20260925190742.1575380-4-jacob.pan@linux.microsoft.com> (raw)
In-Reply-To: <20260925190742.1575380-1-jacob.pan@linux.microsoft.com>

Add IOMMU_HWPT_DATA_EXTERNAL and an IOMMUFD_OBJ_HWPT_EXTERNAL object for
externally managed attachable domains created under a vIOMMU.

Route vIOMMU child HWPT allocation by data type, add the driver
alloc_domain_external callback, and allow device attach/replace to
consume external HWPTs.

Assisted-by: GPT-5.6 Sol
Signed-off-by: Jacob Pan <jacob.pan@linux.microsoft.com>
---
 drivers/iommu/iommufd/device.c          |  9 +--
 drivers/iommu/iommufd/hw_pagetable.c    | 88 +++++++++++++++++++++++--
 drivers/iommu/iommufd/iommufd_private.h |  7 ++
 drivers/iommu/iommufd/main.c            |  4 ++
 include/linux/iommufd.h                 | 11 ++++
 include/uapi/linux/iommufd.h            | 17 +++++
 6 files changed, 126 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index 5c4b06eda546..f99b4730994c 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -1026,6 +1026,7 @@ static int iommufd_device_change_pt(struct iommufd_device *idev,
 		return PTR_ERR(pt_obj);
 
 	switch (pt_obj->type) {
+	case IOMMUFD_OBJ_HWPT_EXTERNAL:
 	case IOMMUFD_OBJ_HWPT_NESTED:
 	case IOMMUFD_OBJ_HWPT_PAGING: {
 		struct iommufd_hw_pagetable *hwpt =
@@ -1066,8 +1067,8 @@ static int iommufd_device_change_pt(struct iommufd_device *idev,
  * iommufd_device_attach - Connect a device/pasid to an iommu_domain
  * @idev: device to attach
  * @pasid: pasid to attach
- * @pt_id: Input an IOMMUFD_OBJ_IOAS, or IOMMUFD_OBJ_HWPT_PAGING
- *         Output the IOMMUFD_OBJ_HWPT_PAGING ID
+ * @pt_id: Input an IOMMUFD_OBJ_IOAS, IOMMUFD_OBJ_HWPT_PAGING, or
+ *         IOMMUFD_OBJ_HWPT_EXTERNAL. Output the HWPT ID
  *
  * This connects the device/pasid to an iommu_domain, either automatically
  * or manually selected. Once this completes the device could do DMA with
@@ -1099,8 +1100,8 @@ EXPORT_SYMBOL_NS_GPL(iommufd_device_attach, "IOMMUFD");
  * iommufd_device_replace - Change the device/pasid's iommu_domain
  * @idev: device to change
  * @pasid: pasid to change
- * @pt_id: Input an IOMMUFD_OBJ_IOAS, or IOMMUFD_OBJ_HWPT_PAGING
- *         Output the IOMMUFD_OBJ_HWPT_PAGING ID
+ * @pt_id: Input an IOMMUFD_OBJ_IOAS, IOMMUFD_OBJ_HWPT_PAGING, or
+ *         IOMMUFD_OBJ_HWPT_EXTERNAL. Output the HWPT ID
  *
  * This is the same as::
  *
diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c
index ef6e119c2a75..324a81d9bae4 100644
--- a/drivers/iommu/iommufd/hw_pagetable.c
+++ b/drivers/iommu/iommufd/hw_pagetable.c
@@ -77,6 +77,20 @@ void iommufd_hwpt_nested_abort(struct iommufd_object *obj)
 	iommufd_hwpt_nested_destroy(obj);
 }
 
+void iommufd_hwpt_external_destroy(struct iommufd_object *obj)
+{
+	struct iommufd_hwpt_external *hwpt_external =
+		container_of(obj, struct iommufd_hwpt_external, common.obj);
+
+	__iommufd_hwpt_destroy(&hwpt_external->common);
+	refcount_dec(&hwpt_external->viommu->obj.users);
+}
+
+void iommufd_hwpt_external_abort(struct iommufd_object *obj)
+{
+	iommufd_hwpt_external_destroy(obj);
+}
+
 static int
 iommufd_hwpt_paging_enforce_cc(struct iommufd_hwpt_paging *hwpt_paging)
 {
@@ -306,6 +320,8 @@ iommufd_viommu_alloc_hwpt_nested(struct iommufd_viommu *viommu, u32 flags,
 		return ERR_PTR(-EOPNOTSUPP);
 	if (!user_data->len)
 		return ERR_PTR(-EOPNOTSUPP);
+	if (!viommu->hwpt)
+		return ERR_PTR(-EINVAL);
 	if (!viommu->ops || !viommu->ops->alloc_domain_nested)
 		return ERR_PTR(-EOPNOTSUPP);
 
@@ -342,6 +358,53 @@ iommufd_viommu_alloc_hwpt_nested(struct iommufd_viommu *viommu, u32 flags,
 	return ERR_PTR(rc);
 }
 
+static struct iommufd_hwpt_external *
+iommufd_viommu_alloc_hwpt_external(struct iommufd_viommu *viommu, u32 flags,
+				   const struct iommu_user_data *user_data)
+{
+	struct iommufd_hwpt_external *hwpt_external;
+	struct iommufd_hw_pagetable *hwpt;
+	int rc;
+
+	if (flags)
+		return ERR_PTR(-EOPNOTSUPP);
+	if (!user_data->len)
+		return ERR_PTR(-EOPNOTSUPP);
+	if (!viommu->ops || !viommu->ops->alloc_domain_external)
+		return ERR_PTR(-EOPNOTSUPP);
+
+	hwpt_external = __iommufd_object_alloc(viommu->ictx, hwpt_external,
+					       IOMMUFD_OBJ_HWPT_EXTERNAL,
+					       common.obj);
+	if (IS_ERR(hwpt_external))
+		return ERR_CAST(hwpt_external);
+	hwpt = &hwpt_external->common;
+
+	hwpt_external->viommu = viommu;
+	refcount_inc(&viommu->obj.users);
+
+	hwpt->domain = viommu->ops->alloc_domain_external(viommu, flags,
+							user_data);
+	if (IS_ERR(hwpt->domain)) {
+		rc = PTR_ERR(hwpt->domain);
+		hwpt->domain = NULL;
+		goto out_abort;
+	}
+	hwpt->domain->iommufd_hwpt = hwpt;
+	hwpt->domain->owner = viommu->iommu_dev->ops;
+	hwpt->domain->cookie_type = IOMMU_COOKIE_IOMMUFD;
+
+	if (WARN_ON_ONCE(hwpt->domain->type != IOMMU_DOMAIN_EXTERNAL)) {
+		rc = -EOPNOTSUPP;
+		goto out_abort;
+	}
+	return hwpt_external;
+
+out_abort:
+	iommufd_object_abort_and_destroy(viommu->ictx, &hwpt->obj);
+	return ERR_PTR(rc);
+}
+
 int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
 {
 	struct iommu_hwpt_alloc *cmd = ucmd->cmd;
@@ -399,6 +462,7 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
 		}
 		hwpt = &hwpt_nested->common;
 	} else if (pt_obj->type == IOMMUFD_OBJ_VIOMMU) {
+		struct iommufd_hwpt_external *hwpt_external;
 		struct iommufd_hwpt_nested *hwpt_nested;
 		struct iommu_device *iommu_dev;
 		struct iommufd_viommu *viommu;
@@ -409,13 +473,25 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
 			rc = -EINVAL;
 			goto out_unlock;
 		}
-		hwpt_nested = iommufd_viommu_alloc_hwpt_nested(
-			viommu, cmd->flags, &user_data);
-		if (IS_ERR(hwpt_nested)) {
-			rc = PTR_ERR(hwpt_nested);
-			goto out_unlock;
+		if (cmd->data_type == IOMMU_HWPT_DATA_EXTERNAL) {
+			hwpt_external =
+				iommufd_viommu_alloc_hwpt_external(viommu,
+								   cmd->flags,
+								   &user_data);
+			if (IS_ERR(hwpt_external)) {
+				rc = PTR_ERR(hwpt_external);
+				goto out_unlock;
+			}
+			hwpt = &hwpt_external->common;
+		} else {
+			hwpt_nested = iommufd_viommu_alloc_hwpt_nested(
+				viommu, cmd->flags, &user_data);
+			if (IS_ERR(hwpt_nested)) {
+				rc = PTR_ERR(hwpt_nested);
+				goto out_unlock;
+			}
+			hwpt = &hwpt_nested->common;
 		}
-		hwpt = &hwpt_nested->common;
 	} else {
 		rc = -EINVAL;
 		goto out_put_pt;
diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index eb2e85b27e42..8b7aaaaba194 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -403,6 +403,11 @@ struct iommufd_hwpt_nested {
 	struct iommufd_viommu *viommu;
 };
 
+struct iommufd_hwpt_external {
+	struct iommufd_hw_pagetable common;
+	struct iommufd_viommu *viommu;
+};
+
 static inline bool hwpt_is_paging(struct iommufd_hw_pagetable *hwpt)
 {
 	return hwpt->obj.type == IOMMUFD_OBJ_HWPT_PAGING;
@@ -465,6 +470,8 @@ void iommufd_hwpt_paging_destroy(struct iommufd_object *obj);
 void iommufd_hwpt_paging_abort(struct iommufd_object *obj);
 void iommufd_hwpt_nested_destroy(struct iommufd_object *obj);
 void iommufd_hwpt_nested_abort(struct iommufd_object *obj);
+void iommufd_hwpt_external_destroy(struct iommufd_object *obj);
+void iommufd_hwpt_external_abort(struct iommufd_object *obj);
 int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd);
 int iommufd_hwpt_invalidate(struct iommufd_ucmd *ucmd);
 
diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
index 9a921b153162..6835bb87916a 100644
--- a/drivers/iommu/iommufd/main.c
+++ b/drivers/iommu/iommufd/main.c
@@ -736,6 +736,10 @@ static const struct iommufd_object_ops iommufd_object_ops[] = {
 		.destroy = iommufd_hwpt_nested_destroy,
 		.abort = iommufd_hwpt_nested_abort,
 	},
+	[IOMMUFD_OBJ_HWPT_EXTERNAL] = {
+		.destroy = iommufd_hwpt_external_destroy,
+		.abort = iommufd_hwpt_external_abort,
+	},
 	[IOMMUFD_OBJ_IOAS] = {
 		.destroy = iommufd_ioas_destroy,
 	},
diff --git a/include/linux/iommufd.h b/include/linux/iommufd.h
index 6e7efe83bc5d..ce740a2d1588 100644
--- a/include/linux/iommufd.h
+++ b/include/linux/iommufd.h
@@ -31,6 +31,7 @@ enum iommufd_object_type {
 	IOMMUFD_OBJ_DEVICE,
 	IOMMUFD_OBJ_HWPT_PAGING,
 	IOMMUFD_OBJ_HWPT_NESTED,
+	IOMMUFD_OBJ_HWPT_EXTERNAL,
 	IOMMUFD_OBJ_IOAS,
 	IOMMUFD_OBJ_ACCESS,
 	IOMMUFD_OBJ_FAULT,
@@ -149,6 +150,12 @@ struct iommufd_hw_queue {
  *                       must be defined in include/uapi/linux/iommufd.h.
  *                       It must fully initialize the new iommu_domain before
  *                       returning. Upon failure, ERR_PTR must be returned.
+ * @alloc_domain_external: Allocate a IOMMU_DOMAIN_EXTERNAL on a vIOMMU that holds
+ *                       the VM identity for an external attach domain. @user_data must
+ *                       be defined in
+ *                       include/uapi/linux/iommufd.h. It must fully initialize
+ *                       the new iommu_domain before returning. Upon failure,
+ *                       ERR_PTR must be returned.
  * @cache_invalidate: Flush hardware cache used by a vIOMMU. It can be used for
  *                    any IOMMU hardware specific cache: TLB and device cache.
  *                    The @array passes in the cache invalidation requests, in
@@ -186,6 +193,10 @@ struct iommufd_viommu_ops {
 	struct iommu_domain *(*alloc_domain_nested)(
 		struct iommufd_viommu *viommu, u32 flags,
 		const struct iommu_user_data *user_data);
+	struct iommu_domain *
+		(*alloc_domain_external)(struct iommufd_viommu *viommu,
+					 u32 flags,
+					 const struct iommu_user_data *user_data);
 	int (*cache_invalidate)(struct iommufd_viommu *viommu,
 				struct iommu_user_data_array *array);
 	const size_t vdevice_size;
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index bffa25c5267e..fa6185f04c1c 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -506,18 +506,31 @@ struct iommu_hwpt_amd_guest {
 	__aligned_u64 dte[4];
 };
 
+/**
+ * struct iommu_hwpt_external - external attach domain
+ *			      (IOMMU_HWPT_DATA_EXTERNAL)
+ * @flags: Must be 0
+ * @__reserved: Must be 0
+ */
+struct iommu_hwpt_external {
+	__u32 flags;
+	__u32 __reserved;
+};
+
 /**
  * enum iommu_hwpt_data_type - IOMMU HWPT Data Type
  * @IOMMU_HWPT_DATA_NONE: no data
  * @IOMMU_HWPT_DATA_VTD_S1: Intel VT-d stage-1 page table
  * @IOMMU_HWPT_DATA_ARM_SMMUV3: ARM SMMUv3 Context Descriptor Table
  * @IOMMU_HWPT_DATA_AMD_GUEST: AMD IOMMU guest page table
+ * @IOMMU_HWPT_DATA_EXTERNAL: external attach domain
  */
 enum iommu_hwpt_data_type {
 	IOMMU_HWPT_DATA_NONE = 0,
 	IOMMU_HWPT_DATA_VTD_S1 = 1,
 	IOMMU_HWPT_DATA_ARM_SMMUV3 = 2,
 	IOMMU_HWPT_DATA_AMD_GUEST = 3,
+	IOMMU_HWPT_DATA_EXTERNAL = 4,
 };
 
 /**
@@ -552,6 +565,10 @@ enum iommu_hwpt_data_type {
  * via @dev_id and the vIOMMU via @pt_id must be associated to the same IOMMU
  * instance.
  *
+ * An external attach HWPT can be created from a given vIOMMU via @pt_id. In this
+ * case, @data_type selects the external attach domain type, such as
+ * IOMMU_HWPT_DATA_EXTERNAL, and the created HWPT is not IOAS-backed.
+ *
  * If the @data_type is set to IOMMU_HWPT_DATA_NONE, @data_len and
  * @data_uptr should be zero. Otherwise, both @data_len and @data_uptr
  * must be given.
-- 
2.43.0


  parent reply	other threads:[~2026-09-25 19:07 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-25 19:07 [RFC PATCH 0/9] iommu/iommufd: Add hypervisor external attach Jacob Pan
2026-09-25 19:07 ` [PATCH RFC 1/9] iommu: Introduce external attach domain type Jacob Pan
2026-09-25 19:07 ` [PATCH RFC 2/9] iommufd: Introduce hypervisor vIOMMU type Jacob Pan
2026-09-25 19:07 ` Jacob Pan [this message]
2026-09-25 19:07 ` [PATCH RFC 4/9] iommufd/selftest: Add hypervisor external attach backend Jacob Pan
2026-09-25 19:07 ` [PATCH RFC 5/9] mshv: Add partition file identity helper Jacob Pan
2026-09-25 19:07 ` [PATCH RFC 6/9] mshv: Add prepare callback for external device attach Jacob Pan
2026-09-25 19:07 ` [PATCH RFC 7/9] iommu/hyperv: Split root IOMMU declarations Jacob Pan
2026-09-25 19:07 ` [PATCH RFC 8/9] iommu/hyperv: Add fd-backed vIOMMU support Jacob Pan
2026-09-25 19:07 ` [PATCH RFC 9/9] iommu/hyperv: Add IOMMUFD external domains Jacob Pan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260925190742.1575380-4-jacob.pan@linux.microsoft.com \
    --to=jacob.pan@linux.microsoft.com \
    --cc=John.Starks@microsoft.com \
    --cc=alex@shazbot.org \
    --cc=aneesh.kumar@kernel.org \
    --cc=arnd@arndb.de \
    --cc=decui@microsoft.com \
    --cc=eahariha@linux.microsoft.com \
    --cc=haiyangz@microsoft.com \
    --cc=iommu@lists.linux.dev \
    --cc=jgg@ziepe.ca \
    --cc=joro@8bytes.org \
    --cc=kevin.tian@intel.com \
    --cc=kys@microsoft.com \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-hyperv@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=longli@microsoft.com \
    --cc=mukeshrathor@microsoft.com \
    --cc=nicolinc@nvidia.com \
    --cc=robin.murphy@arm.com \
    --cc=schakrabarti@microsoft.com \
    --cc=suravee.suthikulpanit@amd.com \
    --cc=vasant.hegde@amd.com \
    --cc=wei.liu@kernel.org \
    --cc=will@kernel.org \
    --cc=zhangyu1@linux.microsoft.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.