aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBorislav Petkov <borislav.petkov@amd.com>2009-10-07 07:20:38 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-12 06:24:45 -0400
commitfb2531953fd8855abdcf458459020fd382c5deca (patch)
tree2967323398aba0369bff02225f0e9d4d00db0c35
parentd93a8f829fe1d2f3002f2c6ddb553d12db420412 (diff)
mce, edac: Use an atomic notifier for MCEs decoding
Add an atomic notifier which ensures proper locking when conveying MCE info to EDAC for decoding. The actual notifier call overrides a default, negative priority notifier. Note: make sure we register the default decoder only once since mcheck_init() runs on each CPU. Signed-off-by: Borislav Petkov <borislav.petkov@amd.com> LKML-Reference: <20091003065752.GA8935@liondog.tnic> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/include/asm/mce.h3
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c29
-rw-r--r--drivers/edac/edac_mce_amd.c21
3 files changed, 34 insertions, 19 deletions
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index f1363b72364f..227a72df6441 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -108,6 +108,8 @@ struct mce_log {
108#define K8_MCE_THRESHOLD_BANK_5 (MCE_THRESHOLD_BASE + 5 * 9) 108#define K8_MCE_THRESHOLD_BANK_5 (MCE_THRESHOLD_BASE + 5 * 9)
109#define K8_MCE_THRESHOLD_DRAM_ECC (MCE_THRESHOLD_BANK_4 + 0) 109#define K8_MCE_THRESHOLD_DRAM_ECC (MCE_THRESHOLD_BANK_4 + 0)
110 110
111extern struct atomic_notifier_head x86_mce_decoder_chain;
112
111#ifdef __KERNEL__ 113#ifdef __KERNEL__
112 114
113#include <linux/percpu.h> 115#include <linux/percpu.h>
@@ -213,6 +215,5 @@ extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
213void intel_init_thermal(struct cpuinfo_x86 *c); 215void intel_init_thermal(struct cpuinfo_x86 *c);
214 216
215void mce_log_therm_throt_event(__u64 status); 217void mce_log_therm_throt_event(__u64 status);
216
217#endif /* __KERNEL__ */ 218#endif /* __KERNEL__ */
218#endif /* _ASM_X86_MCE_H */ 219#endif /* _ASM_X86_MCE_H */
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index b1598a9436d0..15ba9c972d7a 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -85,18 +85,26 @@ static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
85static DEFINE_PER_CPU(struct mce, mces_seen); 85static DEFINE_PER_CPU(struct mce, mces_seen);
86static int cpu_missing; 86static int cpu_missing;
87 87
88static void default_decode_mce(struct mce *m) 88/*
89 * CPU/chipset specific EDAC code can register a notifier call here to print
90 * MCE errors in a human-readable form.
91 */
92ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain);
93EXPORT_SYMBOL_GPL(x86_mce_decoder_chain);
94
95static int default_decode_mce(struct notifier_block *nb, unsigned long val,
96 void *data)
89{ 97{
90 pr_emerg("No human readable MCE decoding support on this CPU type.\n"); 98 pr_emerg("No human readable MCE decoding support on this CPU type.\n");
91 pr_emerg("Run the message through 'mcelog --ascii' to decode.\n"); 99 pr_emerg("Run the message through 'mcelog --ascii' to decode.\n");
100
101 return NOTIFY_STOP;
92} 102}
93 103
94/* 104static struct notifier_block mce_dec_nb = {
95 * CPU/chipset specific EDAC code can register a callback here to print 105 .notifier_call = default_decode_mce,
96 * MCE errors in a human-readable form: 106 .priority = -1,
97 */ 107};
98void (*x86_mce_decode_callback)(struct mce *m) = default_decode_mce;
99EXPORT_SYMBOL(x86_mce_decode_callback);
100 108
101/* MCA banks polled by the period polling timer for corrected events */ 109/* MCA banks polled by the period polling timer for corrected events */
102DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { 110DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
@@ -204,9 +212,9 @@ static void print_mce(struct mce *m)
204 212
205 /* 213 /*
206 * Print out human-readable details about the MCE error, 214 * Print out human-readable details about the MCE error,
207 * (if the CPU has an implementation for that): 215 * (if the CPU has an implementation for that)
208 */ 216 */
209 x86_mce_decode_callback(m); 217 atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
210} 218}
211 219
212static void print_mce_head(void) 220static void print_mce_head(void)
@@ -1420,6 +1428,9 @@ void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
1420 mce_cpu_features(c); 1428 mce_cpu_features(c);
1421 mce_init_timer(); 1429 mce_init_timer();
1422 INIT_WORK(&__get_cpu_var(mce_work), mce_process_work); 1430 INIT_WORK(&__get_cpu_var(mce_work), mce_process_work);
1431
1432 if (raw_smp_processor_id() == 0)
1433 atomic_notifier_chain_register(&x86_mce_decoder_chain, &mce_dec_nb);
1423} 1434}
1424 1435
1425/* 1436/*
diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c
index 713ed7d37247..689cc6a6214d 100644
--- a/drivers/edac/edac_mce_amd.c
+++ b/drivers/edac/edac_mce_amd.c
@@ -3,7 +3,6 @@
3 3
4static bool report_gart_errors; 4static bool report_gart_errors;
5static void (*nb_bus_decoder)(int node_id, struct err_regs *regs); 5static void (*nb_bus_decoder)(int node_id, struct err_regs *regs);
6static void (*orig_mce_callback)(struct mce *m);
7 6
8void amd_report_gart_errors(bool v) 7void amd_report_gart_errors(bool v)
9{ 8{
@@ -363,8 +362,10 @@ static inline void amd_decode_err_code(unsigned int ec)
363 pr_warning("Huh? Unknown MCE error 0x%x\n", ec); 362 pr_warning("Huh? Unknown MCE error 0x%x\n", ec);
364} 363}
365 364
366static void amd_decode_mce(struct mce *m) 365static int amd_decode_mce(struct notifier_block *nb, unsigned long val,
366 void *data)
367{ 367{
368 struct mce *m = (struct mce *)data;
368 struct err_regs regs; 369 struct err_regs regs;
369 int node, ecc; 370 int node, ecc;
370 371
@@ -420,20 +421,22 @@ static void amd_decode_mce(struct mce *m)
420 } 421 }
421 422
422 amd_decode_err_code(m->status & 0xffff); 423 amd_decode_err_code(m->status & 0xffff);
424
425 return NOTIFY_STOP;
423} 426}
424 427
428static struct notifier_block amd_mce_dec_nb = {
429 .notifier_call = amd_decode_mce,
430};
431
425static int __init mce_amd_init(void) 432static int __init mce_amd_init(void)
426{ 433{
427 /* 434 /*
428 * We can decode MCEs for Opteron and later CPUs: 435 * We can decode MCEs for Opteron and later CPUs:
429 */ 436 */
430 if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && 437 if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
431 (boot_cpu_data.x86 >= 0xf)) { 438 (boot_cpu_data.x86 >= 0xf))
432 /* safe the default decode mce callback */ 439 atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb);
433 orig_mce_callback = x86_mce_decode_callback;
434
435 x86_mce_decode_callback = amd_decode_mce;
436 }
437 440
438 return 0; 441 return 0;
439} 442}
@@ -442,7 +445,7 @@ early_initcall(mce_amd_init);
442#ifdef MODULE 445#ifdef MODULE
443static void __exit mce_amd_exit(void) 446static void __exit mce_amd_exit(void)
444{ 447{
445 x86_mce_decode_callback = orig_mce_callback; 448 atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb);
446} 449}
447 450
448MODULE_DESCRIPTION("AMD MCE decoder"); 451MODULE_DESCRIPTION("AMD MCE decoder");