diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-09-07 20:58:50 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-09-08 09:31:58 -0400 |
commit | 11fdd252bb5b461289fc5c21dc8fc87dc66f3284 (patch) | |
tree | 75d3c11ee3af4d0dd59291a0f062302fcf79b072 /arch/x86/kernel/cpu/amd.c | |
parent | 2d9cd6c27f00958a31622b8e9909d5e35f069b28 (diff) |
x86: cpu make amd.c more like amd_64.c v2
1. make 32bit have early_init_amd_mc and amd_detect_cmp
2. seperate init_amd_k5/k6/k7 ...
v2: fix compiling for !CONFIG_SMP
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/cpu/amd.c')
-rw-r--r-- | arch/x86/kernel/cpu/amd.c | 396 |
1 files changed, 224 insertions, 172 deletions
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index c3175da7bc69..a3a9e3cbdea9 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c | |||
@@ -24,8 +24,200 @@ | |||
24 | extern void vide(void); | 24 | extern void vide(void); |
25 | __asm__(".align 4\nvide: ret"); | 25 | __asm__(".align 4\nvide: ret"); |
26 | 26 | ||
27 | static void __cpuinit init_amd_k5(struct cpuinfo_x86 *c) | ||
28 | { | ||
29 | /* | ||
30 | * General Systems BIOSen alias the cpu frequency registers | ||
31 | * of the Elan at 0x000df000. Unfortuantly, one of the Linux | ||
32 | * drivers subsequently pokes it, and changes the CPU speed. | ||
33 | * Workaround : Remove the unneeded alias. | ||
34 | */ | ||
35 | #define CBAR (0xfffc) /* Configuration Base Address (32-bit) */ | ||
36 | #define CBAR_ENB (0x80000000) | ||
37 | #define CBAR_KEY (0X000000CB) | ||
38 | if (c->x86_model == 9 || c->x86_model == 10) { | ||
39 | if (inl (CBAR) & CBAR_ENB) | ||
40 | outl (0 | CBAR_KEY, CBAR); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | |||
45 | static void __cpuinit init_amd_k6(struct cpuinfo_x86 *c) | ||
46 | { | ||
47 | u32 l, h; | ||
48 | int mbytes = num_physpages >> (20-PAGE_SHIFT); | ||
49 | |||
50 | if (c->x86_model < 6) { | ||
51 | /* Based on AMD doc 20734R - June 2000 */ | ||
52 | if (c->x86_model == 0) { | ||
53 | clear_cpu_cap(c, X86_FEATURE_APIC); | ||
54 | set_cpu_cap(c, X86_FEATURE_PGE); | ||
55 | } | ||
56 | return; | ||
57 | } | ||
58 | |||
59 | if (c->x86_model == 6 && c->x86_mask == 1) { | ||
60 | const int K6_BUG_LOOP = 1000000; | ||
61 | int n; | ||
62 | void (*f_vide)(void); | ||
63 | unsigned long d, d2; | ||
64 | |||
65 | printk(KERN_INFO "AMD K6 stepping B detected - "); | ||
66 | |||
67 | /* | ||
68 | * It looks like AMD fixed the 2.6.2 bug and improved indirect | ||
69 | * calls at the same time. | ||
70 | */ | ||
71 | |||
72 | n = K6_BUG_LOOP; | ||
73 | f_vide = vide; | ||
74 | rdtscl(d); | ||
75 | while (n--) | ||
76 | f_vide(); | ||
77 | rdtscl(d2); | ||
78 | d = d2-d; | ||
79 | |||
80 | if (d > 20*K6_BUG_LOOP) | ||
81 | printk("system stability may be impaired when more than 32 MB are used.\n"); | ||
82 | else | ||
83 | printk("probably OK (after B9730xxxx).\n"); | ||
84 | printk(KERN_INFO "Please see http://membres.lycos.fr/poulot/k6bug.html\n"); | ||
85 | } | ||
86 | |||
87 | /* K6 with old style WHCR */ | ||
88 | if (c->x86_model < 8 || | ||
89 | (c->x86_model == 8 && c->x86_mask < 8)) { | ||
90 | /* We can only write allocate on the low 508Mb */ | ||
91 | if (mbytes > 508) | ||
92 | mbytes = 508; | ||
93 | |||
94 | rdmsr(MSR_K6_WHCR, l, h); | ||
95 | if ((l&0x0000FFFF) == 0) { | ||
96 | unsigned long flags; | ||
97 | l = (1<<0)|((mbytes/4)<<1); | ||
98 | local_irq_save(flags); | ||
99 | wbinvd(); | ||
100 | wrmsr(MSR_K6_WHCR, l, h); | ||
101 | local_irq_restore(flags); | ||
102 | printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n", | ||
103 | mbytes); | ||
104 | } | ||
105 | return; | ||
106 | } | ||
107 | |||
108 | if ((c->x86_model == 8 && c->x86_mask > 7) || | ||
109 | c->x86_model == 9 || c->x86_model == 13) { | ||
110 | /* The more serious chips .. */ | ||
111 | |||
112 | if (mbytes > 4092) | ||
113 | mbytes = 4092; | ||
114 | |||
115 | rdmsr(MSR_K6_WHCR, l, h); | ||
116 | if ((l&0xFFFF0000) == 0) { | ||
117 | unsigned long flags; | ||
118 | l = ((mbytes>>2)<<22)|(1<<16); | ||
119 | local_irq_save(flags); | ||
120 | wbinvd(); | ||
121 | wrmsr(MSR_K6_WHCR, l, h); | ||
122 | local_irq_restore(flags); | ||
123 | printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n", | ||
124 | mbytes); | ||
125 | } | ||
126 | |||
127 | return; | ||
128 | } | ||
129 | |||
130 | if (c->x86_model == 10) { | ||
131 | /* AMD Geode LX is model 10 */ | ||
132 | /* placeholder for any needed mods */ | ||
133 | return; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c) | ||
138 | { | ||
139 | u32 l, h; | ||
140 | |||
141 | /* | ||
142 | * Bit 15 of Athlon specific MSR 15, needs to be 0 | ||
143 | * to enable SSE on Palomino/Morgan/Barton CPU's. | ||
144 | * If the BIOS didn't enable it already, enable it here. | ||
145 | */ | ||
146 | if (c->x86_model >= 6 && c->x86_model <= 10) { | ||
147 | if (!cpu_has(c, X86_FEATURE_XMM)) { | ||
148 | printk(KERN_INFO "Enabling disabled K7/SSE Support.\n"); | ||
149 | rdmsr(MSR_K7_HWCR, l, h); | ||
150 | l &= ~0x00008000; | ||
151 | wrmsr(MSR_K7_HWCR, l, h); | ||
152 | set_cpu_cap(c, X86_FEATURE_XMM); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * It's been determined by AMD that Athlons since model 8 stepping 1 | ||
158 | * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx | ||
159 | * As per AMD technical note 27212 0.2 | ||
160 | */ | ||
161 | if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) { | ||
162 | rdmsr(MSR_K7_CLK_CTL, l, h); | ||
163 | if ((l & 0xfff00000) != 0x20000000) { | ||
164 | printk ("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", l, | ||
165 | ((l & 0x000fffff)|0x20000000)); | ||
166 | wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | set_cpu_cap(c, X86_FEATURE_K7); | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * On a AMD dual core setup the lower bits of the APIC id distingush the cores. | ||
175 | * Assumes number of cores is a power of two. | ||
176 | */ | ||
177 | static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c) | ||
178 | { | ||
179 | #ifdef CONFIG_X86_HT | ||
180 | unsigned bits; | ||
181 | |||
182 | bits = c->x86_coreid_bits; | ||
183 | |||
184 | /* Low order bits define the core id (index of core in socket) */ | ||
185 | c->cpu_core_id = c->initial_apicid & ((1 << bits)-1); | ||
186 | /* Convert the initial APIC ID into the socket ID */ | ||
187 | c->phys_proc_id = c->initial_apicid >> bits; | ||
188 | #endif | ||
189 | } | ||
190 | |||
191 | static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c) | ||
192 | { | ||
193 | #ifdef CONFIG_X86_HT | ||
194 | unsigned bits, ecx; | ||
195 | |||
196 | /* Multi core CPU? */ | ||
197 | if (c->extended_cpuid_level < 0x80000008) | ||
198 | return; | ||
199 | |||
200 | ecx = cpuid_ecx(0x80000008); | ||
201 | |||
202 | c->x86_max_cores = (ecx & 0xff) + 1; | ||
203 | |||
204 | /* CPU telling us the core id bits shift? */ | ||
205 | bits = (ecx >> 12) & 0xF; | ||
206 | |||
207 | /* Otherwise recompute */ | ||
208 | if (bits == 0) { | ||
209 | while ((1 << bits) < c->x86_max_cores) | ||
210 | bits++; | ||
211 | } | ||
212 | |||
213 | c->x86_coreid_bits = bits; | ||
214 | #endif | ||
215 | } | ||
216 | |||
27 | static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) | 217 | static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) |
28 | { | 218 | { |
219 | early_init_amd_mc(c); | ||
220 | |||
29 | if (c->x86_power & (1<<8)) | 221 | if (c->x86_power & (1<<8)) |
30 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); | 222 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); |
31 | 223 | ||
@@ -37,9 +229,6 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) | |||
37 | 229 | ||
38 | static void __cpuinit init_amd(struct cpuinfo_x86 *c) | 230 | static void __cpuinit init_amd(struct cpuinfo_x86 *c) |
39 | { | 231 | { |
40 | u32 l, h; | ||
41 | int mbytes = num_physpages >> (20-PAGE_SHIFT); | ||
42 | |||
43 | #ifdef CONFIG_SMP | 232 | #ifdef CONFIG_SMP |
44 | unsigned long long value; | 233 | unsigned long long value; |
45 | 234 | ||
@@ -50,7 +239,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
50 | * Errata 63 for SH-B3 steppings | 239 | * Errata 63 for SH-B3 steppings |
51 | * Errata 122 for all steppings (F+ have it disabled by default) | 240 | * Errata 122 for all steppings (F+ have it disabled by default) |
52 | */ | 241 | */ |
53 | if (c->x86 == 15) { | 242 | if (c->x86 == 0xf) { |
54 | rdmsrl(MSR_K7_HWCR, value); | 243 | rdmsrl(MSR_K7_HWCR, value); |
55 | value |= 1 << 6; | 244 | value |= 1 << 6; |
56 | wrmsrl(MSR_K7_HWCR, value); | 245 | wrmsrl(MSR_K7_HWCR, value); |
@@ -73,192 +262,55 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
73 | 262 | ||
74 | switch (c->x86) { | 263 | switch (c->x86) { |
75 | case 4: | 264 | case 4: |
76 | /* | 265 | init_amd_k5(c); |
77 | * General Systems BIOSen alias the cpu frequency registers | 266 | break; |
78 | * of the Elan at 0x000df000. Unfortuantly, one of the Linux | ||
79 | * drivers subsequently pokes it, and changes the CPU speed. | ||
80 | * Workaround : Remove the unneeded alias. | ||
81 | */ | ||
82 | #define CBAR (0xfffc) /* Configuration Base Address (32-bit) */ | ||
83 | #define CBAR_ENB (0x80000000) | ||
84 | #define CBAR_KEY (0X000000CB) | ||
85 | if (c->x86_model == 9 || c->x86_model == 10) { | ||
86 | if (inl (CBAR) & CBAR_ENB) | ||
87 | outl (0 | CBAR_KEY, CBAR); | ||
88 | } | ||
89 | break; | ||
90 | case 5: | 267 | case 5: |
91 | if (c->x86_model < 6) { | 268 | init_amd_k6(c); |
92 | /* Based on AMD doc 20734R - June 2000 */ | ||
93 | if (c->x86_model == 0) { | ||
94 | clear_cpu_cap(c, X86_FEATURE_APIC); | ||
95 | set_cpu_cap(c, X86_FEATURE_PGE); | ||
96 | } | ||
97 | break; | ||
98 | } | ||
99 | |||
100 | if (c->x86_model == 6 && c->x86_mask == 1) { | ||
101 | const int K6_BUG_LOOP = 1000000; | ||
102 | int n; | ||
103 | void (*f_vide)(void); | ||
104 | unsigned long d, d2; | ||
105 | |||
106 | printk(KERN_INFO "AMD K6 stepping B detected - "); | ||
107 | |||
108 | /* | ||
109 | * It looks like AMD fixed the 2.6.2 bug and improved indirect | ||
110 | * calls at the same time. | ||
111 | */ | ||
112 | |||
113 | n = K6_BUG_LOOP; | ||
114 | f_vide = vide; | ||
115 | rdtscl(d); | ||
116 | while (n--) | ||
117 | f_vide(); | ||
118 | rdtscl(d2); | ||
119 | d = d2-d; | ||
120 | |||
121 | if (d > 20*K6_BUG_LOOP) | ||
122 | printk("system stability may be impaired when more than 32 MB are used.\n"); | ||
123 | else | ||
124 | printk("probably OK (after B9730xxxx).\n"); | ||
125 | printk(KERN_INFO "Please see http://membres.lycos.fr/poulot/k6bug.html\n"); | ||
126 | } | ||
127 | |||
128 | /* K6 with old style WHCR */ | ||
129 | if (c->x86_model < 8 || | ||
130 | (c->x86_model == 8 && c->x86_mask < 8)) { | ||
131 | /* We can only write allocate on the low 508Mb */ | ||
132 | if (mbytes > 508) | ||
133 | mbytes = 508; | ||
134 | |||
135 | rdmsr(MSR_K6_WHCR, l, h); | ||
136 | if ((l&0x0000FFFF) == 0) { | ||
137 | unsigned long flags; | ||
138 | l = (1<<0)|((mbytes/4)<<1); | ||
139 | local_irq_save(flags); | ||
140 | wbinvd(); | ||
141 | wrmsr(MSR_K6_WHCR, l, h); | ||
142 | local_irq_restore(flags); | ||
143 | printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n", | ||
144 | mbytes); | ||
145 | } | ||
146 | break; | ||
147 | } | ||
148 | |||
149 | if ((c->x86_model == 8 && c->x86_mask > 7) || | ||
150 | c->x86_model == 9 || c->x86_model == 13) { | ||
151 | /* The more serious chips .. */ | ||
152 | |||
153 | if (mbytes > 4092) | ||
154 | mbytes = 4092; | ||
155 | |||
156 | rdmsr(MSR_K6_WHCR, l, h); | ||
157 | if ((l&0xFFFF0000) == 0) { | ||
158 | unsigned long flags; | ||
159 | l = ((mbytes>>2)<<22)|(1<<16); | ||
160 | local_irq_save(flags); | ||
161 | wbinvd(); | ||
162 | wrmsr(MSR_K6_WHCR, l, h); | ||
163 | local_irq_restore(flags); | ||
164 | printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n", | ||
165 | mbytes); | ||
166 | } | ||
167 | |||
168 | break; | ||
169 | } | ||
170 | |||
171 | if (c->x86_model == 10) { | ||
172 | /* AMD Geode LX is model 10 */ | ||
173 | /* placeholder for any needed mods */ | ||
174 | break; | ||
175 | } | ||
176 | break; | ||
177 | case 6: /* An Athlon/Duron */ | ||
178 | |||
179 | /* | ||
180 | * Bit 15 of Athlon specific MSR 15, needs to be 0 | ||
181 | * to enable SSE on Palomino/Morgan/Barton CPU's. | ||
182 | * If the BIOS didn't enable it already, enable it here. | ||
183 | */ | ||
184 | if (c->x86_model >= 6 && c->x86_model <= 10) { | ||
185 | if (!cpu_has(c, X86_FEATURE_XMM)) { | ||
186 | printk(KERN_INFO "Enabling disabled K7/SSE Support.\n"); | ||
187 | rdmsr(MSR_K7_HWCR, l, h); | ||
188 | l &= ~0x00008000; | ||
189 | wrmsr(MSR_K7_HWCR, l, h); | ||
190 | set_cpu_cap(c, X86_FEATURE_XMM); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * It's been determined by AMD that Athlons since model 8 stepping 1 | ||
196 | * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx | ||
197 | * As per AMD technical note 27212 0.2 | ||
198 | */ | ||
199 | if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) { | ||
200 | rdmsr(MSR_K7_CLK_CTL, l, h); | ||
201 | if ((l & 0xfff00000) != 0x20000000) { | ||
202 | printk ("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", l, | ||
203 | ((l & 0x000fffff)|0x20000000)); | ||
204 | wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h); | ||
205 | } | ||
206 | } | ||
207 | break; | ||
208 | } | ||
209 | |||
210 | switch (c->x86) { | ||
211 | case 15: | ||
212 | /* Use K8 tuning for Fam10h and Fam11h */ | ||
213 | case 0x10: | ||
214 | case 0x11: | ||
215 | set_cpu_cap(c, X86_FEATURE_K8); | ||
216 | break; | 269 | break; |
217 | case 6: | 270 | case 6: /* An Athlon/Duron */ |
218 | set_cpu_cap(c, X86_FEATURE_K7); | 271 | init_amd_k7(c); |
219 | break; | 272 | break; |
220 | } | 273 | } |
274 | |||
275 | /* K6s reports MCEs but don't actually have all the MSRs */ | ||
276 | if (c->x86 < 6) | ||
277 | clear_cpu_cap(c, X86_FEATURE_MCE); | ||
278 | |||
221 | if (c->x86 >= 6) | 279 | if (c->x86 >= 6) |
222 | set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK); | 280 | set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK); |
223 | 281 | ||
224 | display_cacheinfo(c); | 282 | if (!c->x86_model_id[0]) { |
283 | switch (c->x86) { | ||
284 | case 0xf: | ||
285 | /* Should distinguish Models here, but this is only | ||
286 | a fallback anyways. */ | ||
287 | strcpy(c->x86_model_id, "Hammer"); | ||
288 | break; | ||
289 | } | ||
290 | } | ||
225 | 291 | ||
226 | if (cpuid_eax(0x80000000) >= 0x80000008) | 292 | display_cacheinfo(c); |
227 | c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1; | ||
228 | 293 | ||
229 | #ifdef CONFIG_X86_HT | 294 | /* Multi core CPU? */ |
230 | /* | 295 | if (c->extended_cpuid_level >= 0x80000008) |
231 | * On a AMD multi core setup the lower bits of the APIC id | 296 | amd_detect_cmp(c); |
232 | * distinguish the cores. | ||
233 | */ | ||
234 | if (c->x86_max_cores > 1) { | ||
235 | int cpu = smp_processor_id(); | ||
236 | unsigned bits = (cpuid_ecx(0x80000008) >> 12) & 0xf; | ||
237 | 297 | ||
238 | if (bits == 0) { | 298 | detect_ht(c); |
239 | while ((1 << bits) < c->x86_max_cores) | ||
240 | bits++; | ||
241 | } | ||
242 | c->cpu_core_id = c->phys_proc_id & ((1<<bits)-1); | ||
243 | c->phys_proc_id >>= bits; | ||
244 | printk(KERN_INFO "CPU %d(%d) -> Core %d\n", | ||
245 | cpu, c->x86_max_cores, c->cpu_core_id); | ||
246 | } | ||
247 | #endif | ||
248 | 299 | ||
249 | if (cpuid_eax(0x80000000) >= 0x80000006) { | 300 | if (c->extended_cpuid_level >= 0x80000006) { |
250 | if ((c->x86 == 0x10) && (cpuid_edx(0x80000006) & 0xf000)) | 301 | if ((c->x86 >= 0x0f) && (cpuid_edx(0x80000006) & 0xf000)) |
251 | num_cache_leaves = 4; | 302 | num_cache_leaves = 4; |
252 | else | 303 | else |
253 | num_cache_leaves = 3; | 304 | num_cache_leaves = 3; |
254 | } | 305 | } |
255 | 306 | ||
256 | /* K6s reports MCEs but don't actually have all the MSRs */ | 307 | if (c->x86 >= 0xf && c->x86 <= 0x11) |
257 | if (c->x86 < 6) | 308 | set_cpu_cap(c, X86_FEATURE_K8); |
258 | clear_cpu_cap(c, X86_FEATURE_MCE); | ||
259 | 309 | ||
260 | if (cpu_has_xmm2) | 310 | if (cpu_has_xmm2) { |
311 | /* MFENCE stops RDTSC speculation */ | ||
261 | set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); | 312 | set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); |
313 | } | ||
262 | } | 314 | } |
263 | 315 | ||
264 | static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) | 316 | static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) |