blob: adc0ebd8bed0e17be1716f3fb7c3eab51b7fa0c4 [file] [log] [blame]
Peter Zijlstraacb04052017-01-19 14:36:33 +01001
2#include <linux/sched.h>
Ingo Molnare6017572017-02-01 16:36:40 +01003#include <linux/sched/clock.h>
Ingo Molnaredc05e62008-02-18 03:30:47 +01004
Borislav Petkovcd4d09e2016-01-26 22:12:04 +01005#include <asm/cpufeature.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#include <asm/e820.h>
Jesper Juhl52f4a912006-03-23 02:59:50 -08007#include <asm/mtrr.h>
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +01008#include <asm/msr.h>
Ingo Molnaredc05e62008-02-18 03:30:47 +01009
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include "cpu.h"
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#define ACE_PRESENT (1 << 6)
13#define ACE_ENABLED (1 << 7)
14#define ACE_FCR (1 << 28) /* MSR_VIA_FCR */
15
16#define RNG_PRESENT (1 << 2)
17#define RNG_ENABLED (1 << 3)
18#define RNG_ENABLE (1 << 6) /* MSR_VIA_RNG */
19
Paul Gortmaker148f9bb2013-06-18 18:23:59 -040020static void init_c3(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -070021{
22 u32 lo, hi;
23
24 /* Test for Centaur Extended Feature Flags presence */
25 if (cpuid_eax(0xC0000000) >= 0xC0000001) {
26 u32 tmp = cpuid_edx(0xC0000001);
27
28 /* enable ACE unit, if present and disabled */
29 if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) {
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +010030 rdmsr(MSR_VIA_FCR, lo, hi);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031 lo |= ACE_FCR; /* enable ACE unit */
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +010032 wrmsr(MSR_VIA_FCR, lo, hi);
Chen Yucong1b74dde2016-02-02 11:45:02 +080033 pr_info("CPU: Enabled ACE h/w crypto\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 }
35
36 /* enable RNG unit, if present and disabled */
37 if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) {
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +010038 rdmsr(MSR_VIA_RNG, lo, hi);
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 lo |= RNG_ENABLE; /* enable RNG unit */
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +010040 wrmsr(MSR_VIA_RNG, lo, hi);
Chen Yucong1b74dde2016-02-02 11:45:02 +080041 pr_info("CPU: Enabled h/w RNG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 }
43
44 /* store Centaur Extended Feature Flags as
45 * word 5 of the CPU capability bit array
46 */
Borislav Petkov39c06df2015-12-07 10:39:40 +010047 c->x86_capability[CPUID_C000_0001_EDX] = cpuid_edx(0xC0000001);
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 }
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +010049#ifdef CONFIG_X86_32
Simon Arlott27b46d72007-10-20 01:13:56 +020050 /* Cyrix III family needs CX8 & PGE explicitly enabled. */
Timo Teräscb3f7182011-12-15 17:11:28 +020051 if (c->x86_model >= 6 && c->x86_model <= 13) {
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +010052 rdmsr(MSR_VIA_FCR, lo, hi);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 lo |= (1<<1 | 1<<7);
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +010054 wrmsr(MSR_VIA_FCR, lo, hi);
Ingo Molnare1a94a92008-02-26 08:51:22 +010055 set_cpu_cap(c, X86_FEATURE_CX8);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 }
57
58 /* Before Nehemiah, the C3's had 3dNOW! */
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +010059 if (c->x86_model >= 6 && c->x86_model < 9)
Ingo Molnare1a94a92008-02-26 08:51:22 +010060 set_cpu_cap(c, X86_FEATURE_3DNOW);
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +010061#endif
62 if (c->x86 == 0x6 && c->x86_model >= 0xf) {
63 c->x86_cache_alignment = c->x86_clflush_size * 2;
64 set_cpu_cap(c, X86_FEATURE_REP_GOOD);
65 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Borislav Petkov27c13ec2009-11-21 14:01:45 +010067 cpu_detect_cache_sizes(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068}
69
Ingo Molnaredc05e62008-02-18 03:30:47 +010070enum {
71 ECX8 = 1<<1,
72 EIERRINT = 1<<2,
73 DPM = 1<<3,
74 DMCE = 1<<4,
75 DSTPCLK = 1<<5,
76 ELINEAR = 1<<6,
77 DSMC = 1<<7,
78 DTLOCK = 1<<8,
79 EDCTLB = 1<<8,
80 EMMX = 1<<9,
81 DPDC = 1<<11,
82 EBRPRED = 1<<12,
83 DIC = 1<<13,
84 DDC = 1<<14,
85 DNA = 1<<15,
86 ERETSTK = 1<<16,
87 E2MMX = 1<<19,
88 EAMD3D = 1<<20,
89};
90
Paul Gortmaker148f9bb2013-06-18 18:23:59 -040091static void early_init_centaur(struct cpuinfo_x86 *c)
Yinghai Lu5fef55f2008-09-04 21:09:43 +020092{
93 switch (c->x86) {
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +010094#ifdef CONFIG_X86_32
Yinghai Lu5fef55f2008-09-04 21:09:43 +020095 case 5:
96 /* Emulate MTRRs using Centaur's MCR. */
97 set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR);
98 break;
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +010099#endif
100 case 6:
101 if (c->x86_model >= 0xf)
102 set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
103 break;
Yinghai Lu5fef55f2008-09-04 21:09:43 +0200104 }
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +0100105#ifdef CONFIG_X86_64
106 set_cpu_cap(c, X86_FEATURE_SYSENTER32);
107#endif
Peter Zijlstraacb04052017-01-19 14:36:33 +0100108
109 clear_sched_clock_stable();
Yinghai Lu5fef55f2008-09-04 21:09:43 +0200110}
111
Paul Gortmaker148f9bb2013-06-18 18:23:59 -0400112static void init_centaur(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +0100114#ifdef CONFIG_X86_32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 char *name;
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +0100116 u32 fcr_set = 0;
117 u32 fcr_clr = 0;
118 u32 lo, hi, newlo;
119 u32 aa, bb, cc, dd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Ingo Molnaredc05e62008-02-18 03:30:47 +0100121 /*
122 * Bit 31 in normal CPUID used for nonstandard 3DNow ID;
123 * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway
124 */
Ingo Molnare1a94a92008-02-26 08:51:22 +0100125 clear_cpu_cap(c, 0*32+31);
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +0100126#endif
127 early_init_centaur(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 switch (c->x86) {
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +0100129#ifdef CONFIG_X86_32
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +0100130 case 5:
Ingo Molnaredc05e62008-02-18 03:30:47 +0100131 switch (c->x86_model) {
132 case 4:
133 name = "C6";
134 fcr_set = ECX8|DSMC|EDCTLB|EMMX|ERETSTK;
135 fcr_clr = DPDC;
Chen Yucong1b74dde2016-02-02 11:45:02 +0800136 pr_notice("Disabling bugged TSC.\n");
Ingo Molnare1a94a92008-02-26 08:51:22 +0100137 clear_cpu_cap(c, X86_FEATURE_TSC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 break;
Ingo Molnaredc05e62008-02-18 03:30:47 +0100139 case 8:
140 switch (c->x86_mask) {
141 default:
142 name = "2";
143 break;
144 case 7 ... 9:
145 name = "2A";
146 break;
147 case 10 ... 15:
148 name = "2B";
149 break;
150 }
151 fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
152 E2MMX|EAMD3D;
153 fcr_clr = DPDC;
Ingo Molnaredc05e62008-02-18 03:30:47 +0100154 break;
155 case 9:
156 name = "3";
157 fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
158 E2MMX|EAMD3D;
159 fcr_clr = DPDC;
Ingo Molnaredc05e62008-02-18 03:30:47 +0100160 break;
161 default:
162 name = "??";
163 }
164
165 rdmsr(MSR_IDT_FCR1, lo, hi);
166 newlo = (lo|fcr_set) & (~fcr_clr);
167
168 if (newlo != lo) {
Chen Yucong1b74dde2016-02-02 11:45:02 +0800169 pr_info("Centaur FCR was 0x%X now 0x%X\n",
Ingo Molnaredc05e62008-02-18 03:30:47 +0100170 lo, newlo);
171 wrmsr(MSR_IDT_FCR1, newlo, hi);
172 } else {
Chen Yucong1b74dde2016-02-02 11:45:02 +0800173 pr_info("Centaur FCR is 0x%X\n", lo);
Ingo Molnaredc05e62008-02-18 03:30:47 +0100174 }
175 /* Emulate MTRRs using Centaur's MCR. */
Ingo Molnare1a94a92008-02-26 08:51:22 +0100176 set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR);
Ingo Molnaredc05e62008-02-18 03:30:47 +0100177 /* Report CX8 */
Ingo Molnare1a94a92008-02-26 08:51:22 +0100178 set_cpu_cap(c, X86_FEATURE_CX8);
Ingo Molnaredc05e62008-02-18 03:30:47 +0100179 /* Set 3DNow! on Winchip 2 and above. */
180 if (c->x86_model >= 8)
Ingo Molnare1a94a92008-02-26 08:51:22 +0100181 set_cpu_cap(c, X86_FEATURE_3DNOW);
Ingo Molnaredc05e62008-02-18 03:30:47 +0100182 /* See if we can find out some more. */
183 if (cpuid_eax(0x80000000) >= 0x80000005) {
184 /* Yes, we can. */
185 cpuid(0x80000005, &aa, &bb, &cc, &dd);
186 /* Add L1 data and code cache sizes. */
187 c->x86_cache_size = (cc>>24)+(dd>>24);
188 }
189 sprintf(c->x86_model_id, "WinChip %s", name);
190 break;
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +0100191#endif
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +0100192 case 6:
Ingo Molnaredc05e62008-02-18 03:30:47 +0100193 init_c3(c);
194 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 }
Sebastian Andrzej Siewior48f4c482009-03-14 12:24:02 +0100196#ifdef CONFIG_X86_64
197 set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
198#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
Jan Beulich09dc68d2013-10-21 09:35:20 +0100201#ifdef CONFIG_X86_32
Paul Gortmaker148f9bb2013-06-18 18:23:59 -0400202static unsigned int
Ingo Molnaredc05e62008-02-18 03:30:47 +0100203centaur_size_cache(struct cpuinfo_x86 *c, unsigned int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
205 /* VIA C3 CPUs (670-68F) need further shifting. */
206 if ((c->x86 == 6) && ((c->x86_model == 7) || (c->x86_model == 8)))
207 size >>= 8;
208
Ingo Molnaredc05e62008-02-18 03:30:47 +0100209 /*
210 * There's also an erratum in Nehemiah stepping 1, which
211 * returns '65KB' instead of '64KB'
212 * - Note, it seems this may only be in engineering samples.
213 */
214 if ((c->x86 == 6) && (c->x86_model == 9) &&
215 (c->x86_mask == 1) && (size == 65))
Paolo Ciarrocchi29a99942008-02-17 23:30:23 +0100216 size -= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 return size;
218}
Jan Beulich09dc68d2013-10-21 09:35:20 +0100219#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Paul Gortmaker148f9bb2013-06-18 18:23:59 -0400221static const struct cpu_dev centaur_cpu_dev = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 .c_vendor = "Centaur",
223 .c_ident = { "CentaurHauls" },
Yinghai Lu5fef55f2008-09-04 21:09:43 +0200224 .c_early_init = early_init_centaur,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 .c_init = init_centaur,
Jan Beulich09dc68d2013-10-21 09:35:20 +0100226#ifdef CONFIG_X86_32
227 .legacy_cache_size = centaur_size_cache,
228#endif
Yinghai Lu10a434f2008-09-04 21:09:45 +0200229 .c_x86_vendor = X86_VENDOR_CENTAUR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230};
231
Yinghai Lu10a434f2008-09-04 21:09:45 +0200232cpu_dev_register(centaur_cpu_dev);