Skip to content

Commit f594496

Browse files
hegdevasantjoergroedel
authored andcommitted
iommu/amd: Add 5 level guest page table support
Newer AMD IOMMU supports 5 level guest page table (v2 page table). If both processor and IOMMU supports 5 level page table then enable it. Otherwise fall back to 4 level page table. Co-developed-by: Wei Huang <[email protected]> Signed-off-by: Wei Huang <[email protected]> Reviewed-by: Suravee Suthikulpanit <[email protected]> Signed-off-by: Vasant Hegde <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 4d4a0db commit f594496

File tree

5 files changed

+40
-5
lines changed

5 files changed

+40
-5
lines changed

drivers/iommu/amd/amd_iommu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extern int amd_iommu_reenable(int);
3434
extern int amd_iommu_enable_faulting(void);
3535
extern int amd_iommu_guest_ir;
3636
extern enum io_pgtable_fmt amd_iommu_pgtable;
37+
extern int amd_iommu_gpt_level;
3738

3839
/* IOMMUv2 specific functions */
3940
struct iommu_domain;

drivers/iommu/amd/amd_iommu_types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@
9393
#define FEATURE_GA (1ULL<<7)
9494
#define FEATURE_HE (1ULL<<8)
9595
#define FEATURE_PC (1ULL<<9)
96+
#define FEATURE_GATS_SHIFT (12)
97+
#define FEATURE_GATS_MASK (3ULL)
9698
#define FEATURE_GAM_VAPIC (1ULL<<21)
9799
#define FEATURE_GIOSUP (1ULL<<48)
98100
#define FEATURE_EPHSUP (1ULL<<50)
@@ -305,6 +307,9 @@
305307
#define PAGE_MODE_6_LEVEL 0x06
306308
#define PAGE_MODE_7_LEVEL 0x07
307309

310+
#define GUEST_PGTABLE_4_LEVEL 0x00
311+
#define GUEST_PGTABLE_5_LEVEL 0x01
312+
308313
#define PM_LEVEL_SHIFT(x) (12 + ((x) * 9))
309314
#define PM_LEVEL_SIZE(x) (((x) < 6) ? \
310315
((1ULL << PM_LEVEL_SHIFT((x))) - 1): \
@@ -398,6 +403,8 @@
398403
#define DTE_GCR3_SHIFT_B 16
399404
#define DTE_GCR3_SHIFT_C 43
400405

406+
#define DTE_GPT_LEVEL_SHIFT 54
407+
401408
#define GCR3_VALID 0x01ULL
402409

403410
#define IOMMU_PAGE_MASK (((1ULL << 52) - 1) & ~0xfffULL)

drivers/iommu/amd/init.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ bool amd_iommu_dump;
153153
bool amd_iommu_irq_remap __read_mostly;
154154

155155
enum io_pgtable_fmt amd_iommu_pgtable = AMD_IOMMU_V1;
156+
/* Guest page table level */
157+
int amd_iommu_gpt_level = PAGE_MODE_4_LEVEL;
156158

157159
int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC;
158160
static int amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE;
@@ -306,6 +308,11 @@ static bool check_feature_on_all_iommus(u64 mask)
306308
return !!(amd_iommu_efr & mask);
307309
}
308310

311+
static inline int check_feature_gpt_level(void)
312+
{
313+
return ((amd_iommu_efr >> FEATURE_GATS_SHIFT) & FEATURE_GATS_MASK);
314+
}
315+
309316
/*
310317
* For IVHD type 0x11/0x40, EFR is also available via IVHD.
311318
* Default to IVHD EFR since it is available sooner
@@ -2155,8 +2162,10 @@ static void print_iommu_info(void)
21552162
if (amd_iommu_xt_mode == IRQ_REMAP_X2APIC_MODE)
21562163
pr_info("X2APIC enabled\n");
21572164
}
2158-
if (amd_iommu_pgtable == AMD_IOMMU_V2)
2159-
pr_info("V2 page table enabled\n");
2165+
if (amd_iommu_pgtable == AMD_IOMMU_V2) {
2166+
pr_info("V2 page table enabled (Paging mode : %d level)\n",
2167+
amd_iommu_gpt_level);
2168+
}
21602169
}
21612170

21622171
static int __init amd_iommu_init_pci(void)
@@ -3026,6 +3035,11 @@ static int __init early_amd_iommu_init(void)
30263035
if (ret)
30273036
goto out;
30283037

3038+
/* 5 level guest page table */
3039+
if (cpu_feature_enabled(X86_FEATURE_LA57) &&
3040+
check_feature_gpt_level() == GUEST_PGTABLE_5_LEVEL)
3041+
amd_iommu_gpt_level = PAGE_MODE_5_LEVEL;
3042+
30293043
/* Disable any previously enabled IOMMUs */
30303044
if (!is_kdump_kernel() || amd_iommu_disabled)
30313045
disable_iommus();
@@ -3557,6 +3571,11 @@ __setup("ivrs_acpihid", parse_ivrs_acpihid);
35573571

35583572
bool amd_iommu_v2_supported(void)
35593573
{
3574+
/* CPU page table size should match IOMMU guest page table size */
3575+
if (cpu_feature_enabled(X86_FEATURE_LA57) &&
3576+
amd_iommu_gpt_level != PAGE_MODE_5_LEVEL)
3577+
return false;
3578+
35603579
/*
35613580
* Since DTE[Mode]=0 is prohibited on SNP-enabled system
35623581
* (i.e. EFR[SNPSup]=1), IOMMUv2 page table cannot be used without

drivers/iommu/amd/io_pgtable_v2.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@
3737

3838
static inline int get_pgtable_level(void)
3939
{
40-
/* 5 level page table is not supported */
41-
return PAGE_MODE_4_LEVEL;
40+
return amd_iommu_gpt_level;
4241
}
4342

4443
static inline bool is_large_pte(u64 pte)
@@ -379,6 +378,7 @@ static struct io_pgtable *v2_alloc_pgtable(struct io_pgtable_cfg *cfg, void *coo
379378
struct amd_io_pgtable *pgtable = io_pgtable_cfg_to_data(cfg);
380379
struct protection_domain *pdom = (struct protection_domain *)cookie;
381380
int ret;
381+
int ias = IOMMU_IN_ADDR_BIT_SIZE;
382382

383383
pgtable->pgd = alloc_pgtable_page(pdom->nid, GFP_ATOMIC);
384384
if (!pgtable->pgd)
@@ -388,12 +388,15 @@ static struct io_pgtable *v2_alloc_pgtable(struct io_pgtable_cfg *cfg, void *coo
388388
if (ret)
389389
goto err_free_pgd;
390390

391+
if (get_pgtable_level() == PAGE_MODE_5_LEVEL)
392+
ias = 57;
393+
391394
pgtable->iop.ops.map_pages = iommu_v2_map_pages;
392395
pgtable->iop.ops.unmap_pages = iommu_v2_unmap_pages;
393396
pgtable->iop.ops.iova_to_phys = iommu_v2_iova_to_phys;
394397

395398
cfg->pgsize_bitmap = AMD_IOMMU_PGSIZES_V2,
396-
cfg->ias = IOMMU_IN_ADDR_BIT_SIZE,
399+
cfg->ias = ias,
397400
cfg->oas = IOMMU_OUT_ADDR_BIT_SIZE,
398401
cfg->tlb = &v2_flush_ops;
399402

drivers/iommu/amd/iommu.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,11 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 devid,
16111611
tmp = DTE_GCR3_VAL_C(gcr3) << DTE_GCR3_SHIFT_C;
16121612
flags |= tmp;
16131613

1614+
if (amd_iommu_gpt_level == PAGE_MODE_5_LEVEL) {
1615+
dev_table[devid].data[2] |=
1616+
((u64)GUEST_PGTABLE_5_LEVEL << DTE_GPT_LEVEL_SHIFT);
1617+
}
1618+
16141619
if (domain->flags & PD_GIOV_MASK)
16151620
pte_root |= DTE_FLAG_GIOV;
16161621
}

0 commit comments

Comments
 (0)