* [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* 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
* [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
* 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
* [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