public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/4] Respect VASIZE for address limits
@ 2026-04-13 14:45 Ankit Soni
  2026-04-13 14:45 ` [PATCH v5 1/4] iommu_pt: Fix pgsize_bitmap calculation in get_info for smaller vasz's Ankit Soni
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Ankit Soni @ 2026-04-13 14:45 UTC (permalink / raw)
  To: iommu
  Cc: vasant.hegde, suravee.suthikulpanit, joro, will, robin.murphy,
	linux-kernel, jgg

The AMD IOMMU driver was only using EFR[HATS] to derive the VA size,
ignoring the IVINFO[VASIZE] limit. This could create domains that
exceed the bounds advertised by hypervisor. With this series, driver
respects IVINFO[VASIZE] when determining the addressable VA range.

For a small VA size, domain initialization in the generic page table
framework can fail with -EOPNOTSUPP. This happens because the page table
clears the dynamic top feature from the force enabled feature set, as no
page table growth is needed beyond the current level.
This series also fixes this issue and adds KUnit test coverage for the
32-bit VA configuration.

Changes:
v5: - Added Jason's suggestion for modifying get_info().
v4: - Remove PT_FEAT_DYNAMIC_TOP check from pt_init_common().
    - Add test coverage in amdv1 for 32bit va size.
v3: - Remove specific value checking for vasize.
    - Add patch for PT_FORCE_ENABLED_FEATURES.
v2: - Mark ivinfo_vasize_bits() as __init.

Ankit Soni (4):
  iommu_pt: Fix pgsize_bitmap calculation in get_info for smaller vasz's
  iommu_pt: support small VA for AMDv1
  iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1)
  iommu/amd: Adhere to IVINFO[VASIZE] for address limits

 drivers/iommu/amd/amd_iommu.h               |  2 +-
 drivers/iommu/amd/amd_iommu_types.h         |  1 +
 drivers/iommu/amd/init.c                    | 13 +++++++++----
 drivers/iommu/amd/iommu.c                   |  3 +--
 drivers/iommu/generic_pt/fmt/amdv1.h        |  1 +
 drivers/iommu/generic_pt/iommu_pt.h         | 12 ++++++------
 drivers/iommu/generic_pt/kunit_generic_pt.h | 10 +++++++---
 drivers/iommu/generic_pt/kunit_iommu_pt.h   |  5 +++--
 8 files changed, 29 insertions(+), 18 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v5 1/4] iommu_pt: Fix pgsize_bitmap calculation in get_info for smaller vasz's
  2026-04-13 14:45 [PATCH v5 0/4] Respect VASIZE for address limits Ankit Soni
@ 2026-04-13 14:45 ` Ankit Soni
  2026-04-13 16:11   ` Jason Gunthorpe
  2026-04-13 14:45 ` [PATCH v5 2/4] iommu_pt: support small VA for AMDv1 Ankit Soni
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Ankit Soni @ 2026-04-13 14:45 UTC (permalink / raw)
  To: iommu
  Cc: vasant.hegde, suravee.suthikulpanit, joro, will, robin.murphy,
	linux-kernel, jgg

To properly enforce the domain VA limit, clamp pgsize_bitmap using the
requested max_vasz_lg2 in get_info().
Apply the same VA limit as get_info() in the kunit possible_sizes test so
assertions stay consistent with the domain bitmap.

Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
---
 drivers/iommu/generic_pt/iommu_pt.h         |  8 ++++++--
 drivers/iommu/generic_pt/kunit_generic_pt.h | 10 +++++++---
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h
index 3e33fe64feab..f150e3a7f545 100644
--- a/drivers/iommu/generic_pt/iommu_pt.h
+++ b/drivers/iommu/generic_pt/iommu_pt.h
@@ -1084,8 +1084,12 @@ static void NS(get_info)(struct pt_iommu *iommu_table,
 			pgsize_bitmap |= pt_possible_sizes(&pts);
 	}
 
-	/* Hide page sizes larger than the maximum OA */
-	info->pgsize_bitmap = oalog2_mod(pgsize_bitmap, common->max_oasz_lg2);
+	/*
+	 * Hide page sizes larger than the maximum. -1 because a whole table
+	 * pgsize is not allowed
+	 */
+	info->pgsize_bitmap = log2_mod(pgsize_bitmap, common->max_vasz_lg2 - 1);
+	info->pgsize_bitmap = oalog2_mod(info->pgsize_bitmap, common->max_oasz_lg2);
 }
 
 static void NS(deinit)(struct pt_iommu *iommu_table)
diff --git a/drivers/iommu/generic_pt/kunit_generic_pt.h b/drivers/iommu/generic_pt/kunit_generic_pt.h
index 68278bf15cfe..3672f1c7e4cb 100644
--- a/drivers/iommu/generic_pt/kunit_generic_pt.h
+++ b/drivers/iommu/generic_pt/kunit_generic_pt.h
@@ -427,6 +427,9 @@ static void test_lvl_possible_sizes(struct kunit *test, struct pt_state *pts,
 {
 	unsigned int num_items_lg2 = safe_pt_num_items_lg2(pts);
 	pt_vaddr_t pgsize_bitmap = pt_possible_sizes(pts);
+	/* Matches get_info() */
+	pt_vaddr_t limited_pgsize_bitmap =
+		log2_mod(pgsize_bitmap, pts->range->common->max_vasz_lg2 - 1);
 	unsigned int isz_lg2 = pt_table_item_lg2sz(pts);
 
 	if (!pt_can_have_leaf(pts)) {
@@ -437,7 +440,8 @@ static void test_lvl_possible_sizes(struct kunit *test, struct pt_state *pts,
 	/* No bits for sizes that would be outside this table */
 	KUNIT_ASSERT_EQ(test, log2_mod(pgsize_bitmap, isz_lg2), 0);
 	KUNIT_ASSERT_EQ(
-		test, fvalog2_div(pgsize_bitmap, num_items_lg2 + isz_lg2), 0);
+		test,
+		fvalog2_div(limited_pgsize_bitmap, num_items_lg2 + isz_lg2), 0);
 
 	/*
 	 * Non contiguous must be supported. AMDv1 has a HW bug where it does
@@ -452,8 +456,8 @@ static void test_lvl_possible_sizes(struct kunit *test, struct pt_state *pts,
 	/* A contiguous entry should not span the whole table */
 	if (num_items_lg2 + isz_lg2 != PT_VADDR_MAX_LG2)
 		KUNIT_ASSERT_FALSE(
-			test,
-			pgsize_bitmap & log2_to_int(num_items_lg2 + isz_lg2));
+			test, limited_pgsize_bitmap &
+					log2_to_int(num_items_lg2 + isz_lg2));
 }
 
 static void test_entry_possible_sizes(struct kunit *test)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 2/4] iommu_pt: support small VA for AMDv1
  2026-04-13 14:45 [PATCH v5 0/4] Respect VASIZE for address limits Ankit Soni
  2026-04-13 14:45 ` [PATCH v5 1/4] iommu_pt: Fix pgsize_bitmap calculation in get_info for smaller vasz's Ankit Soni
@ 2026-04-13 14:45 ` Ankit Soni
  2026-04-13 16:11   ` Jason Gunthorpe
  2026-04-13 14:45 ` [PATCH v5 3/4] iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1) Ankit Soni
  2026-04-13 14:45 ` [PATCH v5 4/4] iommu/amd: Adhere to IVINFO[VASIZE] for address limits Ankit Soni
  3 siblings, 1 reply; 7+ messages in thread
From: Ankit Soni @ 2026-04-13 14:45 UTC (permalink / raw)
  To: iommu
  Cc: vasant.hegde, suravee.suthikulpanit, joro, will, robin.murphy,
	linux-kernel, jgg

When hardware/VM request a small VA limit, the generic page-table code
clears PT_FEAT_DYNAMIC_TOP. This later causes domain initialization to
fail with -EOPNOTSUPP.

Remove the clearing so init succeeds when the VA fits in the starting
level and no top-level growth is needed.

Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
---
 drivers/iommu/generic_pt/iommu_pt.h | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h
index f150e3a7f545..d91981e2128b 100644
--- a/drivers/iommu/generic_pt/iommu_pt.h
+++ b/drivers/iommu/generic_pt/iommu_pt.h
@@ -1129,10 +1129,6 @@ static int pt_init_common(struct pt_common *common)
 	if (PT_WARN_ON(top_range.top_level > PT_MAX_TOP_LEVEL))
 		return -EINVAL;
 
-	if (top_range.top_level == PT_MAX_TOP_LEVEL ||
-	    common->max_vasz_lg2 == top_range.max_vasz_lg2)
-		common->features &= ~BIT(PT_FEAT_DYNAMIC_TOP);
-
 	if (top_range.max_vasz_lg2 == PT_VADDR_MAX_LG2)
 		common->features |= BIT(PT_FEAT_FULL_VA);
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 3/4] iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1)
  2026-04-13 14:45 [PATCH v5 0/4] Respect VASIZE for address limits Ankit Soni
  2026-04-13 14:45 ` [PATCH v5 1/4] iommu_pt: Fix pgsize_bitmap calculation in get_info for smaller vasz's Ankit Soni
  2026-04-13 14:45 ` [PATCH v5 2/4] iommu_pt: support small VA for AMDv1 Ankit Soni
@ 2026-04-13 14:45 ` Ankit Soni
  2026-04-13 14:45 ` [PATCH v5 4/4] iommu/amd: Adhere to IVINFO[VASIZE] for address limits Ankit Soni
  3 siblings, 0 replies; 7+ messages in thread
From: Ankit Soni @ 2026-04-13 14:45 UTC (permalink / raw)
  To: iommu
  Cc: vasant.hegde, suravee.suthikulpanit, joro, will, robin.murphy,
	linux-kernel, jgg

Add test coverage for small VAs (32‑bit) starting at level 2 by enabling
the AMDv1 KUnit configuration. This limits level expansion because the
starting level can accommodate only the maximum virtual address requested.

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
---
 drivers/iommu/generic_pt/fmt/amdv1.h      | 1 +
 drivers/iommu/generic_pt/kunit_iommu_pt.h | 5 +++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/generic_pt/fmt/amdv1.h b/drivers/iommu/generic_pt/fmt/amdv1.h
index 3b2c41d9654d..52ea88ee46da 100644
--- a/drivers/iommu/generic_pt/fmt/amdv1.h
+++ b/drivers/iommu/generic_pt/fmt/amdv1.h
@@ -404,6 +404,7 @@ amdv1pt_iommu_fmt_hw_info(struct pt_iommu_amdv1 *table,
 static const struct pt_iommu_amdv1_cfg amdv1_kunit_fmt_cfgs[] = {
 	/* Matches what io_pgtable does */
 	[0] = { .starting_level = 2 },
+	[1] = { .starting_level = 2, .common.hw_max_vasz_lg2 = 32 },
 };
 #define kunit_fmt_cfgs amdv1_kunit_fmt_cfgs
 enum { KUNIT_FMT_FEATURES = 0 };
diff --git a/drivers/iommu/generic_pt/kunit_iommu_pt.h b/drivers/iommu/generic_pt/kunit_iommu_pt.h
index e8a63c8ea850..ece1c9b8c55d 100644
--- a/drivers/iommu/generic_pt/kunit_iommu_pt.h
+++ b/drivers/iommu/generic_pt/kunit_iommu_pt.h
@@ -112,8 +112,9 @@ static void test_increase_level(struct kunit *test)
 	if (IS_32BIT)
 		kunit_skip(test, "Unable to test on 32bit");
 
-	KUNIT_ASSERT_GT(test, common->max_vasz_lg2,
-			pt_top_range(common).max_vasz_lg2);
+	if (common->max_vasz_lg2 <= pt_top_range(common).max_vasz_lg2)
+		kunit_skip(test,
+			   "max_vasz_lg2 fits in starting level, no growth possible");
 
 	/* Add every possible level to the max */
 	while (common->max_vasz_lg2 != pt_top_range(common).max_vasz_lg2) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 4/4] iommu/amd: Adhere to IVINFO[VASIZE] for address limits
  2026-04-13 14:45 [PATCH v5 0/4] Respect VASIZE for address limits Ankit Soni
                   ` (2 preceding siblings ...)
  2026-04-13 14:45 ` [PATCH v5 3/4] iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1) Ankit Soni
@ 2026-04-13 14:45 ` Ankit Soni
  3 siblings, 0 replies; 7+ messages in thread
From: Ankit Soni @ 2026-04-13 14:45 UTC (permalink / raw)
  To: iommu
  Cc: vasant.hegde, suravee.suthikulpanit, joro, will, robin.murphy,
	linux-kernel, jgg

ACPI IVRS IVHD’s IVINFO field reports the maximum virtual address
size (VASIZE) supported by the IOMMU. The AMD IOMMU driver currently
caps this with pagetable level reported by EFR[HATS] when configuring
paging domains (hw_max_vasz_lg2). On systems where firmware or VM
advertises smaller or different limits, the driver may over-advertise
capabilities and create domains outside the hardware’s actual bounds.

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
---
 drivers/iommu/amd/amd_iommu.h       |  2 +-
 drivers/iommu/amd/amd_iommu_types.h |  1 +
 drivers/iommu/amd/init.c            | 13 +++++++++----
 drivers/iommu/amd/iommu.c           |  3 +--
 4 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 1342e764a548..f915938a3a08 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -41,7 +41,7 @@ int amd_iommu_enable_faulting(unsigned int cpu);
 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_level;
+extern u8 amd_iommu_hpt_vasize;
 extern unsigned long amd_iommu_pgsize_bitmap;
 extern bool amd_iommu_hatdis;
 
diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
index c685d3771436..6a85a38d34bd 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -395,6 +395,7 @@
 #define IOMMU_IVINFO_OFFSET     36
 #define IOMMU_IVINFO_EFRSUP     BIT(0)
 #define IOMMU_IVINFO_DMA_REMAP  BIT(1)
+#define IOMMU_IVINFO_VASIZE	GENMASK_ULL(21, 15)
 
 /* IOMMU Feature Reporting Field (for IVHD type 10h */
 #define IOMMU_FEAT_GASUP_SHIFT	6
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index f3fd7f39efb4..e874a4135d5c 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -152,8 +152,8 @@ bool amd_iommu_dump;
 bool amd_iommu_irq_remap __read_mostly;
 
 enum protection_domain_mode amd_iommu_pgtable = PD_MODE_V1;
-/* Host page table level */
-u8 amd_iommu_hpt_level;
+/* Virtual address size */
+u8 amd_iommu_hpt_vasize;
 /* Guest page table level */
 int amd_iommu_gpt_level = PAGE_MODE_4_LEVEL;
 
@@ -3188,7 +3188,7 @@ static int __init early_amd_iommu_init(void)
 	struct acpi_table_header *ivrs_base;
 	int ret;
 	acpi_status status;
-	u8 efr_hats;
+	u8 efr_hats, max_vasize;
 
 	if (!amd_iommu_detected)
 		return -ENODEV;
@@ -3218,6 +3218,10 @@ 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);
 
@@ -3240,7 +3244,8 @@ static int __init early_amd_iommu_init(void)
 		 * efr[HATS] bits specify the maximum host translation level
 		 * supported, with LEVEL 4 being initial max level.
 		 */
-		amd_iommu_hpt_level = efr_hats + PAGE_MODE_4_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);
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 760d5f4623b5..c18252a2c857 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2712,8 +2712,7 @@ static struct iommu_domain *amd_iommu_domain_alloc_paging_v1(struct device *dev,
 	else
 		cfg.common.features |= BIT(PT_FEAT_FLUSH_RANGE);
 
-	cfg.common.hw_max_vasz_lg2 =
-		min(64, (amd_iommu_hpt_level - 1) * 9 + 21);
+	cfg.common.hw_max_vasz_lg2 = amd_iommu_hpt_vasize;
 	cfg.common.hw_max_oasz_lg2 = 52;
 	cfg.starting_level = 2;
 	domain->domain.ops = &amdv1_ops;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v5 1/4] iommu_pt: Fix pgsize_bitmap calculation in get_info for smaller vasz's
  2026-04-13 14:45 ` [PATCH v5 1/4] iommu_pt: Fix pgsize_bitmap calculation in get_info for smaller vasz's Ankit Soni
@ 2026-04-13 16:11   ` Jason Gunthorpe
  0 siblings, 0 replies; 7+ messages in thread
From: Jason Gunthorpe @ 2026-04-13 16:11 UTC (permalink / raw)
  To: Ankit Soni
  Cc: iommu, vasant.hegde, suravee.suthikulpanit, joro, will,
	robin.murphy, linux-kernel

On Mon, Apr 13, 2026 at 02:45:18PM +0000, Ankit Soni wrote:
> To properly enforce the domain VA limit, clamp pgsize_bitmap using the
> requested max_vasz_lg2 in get_info().
> Apply the same VA limit as get_info() in the kunit possible_sizes test so
> assertions stay consistent with the domain bitmap.
> 
> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
> ---
>  drivers/iommu/generic_pt/iommu_pt.h         |  8 ++++++--
>  drivers/iommu/generic_pt/kunit_generic_pt.h | 10 +++++++---
>  2 files changed, 13 insertions(+), 5 deletions(-)

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>

Jason

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v5 2/4] iommu_pt: support small VA for AMDv1
  2026-04-13 14:45 ` [PATCH v5 2/4] iommu_pt: support small VA for AMDv1 Ankit Soni
@ 2026-04-13 16:11   ` Jason Gunthorpe
  0 siblings, 0 replies; 7+ messages in thread
From: Jason Gunthorpe @ 2026-04-13 16:11 UTC (permalink / raw)
  To: Ankit Soni
  Cc: iommu, vasant.hegde, suravee.suthikulpanit, joro, will,
	robin.murphy, linux-kernel

On Mon, Apr 13, 2026 at 02:45:19PM +0000, Ankit Soni wrote:
> When hardware/VM request a small VA limit, the generic page-table code
> clears PT_FEAT_DYNAMIC_TOP. This later causes domain initialization to
> fail with -EOPNOTSUPP.
> 
> Remove the clearing so init succeeds when the VA fits in the starting
> level and no top-level growth is needed.
> 
> Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
> ---
>  drivers/iommu/generic_pt/iommu_pt.h | 4 ----
>  1 file changed, 4 deletions(-)

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>

Jason

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-04-13 16:11 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-13 14:45 [PATCH v5 0/4] Respect VASIZE for address limits Ankit Soni
2026-04-13 14:45 ` [PATCH v5 1/4] iommu_pt: Fix pgsize_bitmap calculation in get_info for smaller vasz's Ankit Soni
2026-04-13 16:11   ` Jason Gunthorpe
2026-04-13 14:45 ` [PATCH v5 2/4] iommu_pt: support small VA for AMDv1 Ankit Soni
2026-04-13 16:11   ` Jason Gunthorpe
2026-04-13 14:45 ` [PATCH v5 3/4] iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1) Ankit Soni
2026-04-13 14:45 ` [PATCH v5 4/4] iommu/amd: Adhere to IVINFO[VASIZE] for address limits Ankit Soni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox