diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-28 08:14:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-28 08:14:48 -0400 |
commit | 8237eb946a1a23c600fb289cf8dd3b399b10604e (patch) | |
tree | e3985782029601ede4035cfec7ee59e1a54324fd | |
parent | cc21fe518a971bb2b0ab8370ec46ea21e84c57ab (diff) | |
parent | bcb80e53877c2045d9e52f4a71372c3fe6501f6f (diff) |
Merge branch 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
* 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86, microcode, AMD: Add microcode revision to /proc/cpuinfo
x86, microcode: Correct microcode revision format
coretemp: Get microcode revision from cpu_data
x86, intel: Use c->microcode for Atom errata check
x86, intel: Output microcode revision in /proc/cpuinfo
x86, microcode: Don't request microcode from userspace unnecessarily
Fix up trivial conflicts in arch/x86/kernel/cpu/amd.c (conflict between
moving AMD BSP code to cpu_dev helper function and adding AMD microcode
revision to /proc/cpuinfo code)
-rw-r--r-- | arch/x86/include/asm/processor.h | 4 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/amd.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/intel.c | 24 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 9 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/proc.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_amd.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_core.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_intel.c | 14 | ||||
-rw-r--r-- | drivers/hwmon/coretemp.c | 28 |
9 files changed, 48 insertions, 50 deletions
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 0d1171c97729..b650435ffb53 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -111,6 +111,7 @@ struct cpuinfo_x86 { | |||
111 | /* Index into per_cpu list: */ | 111 | /* Index into per_cpu list: */ |
112 | u16 cpu_index; | 112 | u16 cpu_index; |
113 | #endif | 113 | #endif |
114 | u32 microcode; | ||
114 | } __attribute__((__aligned__(SMP_CACHE_BYTES))); | 115 | } __attribute__((__aligned__(SMP_CACHE_BYTES))); |
115 | 116 | ||
116 | #define X86_VENDOR_INTEL 0 | 117 | #define X86_VENDOR_INTEL 0 |
@@ -179,7 +180,8 @@ static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, | |||
179 | "=b" (*ebx), | 180 | "=b" (*ebx), |
180 | "=c" (*ecx), | 181 | "=c" (*ecx), |
181 | "=d" (*edx) | 182 | "=d" (*edx) |
182 | : "0" (*eax), "2" (*ecx)); | 183 | : "0" (*eax), "2" (*ecx) |
184 | : "memory"); | ||
183 | } | 185 | } |
184 | 186 | ||
185 | static inline void load_cr3(pgd_t *pgdir) | 187 | static inline void load_cr3(pgd_t *pgdir) |
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 13c6ec812545..46ae4f65fc7f 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c | |||
@@ -441,6 +441,8 @@ static void __cpuinit bsp_init_amd(struct cpuinfo_x86 *c) | |||
441 | 441 | ||
442 | static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) | 442 | static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) |
443 | { | 443 | { |
444 | u32 dummy; | ||
445 | |||
444 | early_init_amd_mc(c); | 446 | early_init_amd_mc(c); |
445 | 447 | ||
446 | /* | 448 | /* |
@@ -470,6 +472,8 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) | |||
470 | set_cpu_cap(c, X86_FEATURE_EXTD_APICID); | 472 | set_cpu_cap(c, X86_FEATURE_EXTD_APICID); |
471 | } | 473 | } |
472 | #endif | 474 | #endif |
475 | |||
476 | rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy); | ||
473 | } | 477 | } |
474 | 478 | ||
475 | static void __cpuinit init_amd(struct cpuinfo_x86 *c) | 479 | static void __cpuinit init_amd(struct cpuinfo_x86 *c) |
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index ed6086eedf1d..523131213f08 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c | |||
@@ -47,6 +47,15 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) | |||
47 | (c->x86 == 0x6 && c->x86_model >= 0x0e)) | 47 | (c->x86 == 0x6 && c->x86_model >= 0x0e)) |
48 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); | 48 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); |
49 | 49 | ||
50 | if (c->x86 >= 6 && !cpu_has(c, X86_FEATURE_IA64)) { | ||
51 | unsigned lower_word; | ||
52 | |||
53 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | ||
54 | /* Required by the SDM */ | ||
55 | sync_core(); | ||
56 | rdmsr(MSR_IA32_UCODE_REV, lower_word, c->microcode); | ||
57 | } | ||
58 | |||
50 | /* | 59 | /* |
51 | * Atom erratum AAE44/AAF40/AAG38/AAH41: | 60 | * Atom erratum AAE44/AAF40/AAG38/AAH41: |
52 | * | 61 | * |
@@ -55,17 +64,10 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) | |||
55 | * need the microcode to have already been loaded... so if it is | 64 | * need the microcode to have already been loaded... so if it is |
56 | * not, recommend a BIOS update and disable large pages. | 65 | * not, recommend a BIOS update and disable large pages. |
57 | */ | 66 | */ |
58 | if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_mask <= 2) { | 67 | if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_mask <= 2 && |
59 | u32 ucode, junk; | 68 | c->microcode < 0x20e) { |
60 | 69 | printk(KERN_WARNING "Atom PSE erratum detected, BIOS microcode update recommended\n"); | |
61 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | 70 | clear_cpu_cap(c, X86_FEATURE_PSE); |
62 | sync_core(); | ||
63 | rdmsr(MSR_IA32_UCODE_REV, junk, ucode); | ||
64 | |||
65 | if (ucode < 0x20e) { | ||
66 | printk(KERN_WARNING "Atom PSE erratum detected, BIOS microcode update recommended\n"); | ||
67 | clear_cpu_cap(c, X86_FEATURE_PSE); | ||
68 | } | ||
69 | } | 71 | } |
70 | 72 | ||
71 | #ifdef CONFIG_X86_64 | 73 | #ifdef CONFIG_X86_64 |
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index fce51ad1f362..7b5063a6ad42 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -217,8 +217,13 @@ static void print_mce(struct mce *m) | |||
217 | pr_cont("MISC %llx ", m->misc); | 217 | pr_cont("MISC %llx ", m->misc); |
218 | 218 | ||
219 | pr_cont("\n"); | 219 | pr_cont("\n"); |
220 | pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n", | 220 | /* |
221 | m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid); | 221 | * Note this output is parsed by external tools and old fields |
222 | * should not be changed. | ||
223 | */ | ||
224 | pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n", | ||
225 | m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid, | ||
226 | cpu_data(m->extcpu).microcode); | ||
222 | 227 | ||
223 | /* | 228 | /* |
224 | * Print out human-readable details about the MCE error, | 229 | * Print out human-readable details about the MCE error, |
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c index 62ac8cb6ba27..14b23140e81f 100644 --- a/arch/x86/kernel/cpu/proc.c +++ b/arch/x86/kernel/cpu/proc.c | |||
@@ -85,6 +85,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
85 | seq_printf(m, "stepping\t: %d\n", c->x86_mask); | 85 | seq_printf(m, "stepping\t: %d\n", c->x86_mask); |
86 | else | 86 | else |
87 | seq_printf(m, "stepping\t: unknown\n"); | 87 | seq_printf(m, "stepping\t: unknown\n"); |
88 | if (c->microcode) | ||
89 | seq_printf(m, "microcode\t: 0x%x\n", c->microcode); | ||
88 | 90 | ||
89 | if (cpu_has(c, X86_FEATURE_TSC)) { | 91 | if (cpu_has(c, X86_FEATURE_TSC)) { |
90 | unsigned int freq = cpufreq_quick_get(cpu); | 92 | unsigned int freq = cpufreq_quick_get(cpu); |
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 591be0ee1934..d494799aafcd 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c | |||
@@ -74,14 +74,13 @@ static struct equiv_cpu_entry *equiv_cpu_table; | |||
74 | static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) | 74 | static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) |
75 | { | 75 | { |
76 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 76 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
77 | u32 dummy; | ||
78 | 77 | ||
79 | if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) { | 78 | if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) { |
80 | pr_warning("CPU%d: family %d not supported\n", cpu, c->x86); | 79 | pr_warning("CPU%d: family %d not supported\n", cpu, c->x86); |
81 | return -1; | 80 | return -1; |
82 | } | 81 | } |
83 | 82 | ||
84 | rdmsr(MSR_AMD64_PATCH_LEVEL, csig->rev, dummy); | 83 | csig->rev = c->microcode; |
85 | pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev); | 84 | pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev); |
86 | 85 | ||
87 | return 0; | 86 | return 0; |
@@ -130,6 +129,7 @@ static int apply_microcode_amd(int cpu) | |||
130 | int cpu_num = raw_smp_processor_id(); | 129 | int cpu_num = raw_smp_processor_id(); |
131 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | 130 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; |
132 | struct microcode_amd *mc_amd = uci->mc; | 131 | struct microcode_amd *mc_amd = uci->mc; |
132 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
133 | 133 | ||
134 | /* We should bind the task to the CPU */ | 134 | /* We should bind the task to the CPU */ |
135 | BUG_ON(cpu_num != cpu); | 135 | BUG_ON(cpu_num != cpu); |
@@ -150,6 +150,7 @@ static int apply_microcode_amd(int cpu) | |||
150 | 150 | ||
151 | pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev); | 151 | pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev); |
152 | uci->cpu_sig.rev = rev; | 152 | uci->cpu_sig.rev = rev; |
153 | c->microcode = rev; | ||
153 | 154 | ||
154 | return 0; | 155 | return 0; |
155 | } | 156 | } |
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index f9242800bc84..f2d2a664e797 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c | |||
@@ -483,7 +483,13 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) | |||
483 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | 483 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); |
484 | pr_debug("CPU%d removed\n", cpu); | 484 | pr_debug("CPU%d removed\n", cpu); |
485 | break; | 485 | break; |
486 | case CPU_DEAD: | 486 | |
487 | /* | ||
488 | * When a CPU goes offline, don't free up or invalidate the copy of | ||
489 | * the microcode in kernel memory, so that we can reuse it when the | ||
490 | * CPU comes back online without unnecessarily requesting the userspace | ||
491 | * for it again. | ||
492 | */ | ||
487 | case CPU_UP_CANCELED_FROZEN: | 493 | case CPU_UP_CANCELED_FROZEN: |
488 | /* The CPU refused to come up during a system resume */ | 494 | /* The CPU refused to come up during a system resume */ |
489 | microcode_fini_cpu(cpu); | 495 | microcode_fini_cpu(cpu); |
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c index 1a1b606d3e92..3ca42d0e43a2 100644 --- a/arch/x86/kernel/microcode_intel.c +++ b/arch/x86/kernel/microcode_intel.c | |||
@@ -161,12 +161,7 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) | |||
161 | csig->pf = 1 << ((val[1] >> 18) & 7); | 161 | csig->pf = 1 << ((val[1] >> 18) & 7); |
162 | } | 162 | } |
163 | 163 | ||
164 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | 164 | csig->rev = c->microcode; |
165 | /* see notes above for revision 1.07. Apparent chip bug */ | ||
166 | sync_core(); | ||
167 | /* get the current revision from MSR 0x8B */ | ||
168 | rdmsr(MSR_IA32_UCODE_REV, val[0], csig->rev); | ||
169 | |||
170 | pr_info("CPU%d sig=0x%x, pf=0x%x, revision=0x%x\n", | 165 | pr_info("CPU%d sig=0x%x, pf=0x%x, revision=0x%x\n", |
171 | cpu_num, csig->sig, csig->pf, csig->rev); | 166 | cpu_num, csig->sig, csig->pf, csig->rev); |
172 | 167 | ||
@@ -299,9 +294,9 @@ static int apply_microcode(int cpu) | |||
299 | struct microcode_intel *mc_intel; | 294 | struct microcode_intel *mc_intel; |
300 | struct ucode_cpu_info *uci; | 295 | struct ucode_cpu_info *uci; |
301 | unsigned int val[2]; | 296 | unsigned int val[2]; |
302 | int cpu_num; | 297 | int cpu_num = raw_smp_processor_id(); |
298 | struct cpuinfo_x86 *c = &cpu_data(cpu_num); | ||
303 | 299 | ||
304 | cpu_num = raw_smp_processor_id(); | ||
305 | uci = ucode_cpu_info + cpu; | 300 | uci = ucode_cpu_info + cpu; |
306 | mc_intel = uci->mc; | 301 | mc_intel = uci->mc; |
307 | 302 | ||
@@ -317,7 +312,7 @@ static int apply_microcode(int cpu) | |||
317 | (unsigned long) mc_intel->bits >> 16 >> 16); | 312 | (unsigned long) mc_intel->bits >> 16 >> 16); |
318 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | 313 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); |
319 | 314 | ||
320 | /* see notes above for revision 1.07. Apparent chip bug */ | 315 | /* As documented in the SDM: Do a CPUID 1 here */ |
321 | sync_core(); | 316 | sync_core(); |
322 | 317 | ||
323 | /* get the current revision from MSR 0x8B */ | 318 | /* get the current revision from MSR 0x8B */ |
@@ -335,6 +330,7 @@ static int apply_microcode(int cpu) | |||
335 | (mc_intel->hdr.date >> 16) & 0xff); | 330 | (mc_intel->hdr.date >> 16) & 0xff); |
336 | 331 | ||
337 | uci->cpu_sig.rev = val[1]; | 332 | uci->cpu_sig.rev = val[1]; |
333 | c->microcode = val[1]; | ||
338 | 334 | ||
339 | return 0; | 335 | return 0; |
340 | } | 336 | } |
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 932383786642..ce18c046f728 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c | |||
@@ -325,15 +325,6 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) | |||
325 | return adjust_tjmax(c, id, dev); | 325 | return adjust_tjmax(c, id, dev); |
326 | } | 326 | } |
327 | 327 | ||
328 | static void __devinit get_ucode_rev_on_cpu(void *edx) | ||
329 | { | ||
330 | u32 eax; | ||
331 | |||
332 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | ||
333 | sync_core(); | ||
334 | rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx); | ||
335 | } | ||
336 | |||
337 | static int create_name_attr(struct platform_data *pdata, struct device *dev) | 328 | static int create_name_attr(struct platform_data *pdata, struct device *dev) |
338 | { | 329 | { |
339 | sysfs_attr_init(&pdata->name_attr.attr); | 330 | sysfs_attr_init(&pdata->name_attr.attr); |
@@ -380,27 +371,16 @@ exit_free: | |||
380 | static int __cpuinit chk_ucode_version(unsigned int cpu) | 371 | static int __cpuinit chk_ucode_version(unsigned int cpu) |
381 | { | 372 | { |
382 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 373 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
383 | int err; | ||
384 | u32 edx; | ||
385 | 374 | ||
386 | /* | 375 | /* |
387 | * Check if we have problem with errata AE18 of Core processors: | 376 | * Check if we have problem with errata AE18 of Core processors: |
388 | * Readings might stop update when processor visited too deep sleep, | 377 | * Readings might stop update when processor visited too deep sleep, |
389 | * fixed for stepping D0 (6EC). | 378 | * fixed for stepping D0 (6EC). |
390 | */ | 379 | */ |
391 | if (c->x86_model == 0xe && c->x86_mask < 0xc) { | 380 | if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) { |
392 | /* check for microcode update */ | 381 | pr_err("Errata AE18 not fixed, update BIOS or " |
393 | err = smp_call_function_single(cpu, get_ucode_rev_on_cpu, | 382 | "microcode of the CPU!\n"); |
394 | &edx, 1); | 383 | return -ENODEV; |
395 | if (err) { | ||
396 | pr_err("Cannot determine microcode revision of " | ||
397 | "CPU#%u (%d)!\n", cpu, err); | ||
398 | return -ENODEV; | ||
399 | } else if (edx < 0x39) { | ||
400 | pr_err("Errata AE18 not fixed, update BIOS or " | ||
401 | "microcode of the CPU!\n"); | ||
402 | return -ENODEV; | ||
403 | } | ||
404 | } | 384 | } |
405 | return 0; | 385 | return 0; |
406 | } | 386 | } |