When SVM is disabled by BIOS, one cannot use KVM but the
SVM feature is still shown in the output of /proc/cpuinfo.
On Intel machines, VMX is cleared by init_ia32_feat_ctl(),
so do the same on AMD and Hygon processors.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20230921114940.957141-1-pbonzini@redhat.com
 #define MSR_IA32_VMX_MISC_INTEL_PT                 (1ULL << 14)
 #define MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS (1ULL << 29)
 #define MSR_IA32_VMX_MISC_PREEMPTION_TIMER_SCALE   0x1F
-/* AMD-V MSRs */
 
+/* AMD-V MSRs */
 #define MSR_VM_CR                       0xc0010114
 #define MSR_VM_IGNNE                    0xc0010115
 #define MSR_VM_HSAVE_PA                 0xc0010117
 
+#define SVM_VM_CR_VALID_MASK           0x001fULL
+#define SVM_VM_CR_SVM_LOCK_MASK                0x0008ULL
+#define SVM_VM_CR_SVM_DIS_MASK         0x0010ULL
+
 /* Hardware Feedback Interface */
 #define MSR_IA32_HW_FEEDBACK_PTR        0x17d0
 #define MSR_IA32_HW_FEEDBACK_CONFIG     0x17d1
 
 #define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT)
 #define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT)
 
-#define SVM_VM_CR_VALID_MASK   0x001fULL
-#define SVM_VM_CR_SVM_LOCK_MASK 0x0008ULL
-#define SVM_VM_CR_SVM_DIS_MASK  0x0010ULL
-
 #define SVM_NESTED_CTL_NP_ENABLE       BIT(0)
 #define SVM_NESTED_CTL_SEV_ENABLE      BIT(1)
 #define SVM_NESTED_CTL_SEV_ES_ENABLE   BIT(2)
 
 #define SVM_CPUID_FUNC 0x8000000a
 
-#define SVM_VM_CR_SVM_DISABLE 4
-
 #define SVM_SELECTOR_S_SHIFT 4
 #define SVM_SELECTOR_DPL_SHIFT 5
 #define SVM_SELECTOR_P_SHIFT 7
 
 
 static void init_amd(struct cpuinfo_x86 *c)
 {
+       u64 vm_cr;
+
        early_init_amd(c);
 
        /*
 
        init_amd_cacheinfo(c);
 
+       if (cpu_has(c, X86_FEATURE_SVM)) {
+               rdmsrl(MSR_VM_CR, vm_cr);
+               if (vm_cr & SVM_VM_CR_SVM_DIS_MASK) {
+                       pr_notice_once("SVM disabled (by BIOS) in MSR_VM_CR\n");
+                       clear_cpu_cap(c, X86_FEATURE_SVM);
+               }
+       }
+
        if (!cpu_has(c, X86_FEATURE_LFENCE_RDTSC) && cpu_has(c, X86_FEATURE_XMM2)) {
                /*
                 * Use LFENCE for execution serialization.  On families which
 
 
 static void init_hygon(struct cpuinfo_x86 *c)
 {
+       u64 vm_cr;
+
        early_init_hygon(c);
 
        /*
 
        init_hygon_cacheinfo(c);
 
+       if (cpu_has(c, X86_FEATURE_SVM)) {
+               rdmsrl(MSR_VM_CR, vm_cr);
+               if (vm_cr & SVM_VM_CR_SVM_DIS_MASK) {
+                       pr_notice_once("SVM disabled (by BIOS) in MSR_VM_CR\n");
+                       clear_cpu_cap(c, X86_FEATURE_SVM);
+               }
+       }
+
        if (cpu_has(c, X86_FEATURE_XMM2)) {
                /*
                 * Use LFENCE for execution serialization.  On families which
 
        int cpu = smp_processor_id();
        struct cpuinfo_x86 *c = &cpu_data(cpu);
 
-       u64 vm_cr;
-
        if (c->x86_vendor != X86_VENDOR_AMD &&
            c->x86_vendor != X86_VENDOR_HYGON) {
                pr_err("CPU %d isn't AMD or Hygon\n", cpu);
                return false;
        }
 
-       rdmsrl(MSR_VM_CR, vm_cr);
-       if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE)) {
-               pr_err("SVM disabled (by BIOS) in MSR_VM_CR on CPU %d\n", cpu);
-               return false;
-       }
-
        return true;
 }