From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
To: <linux-kernel@vger.kernel.org>, <iommu@lists.linux.dev>,
<joro@8bytes.org>, <jgg@nvidia.com>
Cc: <yi.l.liu@intel.com>, <kevin.tian@intel.com>,
<nicolinc@nvidia.com>, <vasant.hegde@amd.com>,
<jon.grimm@amd.com>, <santosh.shukla@amd.com>,
<sairaj.arunkodilkar@amd.com>, <jay.chen@amd.com>,
<wvw@google.com>, <wnliu@google.com>, <dantuluris@google.com>,
<chriscli@google.com>, <kpsingh@google.com>,
Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Subject: [PATCH v3 06/22] iommu/amd: Map vIOMMU VF and VF Control MMIO BARs
Date: Mon, 29 Jun 2026 15:35:19 +0000 [thread overview]
Message-ID: <20260629153535.15775-7-suravee.suthikulpanit@amd.com> (raw)
In-Reply-To: <20260629153535.15775-1-suravee.suthikulpanit@amd.com>
Enable hardware vIOMMU on an IOMMU by locating its PCI vendor-specific
capability (VSC), reading the VF and VF Control BAR addresses, and
mapping them for host access (256MB VF, 4MB VF Control).
VF Control covers the first 4K of guest IOMMU MMIO (control registers,
trapped by QEMU). VF MMIO covers the third 4K (virtualized by the
IOMMU). Per-guest bases use the Guest ID from the previous patch.
Initialize the per-amd_iommu gid_ida here so amd_iommu_gid_alloc() can
run when IOMMUFD creates a vIOMMU instance. Export MMIO map helpers and
call amd_viommu_uninit() from IOMMU teardown.
Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
---
drivers/iommu/amd/amd_iommu.h | 2 +
drivers/iommu/amd/amd_iommu_types.h | 34 ++++++++
drivers/iommu/amd/amd_viommu.h | 6 ++
drivers/iommu/amd/init.c | 5 +-
drivers/iommu/amd/viommu.c | 124 ++++++++++++++++++++++++++++
5 files changed, 169 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 9f2a1a8a6d3c..044bc9a634a1 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -28,6 +28,8 @@ void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid);
void iommu_feature_enable(struct amd_iommu *iommu, u8 bit);
void *__init iommu_alloc_4k_pages(struct amd_iommu *iommu,
gfp_t gfp, size_t size);
+u8 __iomem * __init iommu_map_mmio_space(u64 address, u64 end);
+void __init iommu_unmap_mmio_space(struct amd_iommu *iommu);
#ifdef CONFIG_AMD_IOMMU_DEBUGFS
void amd_iommu_debugfs_setup(void);
diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
index 00f964d5b149..e88e0bacd1a9 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -40,6 +40,12 @@
#define MMIO_RANGE_OFFSET 0x0c
#define MMIO_MISC_OFFSET 0x10
+/* vIOMMU Capability offsets (from IOMMU Capability Header) */
+#define MMIO_VSC_VF_BAR_LO_OFFSET 0x08
+#define MMIO_VSC_VF_BAR_HI_OFFSET 0x0c
+#define MMIO_VSC_VF_CNTL_BAR_LO_OFFSET 0x10
+#define MMIO_VSC_VF_CNTL_BAR_HI_OFFSET 0x14
+
/* Masks, shifts and macros to parse the device range capability */
#define MMIO_RANGE_LD_MASK 0xff000000
#define MMIO_RANGE_FD_MASK 0x00ff0000
@@ -473,6 +479,20 @@ extern bool amdr_ivrs_remap_support;
#define for_each_ivhd_dte_flags(entry) \
list_for_each_entry((entry), &amd_ivhd_dev_flags_list, list)
+/* VIOMMU stuff */
+#define VIOMMU_VF_MMIO_ENTRY_SIZE 4096
+#define VIOMMU_VFCTRL_MMIO_ENTRY_SIZE 64
+
+/* Host ioremap/request_mem_region sizes for VF / VF_CNTL BARs */
+#define VIOMMU_VF_MMIO_MAP_SIZE 0x10000000UL
+#define VIOMMU_VF_CNTL_MMIO_MAP_SIZE 0x400000UL
+
+#define VIOMMU_VF_MMIO_BASE(iommu, guestId) \
+ (iommu->vf_base + (guestId * VIOMMU_VF_MMIO_ENTRY_SIZE))
+
+#define VIOMMU_VFCTRL_MMIO_BASE(iommu, guestId) \
+ (iommu->vfctrl_base + (guestId * VIOMMU_VFCTRL_MMIO_ENTRY_SIZE))
+
struct amd_iommu;
struct iommu_domain;
struct irq_domain;
@@ -686,6 +706,20 @@ struct amd_iommu {
*/
u16 cap_ptr;
+ /* Vendor-Specific Capability (VSC) pointer. */
+ u16 vsc_offset;
+
+ /*
+ * VF MMIO base physical address. This is needed to calculate/pass
+ * per guest VF MMIO address (3rd 4K of IOMMU MMIO space)
+ */
+ u64 vf_base_phys;
+ u64 vf_cntl_phys;
+
+ /* virtual addresses of vIOMMU VF/VF_CNTL BAR */
+ u8 __iomem *vf_base;
+ u8 __iomem *vfctrl_base;
+
/* pci domain of this IOMMU */
struct amd_iommu_pci_seg *pci_seg;
diff --git a/drivers/iommu/amd/amd_viommu.h b/drivers/iommu/amd/amd_viommu.h
index f08ab9ef23a9..d0c4fdd00809 100644
--- a/drivers/iommu/amd/amd_viommu.h
+++ b/drivers/iommu/amd/amd_viommu.h
@@ -10,6 +10,8 @@
int amd_viommu_init(struct amd_iommu *iommu);
+void __init amd_viommu_uninit(struct amd_iommu *iommu);
+
#else
static inline int amd_viommu_init(struct amd_iommu *iommu)
@@ -17,6 +19,10 @@ static inline int amd_viommu_init(struct amd_iommu *iommu)
return -EOPNOTSUPP;
}
+static inline void amd_viommu_uninit(struct amd_iommu *iommu)
+{
+}
+
#endif /* CONFIG_AMD_IOMMU_IOMMUFD */
#endif /* AMD_VIOMMU_H */
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 5ac883429ced..6e69b3dd8b1e 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -459,7 +459,7 @@ static void iommu_disable(struct amd_iommu *iommu)
* mapping and unmapping functions for the IOMMU MMIO space. Each AMD IOMMU in
* the system has one.
*/
-static u8 __iomem * __init iommu_map_mmio_space(u64 address, u64 end)
+u8 __iomem * __init iommu_map_mmio_space(u64 address, u64 end)
{
if (!request_mem_region(address, end, "amd_iommu")) {
pr_err("Can not reserve memory region %llx-%llx for mmio\n",
@@ -471,7 +471,7 @@ static u8 __iomem * __init iommu_map_mmio_space(u64 address, u64 end)
return (u8 __iomem *)ioremap(address, end);
}
-static void __init iommu_unmap_mmio_space(struct amd_iommu *iommu)
+void __init iommu_unmap_mmio_space(struct amd_iommu *iommu)
{
if (iommu->mmio_base)
iounmap(iommu->mmio_base);
@@ -1790,6 +1790,7 @@ static void __init free_iommu_one(struct amd_iommu *iommu)
free_iommu_buffers(iommu);
amd_iommu_free_ppr_log(iommu);
free_ga_log(iommu);
+ amd_viommu_uninit(iommu);
iommu_unmap_mmio_space(iommu);
amd_iommu_iopf_uninit(iommu);
}
diff --git a/drivers/iommu/amd/viommu.c b/drivers/iommu/amd/viommu.c
index f4b5f96d4785..014ae16bf58b 100644
--- a/drivers/iommu/amd/viommu.c
+++ b/drivers/iommu/amd/viommu.c
@@ -7,9 +7,15 @@
#define dev_fmt(fmt) pr_fmt(fmt)
#include <linux/iommu.h>
+#include <linux/amd-iommu.h>
+
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/ioctl.h>
#include <linux/iommufd.h>
#include <linux/amd-iommu.h>
#include <uapi/linux/iommufd.h>
+#include <linux/mem_encrypt.h>
#include <asm/iommu.h>
#include <asm/set_memory.h>
@@ -18,12 +24,130 @@
#include "amd_iommu.h"
#include "amd_iommu_types.h"
#include "amd_viommu.h"
+#include "../iommu-pages.h"
+
+LIST_HEAD(viommu_devid_map);
+
+static int viommu_init_pci_vsc(struct amd_iommu *iommu)
+{
+ iommu->vsc_offset = pci_find_capability(iommu->dev, PCI_CAP_ID_VNDR);
+ if (!iommu->vsc_offset)
+ return -ENODEV;
+
+ DUMP_printk("device:%s, vsc offset:%04x\n",
+ pci_name(iommu->dev), iommu->vsc_offset);
+ return 0;
+}
+
+static void amd_viommu_gid_ida_init(struct amd_iommu *iommu)
+{
+ ida_init(&iommu->gid_ida);
+ iommu->gid_ida_inited = true;
+}
+
+static void amd_viommu_gid_ida_fini(struct amd_iommu *iommu)
+{
+ if (!iommu->gid_ida_inited)
+ return;
+
+ ida_destroy(&iommu->gid_ida);
+ iommu->gid_ida_inited = false;
+}
+
+static void __init amd_viommu_vf_vfcntl_unmap(struct amd_iommu *iommu)
+{
+ if (iommu->vfctrl_base) {
+ iounmap(iommu->vfctrl_base);
+ iommu->vfctrl_base = NULL;
+ }
+ if (iommu->vf_cntl_phys)
+ release_mem_region(iommu->vf_cntl_phys, VIOMMU_VF_CNTL_MMIO_MAP_SIZE);
+
+ if (iommu->vf_base) {
+ iounmap(iommu->vf_base);
+ iommu->vf_base = NULL;
+ }
+ if (iommu->vf_base_phys)
+ release_mem_region(iommu->vf_base_phys, VIOMMU_VF_MMIO_MAP_SIZE);
+}
+
+void __init amd_viommu_uninit(struct amd_iommu *iommu)
+{
+ amd_viommu_gid_ida_fini(iommu);
+ amd_viommu_vf_vfcntl_unmap(iommu);
+}
+
+static int __init viommu_vf_vfcntl_init(struct amd_iommu *iommu)
+{
+ u32 lo, hi;
+ u64 vf_phys, vf_cntl_phys;
+
+ /* Setting up VF and VF_CNTL MMIOs */
+ pci_read_config_dword(iommu->dev, iommu->vsc_offset + MMIO_VSC_VF_BAR_LO_OFFSET, &lo);
+ pci_read_config_dword(iommu->dev, iommu->vsc_offset + MMIO_VSC_VF_BAR_HI_OFFSET, &hi);
+ vf_phys = hi;
+ vf_phys = (vf_phys << 32) | lo;
+ if (!(vf_phys & 1)) {
+ pr_err(FW_BUG "vf_phys disabled\n");
+ return -EINVAL;
+ }
+
+ pci_read_config_dword(iommu->dev, iommu->vsc_offset + MMIO_VSC_VF_CNTL_BAR_LO_OFFSET, &lo);
+ pci_read_config_dword(iommu->dev, iommu->vsc_offset + MMIO_VSC_VF_CNTL_BAR_HI_OFFSET, &hi);
+ vf_cntl_phys = hi;
+ vf_cntl_phys = (vf_cntl_phys << 32) | lo;
+ if (!(vf_cntl_phys & 1)) {
+ pr_err(FW_BUG "vf_cntl_phys disabled\n");
+ return -EINVAL;
+ }
+
+ if (!vf_phys || !vf_cntl_phys) {
+ pr_err(FW_BUG "AMD-Vi: Unassigned VF resources.\n");
+ return -ENOMEM;
+ }
+
+ /* Mapping 256MB of VF and 4MB of VF_CNTL BARs */
+ vf_phys &= ~1ULL;
+ iommu->vf_base = iommu_map_mmio_space(vf_phys, VIOMMU_VF_MMIO_MAP_SIZE);
+ if (!iommu->vf_base) {
+ pr_err("Can't reserve vf_base\n");
+ return -ENOMEM;
+ }
+ iommu->vf_base_phys = vf_phys;
+
+ vf_cntl_phys &= ~1ULL;
+ iommu->vfctrl_base = iommu_map_mmio_space(vf_cntl_phys, VIOMMU_VF_CNTL_MMIO_MAP_SIZE);
+ if (!iommu->vfctrl_base) {
+ pr_err("Can't reserve vfctrl_base\n");
+ goto err_out;
+ }
+ iommu->vf_cntl_phys = vf_cntl_phys;
+
+ pr_debug("%s: IOMMU device:%s, vf_base:%#llx, vfctrl_base:%#llx\n",
+ __func__, pci_name(iommu->dev), vf_phys, vf_cntl_phys);
+ return 0;
+err_out:
+ amd_viommu_uninit(iommu);
+ return -ENOMEM;
+}
int __init amd_viommu_init(struct amd_iommu *iommu)
{
+ int ret;
+
if (!amd_iommu_viommu ||
!check_feature(FEATURE_VIOMMU))
return 0;
+ ret = viommu_init_pci_vsc(iommu);
+ if (ret)
+ return ret;
+
+ ret = viommu_vf_vfcntl_init(iommu);
+ if (ret)
+ return ret;
+
+ amd_viommu_gid_ida_init(iommu);
+
return 0;
}
--
2.34.1
next prev parent reply other threads:[~2026-06-29 15:41 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-29 15:35 [PATCH v3 00/22] iommu/amd: Introduce AMD Hardware-accelerated Virtualized IOMMU (vIOMMU) Support Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 01/22] iommu/amd: Make amd_iommu_completion_wait() non-static Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 02/22] iommu/amd: Introduce vIOMMU-specific events and event Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 03/22] iommu/amd: Detect and initialize AMD vIOMMU feature Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 04/22] iommu/amd: Introduce IOMMUFD vIOMMU support for AMD Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 05/22] iommu/amd: Allocate Guest IDs for IOMMUFD vIOMMU instances Suravee Suthikulpanit
2026-06-29 15:35 ` Suravee Suthikulpanit [this message]
2026-06-29 15:35 ` [PATCH v3 07/22] iommu/amd: Add support for AMD vIOMMU VF MMIO region Suravee Suthikulpanit
2026-07-07 14:33 ` Jason Gunthorpe
2026-06-29 15:35 ` [PATCH v3 08/22] iommu/amd: Introduce Reset vMMIO Command Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 09/22] iommu/amd: Introduce and map vIOMMU private IPA region Suravee Suthikulpanit
2026-07-07 14:07 ` Jason Gunthorpe
2026-06-29 15:35 ` [PATCH v3 10/22] iommu/amd: Pass iommu to device_flush_dte() Suravee Suthikulpanit
2026-07-07 14:18 ` Jason Gunthorpe
2026-06-29 15:35 ` [PATCH v3 11/22] iommu/amd: Export amd_iommu_alloc_dev_data() helper Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 12/22] iommu/amd: Pass iommu and devid to amd_iommu_make_clear_dte() Suravee Suthikulpanit
2026-07-07 14:20 ` Jason Gunthorpe
2026-06-29 15:35 ` [PATCH v3 13/22] iommu/amd: Assign IOMMU Private Address domain to IOMMU Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 14/22] iommu/amd: Add per-VM private IPA alloc/map helpers Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 15/22] iommu/amd: Add helper functions to manage DevID / DomID mapping tables Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 16/22] iommu/amd: Introduce IOMMUFD vDevice support for AMD Suravee Suthikulpanit
2026-07-07 14:31 ` Jason Gunthorpe
2026-06-29 15:35 ` [PATCH v3 17/22] iommu/amd: Introduce helper function for updating domain ID mapping table Suravee Suthikulpanit
2026-07-07 14:32 ` Jason Gunthorpe
2026-06-29 15:35 ` [PATCH v3 18/22] iommu/amd: Introduce helper function for updating device " Suravee Suthikulpanit
2026-06-29 15:35 ` [PATCH v3 19/22] iommu/amd: Add per-segment translate device ID pool Suravee Suthikulpanit
2026-07-07 14:36 ` Jason Gunthorpe
2026-06-29 15:35 ` [PATCH v3 20/22] iommu/amd: Reserve translate-device-id for PCI requestor aliases Suravee Suthikulpanit
2026-07-07 14:39 ` Jason Gunthorpe
2026-06-29 15:35 ` [PATCH v3 21/22] iommu/amd: Add translation DTE and VFctrl TransDevID helpers Suravee Suthikulpanit
2026-07-07 14:43 ` Jason Gunthorpe
2026-06-29 15:35 ` [PATCH v3 22/22] iommu/amd: Assign per-vIOMMU translate device ID Suravee Suthikulpanit
2026-07-07 14:45 ` [PATCH v3 00/22] iommu/amd: Introduce AMD Hardware-accelerated Virtualized IOMMU (vIOMMU) Support Jason Gunthorpe
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=20260629153535.15775-7-suravee.suthikulpanit@amd.com \
--to=suravee.suthikulpanit@amd.com \
--cc=chriscli@google.com \
--cc=dantuluris@google.com \
--cc=iommu@lists.linux.dev \
--cc=jay.chen@amd.com \
--cc=jgg@nvidia.com \
--cc=jon.grimm@amd.com \
--cc=joro@8bytes.org \
--cc=kevin.tian@intel.com \
--cc=kpsingh@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=nicolinc@nvidia.com \
--cc=sairaj.arunkodilkar@amd.com \
--cc=santosh.shukla@amd.com \
--cc=vasant.hegde@amd.com \
--cc=wnliu@google.com \
--cc=wvw@google.com \
--cc=yi.l.liu@intel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox