Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 6cbc09b7719e ("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>

authored by

Jason Gunthorpe and committed by
Joerg Roedel
1eb0ae6f d856f9d2

+38 -26
+5 -2
drivers/iommu/amd/iommu.c
··· 2708 2708 * in both modes the top bit is removed and PT_FEAT_SIGN_EXTEND is not 2709 2709 * set which creates a table that is compatible in both modes. 2710 2710 */ 2711 - if (amd_iommu_gpt_level == PAGE_MODE_5_LEVEL) 2711 + if (amd_iommu_gpt_level == PAGE_MODE_5_LEVEL) { 2712 2712 cfg.common.hw_max_vasz_lg2 = 56; 2713 - else 2713 + cfg.top_level = 4; 2714 + } else { 2714 2715 cfg.common.hw_max_vasz_lg2 = 47; 2716 + cfg.top_level = 3; 2717 + } 2715 2718 cfg.common.hw_max_oasz_lg2 = 52; 2716 2719 domain->domain.ops = &amdv2_ops; 2717 2720
+7 -10
drivers/iommu/generic_pt/fmt/x86_64.h
··· 241 241 { 242 242 struct pt_x86_64 *table = &iommu_table->x86_64_pt; 243 243 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; 247 246 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); 251 248 252 249 table->common.max_oasz_lg2 = 253 250 min(PT_MAX_OUTPUT_ADDRESS_LG2, cfg->common.hw_max_oasz_lg2); ··· 266 269 #if defined(GENERIC_PT_KUNIT) 267 270 static const struct pt_iommu_x86_64_cfg x86_64_kunit_fmt_cfgs[] = { 268 271 [0] = { .common.features = BIT(PT_FEAT_SIGN_EXTEND), 269 - .common.hw_max_vasz_lg2 = 48 }, 272 + .common.hw_max_vasz_lg2 = 48, .top_level = 3 }, 270 273 [1] = { .common.features = BIT(PT_FEAT_SIGN_EXTEND), 271 - .common.hw_max_vasz_lg2 = 57 }, 274 + .common.hw_max_vasz_lg2 = 57, .top_level = 4 }, 272 275 /* AMD IOMMU PASID 0 formats with no SIGN_EXTEND */ 273 - [2] = { .common.hw_max_vasz_lg2 = 47 }, 274 - [3] = { .common.hw_max_vasz_lg2 = 56 }, 276 + [2] = { .common.hw_max_vasz_lg2 = 47, .top_level = 3 }, 277 + [3] = { .common.hw_max_vasz_lg2 = 56, .top_level = 4}, 275 278 }; 276 279 #define kunit_fmt_cfgs x86_64_kunit_fmt_cfgs 277 280 enum { KUNIT_FMT_FEATURES = BIT(PT_FEAT_SIGN_EXTEND)};
+24 -14
drivers/iommu/intel/iommu.c
··· 2794 2794 return domain; 2795 2795 } 2796 2796 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 + 2797 2819 static struct iommu_domain * 2798 2820 intel_iommu_domain_alloc_first_stage(struct device *dev, 2799 2821 struct intel_iommu *iommu, u32 flags) ··· 2835 2813 if (IS_ERR(dmar_domain)) 2836 2814 return ERR_CAST(dmar_domain); 2837 2815 2838 - if (cap_fl5lp_support(iommu->cap)) 2839 - cfg.common.hw_max_vasz_lg2 = 57; 2840 - else 2841 - cfg.common.hw_max_vasz_lg2 = 48; 2842 - 2843 - /* 2844 - * Spec 3.6 First-Stage Translation: 2845 - * 2846 - * Software must limit addresses to less than the minimum of MGAW 2847 - * and the lower canonical address width implied by FSPM (i.e., 2848 - * 47-bit when FSPM is 4-level and 56-bit when FSPM is 5-level). 2849 - */ 2850 - cfg.common.hw_max_vasz_lg2 = min(cap_mgaw(iommu->cap), 2851 - cfg.common.hw_max_vasz_lg2); 2816 + cfg.common.hw_max_vasz_lg2 = 2817 + compute_vasz_lg2_fs(iommu, &cfg.top_level); 2852 2818 cfg.common.hw_max_oasz_lg2 = 52; 2853 2819 cfg.common.features = BIT(PT_FEAT_SIGN_EXTEND) | 2854 2820 BIT(PT_FEAT_FLUSH_RANGE);
+2
include/linux/generic_pt/iommu.h
··· 277 277 278 278 struct pt_iommu_x86_64_cfg { 279 279 struct pt_iommu_cfg common; 280 + /* 4 is a 57 bit 5 level table */ 281 + unsigned int top_level; 280 282 }; 281 283 282 284 struct pt_iommu_x86_64_hw_info {