Skip to contentSkip to conversation

iommu/amd: Honor IVINFO[PAsize] for paging domains

PATCH New Ankit Soni 1 participant 3 messages Oct 19

Subsystems (2)
lore
Share & tools
lore

Ankit Soni

author
#0 lore raw

cover iommu/amd: Honor IVINFO[PAsize] for paging domains

The AMD IOMMU driver hardcodes a 52-bit output address size when it creates paging domains. This series honors the PAsize reported in ACPI IVRS IVinfo instead, so maps cannot exceed what firmware or a VM advertises. Patch 1 moves page-table setup into init_pgtable_params() after the IVHD walk, with no functional change intended. Patch 2 uses that helper for PAsize and applies it to paging domains.

Ankit Soni (2):
iommu/amd: Move page-table setup into init_pgtable_params() iommu/amd: Adhere to IVINFO[PAsize] for output address limits

 drivers/iommu/amd/amd_iommu.h       |  1 +
 drivers/iommu/amd/amd_iommu_types.h |  1 +
 drivers/iommu/amd/init.c            | 95 ++++++++++++++++-------------
 drivers/iommu/amd/iommu.c           |  4 +-
 4 files changed, 58 insertions(+), 43 deletions(-)

base-commit: 90201351a862182bdabfc1ad1c97b1e1b6ed5931

Signature · 1 line
2.43.0
author
#1 lore raw

PATCH 1/2 iommu/amd: Move page-table setup into init_pgtable_params()

early_amd_iommu_init() currently sets guest page-table level, host address size, and v1/v2 fallback inline after the IVHD walk. That clutters the function.

Move the page-table setup into a separate function. No functional change.

---
 drivers/iommu/amd/init.c | 88 +++++++++++++++++++++-------------------
 1 file changed, 47 insertions(+), 41 deletions(-)
drivers/iommu/amd/init.c +47 -41
index edcc187b8f14..89da993d7d15 100644
@@ -3194,6 +3194,52 @@ static void __init ivinfo_init(void *ivrs)
 	amd_iommu_ivinfo = *((u32 *)(ivrs + IOMMU_IVINFO_OFFSET));
 }
 
+static void __init init_pgtable_params(void)
+{
+	u8 vasize, efr_hats;
+
+	vasize = FIELD_GET(IOMMU_IVINFO_VASIZE, amd_iommu_ivinfo);
+	if (!vasize)
+		vasize = 64;
+
+	/* 5 level guest page table */
+	if (cpu_feature_enabled(X86_FEATURE_LA57) &&
+	    FIELD_GET(FEATURE_GATS, amd_iommu_efr) == GUEST_PGTABLE_5_LEVEL)
+		amd_iommu_gpt_level = PAGE_MODE_5_LEVEL;
+
+	efr_hats = FIELD_GET(FEATURE_HATS, amd_iommu_efr);
+	if (efr_hats != 0x3) {
+		/*
+		 * efr[HATS] bits specify the maximum host translation level
+		 * supported, with LEVEL 4 being initial max level.
+		 */
+		amd_iommu_hpt_vasize = min_t(unsigned int, vasize,
+					 (efr_hats + PAGE_MODE_4_LEVEL - 1) * 9 + 21);
+	} else {
+		pr_warn_once(FW_BUG "Disable host address translation due to invalid translation level (%#x).\n",
+			     efr_hats);
+		amd_iommu_hatdis = true;
+	}
+
+	if (amd_iommu_pgtable == PD_MODE_V2) {
+		if (!amd_iommu_v2_pgtbl_supported()) {
+			pr_warn("Cannot enable v2 page table for DMA-API. Fallback to v1.\n");
+			amd_iommu_pgtable = PD_MODE_V1;
+		}
+	}
+
+	if (amd_iommu_hatdis) {
+		/*
+		 * Host (v1) page table is not available. Attempt to use
+		 * Guest (v2) page table.
+		 */
+		if (amd_iommu_v2_pgtbl_supported())
+			amd_iommu_pgtable = PD_MODE_V2;
+		else
+			amd_iommu_pgtable = PD_MODE_NONE;
+	}
+}
+
 /*
  * This is the hardware init function for AMD IOMMU in the system.
  * This function is called either from amd_iommu_init or from the interrupt
@@ -3226,7 +3272,6 @@ static int __init early_amd_iommu_init(void)
 	struct acpi_table_header *ivrs_base;
 	int ret;
 	acpi_status status;
-	u8 efr_hats, max_vasize;
 
 	if (!amd_iommu_detected)
 		return -ENODEV;
@@ -3256,10 +3301,6 @@ static int __init early_amd_iommu_init(void)
 
 	ivinfo_init(ivrs_base);
 
-	max_vasize = FIELD_GET(IOMMU_IVINFO_VASIZE, amd_iommu_ivinfo);
-	if (!max_vasize)
-		max_vasize = 64;
-
 	amd_iommu_target_ivhd_type = get_highest_supported_ivhd_type(ivrs_base);
 	DUMP_printk("Using IVHD type %#x\n", amd_iommu_target_ivhd_type);
 
@@ -3271,42 +3312,7 @@ static int __init early_amd_iommu_init(void)
 	if (ret)
 		goto out;
 
-	/* 5 level guest page table */
-	if (cpu_feature_enabled(X86_FEATURE_LA57) &&
-	    FIELD_GET(FEATURE_GATS, amd_iommu_efr) == GUEST_PGTABLE_5_LEVEL)
-		amd_iommu_gpt_level = PAGE_MODE_5_LEVEL;
-
-	efr_hats = FIELD_GET(FEATURE_HATS, amd_iommu_efr);
-	if (efr_hats != 0x3) {
-		/*
-		 * efr[HATS] bits specify the maximum host translation level
-		 * supported, with LEVEL 4 being initial max level.
-		 */
-		amd_iommu_hpt_vasize = min_t(unsigned int, max_vasize,
-					 (efr_hats + PAGE_MODE_4_LEVEL - 1) * 9 + 21);
-	} else {
-		pr_warn_once(FW_BUG "Disable host address translation due to invalid translation level (%#x).\n",
-			     efr_hats);
-		amd_iommu_hatdis = true;
-	}
-
-	if (amd_iommu_pgtable == PD_MODE_V2) {
-		if (!amd_iommu_v2_pgtbl_supported()) {
-			pr_warn("Cannot enable v2 page table for DMA-API. Fallback to v1.\n");
-			amd_iommu_pgtable = PD_MODE_V1;
-		}
-	}
-
-	if (amd_iommu_hatdis) {
-		/*
-		 * Host (v1) page table is not available. Attempt to use
-		 * Guest (v2) page table.
-		 */
-		if (amd_iommu_v2_pgtbl_supported())
-			amd_iommu_pgtable = PD_MODE_V2;
-		else
-			amd_iommu_pgtable = PD_MODE_NONE;
-	}
+	init_pgtable_params();
 
 	/* Disable any previously enabled IOMMUs */
 	if (!is_kdump_kernel() || amd_iommu_disabled)
Signature · 1 line
2.43.0
author
#2 lore raw

PATCH 2/2 iommu/amd: Adhere to IVINFO[PAsize] for output address limits

In reply to Ankit Soni

ACPI IVRS IVinfo reports the maximum physical address size (PAsize) supported by the IOMMU. The AMD IOMMU driver currently hardcodes 52 bits when configuring paging domains. On systems where firmware or a VM advertises a smaller limit, the driver may over-advertise capabilities and create domains outside the hardware's actual bounds.

---
 drivers/iommu/amd/amd_iommu.h       | 1 +
 drivers/iommu/amd/amd_iommu_types.h | 1 +
 drivers/iommu/amd/init.c            | 9 ++++++++-
 drivers/iommu/amd/iommu.c           | 4 ++--
 4 files changed, 12 insertions(+), 3 deletions(-)
drivers/iommu/amd/amd_iommu.h +1 -0
index 71113e860859..e90fdcc2f4a8 100644
@@ -45,6 +45,7 @@ extern int amd_iommu_guest_ir;
 extern enum protection_domain_mode amd_iommu_pgtable;
 extern int amd_iommu_gpt_level;
 extern u8 amd_iommu_hpt_vasize;
+extern u8 amd_iommu_pasize;
 extern unsigned long amd_iommu_pgsize_bitmap;
 extern bool amd_iommu_hatdis;
 
drivers/iommu/amd/amd_iommu_types.h +1 -0
index 4a15b16bd2ca..35ffeb16c1a3 100644
@@ -382,6 +382,7 @@
 #define IOMMU_IVINFO_EFRSUP     BIT(0)
 #define IOMMU_IVINFO_DMA_REMAP  BIT(1)
 #define IOMMU_IVINFO_VASIZE	GENMASK_ULL(21, 15)
+#define IOMMU_IVINFO_PASIZE	GENMASK_ULL(14, 8)
 
 /* IOMMU Feature Reporting Field (for IVHD type 10h */
 #define IOMMU_FEAT_GASUP_SHIFT	6
drivers/iommu/amd/init.c +8 -1
index 89da993d7d15..136e35362631 100644
@@ -157,6 +157,8 @@ bool amd_iommu_irq_remap __read_mostly;
 enum protection_domain_mode amd_iommu_pgtable = PD_MODE_V1;
 /* Virtual address size */
 u8 amd_iommu_hpt_vasize;
+/* Physical address size */
+u8 amd_iommu_pasize __ro_after_init;
 /* Guest page table level */
 int amd_iommu_gpt_level = PAGE_MODE_4_LEVEL;
 
@@ -3196,7 +3198,12 @@ static void __init ivinfo_init(void *ivrs)
 
 static void __init init_pgtable_params(void)
 {
-	u8 vasize, efr_hats;
+	u8 pasize, vasize, efr_hats;
+
+	pasize = FIELD_GET(IOMMU_IVINFO_PASIZE, amd_iommu_ivinfo);
+	if (!pasize)
+		pasize = 52;
+	amd_iommu_pasize = min_t(u8, pasize, 52);
 
 	vasize = FIELD_GET(IOMMU_IVINFO_VASIZE, amd_iommu_ivinfo);
 	if (!vasize)
drivers/iommu/amd/iommu.c +2 -2
index 893cd2be11a2..a64045f5a54a 100644
@@ -2760,7 +2760,7 @@ static struct iommu_domain *amd_iommu_domain_alloc_paging_v1(struct device *dev,
 		cfg.common.features |= BIT(PT_FEAT_FLUSH_RANGE);
 
 	cfg.common.hw_max_vasz_lg2 = amd_iommu_hpt_vasize;
-	cfg.common.hw_max_oasz_lg2 = 52;
+	cfg.common.hw_max_oasz_lg2 = amd_iommu_pasize;
 	cfg.starting_level = 2;
 	domain->domain.ops = &amdv1_ops;
 
@@ -2835,7 +2835,7 @@ static struct iommu_domain *amd_iommu_domain_alloc_paging_v2(struct device *dev,
 		cfg.common.hw_max_vasz_lg2 = 47;
 		cfg.top_level = 3;
 	}
-	cfg.common.hw_max_oasz_lg2 = 52;
+	cfg.common.hw_max_oasz_lg2 = amd_iommu_pasize;
 	domain->domain.ops = &amdv2_ops;
 
 	ret = pt_iommu_x86_64_init(&domain->amdv2, &cfg, GFP_KERNEL);
Signature · 1 line
2.43.0