]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/amd: Add efr[HATS] max v1 page table level
authorAnkit Soni <Ankit.Soni@amd.com>
Wed, 4 Jun 2025 06:13:25 +0000 (06:13 +0000)
committerJoerg Roedel <joerg.roedel@amd.com>
Fri, 27 Jun 2025 06:51:20 +0000 (08:51 +0200)
The EFR[HATS] bits indicate maximum host translation level supported by
IOMMU. Adding support to set the maximum host page table level as indicated
by EFR[HATS]. If the HATS=11b (reserved), the driver will attempt to use
guest page table for DMA API.

Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
Reviewed-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
Link: https://lore.kernel.org/r/df0f8562c2a20895cc185c86f1a02c4d826fd597.1749016436.git.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/io_pgtable.c
drivers/iommu/amd/iommu.c

index fddfad4a9009468b0ad01170ff47089ec4274155..0bf3744c7b3a526dff8ce09c82526cddf4fbce60 100644 (file)
@@ -42,6 +42,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 unsigned long amd_iommu_pgsize_bitmap;
 extern bool amd_iommu_hatdis;
 
index 69291cef73f7b7f3a680801fda197e723ab515ee..35ee7b0648af6aa26632b3300da04b8d6539d276 100644 (file)
@@ -94,6 +94,7 @@
 #define FEATURE_GA             BIT_ULL(7)
 #define FEATURE_HE             BIT_ULL(8)
 #define FEATURE_PC             BIT_ULL(9)
+#define FEATURE_HATS           GENMASK_ULL(11, 10)
 #define FEATURE_GATS           GENMASK_ULL(13, 12)
 #define FEATURE_GLX            GENMASK_ULL(15, 14)
 #define FEATURE_GAM_VAPIC      BIT_ULL(21)
index 2c181dfa23e029fca19200b8d942339582257f6d..cadb2c735ffcc3627528e68e029f6837fbd732cb 100644 (file)
@@ -152,6 +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;
 /* Guest page table level */
 int amd_iommu_gpt_level = PAGE_MODE_4_LEVEL;
 
@@ -3049,6 +3051,7 @@ static int __init early_amd_iommu_init(void)
        struct acpi_table_header *ivrs_base;
        int ret;
        acpi_status status;
+       u8 efr_hats;
 
        if (!amd_iommu_detected)
                return -ENODEV;
@@ -3093,6 +3096,19 @@ static int __init early_amd_iommu_init(void)
            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_level = efr_hats + PAGE_MODE_4_LEVEL;
+       } 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");
index 4d308c0711349557061733d7fb9c9fc39fd0e472..a91e71f981efb9ff539e046e9e83a8829a50a484 100644 (file)
@@ -125,7 +125,7 @@ static bool increase_address_space(struct amd_io_pgtable *pgtable,
                goto out;
 
        ret = false;
-       if (WARN_ON_ONCE(pgtable->mode == PAGE_MODE_6_LEVEL))
+       if (WARN_ON_ONCE(pgtable->mode == amd_iommu_hpt_level))
                goto out;
 
        *pte = PM_LEVEL_PDE(pgtable->mode, iommu_virt_to_phys(pgtable->root));
@@ -526,7 +526,7 @@ static void v1_free_pgtable(struct io_pgtable *iop)
 
        /* Page-table is not visible to IOMMU anymore, so free it */
        BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
-              pgtable->mode > PAGE_MODE_6_LEVEL);
+              pgtable->mode > amd_iommu_hpt_level);
 
        free_sub_pt(pgtable->root, pgtable->mode, &freelist);
        iommu_put_pages_list(&freelist);
index 8a9babd6dfa7dc1c1bd8a52c75befc675fae5626..9c67f0be2b3538d2eaf94168feca0045070cfa86 100644 (file)
@@ -2534,7 +2534,7 @@ static int pdom_setup_pgtable(struct protection_domain *domain,
 static inline u64 dma_max_address(enum protection_domain_mode pgtable)
 {
        if (pgtable == PD_MODE_V1)
-               return ~0ULL;
+               return PM_LEVEL_SIZE(amd_iommu_hpt_level);
 
        /* V2 with 4/5 level page table */
        return ((1ULL << PM_LEVEL_SHIFT(amd_iommu_gpt_level)) - 1);