diff options
author | Borislav Petkov <borislav.petkov@amd.com> | 2011-12-08 06:28:33 -0500 |
---|---|---|
committer | Borislav Petkov <bp@amd64.org> | 2011-12-14 06:50:13 -0500 |
commit | 0937195715713b37ec843f28d99930dd7b1e8fbe (patch) | |
tree | 11a96986c1768fd117f95267371db27895d487d2 | |
parent | 3653ada5d3e173489b3a466305687cb5c44b2ab1 (diff) |
x86, MCE: Drain mcelog buffer
Add a function which drains whatever MCEs were logged in already during
boot and before the decoder chains were registered.
Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index c3c66ac6ef74..5be2464cce6a 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -189,9 +189,48 @@ void mce_log(struct mce *mce) | |||
189 | set_bit(0, &mce_need_notify); | 189 | set_bit(0, &mce_need_notify); |
190 | } | 190 | } |
191 | 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 | |||
192 | void mce_register_decode_chain(struct notifier_block *nb) | 230 | void mce_register_decode_chain(struct notifier_block *nb) |
193 | { | 231 | { |
194 | atomic_notifier_chain_register(&x86_mce_decoder_chain, nb); | 232 | atomic_notifier_chain_register(&x86_mce_decoder_chain, nb); |
233 | drain_mcelog_buffer(); | ||
195 | } | 234 | } |
196 | EXPORT_SYMBOL_GPL(mce_register_decode_chain); | 235 | EXPORT_SYMBOL_GPL(mce_register_decode_chain); |
197 | 236 | ||