0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #ifdef _SETUP
0022 # include "boot.h"
0023 #endif
0024 #include <linux/types.h>
0025 #include <asm/intel-family.h>
0026 #include <asm/processor-flags.h>
0027 #include <asm/required-features.h>
0028 #include <asm/msr-index.h>
0029 #include "string.h"
0030 #include "msr.h"
0031
0032 static u32 err_flags[NCAPINTS];
0033
0034 static const int req_level = CONFIG_X86_MINIMUM_CPU_FAMILY;
0035
0036 static const u32 req_flags[NCAPINTS] =
0037 {
0038 REQUIRED_MASK0,
0039 REQUIRED_MASK1,
0040 0,
0041 0,
0042 REQUIRED_MASK4,
0043 0,
0044 REQUIRED_MASK6,
0045 0,
0046 0,
0047 0,
0048 0,
0049 0,
0050 0,
0051 0,
0052 0,
0053 0,
0054 REQUIRED_MASK16,
0055 };
0056
0057 #define A32(a, b, c, d) (((d) << 24)+((c) << 16)+((b) << 8)+(a))
0058
0059 static int is_amd(void)
0060 {
0061 return cpu_vendor[0] == A32('A', 'u', 't', 'h') &&
0062 cpu_vendor[1] == A32('e', 'n', 't', 'i') &&
0063 cpu_vendor[2] == A32('c', 'A', 'M', 'D');
0064 }
0065
0066 static int is_centaur(void)
0067 {
0068 return cpu_vendor[0] == A32('C', 'e', 'n', 't') &&
0069 cpu_vendor[1] == A32('a', 'u', 'r', 'H') &&
0070 cpu_vendor[2] == A32('a', 'u', 'l', 's');
0071 }
0072
0073 static int is_transmeta(void)
0074 {
0075 return cpu_vendor[0] == A32('G', 'e', 'n', 'u') &&
0076 cpu_vendor[1] == A32('i', 'n', 'e', 'T') &&
0077 cpu_vendor[2] == A32('M', 'x', '8', '6');
0078 }
0079
0080 static int is_intel(void)
0081 {
0082 return cpu_vendor[0] == A32('G', 'e', 'n', 'u') &&
0083 cpu_vendor[1] == A32('i', 'n', 'e', 'I') &&
0084 cpu_vendor[2] == A32('n', 't', 'e', 'l');
0085 }
0086
0087
0088 static int check_cpuflags(void)
0089 {
0090 u32 err;
0091 int i;
0092
0093 err = 0;
0094 for (i = 0; i < NCAPINTS; i++) {
0095 err_flags[i] = req_flags[i] & ~cpu.flags[i];
0096 if (err_flags[i])
0097 err |= 1 << i;
0098 }
0099
0100 return err;
0101 }
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111 int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)
0112 {
0113 int err;
0114
0115 memset(&cpu.flags, 0, sizeof(cpu.flags));
0116 cpu.level = 3;
0117
0118 if (has_eflag(X86_EFLAGS_AC))
0119 cpu.level = 4;
0120
0121 get_cpuflags();
0122 err = check_cpuflags();
0123
0124 if (test_bit(X86_FEATURE_LM, cpu.flags))
0125 cpu.level = 64;
0126
0127 if (err == 0x01 &&
0128 !(err_flags[0] &
0129 ~((1 << X86_FEATURE_XMM)|(1 << X86_FEATURE_XMM2))) &&
0130 is_amd()) {
0131
0132
0133
0134 struct msr m;
0135
0136 boot_rdmsr(MSR_K7_HWCR, &m);
0137 m.l &= ~(1 << 15);
0138 boot_wrmsr(MSR_K7_HWCR, &m);
0139
0140 get_cpuflags();
0141 err = check_cpuflags();
0142 } else if (err == 0x01 &&
0143 !(err_flags[0] & ~(1 << X86_FEATURE_CX8)) &&
0144 is_centaur() && cpu.model >= 6) {
0145
0146
0147
0148 struct msr m;
0149
0150 boot_rdmsr(MSR_VIA_FCR, &m);
0151 m.l |= (1 << 1) | (1 << 7);
0152 boot_wrmsr(MSR_VIA_FCR, &m);
0153
0154 set_bit(X86_FEATURE_CX8, cpu.flags);
0155 err = check_cpuflags();
0156 } else if (err == 0x01 && is_transmeta()) {
0157
0158
0159 struct msr m, m_tmp;
0160 u32 level = 1;
0161
0162 boot_rdmsr(0x80860004, &m);
0163 m_tmp = m;
0164 m_tmp.l = ~0;
0165 boot_wrmsr(0x80860004, &m_tmp);
0166 asm("cpuid"
0167 : "+a" (level), "=d" (cpu.flags[0])
0168 : : "ecx", "ebx");
0169 boot_wrmsr(0x80860004, &m);
0170
0171 err = check_cpuflags();
0172 } else if (err == 0x01 &&
0173 !(err_flags[0] & ~(1 << X86_FEATURE_PAE)) &&
0174 is_intel() && cpu.level == 6 &&
0175 (cpu.model == 9 || cpu.model == 13)) {
0176
0177 if (cmdline_find_option_bool("forcepae")) {
0178 puts("WARNING: Forcing PAE in CPU flags\n");
0179 set_bit(X86_FEATURE_PAE, cpu.flags);
0180 err = check_cpuflags();
0181 }
0182 else {
0183 puts("WARNING: PAE disabled. Use parameter 'forcepae' to enable at your own risk!\n");
0184 }
0185 }
0186 if (!err)
0187 err = check_knl_erratum();
0188
0189 if (err_flags_ptr)
0190 *err_flags_ptr = err ? err_flags : NULL;
0191 if (cpu_level_ptr)
0192 *cpu_level_ptr = cpu.level;
0193 if (req_level_ptr)
0194 *req_level_ptr = req_level;
0195
0196 return (cpu.level < req_level || err) ? -1 : 0;
0197 }
0198
0199 int check_knl_erratum(void)
0200 {
0201
0202
0203
0204 if (!is_intel() ||
0205 cpu.family != 6 ||
0206 cpu.model != INTEL_FAM6_XEON_PHI_KNL)
0207 return 0;
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217 if (IS_ENABLED(CONFIG_X86_64) || IS_ENABLED(CONFIG_X86_PAE))
0218 return 0;
0219
0220 puts("This 32-bit kernel can not run on this Xeon Phi x200\n"
0221 "processor due to a processor erratum. Use a 64-bit\n"
0222 "kernel, or enable PAE in this 32-bit kernel.\n\n");
0223
0224 return -1;
0225 }
0226
0227