[RFC PATCH 3/7] iommu/kho/abi: add AMD IOMMU live-update serialisation structs

Ankit Soni Ankit.Soni at amd.com
Sun Oct 4 23:40:13 PDT 2026


Describe the AMD IOMMU state that has to cross a live-update kexec: the
device table of a PCI segment, and the domain ID, page-table mode and
GCR3 tree of a preserved device.

Both structs fit inside the existing unions, so the layout and the
version are unchanged. Assert that, since growing either arm past the
Intel one would move the array stride.

Signed-off-by: Ankit Soni <Ankit.Soni at amd.com>
---
 include/linux/kho/abi/iommu.h | 70 +++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/include/linux/kho/abi/iommu.h b/include/linux/kho/abi/iommu.h
index 308cd83fd3e3..5cbc8b3589ed 100644
--- a/include/linux/kho/abi/iommu.h
+++ b/include/linux/kho/abi/iommu.h
@@ -8,6 +8,7 @@
 #ifndef _LINUX_KHO_ABI_IOMMU_H
 #define _LINUX_KHO_ABI_IOMMU_H
 
+#include <linux/bug.h>
 #include <linux/mutex_types.h>
 #include <linux/compiler.h>
 #include <linux/types.h>
@@ -75,6 +76,7 @@
 /**
  * enum iommu_type_ser - Type of the IOMMU being preserved
  * @IOMMU_INVALID: Invalid type of IOMMU
+ * @IOMMU_AMD: AMD-Vi, whose per-instance state is struct iommu_amd_ser
  *
  * IOMMU type is stored in the IOMMU HW state to differentiate between various
  * IOMMU HWs.
@@ -82,6 +84,7 @@
 enum iommu_type_ser {
 	IOMMU_INVALID,
 	IOMMU_INTEL,
+	IOMMU_AMD,
 };
 
 #define IOMMU_SER_FLAG_DELETED	(1 << 0)
@@ -142,6 +145,29 @@ struct iommu_device_intel_ser {
 	u64 max_pasid;
 } __packed;
 
+/*
+ * Page-table mode of the domain a preserved AMD device was attached to. These
+ * are wire values with their own numbering rather than the kernel's
+ * enum protection_domain_mode, so reordering that enum cannot silently change
+ * the handoff format.
+ */
+#define IOMMU_AMD_SER_PD_MODE_NONE	0
+#define IOMMU_AMD_SER_PD_MODE_V1	1
+#define IOMMU_AMD_SER_PD_MODE_V2	2
+
+/**
+ * struct iommu_device_amd_ser - AMD specific state of serialized device
+ * @gcr3_tbl_phys: Physical address of the device's GCR3 table root, or 0 if
+ *		  the device has no PASID/GCR3 table.
+ * @gcr3_glx: Number of GCR3 table levels (0, 1, or 2; see amd_iommu_max_glx_val)
+ * @pd_mode: Page-table format of the domain, one of IOMMU_AMD_SER_PD_MODE_*
+ */
+struct iommu_device_amd_ser {
+	u64 gcr3_tbl_phys;
+	u32 gcr3_glx;
+	u32 pd_mode;
+} __packed;
+
 /**
  * struct iommu_device_ser - Serialized state of a device
  * @hdr: Common object header
@@ -150,6 +176,8 @@ struct iommu_device_intel_ser {
  * @dma_owner_token: Token to identify the DMA owner of this device
  * @domain_iommu_ser: Domain and IOMMU mapping
  * @intel: Intel specific serialization data
+ * @amd: AMD-Vi per-device state, valid when the owning IOMMU record is
+ *	 of type IOMMU_AMD
  */
 struct iommu_device_ser {
 	struct iommu_hdr_ser hdr;
@@ -159,9 +187,18 @@ struct iommu_device_ser {
 	struct iommu_dev_map_ser domain_iommu_ser;
 	union {
 		struct iommu_device_intel_ser intel;
+		struct iommu_device_amd_ser amd;
 	};
 } __packed;
 
+/*
+ * The Intel arm is the larger one and so sets the size of the union, and with
+ * it the stride of the device array. Growing either arm changes that stride and
+ * needs a version bump.
+ */
+static_assert(sizeof(struct iommu_device_amd_ser) == 16);
+static_assert(sizeof(struct iommu_device_intel_ser) == 24);
+
 /* There are maximum 256 buses, so maximum 512 context tables */
 #define VTD_PRESERVED_BITMAP_LONGS  DIV_ROUND_UP(512, BITS_PER_LONG_LONG)
 
@@ -181,12 +218,36 @@ struct iommu_intel_ser {
 	u64 context_tables_bitmap[VTD_PRESERVED_BITMAP_LONGS];
 };
 
+/**
+ * struct iommu_amd_ser - Serialized state of an AMD IOMMU instance
+ * @restored: Whether IOMMU state is restored. Guards against double-restore.
+ * @mmio_phys: Physical address of the IOMMU MMIO register base.
+ * @dev_table_phys: Physical address of this IOMMU's PCI-segment device
+ *		   table (struct amd_iommu_pci_seg.dev_table).
+ * @dev_table_size: Size of the device table, in bytes.
+ * @pci_seg_id: PCI segment ID that owns the device table.
+ * @efr: Extended Feature Register bits (struct amd_iommu.features).
+ *      Compared on restore; a mismatch is fatal.
+ * @efr2: Extended Feature Register 2 bits (struct amd_iommu.features2).
+ */
+struct iommu_amd_ser {
+	u8 restored;
+	u8 padding[7];
+	u64 mmio_phys;
+	u64 dev_table_phys;
+	u32 dev_table_size;
+	u32 pci_seg_id;
+	u64 efr;
+	u64 efr2;
+} __packed;
+
 /**
  * struct iommu_hw_ser - Serialized state of an IOMMU instance
  * @hdr: Common object header
  * @token: Unique token for the IOMMU
  * @type: IOMMU type serialized state belongs to
  * @intel: Intel specific serialization data
+ * @amd: AMD specific serialization data
  */
 struct iommu_hw_ser {
 	struct iommu_hdr_ser hdr;
@@ -194,9 +255,18 @@ struct iommu_hw_ser {
 	u64 type;
 	union {
 		struct iommu_intel_ser intel;
+		struct iommu_amd_ser amd;
 	};
 } __packed;
 
+/*
+ * The Intel arm is the larger one and so sets the size of the union, and with
+ * it the stride of the IOMMU array. Growing either arm changes that stride and
+ * needs a version bump.
+ */
+static_assert(sizeof(struct iommu_amd_ser) == 48);
+static_assert(sizeof(struct iommu_intel_ser) == 88);
+
 /**
  * struct iommu_array_hdr_ser - Header for an array of serialized objects
  * @next_array_phys: Physical address of the next array of objects
-- 
2.43.0




More information about the kexec mailing list