aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu
diff options
context:
space:
mode:
authorAndi Kleen <ak@linux.intel.com>2009-04-28 13:07:31 -0400
committerH. Peter Anvin <hpa@zytor.com>2009-05-28 12:24:13 -0400
commit4efc0670baf4b14bc95502e54a83ccf639146125 (patch)
treee2a4c61f303701d967b0d3fa9eccb4dcb576c690 /arch/x86/kernel/cpu
parentd896a940ef4f12a0a6bc432853b249dcfbacabf0 (diff)
x86, mce: use 64bit machine check code on 32bit
The 64bit machine check code is in many ways much better than the 32bit machine check code: it is more specification compliant, is cleaner, only has a single code base versus one per CPU, has better infrastructure for recovery, has a cleaner way to communicate with user space etc. etc. Use the 64bit code for 32bit too. This is the second attempt to do this. There was one a couple of years ago to unify this code for 32bit and 64bit. Back then this ran into some trouble with K7s and was reverted. I believe this time the K7 problems (and some others) are addressed. I went over the old handlers and was very careful to retain all quirks. But of course this needs a lot of testing on old systems. On newer 64bit capable systems I don't expect much problems because they have been already tested with the 64bit kernel. I made this a CONFIG for now that still allows to select the old machine check code. This is mostly to make testing easier, if someone runs into a problem we can ask them to try with the CONFIG switched. The new code is default y for more coverage. Once there is confidence the 64bit code works well on older hardware too the CONFIG_X86_OLD_MCE and the associated code can be easily removed. This causes a behaviour change for 32bit installations. They now have to install the mcelog package to be able to log corrected machine checks. The 64bit machine check code only handles CPUs which support the standard Intel machine check architecture described in the IA32 SDM. The 32bit code has special support for some older CPUs which have non standard machine check architectures, in particular WinChip C3 and Intel P5. I made those a separate CONFIG option and kept them for now. The WinChip variant could be probably removed without too much pain, it doesn't really do anything interesting. P5 is also disabled by default (like it was before) because many motherboards have it miswired, but according to Alan Cox a few embedded setups use that one. Forward ported/heavily changed version of old patch, original patch included review/fixes from Thomas Gleixner, Bert Wesarg. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/kernel/cpu')
-rw-r--r--arch/x86/kernel/cpu/mcheck/Makefile3
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c32
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.h18
-rw-r--r--arch/x86/kernel/cpu/mcheck/p5.c5
4 files changed, 50 insertions, 8 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/Makefile b/arch/x86/kernel/cpu/mcheck/Makefile
index 55f01b39a105..5f8b09425d39 100644
--- a/arch/x86/kernel/cpu/mcheck/Makefile
+++ b/arch/x86/kernel/cpu/mcheck/Makefile
@@ -1,6 +1,7 @@
1obj-y = mce.o therm_throt.o 1obj-y = mce.o therm_throt.o
2 2
3obj-$(CONFIG_X86_32) += k7.o p4.o p5.o p6.o winchip.o 3obj-$(CONFIG_X86_OLD_MCE) += k7.o p4.o p6.o
4obj-$(CONFIG_X86_ANCIENT_MCE) += winchip.o p5.o
4obj-$(CONFIG_X86_MCE_P4THERMAL) += mce_intel.o 5obj-$(CONFIG_X86_MCE_P4THERMAL) += mce_intel.o
5obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o mce_intel.o 6obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o mce_intel.o
6obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o 7obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index f4d6841d2bdf..e193de44ef19 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -52,7 +52,7 @@ void (*machine_check_vector)(struct pt_regs *, long error_code) =
52 52
53int mce_disabled; 53int mce_disabled;
54 54
55#ifdef CONFIG_X86_64 55#ifdef CONFIG_X86_NEW_MCE
56 56
57#define MISC_MCELOG_MINOR 227 57#define MISC_MCELOG_MINOR 227
58 58
@@ -662,6 +662,21 @@ static void mce_cpu_quirks(struct cpuinfo_x86 *c)
662 } 662 }
663} 663}
664 664
665static void __cpuinit mce_ancient_init(struct cpuinfo_x86 *c)
666{
667 if (c->x86 != 5)
668 return;
669 switch (c->x86_vendor) {
670 case X86_VENDOR_INTEL:
671 if (mce_p5_enabled())
672 intel_p5_mcheck_init(c);
673 break;
674 case X86_VENDOR_CENTAUR:
675 winchip_mcheck_init(c);
676 break;
677 }
678}
679
665static void mce_cpu_features(struct cpuinfo_x86 *c) 680static void mce_cpu_features(struct cpuinfo_x86 *c)
666{ 681{
667 switch (c->x86_vendor) { 682 switch (c->x86_vendor) {
@@ -695,6 +710,11 @@ static void mce_init_timer(void)
695 */ 710 */
696void __cpuinit mcheck_init(struct cpuinfo_x86 *c) 711void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
697{ 712{
713 if (mce_disabled)
714 return;
715
716 mce_ancient_init(c);
717
698 if (!mce_available(c)) 718 if (!mce_available(c))
699 return; 719 return;
700 720
@@ -893,6 +913,10 @@ static struct miscdevice mce_log_device = {
893 */ 913 */
894static int __init mcheck_enable(char *str) 914static int __init mcheck_enable(char *str)
895{ 915{
916 if (*str == 0)
917 enable_p5_mce();
918 if (*str == '=')
919 str++;
896 if (!strcmp(str, "off")) 920 if (!strcmp(str, "off"))
897 mce_disabled = 1; 921 mce_disabled = 1;
898 else if (!strcmp(str, "bootlog") || !strcmp(str, "nobootlog")) 922 else if (!strcmp(str, "bootlog") || !strcmp(str, "nobootlog"))
@@ -900,13 +924,13 @@ static int __init mcheck_enable(char *str)
900 else if (isdigit(str[0])) 924 else if (isdigit(str[0]))
901 get_option(&str, &tolerant); 925 get_option(&str, &tolerant);
902 else { 926 else {
903 printk(KERN_INFO "mce= argument %s ignored. Please use /sys\n", 927 printk(KERN_INFO "mce argument %s ignored. Please use /sys\n",
904 str); 928 str);
905 return 0; 929 return 0;
906 } 930 }
907 return 1; 931 return 1;
908} 932}
909__setup("mce=", mcheck_enable); 933__setup("mce", mcheck_enable);
910 934
911/* 935/*
912 * Sysfs support 936 * Sysfs support
@@ -1259,7 +1283,7 @@ static __init int mce_init_device(void)
1259 1283
1260device_initcall(mce_init_device); 1284device_initcall(mce_init_device);
1261 1285
1262#else /* CONFIG_X86_32: */ 1286#else /* CONFIG_X86_OLD_MCE: */
1263 1287
1264int nr_mce_banks; 1288int nr_mce_banks;
1265EXPORT_SYMBOL_GPL(nr_mce_banks); /* non-fatal.o */ 1289EXPORT_SYMBOL_GPL(nr_mce_banks); /* non-fatal.o */
diff --git a/arch/x86/kernel/cpu/mcheck/mce.h b/arch/x86/kernel/cpu/mcheck/mce.h
index 966ae3c5cb11..84a552b458c8 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.h
+++ b/arch/x86/kernel/cpu/mcheck/mce.h
@@ -1,17 +1,29 @@
1#include <linux/init.h> 1#include <linux/init.h>
2#include <asm/mce.h> 2#include <asm/mce.h>
3 3
4#ifdef CONFIG_X86_OLD_MCE
4void amd_mcheck_init(struct cpuinfo_x86 *c); 5void amd_mcheck_init(struct cpuinfo_x86 *c);
5void intel_p4_mcheck_init(struct cpuinfo_x86 *c); 6void intel_p4_mcheck_init(struct cpuinfo_x86 *c);
6void intel_p5_mcheck_init(struct cpuinfo_x86 *c);
7void intel_p6_mcheck_init(struct cpuinfo_x86 *c); 7void intel_p6_mcheck_init(struct cpuinfo_x86 *c);
8void winchip_mcheck_init(struct cpuinfo_x86 *c); 8#endif
9 9
10#ifdef CONFIG_X86_ANCIENT_MCE
11void intel_p5_mcheck_init(struct cpuinfo_x86 *c);
12void winchip_mcheck_init(struct cpuinfo_x86 *c);
13extern int mce_p5_enable;
14static inline int mce_p5_enabled(void) { return mce_p5_enable; }
15static inline void enable_p5_mce(void) { mce_p5_enable = 1; }
16#else
17static inline void intel_p5_mcheck_init(struct cpuinfo_x86 *c) {}
18static inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {}
19static inline int mce_p5_enabled(void) { return 0; }
20static inline void enable_p5_mce(void) { }
21#endif
10 22
11/* Call the installed machine check handler for this CPU setup. */ 23/* Call the installed machine check handler for this CPU setup. */
12extern void (*machine_check_vector)(struct pt_regs *, long error_code); 24extern void (*machine_check_vector)(struct pt_regs *, long error_code);
13 25
14#ifdef CONFIG_X86_32 26#ifdef CONFIG_X86_OLD_MCE
15 27
16extern int nr_mce_banks; 28extern int nr_mce_banks;
17 29
diff --git a/arch/x86/kernel/cpu/mcheck/p5.c b/arch/x86/kernel/cpu/mcheck/p5.c
index 8812f5441830..015f481ab1b0 100644
--- a/arch/x86/kernel/cpu/mcheck/p5.c
+++ b/arch/x86/kernel/cpu/mcheck/p5.c
@@ -14,6 +14,9 @@
14 14
15#include "mce.h" 15#include "mce.h"
16 16
17/* By default disabled */
18int mce_p5_enable;
19
17/* Machine check handler for Pentium class Intel CPUs: */ 20/* Machine check handler for Pentium class Intel CPUs: */
18static void pentium_machine_check(struct pt_regs *regs, long error_code) 21static void pentium_machine_check(struct pt_regs *regs, long error_code)
19{ 22{
@@ -44,9 +47,11 @@ void intel_p5_mcheck_init(struct cpuinfo_x86 *c)
44 if (!cpu_has(c, X86_FEATURE_MCE)) 47 if (!cpu_has(c, X86_FEATURE_MCE))
45 return; 48 return;
46 49
50#ifdef CONFIG_X86_OLD_MCE
47 /* Default P5 to off as its often misconnected: */ 51 /* Default P5 to off as its often misconnected: */
48 if (mce_disabled != -1) 52 if (mce_disabled != -1)
49 return; 53 return;
54#endif
50 55
51 machine_check_vector = pentium_machine_check; 56 machine_check_vector = pentium_machine_check;
52 /* Make sure the vector pointer is visible before we enable MCEs: */ 57 /* Make sure the vector pointer is visible before we enable MCEs: */