diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-09-07 20:58:55 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-09-08 09:32:03 -0400 |
commit | 2a02505055fdd44958efd0e140dd87cb9fdecaf1 (patch) | |
tree | 509caa8bba7b086e80676b940c179871c730c7e7 /arch | |
parent | 6c62aa4a3c12989a1f1fcbbe6f1ee5d4de4b2300 (diff) |
x86: make amd_64 have 32 bit code
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Cc: Yinghai Lu <yhlu.kernel@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/cpu/amd_64.c | 259 |
1 files changed, 247 insertions, 12 deletions
diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c index 1d83601e85ef..32e73520adf7 100644 --- a/arch/x86/kernel/cpu/amd_64.c +++ b/arch/x86/kernel/cpu/amd_64.c | |||
@@ -16,7 +16,171 @@ | |||
16 | 16 | ||
17 | #include "cpu.h" | 17 | #include "cpu.h" |
18 | 18 | ||
19 | #ifdef CONFIG_NUMA | 19 | #ifdef CONFIG_X86_32 |
20 | /* | ||
21 | * B step AMD K6 before B 9730xxxx have hardware bugs that can cause | ||
22 | * misexecution of code under Linux. Owners of such processors should | ||
23 | * contact AMD for precise details and a CPU swap. | ||
24 | * | ||
25 | * See http://www.multimania.com/poulot/k6bug.html | ||
26 | * http://www.amd.com/K6/k6docs/revgd.html | ||
27 | * | ||
28 | * The following test is erm.. interesting. AMD neglected to up | ||
29 | * the chip setting when fixing the bug but they also tweaked some | ||
30 | * performance at the same time.. | ||
31 | */ | ||
32 | |||
33 | extern void vide(void); | ||
34 | __asm__(".align 4\nvide: ret"); | ||
35 | |||
36 | static void __cpuinit init_amd_k5(struct cpuinfo_x86 *c) | ||
37 | { | ||
38 | /* | ||
39 | * General Systems BIOSen alias the cpu frequency registers | ||
40 | * of the Elan at 0x000df000. Unfortuantly, one of the Linux | ||
41 | * drivers subsequently pokes it, and changes the CPU speed. | ||
42 | * Workaround : Remove the unneeded alias. | ||
43 | */ | ||
44 | #define CBAR (0xfffc) /* Configuration Base Address (32-bit) */ | ||
45 | #define CBAR_ENB (0x80000000) | ||
46 | #define CBAR_KEY (0X000000CB) | ||
47 | if (c->x86_model == 9 || c->x86_model == 10) { | ||
48 | if (inl (CBAR) & CBAR_ENB) | ||
49 | outl (0 | CBAR_KEY, CBAR); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | |||
54 | static void __cpuinit init_amd_k6(struct cpuinfo_x86 *c) | ||
55 | { | ||
56 | u32 l, h; | ||
57 | int mbytes = num_physpages >> (20-PAGE_SHIFT); | ||
58 | |||
59 | if (c->x86_model < 6) { | ||
60 | /* Based on AMD doc 20734R - June 2000 */ | ||
61 | if (c->x86_model == 0) { | ||
62 | clear_cpu_cap(c, X86_FEATURE_APIC); | ||
63 | set_cpu_cap(c, X86_FEATURE_PGE); | ||
64 | } | ||
65 | return; | ||
66 | } | ||
67 | |||
68 | if (c->x86_model == 6 && c->x86_mask == 1) { | ||
69 | const int K6_BUG_LOOP = 1000000; | ||
70 | int n; | ||
71 | void (*f_vide)(void); | ||
72 | unsigned long d, d2; | ||
73 | |||
74 | printk(KERN_INFO "AMD K6 stepping B detected - "); | ||
75 | |||
76 | /* | ||
77 | * It looks like AMD fixed the 2.6.2 bug and improved indirect | ||
78 | * calls at the same time. | ||
79 | */ | ||
80 | |||
81 | n = K6_BUG_LOOP; | ||
82 | f_vide = vide; | ||
83 | rdtscl(d); | ||
84 | while (n--) | ||
85 | f_vide(); | ||
86 | rdtscl(d2); | ||
87 | d = d2-d; | ||
88 | |||
89 | if (d > 20*K6_BUG_LOOP) | ||
90 | printk("system stability may be impaired when more than 32 MB are used.\n"); | ||
91 | else | ||
92 | printk("probably OK (after B9730xxxx).\n"); | ||
93 | printk(KERN_INFO "Please see http://membres.lycos.fr/poulot/k6bug.html\n"); | ||
94 | } | ||
95 | |||
96 | /* K6 with old style WHCR */ | ||
97 | if (c->x86_model < 8 || | ||
98 | (c->x86_model == 8 && c->x86_mask < 8)) { | ||
99 | /* We can only write allocate on the low 508Mb */ | ||
100 | if (mbytes > 508) | ||
101 | mbytes = 508; | ||
102 | |||
103 | rdmsr(MSR_K6_WHCR, l, h); | ||
104 | if ((l&0x0000FFFF) == 0) { | ||
105 | unsigned long flags; | ||
106 | l = (1<<0)|((mbytes/4)<<1); | ||
107 | local_irq_save(flags); | ||
108 | wbinvd(); | ||
109 | wrmsr(MSR_K6_WHCR, l, h); | ||
110 | local_irq_restore(flags); | ||
111 | printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n", | ||
112 | mbytes); | ||
113 | } | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | if ((c->x86_model == 8 && c->x86_mask > 7) || | ||
118 | c->x86_model == 9 || c->x86_model == 13) { | ||
119 | /* The more serious chips .. */ | ||
120 | |||
121 | if (mbytes > 4092) | ||
122 | mbytes = 4092; | ||
123 | |||
124 | rdmsr(MSR_K6_WHCR, l, h); | ||
125 | if ((l&0xFFFF0000) == 0) { | ||
126 | unsigned long flags; | ||
127 | l = ((mbytes>>2)<<22)|(1<<16); | ||
128 | local_irq_save(flags); | ||
129 | wbinvd(); | ||
130 | wrmsr(MSR_K6_WHCR, l, h); | ||
131 | local_irq_restore(flags); | ||
132 | printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n", | ||
133 | mbytes); | ||
134 | } | ||
135 | |||
136 | return; | ||
137 | } | ||
138 | |||
139 | if (c->x86_model == 10) { | ||
140 | /* AMD Geode LX is model 10 */ | ||
141 | /* placeholder for any needed mods */ | ||
142 | return; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c) | ||
147 | { | ||
148 | u32 l, h; | ||
149 | |||
150 | /* | ||
151 | * Bit 15 of Athlon specific MSR 15, needs to be 0 | ||
152 | * to enable SSE on Palomino/Morgan/Barton CPU's. | ||
153 | * If the BIOS didn't enable it already, enable it here. | ||
154 | */ | ||
155 | if (c->x86_model >= 6 && c->x86_model <= 10) { | ||
156 | if (!cpu_has(c, X86_FEATURE_XMM)) { | ||
157 | printk(KERN_INFO "Enabling disabled K7/SSE Support.\n"); | ||
158 | rdmsr(MSR_K7_HWCR, l, h); | ||
159 | l &= ~0x00008000; | ||
160 | wrmsr(MSR_K7_HWCR, l, h); | ||
161 | set_cpu_cap(c, X86_FEATURE_XMM); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * It's been determined by AMD that Athlons since model 8 stepping 1 | ||
167 | * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx | ||
168 | * As per AMD technical note 27212 0.2 | ||
169 | */ | ||
170 | if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) { | ||
171 | rdmsr(MSR_K7_CLK_CTL, l, h); | ||
172 | if ((l & 0xfff00000) != 0x20000000) { | ||
173 | printk ("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", l, | ||
174 | ((l & 0x000fffff)|0x20000000)); | ||
175 | wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | set_cpu_cap(c, X86_FEATURE_K7); | ||
180 | } | ||
181 | #endif | ||
182 | |||
183 | #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64) | ||
20 | static int __cpuinit nearby_node(int apicid) | 184 | static int __cpuinit nearby_node(int apicid) |
21 | { | 185 | { |
22 | int i, node; | 186 | int i, node; |
@@ -41,7 +205,7 @@ static int __cpuinit nearby_node(int apicid) | |||
41 | */ | 205 | */ |
42 | static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c) | 206 | static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c) |
43 | { | 207 | { |
44 | #ifdef CONFIG_SMP | 208 | #ifdef CONFIG_X86_HT |
45 | unsigned bits; | 209 | unsigned bits; |
46 | 210 | ||
47 | bits = c->x86_coreid_bits; | 211 | bits = c->x86_coreid_bits; |
@@ -55,7 +219,7 @@ static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c) | |||
55 | 219 | ||
56 | static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c) | 220 | static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c) |
57 | { | 221 | { |
58 | #ifdef CONFIG_NUMA | 222 | #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64) |
59 | int cpu = smp_processor_id(); | 223 | int cpu = smp_processor_id(); |
60 | int node; | 224 | int node; |
61 | unsigned apicid = hard_smp_processor_id(); | 225 | unsigned apicid = hard_smp_processor_id(); |
@@ -91,7 +255,7 @@ static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c) | |||
91 | 255 | ||
92 | static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c) | 256 | static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c) |
93 | { | 257 | { |
94 | #ifdef CONFIG_SMP | 258 | #ifdef CONFIG_X86_HT |
95 | unsigned bits, ecx; | 259 | unsigned bits, ecx; |
96 | 260 | ||
97 | /* Multi core CPU? */ | 261 | /* Multi core CPU? */ |
@@ -112,7 +276,6 @@ static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c) | |||
112 | } | 276 | } |
113 | 277 | ||
114 | c->x86_coreid_bits = bits; | 278 | c->x86_coreid_bits = bits; |
115 | |||
116 | #endif | 279 | #endif |
117 | } | 280 | } |
118 | 281 | ||
@@ -124,15 +287,21 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) | |||
124 | if (c->x86_power & (1<<8)) | 287 | if (c->x86_power & (1<<8)) |
125 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); | 288 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); |
126 | 289 | ||
290 | #ifdef CONFIG_X86_64 | ||
127 | set_cpu_cap(c, X86_FEATURE_SYSCALL32); | 291 | set_cpu_cap(c, X86_FEATURE_SYSCALL32); |
292 | #else | ||
293 | /* Set MTRR capability flag if appropriate */ | ||
294 | if (c->x86 == 5) | ||
295 | if (c->x86_model == 13 || c->x86_model == 9 || | ||
296 | (c->x86_model == 8 && c->x86_mask >= 8)) | ||
297 | set_cpu_cap(c, X86_FEATURE_K6_MTRR); | ||
298 | #endif | ||
128 | } | 299 | } |
129 | 300 | ||
130 | static void __cpuinit init_amd(struct cpuinfo_x86 *c) | 301 | static void __cpuinit init_amd(struct cpuinfo_x86 *c) |
131 | { | 302 | { |
132 | unsigned level; | ||
133 | |||
134 | #ifdef CONFIG_SMP | 303 | #ifdef CONFIG_SMP |
135 | unsigned long value; | 304 | unsigned long long value; |
136 | 305 | ||
137 | /* | 306 | /* |
138 | * Disable TLB flush filter by setting HWCR.FFDIS on K8 | 307 | * Disable TLB flush filter by setting HWCR.FFDIS on K8 |
@@ -142,26 +311,55 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
142 | * Errata 122 for all steppings (F+ have it disabled by default) | 311 | * Errata 122 for all steppings (F+ have it disabled by default) |
143 | */ | 312 | */ |
144 | if (c->x86 == 0xf) { | 313 | if (c->x86 == 0xf) { |
145 | rdmsrl(MSR_K8_HWCR, value); | 314 | rdmsrl(MSR_K7_HWCR, value); |
146 | value |= 1 << 6; | 315 | value |= 1 << 6; |
147 | wrmsrl(MSR_K8_HWCR, value); | 316 | wrmsrl(MSR_K7_HWCR, value); |
148 | } | 317 | } |
149 | #endif | 318 | #endif |
150 | 319 | ||
151 | early_init_amd(c); | 320 | early_init_amd(c); |
152 | 321 | ||
153 | /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; | 322 | /* |
154 | 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ | 323 | * Bit 31 in normal CPUID used for nonstandard 3DNow ID; |
324 | * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway | ||
325 | */ | ||
155 | clear_cpu_cap(c, 0*32+31); | 326 | clear_cpu_cap(c, 0*32+31); |
156 | 327 | ||
328 | #ifdef CONFIG_X86_64 | ||
157 | /* On C+ stepping K8 rep microcode works well for copy/memset */ | 329 | /* On C+ stepping K8 rep microcode works well for copy/memset */ |
158 | if (c->x86 == 0xf) { | 330 | if (c->x86 == 0xf) { |
331 | u32 level; | ||
332 | |||
159 | level = cpuid_eax(1); | 333 | level = cpuid_eax(1); |
160 | if((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58) | 334 | if((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58) |
161 | set_cpu_cap(c, X86_FEATURE_REP_GOOD); | 335 | set_cpu_cap(c, X86_FEATURE_REP_GOOD); |
162 | } | 336 | } |
163 | if (c->x86 == 0x10 || c->x86 == 0x11) | 337 | if (c->x86 == 0x10 || c->x86 == 0x11) |
164 | set_cpu_cap(c, X86_FEATURE_REP_GOOD); | 338 | set_cpu_cap(c, X86_FEATURE_REP_GOOD); |
339 | #else | ||
340 | |||
341 | /* | ||
342 | * FIXME: We should handle the K5 here. Set up the write | ||
343 | * range and also turn on MSR 83 bits 4 and 31 (write alloc, | ||
344 | * no bus pipeline) | ||
345 | */ | ||
346 | |||
347 | switch (c->x86) { | ||
348 | case 4: | ||
349 | init_amd_k5(c); | ||
350 | break; | ||
351 | case 5: | ||
352 | init_amd_k6(c); | ||
353 | break; | ||
354 | case 6: /* An Athlon/Duron */ | ||
355 | init_amd_k7(c); | ||
356 | break; | ||
357 | } | ||
358 | |||
359 | /* K6s reports MCEs but don't actually have all the MSRs */ | ||
360 | if (c->x86 < 6) | ||
361 | clear_cpu_cap(c, X86_FEATURE_MCE); | ||
362 | #endif | ||
165 | 363 | ||
166 | /* Enable workaround for FXSAVE leak */ | 364 | /* Enable workaround for FXSAVE leak */ |
167 | if (c->x86 >= 6) | 365 | if (c->x86 >= 6) |
@@ -176,6 +374,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
176 | break; | 374 | break; |
177 | } | 375 | } |
178 | } | 376 | } |
377 | |||
179 | display_cacheinfo(c); | 378 | display_cacheinfo(c); |
180 | 379 | ||
181 | /* Multi core CPU? */ | 380 | /* Multi core CPU? */ |
@@ -184,6 +383,10 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
184 | srat_detect_node(c); | 383 | srat_detect_node(c); |
185 | } | 384 | } |
186 | 385 | ||
386 | #ifdef CONFIG_X86_32 | ||
387 | detect_ht(c); | ||
388 | #endif | ||
389 | |||
187 | if (c->extended_cpuid_level >= 0x80000006) { | 390 | if (c->extended_cpuid_level >= 0x80000006) { |
188 | if ((c->x86 >= 0x0f) && (cpuid_edx(0x80000006) & 0xf000)) | 391 | if ((c->x86 >= 0x0f) && (cpuid_edx(0x80000006) & 0xf000)) |
189 | num_cache_leaves = 4; | 392 | num_cache_leaves = 4; |
@@ -199,6 +402,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
199 | set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); | 402 | set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); |
200 | } | 403 | } |
201 | 404 | ||
405 | #ifdef CONFIG_X86_64 | ||
202 | if (c->x86 == 0x10) { | 406 | if (c->x86 == 0x10) { |
203 | /* do this for boot cpu */ | 407 | /* do this for boot cpu */ |
204 | if (c == &boot_cpu_data) | 408 | if (c == &boot_cpu_data) |
@@ -225,11 +429,42 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
225 | set_memory_4k((unsigned long)__va(tseg), 1); | 429 | set_memory_4k((unsigned long)__va(tseg), 1); |
226 | } | 430 | } |
227 | } | 431 | } |
432 | #endif | ||
433 | } | ||
434 | |||
435 | #ifdef CONFIG_X86_32 | ||
436 | static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) | ||
437 | { | ||
438 | /* AMD errata T13 (order #21922) */ | ||
439 | if ((c->x86 == 6)) { | ||
440 | if (c->x86_model == 3 && c->x86_mask == 0) /* Duron Rev A0 */ | ||
441 | size = 64; | ||
442 | if (c->x86_model == 4 && | ||
443 | (c->x86_mask == 0 || c->x86_mask == 1)) /* Tbird rev A1/A2 */ | ||
444 | size = 256; | ||
445 | } | ||
446 | return size; | ||
228 | } | 447 | } |
448 | #endif | ||
229 | 449 | ||
230 | static struct cpu_dev amd_cpu_dev __cpuinitdata = { | 450 | static struct cpu_dev amd_cpu_dev __cpuinitdata = { |
231 | .c_vendor = "AMD", | 451 | .c_vendor = "AMD", |
232 | .c_ident = { "AuthenticAMD" }, | 452 | .c_ident = { "AuthenticAMD" }, |
453 | #ifdef CONFIG_X86_32 | ||
454 | .c_models = { | ||
455 | { .vendor = X86_VENDOR_AMD, .family = 4, .model_names = | ||
456 | { | ||
457 | [3] = "486 DX/2", | ||
458 | [7] = "486 DX/2-WB", | ||
459 | [8] = "486 DX/4", | ||
460 | [9] = "486 DX/4-WB", | ||
461 | [14] = "Am5x86-WT", | ||
462 | [15] = "Am5x86-WB" | ||
463 | } | ||
464 | }, | ||
465 | }, | ||
466 | .c_size_cache = amd_size_cache, | ||
467 | #endif | ||
233 | .c_early_init = early_init_amd, | 468 | .c_early_init = early_init_amd, |
234 | .c_init = init_amd, | 469 | .c_init = init_amd, |
235 | .c_x86_vendor = X86_VENDOR_AMD, | 470 | .c_x86_vendor = X86_VENDOR_AMD, |