From: Zhao Liu <zhao1.liu@xxxxxxxxx> The Guest's Intel Thread Director (ITD) feature bit is not only dependent on the Host ITD's enablement, but is also based on the Guest's HFI feature bit. When the Host supports both HFI and ITD, try to support HFI and ITD for the Guest. If Host doesn't support ITD, we won't allow Guest to enable HFI or ITD. Tested-by: Yanting Jiang <yanting.jiang@xxxxxxxxx> Co-developed-by: Zhuocheng Ding <zhuocheng.ding@xxxxxxxxx> Signed-off-by: Zhuocheng Ding <zhuocheng.ding@xxxxxxxxx> Signed-off-by: Zhao Liu <zhao1.liu@xxxxxxxxx> --- arch/x86/kvm/cpuid.c | 55 +++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 4da8f3319917..9e78398f29dc 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -137,7 +137,7 @@ static int kvm_check_hfi_cpuid(struct kvm_vcpu *vcpu, { struct hfi_features hfi_features; struct kvm_cpuid_entry2 *best = NULL; - bool has_hfi; + bool has_hfi, has_itd; int nr_classes, ret; union cpuid6_ecx ecx; union cpuid6_edx edx; @@ -148,9 +148,14 @@ static int kvm_check_hfi_cpuid(struct kvm_vcpu *vcpu, return 0; has_hfi = cpuid_entry_has(best, X86_FEATURE_HFI); - if (!has_hfi) + has_itd = cpuid_entry_has(best, X86_FEATURE_ITD); + if (!has_hfi && !has_itd) return 0; + /* ITD must base on HFI. */ + if (!has_hfi && has_itd) + return -EINVAL; + /* * Only the platform with 1 HFI instance (i.e., client platform) * can enable HFI in Guest. For more information, please refer to @@ -159,11 +164,11 @@ static int kvm_check_hfi_cpuid(struct kvm_vcpu *vcpu, if (intel_hfi_max_instances() != 1) return -EINVAL; - /* - * Currently we haven't supported ITD. HFI is the default feature - * with 1 class. - */ - nr_classes = 1; + /* Guest's ITD must base on Host's ITD enablement. */ + if (!cpu_feature_enabled(X86_FEATURE_ITD) && has_itd) + return -EINVAL; + + nr_classes = has_itd ? 4 : 1; ret = intel_hfi_build_virt_features(&hfi_features, nr_classes, vcpu->kvm->created_vcpus); @@ -718,11 +723,13 @@ void kvm_set_cpu_caps(void) if (boot_cpu_has(X86_FEATURE_PTS)) kvm_cpu_cap_set(X86_FEATURE_PTS); /* - * Set HFI based on hardware capability. Only when the Host has + * Set HFI/ITD based on hardware capability. Only when the Host has * the valid HFI instance, KVM can build the virtual HFI table. */ - if (intel_hfi_enabled()) + if (intel_hfi_enabled()) { kvm_cpu_cap_set(X86_FEATURE_HFI); + kvm_cpu_cap_set(X86_FEATURE_ITD); + } } kvm_cpu_cap_mask(CPUID_7_0_EBX, @@ -1069,19 +1076,35 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) entry->ebx = 0; - if (kvm_cpu_cap_has(X86_FEATURE_HFI)) { + /* + * When Host enables ITD, we will expose ITD and HFI, + * otherwise, HFI/ITD will not be exposed to Guest. + * ITD is an extension of HFI, so after KVM supports ITD + * emulation, HFI-related info in 0x6 leaf should be consistent + * with the Host, that is, use the Host's ITD info, except + * for the HFI index. + * + * HFI table size is related to the HFI table indexes, but + * this item will be checked in kvm_check_cpuid() after + * KVM_SET_CPUID/KVM_SET_CPUID2. + */ + if (kvm_cpu_cap_has(X86_FEATURE_ITD)) { union cpuid6_ecx ecx; union cpuid6_edx edx; + union cpuid6_ecx *host_ecx = (union cpuid6_ecx *)&entry->ecx; + union cpuid6_edx *host_edx = (union cpuid6_edx *)&entry->edx; ecx.full = 0; edx.full = 0; - /* Number of supported HFI classes */ - ecx.split.nr_classes = 1; - /* HFI supports performance and energy efficiency capabilities. */ - edx.split.capabilities.split.performance = 1; - edx.split.capabilities.split.energy_efficiency = 1; + /* Number of supported HFI/ITD classes. */ + ecx.split.nr_classes = host_ecx->split.nr_classes; + /* HFI/ITD supports performance and energy efficiency capabilities. */ + edx.split.capabilities.split.performance = + host_edx->split.capabilities.split.performance; + edx.split.capabilities.split.energy_efficiency = + host_edx->split.capabilities.split.energy_efficiency; /* As default, keep the same HFI table size as host. */ - edx.split.table_pages = ((union cpuid6_edx)entry->edx).split.table_pages; + edx.split.table_pages = host_edx->split.table_pages; /* * Default HFI index = 0. User should be careful that * the index differ for each CPUs. -- 2.34.1