Re: [PATCH 4/4] iommu/amd: Introduce boot option ivmd=seg:bus:dev.fun,start,size,flags
From: Suthikulpanit, Suravee
Date: Thu Apr 23 2026 - 04:09:15 EST
On 4/22/2026 5:56 PM, Yu Zhang wrote:
On Mon, Apr 20, 2026 at 05:00:33PM +0000, Suravee Suthikulpanit wrote:
IVRS table contains IVMD blocks, which allow firmware to specify memory[...]
usage requirements to communicate to system software based on its needs
or on hardware characteristics. Each IVMD entry may be per-device, range
of devices.
Some BIOS specify incorrect or missing IVMD entry. Introduce a new ivmd
boot option to allow user to specify up-to 4 per-device IVMD entries at
boot time. The entries are stored during driver initialization, and will
be added to the per-segment ivmd_entry_map so that they can be included
during struct iommu_ops.get_resv_regions.
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>
---
.../admin-guide/kernel-parameters.txt | 16 +++
drivers/iommu/amd/amd_iommu_types.h | 14 +++
drivers/iommu/amd/init.c | 104 +++++++++++++++++-
3 files changed, 133 insertions(+), 1 deletion(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 03a550630644..e680a258008f 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2897,6 +2897,22 @@ Kernel parameters
PCI device ID 00:14.5, write the parameter as:
ivrs_acpihid[0001:00:14.5]=AMD0020:0
+ ivmd [HW,X86-64]
+ Supplement IVMD unity mapping or exclusion ranges from
+ the kernel command line (in addition to the IVRS ACPI
+ table). May be specified multiple times.
+
+ Form:
+ ivmd=segment:bus:dev.fn,start,length,flags
+
+ start and length are byte counts (decimal or 0x hex).
+ flags is the IVMD flags byte (UNITY, IR, IW, EXCL bits
+ per the AMD IOMMU specification). Use segment 0 for
+ PCI segment zero.
+
+ Example:
+ ivmd=0000:00:01.0,0xe0000000,0x100000,0xb
+
js= [HW,JOY] Analog joystick
See Documentation/input/joydev/joystick.rst.
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 4b62bb89a12c..7d60143d4711 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -208,10 +208,12 @@ enum iommu_init_state {
static struct devid_map __initdata early_ioapic_map[EARLY_MAP_SIZE];
static struct devid_map __initdata early_hpet_map[EARLY_MAP_SIZE];
static struct acpihid_map_entry __initdata early_acpihid_map[EARLY_MAP_SIZE];
+static struct ivmd_cmdline early_ivmd_cmdline_map[EARLY_MAP_SIZE] __initdata;
static int __initdata early_ioapic_map_size;
static int __initdata early_hpet_map_size;
static int __initdata early_acpihid_map_size;
+static int early_ivmd_cmdline_map_size __initdata;
static bool __initdata cmdline_maps;
@@ -2653,6 +2655,47 @@ static int __init init_ivmd_map_range(struct ivmd_header *m,
return 0;
}
+static int __init apply_ivmd_cmdline_entries(struct acpi_table_header *ivrs_base)
+{
+ int i;
+ struct ivmd_entry *e;
+ struct amd_iommu_pci_seg *pci_seg;
+
+ for (i = 0; i < early_ivmd_cmdline_map_size; i++) {
+ struct ivmd_cmdline *cmd = &early_ivmd_cmdline_map[i];
+
+ pci_seg = get_pci_segment(cmd->pci_seg, ivrs_base);
+ if (!pci_seg) {
+ pr_err("ivmd: PCI segment %#x unavailable\n",
+ cmd->pci_seg);
+ continue;
+ }
+
+ if (cmd->devid > pci_seg->last_bdf) {
+ pr_err("%s: requestor %#x:%#02x:%#02x.%#02x exceeds segment %#x last BDF %#x\n",
+ __func__, cmd->pci_seg, PCI_BUS_NUM(cmd->devid),
+ PCI_SLOT(cmd->devid), PCI_FUNC(cmd->devid),
+ pci_seg->id, pci_seg->last_bdf);
+ continue;
+ }
+
+ e = kzalloc(sizeof(*e), GFP_KERNEL);
+ if (!e) {
+ kfree(cmd);
cmd points to the early_ivmd_cmdline_map, shall not be kfreed.
Correct, it was from my older implementation. Thanks for catching. I'll fix it in v2.
+ return -ENOMEM;[...]
+ }
+static int __init parse_ivmd(char *str)
+{
+ u32 seg, bus, dev, fn;
+ unsigned long long range_start, range_len;
+ unsigned int flags;
+ struct ivmd_cmdline *cmd;
+
+ if (!str)
+ goto invalid;
+
+ if (sscanf(str, "%x:%x:%x.%x,%llu,%llu,%x",
+ &seg, &bus, &dev, &fn, &range_start,
+ &range_len, &flags) != 7)
sscanf with %llu cannot parse values with 0x prefix, which the doc above claims
to accept.
I will fix the implementation / documentation to only allow hexadecimal only.
Thanks,
Suravee
+ goto invalid;
+
B.R.
Yu