[PATCH v2 17/26] iommu/amd: Pass KVM FD from userspace when initializing vIOMMU

From: Suravee Suthikulpanit

Date: Thu May 28 2026 - 01:21:54 EST


AMD HW-vIOMMU feature requires IOMMU driver to keep track of each guest.
This information is used by AMD IOMMU driver to manage the following:

* GID: Each guest is assigned a unique 16-bit Guest ID (GID), which is
used to index into various data structures for configuring the hardware.

* Translation-devid: Each guest has one GPA->SPA mapping, which requires
one trans_devid to program the v1 page table in the DTE[trans_devid].

* Extended interrupt remapping: The AMD HW-vIOMMU uses AVIC to implement
extended interrupt remapping to virtualize Event/PPR log interrupts.
A KVM reference is neeed to get the AVIC vm_id.

The KVM FD can be used for these purposes.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>
---
drivers/iommu/amd/amd_iommu_types.h | 2 ++
drivers/iommu/amd/iommufd.c | 27 ++++++++++++++++++++++++++-
include/uapi/linux/iommufd.h | 2 ++
3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
index 836d5cd08134..e9b49f0b9051 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -547,6 +547,8 @@ struct amd_iommu_viommu {
struct protection_domain *parent; /* nest parent domain for this viommu */
struct list_head pdom_list; /* For protection_domain->viommu_list */
u16 gid; /* Guest ID for the vIOMMU */
+ u32 kvmfd; /* KVM fd from VMM */
+ void *kvm; /* Hold struct kvm pointer */

/*
* Per-vIOMMU guest domain ID to host domain ID mapping.
diff --git a/drivers/iommu/amd/iommufd.c b/drivers/iommu/amd/iommufd.c
index 6020f2caf445..7c7ef267088b 100644
--- a/drivers/iommu/amd/iommufd.c
+++ b/drivers/iommu/amd/iommufd.c
@@ -4,6 +4,8 @@
*/

#include <linux/iommu.h>
+#include <linux/file.h>
+#include <linux/amd-iommu.h>

#include "iommufd.h"
#include "amd_iommu.h"
@@ -42,13 +44,27 @@ size_t amd_iommufd_get_viommu_size(struct device *dev, enum iommu_viommu_type vi
return VIOMMU_STRUCT_SIZE(struct amd_iommu_viommu, core);
}

+static void *get_kvm_handler(u32 kvmfd)
+{
+ struct fd f;
+
+ f = fdget(kvmfd);
+
+ if (fd_empty(f)) {
+ pr_warn("%s: fdget failed\n", __func__);
+ return NULL;
+ }
+
+ return fd_file(f)->private_data;
+}
+
int amd_iommufd_viommu_init(struct iommufd_viommu *viommu, struct iommu_domain *parent,
const struct iommu_user_data *user_data)
{
int ret;
phys_addr_t page_base;
unsigned long flags;
- struct iommu_viommu_amd data;
+ struct iommu_viommu_amd data = {};
struct protection_domain *pdom = to_pdomain(parent);
struct amd_iommu *iommu = container_of(viommu->iommu_dev, struct amd_iommu, iommu);
struct amd_iommu_viommu *aviommu = container_of(viommu, struct amd_iommu_viommu, core);
@@ -81,6 +97,13 @@ int amd_iommufd_viommu_init(struct iommufd_viommu *viommu, struct iommu_domain *

aviommu->vfmmio_mmap_offset = data.out_vfmmio_mmap_offset;

+ aviommu->kvm = get_kvm_handler(data.kvmfd);
+ if (aviommu->kvm == NULL) {
+ pr_err("%s: Failed to get KVM handler (kvmfd=%#x)\n", __func__, data.kvmfd);
+ ret = -EINVAL;
+ goto err_kvmfd;
+ }
+
/* Reset vIOMMU MMIOs to initialize the vIOMMU */
iommu_reset_vmmio(iommu, aviommu->gid);

@@ -94,6 +117,7 @@ int amd_iommufd_viommu_init(struct iommufd_viommu *viommu, struct iommu_domain *
if (ret)
goto err_init;

+ aviommu->kvmfd = data.kvmfd;
viommu->ops = &amd_viommu_ops;

spin_lock_irqsave(&pdom->lock, flags);
@@ -102,6 +126,7 @@ int amd_iommufd_viommu_init(struct iommufd_viommu *viommu, struct iommu_domain *

return 0;
err_init:
+err_kvmfd:
iommufd_viommu_destroy_mmap(&aviommu->core, aviommu->vfmmio_mmap_offset);
err_mmap:
amd_iommu_gid_free(iommu, aviommu->gid);
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 0b7a3e5b057c..69aa44bba95a 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -1085,10 +1085,12 @@ struct iommu_viommu_tegra241_cmdqv {
/**
* struct iommu_viommu_amd - AMD vIOMMU Interface (IOMMU_VIOMMU_TYPE_AMD)
* @out_vfmmio_mmap_offset: (out) mmap offset for vIOMMU VF-MMIO
+ * @kvmfd: KVM FD handler
* @reserved: Must be zero
*/
struct iommu_viommu_amd {
__aligned_u64 out_vfmmio_mmap_offset;
+ __u32 kvmfd;
__u32 reserved; /* must be last */
};

--
2.34.1