Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | // SPDX-License-Identifier: GPL-2.0 #include <linux/sched.h> #include <linux/sched/clock.h> #include <asm/cpu.h> #include <asm/cpufeature.h> #include <asm/e820/api.h> #include <asm/mtrr.h> #include <asm/msr.h> #include "cpu.h" #define ACE_PRESENT (1 << 6) #define ACE_ENABLED (1 << 7) #define ACE_FCR (1 << 28) /* MSR_VIA_FCR */ #define RNG_PRESENT (1 << 2) #define RNG_ENABLED (1 << 3) #define RNG_ENABLE (1 << 6) /* MSR_VIA_RNG */ static void init_c3(struct cpuinfo_x86 *c) { u32 lo, hi; /* Test for Centaur Extended Feature Flags presence */ if (cpuid_eax(0xC0000000) >= 0xC0000001) { u32 tmp = cpuid_edx(0xC0000001); /* enable ACE unit, if present and disabled */ if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) { rdmsr(MSR_VIA_FCR, lo, hi); lo |= ACE_FCR; /* enable ACE unit */ wrmsr(MSR_VIA_FCR, lo, hi); pr_info("CPU: Enabled ACE h/w crypto\n"); } /* enable RNG unit, if present and disabled */ if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) { rdmsr(MSR_VIA_RNG, lo, hi); lo |= RNG_ENABLE; /* enable RNG unit */ wrmsr(MSR_VIA_RNG, lo, hi); pr_info("CPU: Enabled h/w RNG\n"); } /* store Centaur Extended Feature Flags as * word 5 of the CPU capability bit array */ c->x86_capability[CPUID_C000_0001_EDX] = cpuid_edx(0xC0000001); } #ifdef CONFIG_X86_32 /* Cyrix III family needs CX8 & PGE explicitly enabled. */ if (c->x86_model >= 6 && c->x86_model <= 13) { rdmsr(MSR_VIA_FCR, lo, hi); lo |= (1<<1 | 1<<7); wrmsr(MSR_VIA_FCR, lo, hi); set_cpu_cap(c, X86_FEATURE_CX8); } /* Before Nehemiah, the C3's had 3dNOW! */ if (c->x86_model >= 6 && c->x86_model < 9) set_cpu_cap(c, X86_FEATURE_3DNOW); #endif if (c->x86 == 0x6 && c->x86_model >= 0xf) { c->x86_cache_alignment = c->x86_clflush_size * 2; set_cpu_cap(c, X86_FEATURE_REP_GOOD); } if (c->x86 >= 7) set_cpu_cap(c, X86_FEATURE_REP_GOOD); } enum { ECX8 = 1<<1, EIERRINT = 1<<2, DPM = 1<<3, DMCE = 1<<4, DSTPCLK = 1<<5, ELINEAR = 1<<6, DSMC = 1<<7, DTLOCK = 1<<8, EDCTLB = 1<<8, EMMX = 1<<9, DPDC = 1<<11, EBRPRED = 1<<12, DIC = 1<<13, DDC = 1<<14, DNA = 1<<15, ERETSTK = 1<<16, E2MMX = 1<<19, EAMD3D = 1<<20, }; static void early_init_centaur(struct cpuinfo_x86 *c) { #ifdef CONFIG_X86_32 /* Emulate MTRRs using Centaur's MCR. */ if (c->x86 == 5) set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR); #endif if ((c->x86 == 6 && c->x86_model >= 0xf) || (c->x86 >= 7)) set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); #ifdef CONFIG_X86_64 set_cpu_cap(c, X86_FEATURE_SYSENTER32); #endif if (c->x86_power & (1 << 8)) { set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC); } } static void init_centaur(struct cpuinfo_x86 *c) { #ifdef CONFIG_X86_32 char *name; u32 fcr_set = 0; u32 fcr_clr = 0; u32 lo, hi, newlo; u32 aa, bb, cc, dd; /* * Bit 31 in normal CPUID used for nonstandard 3DNow ID; * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ clear_cpu_cap(c, 0*32+31); #endif early_init_centaur(c); init_intel_cacheinfo(c); if (c->cpuid_level > 9) { unsigned int eax = cpuid_eax(10); /* * Check for version and the number of counters * Version(eax[7:0]) can't be 0; * Counters(eax[15:8]) should be greater than 1; */ if ((eax & 0xff) && (((eax >> 8) & 0xff) > 1)) set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON); } #ifdef CONFIG_X86_32 if (c->x86 == 5) { switch (c->x86_model) { case 4: name = "C6"; fcr_set = ECX8|DSMC|EDCTLB|EMMX|ERETSTK; fcr_clr = DPDC; pr_notice("Disabling bugged TSC.\n"); clear_cpu_cap(c, X86_FEATURE_TSC); break; case 8: switch (c->x86_stepping) { default: name = "2"; break; case 7 ... 9: name = "2A"; break; case 10 ... 15: name = "2B"; break; } fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK| E2MMX|EAMD3D; fcr_clr = DPDC; break; case 9: name = "3"; fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK| E2MMX|EAMD3D; fcr_clr = DPDC; break; default: name = "??"; } rdmsr(MSR_IDT_FCR1, lo, hi); newlo = (lo|fcr_set) & (~fcr_clr); if (newlo != lo) { pr_info("Centaur FCR was 0x%X now 0x%X\n", lo, newlo); wrmsr(MSR_IDT_FCR1, newlo, hi); } else { pr_info("Centaur FCR is 0x%X\n", lo); } /* Emulate MTRRs using Centaur's MCR. */ set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR); /* Report CX8 */ set_cpu_cap(c, X86_FEATURE_CX8); /* Set 3DNow! on Winchip 2 and above. */ if (c->x86_model >= 8) set_cpu_cap(c, X86_FEATURE_3DNOW); /* See if we can find out some more. */ if (cpuid_eax(0x80000000) >= 0x80000005) { /* Yes, we can. */ cpuid(0x80000005, &aa, &bb, &cc, &dd); /* Add L1 data and code cache sizes. */ c->x86_cache_size = (cc>>24)+(dd>>24); } sprintf(c->x86_model_id, "WinChip %s", name); } #endif if (c->x86 == 6 || c->x86 >= 7) init_c3(c); #ifdef CONFIG_X86_64 set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC); #endif init_ia32_feat_ctl(c); } #ifdef CONFIG_X86_32 static unsigned int centaur_size_cache(struct cpuinfo_x86 *c, unsigned int size) { /* VIA C3 CPUs (670-68F) need further shifting. */ if ((c->x86 == 6) && ((c->x86_model == 7) || (c->x86_model == 8))) size >>= 8; /* * There's also an erratum in Nehemiah stepping 1, which * returns '65KB' instead of '64KB' * - Note, it seems this may only be in engineering samples. */ if ((c->x86 == 6) && (c->x86_model == 9) && (c->x86_stepping == 1) && (size == 65)) size -= 1; return size; } #endif static const struct cpu_dev centaur_cpu_dev = { .c_vendor = "Centaur", .c_ident = { "CentaurHauls" }, .c_early_init = early_init_centaur, .c_init = init_centaur, #ifdef CONFIG_X86_32 .legacy_cache_size = centaur_size_cache, #endif .c_x86_vendor = X86_VENDOR_CENTAUR, }; cpu_dev_register(centaur_cpu_dev); |