summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/iommu/amd/iommu.c7
-rw-r--r--drivers/iommu/generic_pt/fmt/x86_64.h17
-rw-r--r--drivers/iommu/intel/iommu.c38
-rw-r--r--include/linux/generic_pt/iommu.h2
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 {