projects/linux·blob master · refs

240 lines · 5.5 KiB

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