]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/amd: Adhere to IVINFO[VASIZE] for address limits
authorAnkit Soni <Ankit.Soni@amd.com>
Mon, 13 Apr 2026 14:45:21 +0000 (14:45 +0000)
committerJoerg Roedel <joerg.roedel@amd.com>
Tue, 19 May 2026 08:49:03 +0000 (10:49 +0200)
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>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
drivers/iommu/amd/amd_iommu.h
drivers/iommu/amd/amd_iommu_types.h
drivers/iommu/amd/init.c
drivers/iommu/amd/iommu.c

index 834d8fabfba3873ce00b96547f9eb06bbf435080..af720bf14914d9694cc4273a90ba6914fee4b397 100644 (file)
@@ -44,7 +44,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;
 
index f9f7180878930341e92a42b318cb61de6d569637..315c77e5adb2f7ed7b62584861fd9b53a9e897a7 100644 (file)
 #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
index 3bdb380d23e9a93c9ab9399afe7872645964b2bd..b4d810a1cf33c932f0ef0f28e129ae56744d1040 100644 (file)
@@ -155,8 +155,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;
 
@@ -3202,7 +3202,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;
@@ -3232,6 +3232,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);
 
@@ -3254,7 +3258,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);
index f78e23f03938d60b3526447dc3fbbdfd321fa3a4..65082b9e4b5253863e980cdd219dd644aeb30a5e 100644 (file)
@@ -2714,8 +2714,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;