* [PATCH v4 0/3] Respect VASIZE for address limits
@ 2026-04-01 14:43 Ankit Soni
2026-04-01 14:43 ` [PATCH v4 1/3] iommu_pt: support small VA for AMDv1 Ankit Soni
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Ankit Soni @ 2026-04-01 14:43 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.
And 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:
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 (3):
iommu/generic_pt: support small VA for AMDv1
iommu/generic_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 | 5 ++++-
drivers/iommu/generic_pt/iommu_pt.h | 4 ----
drivers/iommu/generic_pt/kunit_iommu_pt.h | 5 +++--
7 files changed, 19 insertions(+), 14 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 1/3] iommu_pt: support small VA for AMDv1
2026-04-01 14:43 [PATCH v4 0/3] Respect VASIZE for address limits Ankit Soni
@ 2026-04-01 14:43 ` Ankit Soni
2026-04-06 13:28 ` Jason Gunthorpe
2026-04-01 14:43 ` [PATCH v4 2/3] iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1) Ankit Soni
2026-04-01 14:43 ` [PATCH v4 3/3] iommu/amd: Adhere to IVINFO[VASIZE] for address limits Ankit Soni
2 siblings, 1 reply; 6+ messages in thread
From: Ankit Soni @ 2026-04-01 14:43 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.
To properly enforce the domain VA limit, clamp amdv1pt_possible_sizes
using the requested max_vasz_lg2.
Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
---
drivers/iommu/generic_pt/fmt/amdv1.h | 4 +++-
drivers/iommu/generic_pt/iommu_pt.h | 4 ----
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/generic_pt/fmt/amdv1.h b/drivers/iommu/generic_pt/fmt/amdv1.h
index 3b2c41d9654d..bc04d482c12f 100644
--- a/drivers/iommu/generic_pt/fmt/amdv1.h
+++ b/drivers/iommu/generic_pt/fmt/amdv1.h
@@ -156,6 +156,7 @@ static inline unsigned int amdv1pt_num_items_lg2(const struct pt_state *pts)
static inline pt_vaddr_t amdv1pt_possible_sizes(const struct pt_state *pts)
{
unsigned int isz_lg2 = pt_table_item_lg2sz(pts);
+ pt_vaddr_t raw;
if (!amdv1pt_can_have_leaf(pts))
return 0;
@@ -168,8 +169,9 @@ static inline pt_vaddr_t amdv1pt_possible_sizes(const struct pt_state *pts)
* 512GB Pages are not supported due to a hardware bug.
* Otherwise every power of two size is supported.
*/
- return GENMASK_ULL(min(51, isz_lg2 + amdv1pt_num_items_lg2(pts) - 1),
+ raw = GENMASK_ULL(min(51, isz_lg2 + amdv1pt_num_items_lg2(pts) - 1),
isz_lg2) & ~SZ_512G;
+ return fvalog2_mod(raw, pts->range->common->max_vasz_lg2);
}
#define pt_possible_sizes amdv1pt_possible_sizes
diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h
index 3e33fe64feab..a3dc5cf14aeb 100644
--- a/drivers/iommu/generic_pt/iommu_pt.h
+++ b/drivers/iommu/generic_pt/iommu_pt.h
@@ -1125,10 +1125,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] 6+ messages in thread
* [PATCH v4 2/3] iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1)
2026-04-01 14:43 [PATCH v4 0/3] Respect VASIZE for address limits Ankit Soni
2026-04-01 14:43 ` [PATCH v4 1/3] iommu_pt: support small VA for AMDv1 Ankit Soni
@ 2026-04-01 14:43 ` Ankit Soni
2026-04-06 13:28 ` Jason Gunthorpe
2026-04-01 14:43 ` [PATCH v4 3/3] iommu/amd: Adhere to IVINFO[VASIZE] for address limits Ankit Soni
2 siblings, 1 reply; 6+ messages in thread
From: Ankit Soni @ 2026-04-01 14:43 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.
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 bc04d482c12f..289c1c010e18 100644
--- a/drivers/iommu/generic_pt/fmt/amdv1.h
+++ b/drivers/iommu/generic_pt/fmt/amdv1.h
@@ -406,6 +406,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] 6+ messages in thread
* [PATCH v4 3/3] iommu/amd: Adhere to IVINFO[VASIZE] for address limits
2026-04-01 14:43 [PATCH v4 0/3] Respect VASIZE for address limits Ankit Soni
2026-04-01 14:43 ` [PATCH v4 1/3] iommu_pt: support small VA for AMDv1 Ankit Soni
2026-04-01 14:43 ` [PATCH v4 2/3] iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1) Ankit Soni
@ 2026-04-01 14:43 ` Ankit Soni
2 siblings, 0 replies; 6+ messages in thread
From: Ankit Soni @ 2026-04-01 14:43 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] 6+ messages in thread
* Re: [PATCH v4 1/3] iommu_pt: support small VA for AMDv1
2026-04-01 14:43 ` [PATCH v4 1/3] iommu_pt: support small VA for AMDv1 Ankit Soni
@ 2026-04-06 13:28 ` Jason Gunthorpe
0 siblings, 0 replies; 6+ messages in thread
From: Jason Gunthorpe @ 2026-04-06 13:28 UTC (permalink / raw)
To: Ankit Soni
Cc: iommu, vasant.hegde, suravee.suthikulpanit, joro, will,
robin.murphy, linux-kernel
On Wed, Apr 01, 2026 at 02:43:55PM +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.
> To properly enforce the domain VA limit, clamp amdv1pt_possible_sizes
> using the requested max_vasz_lg2.
>
> Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
> ---
> drivers/iommu/generic_pt/fmt/amdv1.h | 4 +++-
> drivers/iommu/generic_pt/iommu_pt.h | 4 ----
> 2 files changed, 3 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/iommu/generic_pt/fmt/amdv1.h b/drivers/iommu/generic_pt/fmt/amdv1.h
> index 3b2c41d9654d..bc04d482c12f 100644
> --- a/drivers/iommu/generic_pt/fmt/amdv1.h
> +++ b/drivers/iommu/generic_pt/fmt/amdv1.h
> @@ -156,6 +156,7 @@ static inline unsigned int amdv1pt_num_items_lg2(const struct pt_state *pts)
> static inline pt_vaddr_t amdv1pt_possible_sizes(const struct pt_state *pts)
> {
> unsigned int isz_lg2 = pt_table_item_lg2sz(pts);
> + pt_vaddr_t raw;
>
> if (!amdv1pt_can_have_leaf(pts))
> return 0;
> @@ -168,8 +169,9 @@ static inline pt_vaddr_t amdv1pt_possible_sizes(const struct pt_state *pts)
> * 512GB Pages are not supported due to a hardware bug.
> * Otherwise every power of two size is supported.
> */
> - return GENMASK_ULL(min(51, isz_lg2 + amdv1pt_num_items_lg2(pts) - 1),
> + raw = GENMASK_ULL(min(51, isz_lg2 + amdv1pt_num_items_lg2(pts) - 1),
> isz_lg2) & ~SZ_512G;
> + return fvalog2_mod(raw, pts->range->common->max_vasz_lg2);
> }
> #define pt_possible_sizes amdv1pt_possible_sizes
This is a generic issue, I think it should be fixed like this instead:
@@ -1153,8 +1153,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);
}
pt_possible_sizes() always has to be masked with the pgsize_bitmap, so
fixing it here is enough to remove those sizes from all the other
places..
Then one of the tests isn't following that rule, so it needs a fix too:
@@ -438,6 +440,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)) {
@@ -448,7 +453,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
@@ -463,8 +469,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));
}
And it should go in its own patch: "fix pgsize_bitmap calculation in
get_info for smaller vasz's"
Jason
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 2/3] iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1)
2026-04-01 14:43 ` [PATCH v4 2/3] iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1) Ankit Soni
@ 2026-04-06 13:28 ` Jason Gunthorpe
0 siblings, 0 replies; 6+ messages in thread
From: Jason Gunthorpe @ 2026-04-06 13:28 UTC (permalink / raw)
To: Ankit Soni
Cc: iommu, vasant.hegde, suravee.suthikulpanit, joro, will,
robin.murphy, linux-kernel
On Wed, Apr 01, 2026 at 02:43:56PM +0000, Ankit Soni wrote:
> 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.
>
> 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(-)
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Jason
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-06 13:28 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-01 14:43 [PATCH v4 0/3] Respect VASIZE for address limits Ankit Soni
2026-04-01 14:43 ` [PATCH v4 1/3] iommu_pt: support small VA for AMDv1 Ankit Soni
2026-04-06 13:28 ` Jason Gunthorpe
2026-04-01 14:43 ` [PATCH v4 2/3] iommu_pt: add kunit config for 32-bit VA (amdv1_cfg_1) Ankit Soni
2026-04-06 13:28 ` Jason Gunthorpe
2026-04-01 14:43 ` [PATCH v4 3/3] 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