diff options
Diffstat (limited to 'arch/x86/kernel/cpu/mcheck')
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 39caea3d8bc3..0fb9dc50697e 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -88,18 +88,26 @@ static DECLARE_WAIT_QUEUE_HEAD(mce_wait); | |||
88 | static DEFINE_PER_CPU(struct mce, mces_seen); | 88 | static DEFINE_PER_CPU(struct mce, mces_seen); |
89 | static int cpu_missing; | 89 | static int cpu_missing; |
90 | 90 | ||
91 | static void default_decode_mce(struct mce *m) | 91 | /* |
92 | * CPU/chipset specific EDAC code can register a notifier call here to print | ||
93 | * MCE errors in a human-readable form. | ||
94 | */ | ||
95 | ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); | ||
96 | EXPORT_SYMBOL_GPL(x86_mce_decoder_chain); | ||
97 | |||
98 | static int default_decode_mce(struct notifier_block *nb, unsigned long val, | ||
99 | void *data) | ||
92 | { | 100 | { |
93 | pr_emerg("No human readable MCE decoding support on this CPU type.\n"); | 101 | pr_emerg("No human readable MCE decoding support on this CPU type.\n"); |
94 | pr_emerg("Run the message through 'mcelog --ascii' to decode.\n"); | 102 | pr_emerg("Run the message through 'mcelog --ascii' to decode.\n"); |
103 | |||
104 | return NOTIFY_STOP; | ||
95 | } | 105 | } |
96 | 106 | ||
97 | /* | 107 | static struct notifier_block mce_dec_nb = { |
98 | * CPU/chipset specific EDAC code can register a callback here to print | 108 | .notifier_call = default_decode_mce, |
99 | * MCE errors in a human-readable form: | 109 | .priority = -1, |
100 | */ | 110 | }; |
101 | void (*x86_mce_decode_callback)(struct mce *m) = default_decode_mce; | ||
102 | EXPORT_SYMBOL(x86_mce_decode_callback); | ||
103 | 111 | ||
104 | /* MCA banks polled by the period polling timer for corrected events */ | 112 | /* MCA banks polled by the period polling timer for corrected events */ |
105 | DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { | 113 | DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { |
@@ -210,9 +218,9 @@ static void print_mce(struct mce *m) | |||
210 | 218 | ||
211 | /* | 219 | /* |
212 | * Print out human-readable details about the MCE error, | 220 | * Print out human-readable details about the MCE error, |
213 | * (if the CPU has an implementation for that): | 221 | * (if the CPU has an implementation for that) |
214 | */ | 222 | */ |
215 | x86_mce_decode_callback(m); | 223 | atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m); |
216 | } | 224 | } |
217 | 225 | ||
218 | static void print_mce_head(void) | 226 | static void print_mce_head(void) |
@@ -1220,7 +1228,8 @@ static int __cpuinit mce_cap_init(void) | |||
1220 | rdmsrl(MSR_IA32_MCG_CAP, cap); | 1228 | rdmsrl(MSR_IA32_MCG_CAP, cap); |
1221 | 1229 | ||
1222 | b = cap & MCG_BANKCNT_MASK; | 1230 | b = cap & MCG_BANKCNT_MASK; |
1223 | printk(KERN_INFO "mce: CPU supports %d MCE banks\n", b); | 1231 | if (!banks) |
1232 | printk(KERN_INFO "mce: CPU supports %d MCE banks\n", b); | ||
1224 | 1233 | ||
1225 | if (b > MAX_NR_BANKS) { | 1234 | if (b > MAX_NR_BANKS) { |
1226 | printk(KERN_WARNING | 1235 | printk(KERN_WARNING |
@@ -1426,6 +1435,9 @@ void __cpuinit mcheck_init(struct cpuinfo_x86 *c) | |||
1426 | mce_cpu_features(c); | 1435 | mce_cpu_features(c); |
1427 | mce_init_timer(); | 1436 | mce_init_timer(); |
1428 | INIT_WORK(&__get_cpu_var(mce_work), mce_process_work); | 1437 | INIT_WORK(&__get_cpu_var(mce_work), mce_process_work); |
1438 | |||
1439 | if (raw_smp_processor_id() == 0) | ||
1440 | atomic_notifier_chain_register(&x86_mce_decoder_chain, &mce_dec_nb); | ||
1429 | } | 1441 | } |
1430 | 1442 | ||
1431 | /* | 1443 | /* |