aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/amd.c
diff options
context:
space:
mode:
authorYinghai Lu <yhlu.kernel@gmail.com>2008-09-07 20:58:50 -0400
committerIngo Molnar <mingo@elte.hu>2008-09-08 09:31:58 -0400
commit11fdd252bb5b461289fc5c21dc8fc87dc66f3284 (patch)
tree75d3c11ee3af4d0dd59291a0f062302fcf79b072 /arch/x86/kernel/cpu/amd.c
parent2d9cd6c27f00958a31622b8e9909d5e35f069b28 (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.c396
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 @@
24extern void vide(void); 24extern void vide(void);
25__asm__(".align 4\nvide: ret"); 25__asm__(".align 4\nvide: ret");
26 26
27static 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
45static 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
137static 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 */
177static 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
191static 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
27static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) 217static 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
38static void __cpuinit init_amd(struct cpuinfo_x86 *c) 230static 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
264static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) 316static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int size)