diff options
| -rw-r--r-- | drivers/iommu/amd/iommu.c | 7 | ||||
| -rw-r--r-- | drivers/iommu/generic_pt/fmt/x86_64.h | 17 | ||||
| -rw-r--r-- | drivers/iommu/intel/iommu.c | 38 | ||||
| -rw-r--r-- | include/linux/generic_pt/iommu.h | 2 |
4 files changed, 38 insertions, 26 deletions
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 48bca4dc8eb6..273951b4501c 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2708,10 +2708,13 @@ static struct iommu_domain *amd_iommu_domain_alloc_paging_v2(struct device *dev, * in both modes the top bit is removed and PT_FEAT_SIGN_EXTEND is not * set which creates a table that is compatible in both modes. */ - if (amd_iommu_gpt_level == PAGE_MODE_5_LEVEL) + if (amd_iommu_gpt_level == PAGE_MODE_5_LEVEL) { cfg.common.hw_max_vasz_lg2 = 56; - else + cfg.top_level = 4; + } else { cfg.common.hw_max_vasz_lg2 = 47; + cfg.top_level = 3; + } cfg.common.hw_max_oasz_lg2 = 52; domain->domain.ops = &amdv2_ops; diff --git a/drivers/iommu/generic_pt/fmt/x86_64.h b/drivers/iommu/generic_pt/fmt/x86_64.h index 507abf2c934c..210748d9d6e8 100644 --- a/drivers/iommu/generic_pt/fmt/x86_64.h +++ b/drivers/iommu/generic_pt/fmt/x86_64.h @@ -241,13 +241,10 @@ x86_64_pt_iommu_fmt_init(struct pt_iommu_x86_64 *iommu_table, { struct pt_x86_64 *table = &iommu_table->x86_64_pt; - if (cfg->common.hw_max_vasz_lg2 < 31 || - cfg->common.hw_max_vasz_lg2 > 57) - return -EINVAL; + if (cfg->top_level < 3 || cfg->top_level > 4) + return -EOPNOTSUPP; - /* Top of 2, 3, 4 */ - pt_top_set_level(&table->common, - (cfg->common.hw_max_vasz_lg2 - 31) / 9 + 2); + pt_top_set_level(&table->common, cfg->top_level); table->common.max_oasz_lg2 = 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, #if defined(GENERIC_PT_KUNIT) static const struct pt_iommu_x86_64_cfg x86_64_kunit_fmt_cfgs[] = { [0] = { .common.features = BIT(PT_FEAT_SIGN_EXTEND), - .common.hw_max_vasz_lg2 = 48 }, + .common.hw_max_vasz_lg2 = 48, .top_level = 3 }, [1] = { .common.features = BIT(PT_FEAT_SIGN_EXTEND), - .common.hw_max_vasz_lg2 = 57 }, + .common.hw_max_vasz_lg2 = 57, .top_level = 4 }, /* AMD IOMMU PASID 0 formats with no SIGN_EXTEND */ - [2] = { .common.hw_max_vasz_lg2 = 47 }, - [3] = { .common.hw_max_vasz_lg2 = 56 }, + [2] = { .common.hw_max_vasz_lg2 = 47, .top_level = 3 }, + [3] = { .common.hw_max_vasz_lg2 = 56, .top_level = 4}, }; #define kunit_fmt_cfgs x86_64_kunit_fmt_cfgs enum { KUNIT_FMT_FEATURES = BIT(PT_FEAT_SIGN_EXTEND)}; diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index f117349d67db..4e888867e85c 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -2794,6 +2794,28 @@ static struct dmar_domain *paging_domain_alloc(void) return domain; } +static unsigned int compute_vasz_lg2_fs(struct intel_iommu *iommu, + unsigned int *top_level) +{ + unsigned int mgaw = cap_mgaw(iommu->cap); + + /* + * Spec 3.6 First-Stage Translation: + * + * Software must limit addresses to less than the minimum of MGAW + * and the lower canonical address width implied by FSPM (i.e., + * 47-bit when FSPM is 4-level and 56-bit when FSPM is 5-level). + */ + if (mgaw > 48 && cap_fl5lp_support(iommu->cap)) { + *top_level = 4; + return min(57, mgaw); + } + + /* Four level is always supported */ + *top_level = 3; + return min(48, mgaw); +} + static struct iommu_domain * intel_iommu_domain_alloc_first_stage(struct device *dev, struct intel_iommu *iommu, u32 flags) @@ -2813,20 +2835,8 @@ intel_iommu_domain_alloc_first_stage(struct device *dev, if (IS_ERR(dmar_domain)) return ERR_CAST(dmar_domain); - if (cap_fl5lp_support(iommu->cap)) - cfg.common.hw_max_vasz_lg2 = 57; - else - cfg.common.hw_max_vasz_lg2 = 48; - - /* - * Spec 3.6 First-Stage Translation: - * - * Software must limit addresses to less than the minimum of MGAW - * and the lower canonical address width implied by FSPM (i.e., - * 47-bit when FSPM is 4-level and 56-bit when FSPM is 5-level). - */ - cfg.common.hw_max_vasz_lg2 = min(cap_mgaw(iommu->cap), - cfg.common.hw_max_vasz_lg2); + cfg.common.hw_max_vasz_lg2 = + compute_vasz_lg2_fs(iommu, &cfg.top_level); cfg.common.hw_max_oasz_lg2 = 52; cfg.common.features = BIT(PT_FEAT_SIGN_EXTEND) | BIT(PT_FEAT_FLUSH_RANGE); diff --git a/include/linux/generic_pt/iommu.h b/include/linux/generic_pt/iommu.h index c134132ed10f..9eefbb74efd0 100644 --- a/include/linux/generic_pt/iommu.h +++ b/include/linux/generic_pt/iommu.h @@ -277,6 +277,8 @@ IOMMU_FORMAT(vtdss, vtdss_pt); struct pt_iommu_x86_64_cfg { struct pt_iommu_cfg common; + /* 4 is a 57 bit 5 level table */ + unsigned int top_level; }; struct pt_iommu_x86_64_hw_info { |
