diff options
| -rw-r--r-- | arch/x86/include/asm/mce.h | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 64 | ||||
| -rw-r--r-- | drivers/edac/i7core_edac.c | 4 | ||||
| -rw-r--r-- | drivers/edac/mce_amd.c | 4 | ||||
| -rw-r--r-- | drivers/edac/sb_edac.c | 6 |
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 | ||
| 123 | extern struct atomic_notifier_head x86_mce_decoder_chain; | 123 | extern void mce_register_decode_chain(struct notifier_block *nb); |
| 124 | extern 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); | |||
| 95 | static DEFINE_PER_CPU(struct mce, mces_seen); | 95 | static DEFINE_PER_CPU(struct mce, mces_seen); |
| 96 | static int cpu_missing; | 96 | static 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 | */ | ||
| 102 | ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); | ||
| 103 | EXPORT_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 */ |
| 106 | DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { | 99 | DEFINE_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 | ||
| 110 | static DEFINE_PER_CPU(struct work_struct, mce_work); | 103 | static 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 | */ | ||
| 109 | ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); | ||
| 110 | |||
| 112 | /* Do initial initialization of a struct mce */ | 111 | /* Do initial initialization of a struct mce */ |
| 113 | void mce_setup(struct mce *m) | 112 | void 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 | ||
| 192 | static 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 | |||
| 230 | void mce_register_decode_chain(struct notifier_block *nb) | ||
| 231 | { | ||
| 232 | atomic_notifier_chain_register(&x86_mce_decoder_chain, nb); | ||
| 233 | drain_mcelog_buffer(); | ||
| 234 | } | ||
| 235 | EXPORT_SYMBOL_GPL(mce_register_decode_chain); | ||
| 236 | |||
| 237 | void mce_unregister_decode_chain(struct notifier_block *nb) | ||
| 238 | { | ||
| 239 | atomic_notifier_chain_unregister(&x86_mce_decoder_chain, nb); | ||
| 240 | } | ||
| 241 | EXPORT_SYMBOL_GPL(mce_unregister_decode_chain); | ||
| 242 | |||
| 193 | static void print_mce(struct mce *m) | 243 | static 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 |
| 894 | static void __exit mce_amd_exit(void) | 894 | static 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 | ||
| 1738 | fail0: | 1736 | fail0: |
