Skip to content

Commit 1eb0ae6

Browse files
jgunthorpejoergroedel
authored andcommitted
iommupt/vtd: Support mgaw's less than a 4 level walk for first stage
If the IOVA is limited to less than 48 the page table will be constructed with a 3 level configuration which is unsupported by hardware. Like the second stage the caller needs to pass in both the top_level an the vasz to specify a table that has more levels than required to hold the IOVA range. Fixes: 6cbc09b ("iommu/vt-d: Restore previous domain::aperture_end calculation") Reported-by: Calvin Owens <calvin@wbinvd.org> Closes: https://lore.kernel.org/r/8f257d2651eb8a4358fcbd47b0145002e5f1d638.1764237717.git.calvin@wbinvd.org Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Tested-by: Calvin Owens <calvin@wbinvd.org> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
1 parent d856f9d commit 1eb0ae6

4 files changed

Lines changed: 38 additions & 26 deletions

File tree

drivers/iommu/amd/iommu.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2708,10 +2708,13 @@ static struct iommu_domain *amd_iommu_domain_alloc_paging_v2(struct device *dev,
27082708
* in both modes the top bit is removed and PT_FEAT_SIGN_EXTEND is not
27092709
* set which creates a table that is compatible in both modes.
27102710
*/
2711-
if (amd_iommu_gpt_level == PAGE_MODE_5_LEVEL)
2711+
if (amd_iommu_gpt_level == PAGE_MODE_5_LEVEL) {
27122712
cfg.common.hw_max_vasz_lg2 = 56;
2713-
else
2713+
cfg.top_level = 4;
2714+
} else {
27142715
cfg.common.hw_max_vasz_lg2 = 47;
2716+
cfg.top_level = 3;
2717+
}
27152718
cfg.common.hw_max_oasz_lg2 = 52;
27162719
domain->domain.ops = &amdv2_ops;
27172720

drivers/iommu/generic_pt/fmt/x86_64.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,10 @@ x86_64_pt_iommu_fmt_init(struct pt_iommu_x86_64 *iommu_table,
241241
{
242242
struct pt_x86_64 *table = &iommu_table->x86_64_pt;
243243

244-
if (cfg->common.hw_max_vasz_lg2 < 31 ||
245-
cfg->common.hw_max_vasz_lg2 > 57)
246-
return -EINVAL;
244+
if (cfg->top_level < 3 || cfg->top_level > 4)
245+
return -EOPNOTSUPP;
247246

248-
/* Top of 2, 3, 4 */
249-
pt_top_set_level(&table->common,
250-
(cfg->common.hw_max_vasz_lg2 - 31) / 9 + 2);
247+
pt_top_set_level(&table->common, cfg->top_level);
251248

252249
table->common.max_oasz_lg2 =
253250
min(PT_MAX_OUTPUT_ADDRESS_LG2, cfg->common.hw_max_oasz_lg2);
@@ -269,12 +266,12 @@ x86_64_pt_iommu_fmt_hw_info(struct pt_iommu_x86_64 *table,
269266
#if defined(GENERIC_PT_KUNIT)
270267
static const struct pt_iommu_x86_64_cfg x86_64_kunit_fmt_cfgs[] = {
271268
[0] = { .common.features = BIT(PT_FEAT_SIGN_EXTEND),
272-
.common.hw_max_vasz_lg2 = 48 },
269+
.common.hw_max_vasz_lg2 = 48, .top_level = 3 },
273270
[1] = { .common.features = BIT(PT_FEAT_SIGN_EXTEND),
274-
.common.hw_max_vasz_lg2 = 57 },
271+
.common.hw_max_vasz_lg2 = 57, .top_level = 4 },
275272
/* AMD IOMMU PASID 0 formats with no SIGN_EXTEND */
276-
[2] = { .common.hw_max_vasz_lg2 = 47 },
277-
[3] = { .common.hw_max_vasz_lg2 = 56 },
273+
[2] = { .common.hw_max_vasz_lg2 = 47, .top_level = 3 },
274+
[3] = { .common.hw_max_vasz_lg2 = 56, .top_level = 4},
278275
};
279276
#define kunit_fmt_cfgs x86_64_kunit_fmt_cfgs
280277
enum { KUNIT_FMT_FEATURES = BIT(PT_FEAT_SIGN_EXTEND)};

drivers/iommu/intel/iommu.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,6 +2794,28 @@ static struct dmar_domain *paging_domain_alloc(void)
27942794
return domain;
27952795
}
27962796

2797+
static unsigned int compute_vasz_lg2_fs(struct intel_iommu *iommu,
2798+
unsigned int *top_level)
2799+
{
2800+
unsigned int mgaw = cap_mgaw(iommu->cap);
2801+
2802+
/*
2803+
* Spec 3.6 First-Stage Translation:
2804+
*
2805+
* Software must limit addresses to less than the minimum of MGAW
2806+
* and the lower canonical address width implied by FSPM (i.e.,
2807+
* 47-bit when FSPM is 4-level and 56-bit when FSPM is 5-level).
2808+
*/
2809+
if (mgaw > 48 && cap_fl5lp_support(iommu->cap)) {
2810+
*top_level = 4;
2811+
return min(57, mgaw);
2812+
}
2813+
2814+
/* Four level is always supported */
2815+
*top_level = 3;
2816+
return min(48, mgaw);
2817+
}
2818+
27972819
static struct iommu_domain *
27982820
intel_iommu_domain_alloc_first_stage(struct device *dev,
27992821
struct intel_iommu *iommu, u32 flags)
@@ -2813,20 +2835,8 @@ intel_iommu_domain_alloc_first_stage(struct device *dev,
28132835
if (IS_ERR(dmar_domain))
28142836
return ERR_CAST(dmar_domain);
28152837

2816-
if (cap_fl5lp_support(iommu->cap))
2817-
cfg.common.hw_max_vasz_lg2 = 57;
2818-
else
2819-
cfg.common.hw_max_vasz_lg2 = 48;
2820-
2821-
/*
2822-
* Spec 3.6 First-Stage Translation:
2823-
*
2824-
* Software must limit addresses to less than the minimum of MGAW
2825-
* and the lower canonical address width implied by FSPM (i.e.,
2826-
* 47-bit when FSPM is 4-level and 56-bit when FSPM is 5-level).
2827-
*/
2828-
cfg.common.hw_max_vasz_lg2 = min(cap_mgaw(iommu->cap),
2829-
cfg.common.hw_max_vasz_lg2);
2838+
cfg.common.hw_max_vasz_lg2 =
2839+
compute_vasz_lg2_fs(iommu, &cfg.top_level);
28302840
cfg.common.hw_max_oasz_lg2 = 52;
28312841
cfg.common.features = BIT(PT_FEAT_SIGN_EXTEND) |
28322842
BIT(PT_FEAT_FLUSH_RANGE);

include/linux/generic_pt/iommu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ IOMMU_FORMAT(vtdss, vtdss_pt);
277277

278278
struct pt_iommu_x86_64_cfg {
279279
struct pt_iommu_cfg common;
280+
/* 4 is a 57 bit 5 level table */
281+
unsigned int top_level;
280282
};
281283

282284
struct pt_iommu_x86_64_hw_info {

0 commit comments

Comments
 (0)