aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2011-12-15 02:13:40 -0500
committerIngo Molnar <mingo@elte.hu>2011-12-15 02:13:40 -0500
commit715a43182a20a9e2bae59b4e0826a91ee30f355c (patch)
tree3757a7cd5231a6d4ee4728b60e6a3ed6ee2ce06e
parent29e9bf1841e4f9df13b4992a716fece7087dd237 (diff)
parent0937195715713b37ec843f28d99930dd7b1e8fbe (diff)
Merge branch 'early-mce-decode' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp into x86/mce
-rw-r--r--arch/x86/include/asm/mce.h3
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c64
-rw-r--r--drivers/edac/i7core_edac.c4
-rw-r--r--drivers/edac/mce_amd.c4
-rw-r--r--drivers/edac/sb_edac.c6
5 files changed, 65 insertions, 16 deletions
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 0e8ae57d3656..b7c47a468fde 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -120,7 +120,8 @@ struct mce_log {
120 120
121#ifdef __KERNEL__ 121#ifdef __KERNEL__
122 122
123extern struct atomic_notifier_head x86_mce_decoder_chain; 123extern void mce_register_decode_chain(struct notifier_block *nb);
124extern void mce_unregister_decode_chain(struct notifier_block *nb);
124 125
125#include <linux/percpu.h> 126#include <linux/percpu.h>
126#include <linux/init.h> 127#include <linux/init.h>
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 2af127d4c3d1..5be2464cce6a 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -95,13 +95,6 @@ static DECLARE_WAIT_QUEUE_HEAD(mce_chrdev_wait);
95static DEFINE_PER_CPU(struct mce, mces_seen); 95static DEFINE_PER_CPU(struct mce, mces_seen);
96static int cpu_missing; 96static int cpu_missing;
97 97
98/*
99 * CPU/chipset specific EDAC code can register a notifier call here to print
100 * MCE errors in a human-readable form.
101 */
102ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain);
103EXPORT_SYMBOL_GPL(x86_mce_decoder_chain);
104
105/* MCA banks polled by the period polling timer for corrected events */ 98/* MCA banks polled by the period polling timer for corrected events */
106DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { 99DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
107 [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL 100 [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
@@ -109,6 +102,12 @@ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
109 102
110static DEFINE_PER_CPU(struct work_struct, mce_work); 103static DEFINE_PER_CPU(struct work_struct, mce_work);
111 104
105/*
106 * CPU/chipset specific EDAC code can register a notifier call here to print
107 * MCE errors in a human-readable form.
108 */
109ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain);
110
112/* Do initial initialization of a struct mce */ 111/* Do initial initialization of a struct mce */
113void mce_setup(struct mce *m) 112void mce_setup(struct mce *m)
114{ 113{
@@ -190,6 +189,57 @@ void mce_log(struct mce *mce)
190 set_bit(0, &mce_need_notify); 189 set_bit(0, &mce_need_notify);
191} 190}
192 191
192static void drain_mcelog_buffer(void)
193{
194 unsigned int next, i, prev = 0;
195
196 next = rcu_dereference_check_mce(mcelog.next);
197
198 do {
199 struct mce *m;
200
201 /* drain what was logged during boot */
202 for (i = prev; i < next; i++) {
203 unsigned long start = jiffies;
204 unsigned retries = 1;
205
206 m = &mcelog.entry[i];
207
208 while (!m->finished) {
209 if (time_after_eq(jiffies, start + 2*retries))
210 retries++;
211
212 cpu_relax();
213
214 if (!m->finished && retries >= 4) {
215 pr_err("MCE: skipping error being logged currently!\n");
216 break;
217 }
218 }
219 smp_rmb();
220 atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
221 }
222
223 memset(mcelog.entry + prev, 0, (next - prev) * sizeof(*m));
224 prev = next;
225 next = cmpxchg(&mcelog.next, prev, 0);
226 } while (next != prev);
227}
228
229
230void mce_register_decode_chain(struct notifier_block *nb)
231{
232 atomic_notifier_chain_register(&x86_mce_decoder_chain, nb);
233 drain_mcelog_buffer();
234}
235EXPORT_SYMBOL_GPL(mce_register_decode_chain);
236
237void mce_unregister_decode_chain(struct notifier_block *nb)
238{
239 atomic_notifier_chain_unregister(&x86_mce_decoder_chain, nb);
240}
241EXPORT_SYMBOL_GPL(mce_unregister_decode_chain);
242
193static void print_mce(struct mce *m) 243static void print_mce(struct mce *m)
194{ 244{
195 int ret = 0; 245 int ret = 0;
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 70ad8923f1d7..8568d9b61875 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -2234,7 +2234,7 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
2234 if (pvt->enable_scrub) 2234 if (pvt->enable_scrub)
2235 disable_sdram_scrub_setting(mci); 2235 disable_sdram_scrub_setting(mci);
2236 2236
2237 atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &i7_mce_dec); 2237 mce_unregister_decode_chain(&i7_mce_dec);
2238 2238
2239 /* Disable EDAC polling */ 2239 /* Disable EDAC polling */
2240 i7core_pci_ctl_release(pvt); 2240 i7core_pci_ctl_release(pvt);
@@ -2336,7 +2336,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
2336 /* DCLK for scrub rate setting */ 2336 /* DCLK for scrub rate setting */
2337 pvt->dclk_freq = get_dclk_freq(); 2337 pvt->dclk_freq = get_dclk_freq();
2338 2338
2339 atomic_notifier_chain_register(&x86_mce_decoder_chain, &i7_mce_dec); 2339 mce_register_decode_chain(&i7_mce_dec);
2340 2340
2341 return 0; 2341 return 0;
2342 2342
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index d0864d9c38ad..bd926ea2e00c 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -884,7 +884,7 @@ static int __init mce_amd_init(void)
884 884
885 pr_info("MCE: In-kernel MCE decoding enabled.\n"); 885 pr_info("MCE: In-kernel MCE decoding enabled.\n");
886 886
887 atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb); 887 mce_register_decode_chain(&amd_mce_dec_nb);
888 888
889 return 0; 889 return 0;
890} 890}
@@ -893,7 +893,7 @@ early_initcall(mce_amd_init);
893#ifdef MODULE 893#ifdef MODULE
894static void __exit mce_amd_exit(void) 894static void __exit mce_amd_exit(void)
895{ 895{
896 atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb); 896 mce_unregister_decode_chain(&amd_mce_dec_nb);
897 kfree(fam_ops); 897 kfree(fam_ops);
898} 898}
899 899
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 7a402bfbee7d..965bc0cc0cf6 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -1661,8 +1661,7 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
1661 debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", 1661 debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
1662 __func__, mci, &sbridge_dev->pdev[0]->dev); 1662 __func__, mci, &sbridge_dev->pdev[0]->dev);
1663 1663
1664 atomic_notifier_chain_unregister(&x86_mce_decoder_chain, 1664 mce_unregister_decode_chain(&sbridge_mce_dec);
1665 &sbridge_mce_dec);
1666 1665
1667 /* Remove MC sysfs nodes */ 1666 /* Remove MC sysfs nodes */
1668 edac_mc_del_mc(mci->dev); 1667 edac_mc_del_mc(mci->dev);
@@ -1731,8 +1730,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
1731 goto fail0; 1730 goto fail0;
1732 } 1731 }
1733 1732
1734 atomic_notifier_chain_register(&x86_mce_decoder_chain, 1733 mce_register_decode_chain(&sbridge_mce_dec);
1735 &sbridge_mce_dec);
1736 return 0; 1734 return 0;
1737 1735
1738fail0: 1736fail0: