aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
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 /arch/x86/kernel
parent29e9bf1841e4f9df13b4992a716fece7087dd237 (diff)
parent0937195715713b37ec843f28d99930dd7b1e8fbe (diff)
Merge branch 'early-mce-decode' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp into x86/mce
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c64
1 files changed, 57 insertions, 7 deletions
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;