Blame view
arch/x86/kernel/cpu/mcheck/mce.c
51.5 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 |
/* * Machine check handler. |
e9eee03e9 x86, mce: clean u... |
3 |
* |
1da177e4c Linux-2.6.12-rc2 |
4 |
* K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs. |
d88203d1a x86: whitespace c... |
5 6 |
* Rest from unknown author(s). * 2004 Andi Kleen. Rewrote most of it. |
b79109c3b x86, mce: separat... |
7 8 |
* Copyright 2008 Intel Corporation * Author: Andi Kleen |
1da177e4c Linux-2.6.12-rc2 |
9 |
*/ |
e9eee03e9 x86, mce: clean u... |
10 11 12 13 14 15 |
#include <linux/thread_info.h> #include <linux/capability.h> #include <linux/miscdevice.h> #include <linux/ratelimit.h> #include <linux/kallsyms.h> #include <linux/rcupdate.h> |
e9eee03e9 x86, mce: clean u... |
16 |
#include <linux/kobject.h> |
14a02530e x86, mce: trivial... |
17 |
#include <linux/uaccess.h> |
e9eee03e9 x86, mce: clean u... |
18 19 20 |
#include <linux/kdebug.h> #include <linux/kernel.h> #include <linux/percpu.h> |
1da177e4c Linux-2.6.12-rc2 |
21 |
#include <linux/string.h> |
8a25a2fd1 cpu: convert 'cpu... |
22 |
#include <linux/device.h> |
f3c6ea1b0 x86: Use syscore_... |
23 |
#include <linux/syscore_ops.h> |
3c0797925 x86, mce: switch ... |
24 |
#include <linux/delay.h> |
8c566ef5f [PATCH] x86-64: A... |
25 |
#include <linux/ctype.h> |
e9eee03e9 x86, mce: clean u... |
26 |
#include <linux/sched.h> |
0d7482e3d x86, mce: impleme... |
27 |
#include <linux/sysfs.h> |
e9eee03e9 x86, mce: clean u... |
28 |
#include <linux/types.h> |
5a0e3ad6a include cleanup: ... |
29 |
#include <linux/slab.h> |
e9eee03e9 x86, mce: clean u... |
30 31 32 |
#include <linux/init.h> #include <linux/kmod.h> #include <linux/poll.h> |
3c0797925 x86, mce: switch ... |
33 |
#include <linux/nmi.h> |
e9eee03e9 x86, mce: clean u... |
34 |
#include <linux/cpu.h> |
14a02530e x86, mce: trivial... |
35 |
#include <linux/smp.h> |
e9eee03e9 x86, mce: clean u... |
36 |
#include <linux/fs.h> |
9b1beaf2b x86, mce: support... |
37 |
#include <linux/mm.h> |
5be9ed251 x86, mce: Move de... |
38 |
#include <linux/debugfs.h> |
b77e70bf3 x86, mce: Replace... |
39 |
#include <linux/irq_work.h> |
69c60c88e x86: Fix files ex... |
40 |
#include <linux/export.h> |
e9eee03e9 x86, mce: clean u... |
41 |
|
d88203d1a x86: whitespace c... |
42 |
#include <asm/processor.h> |
e9eee03e9 x86, mce: clean u... |
43 44 |
#include <asm/mce.h> #include <asm/msr.h> |
1da177e4c Linux-2.6.12-rc2 |
45 |
|
bd19a5e6b x86, mce: check e... |
46 |
#include "mce-internal.h" |
711c2e481 x86, mce: unify, ... |
47 |
|
93b62c3cf x86, mce: Use mce... |
48 |
static DEFINE_MUTEX(mce_chrdev_read_mutex); |
2aa2b50dd x86/mce: Fix buil... |
49 |
|
f56e8a076 x86/mce: Fix RCU ... |
50 |
#define rcu_dereference_check_mce(p) \ |
ec8c27e04 mce: convert to r... |
51 |
rcu_dereference_index_check((p), \ |
f56e8a076 x86/mce: Fix RCU ... |
52 |
rcu_read_lock_sched_held() || \ |
93b62c3cf x86, mce: Use mce... |
53 |
lockdep_is_held(&mce_chrdev_read_mutex)) |
f56e8a076 x86/mce: Fix RCU ... |
54 |
|
8968f9d3d perf_event, x86, ... |
55 56 |
#define CREATE_TRACE_POINTS #include <trace/events/mce.h> |
4e5b3e690 x86, mce: add __r... |
57 |
int mce_disabled __read_mostly; |
04b2b1a4d x86, mce: rename ... |
58 |
|
e9eee03e9 x86, mce: clean u... |
59 |
#define MISC_MCELOG_MINOR 227 |
0d7482e3d x86, mce: impleme... |
60 |
|
3c0797925 x86, mce: switch ... |
61 |
#define SPINUNIT 100 /* 100ns */ |
553f265fe [PATCH] x86_64: D... |
62 |
atomic_t mce_entry; |
01ca79f14 x86, mce: add mac... |
63 |
DEFINE_PER_CPU(unsigned, mce_exception_count); |
bd78432c8 x86_64: mcelog to... |
64 65 66 67 68 69 70 |
/* * Tolerant levels: * 0: always panic on uncorrected errors, log corrected errors * 1: panic or SIGBUS on uncorrected errors, log corrected errors * 2: SIGBUS or log uncorrected errors (if possible), log corrected errors * 3: never panic or SIGBUS, log all errors (for testing only) */ |
4e5b3e690 x86, mce: add __r... |
71 72 |
static int tolerant __read_mostly = 1; static int banks __read_mostly; |
4e5b3e690 x86, mce: add __r... |
73 74 75 76 77 78 79 80 |
static int rip_msr __read_mostly; static int mce_bootlog __read_mostly = -1; static int monarch_timeout __read_mostly = -1; static int mce_panic_timeout __read_mostly; static int mce_dont_log_ce __read_mostly; int mce_cmci_disabled __read_mostly; int mce_ignore_ce __read_mostly; int mce_ser __read_mostly; |
a98f0dd34 [PATCH] x86-64: A... |
81 |
|
cebe18203 x86: mce: Move pe... |
82 |
struct mce_bank *mce_banks __read_mostly; |
1020bcbcc x86, mce: rename ... |
83 84 85 86 |
/* User mode helper program triggered by machine check event */ static unsigned long mce_need_notify; static char mce_helper[128]; static char *mce_helper_argv[2] = { mce_helper, NULL }; |
1da177e4c Linux-2.6.12-rc2 |
87 |
|
93b62c3cf x86, mce: Use mce... |
88 |
static DECLARE_WAIT_QUEUE_HEAD(mce_chrdev_wait); |
3c0797925 x86, mce: switch ... |
89 90 |
static DEFINE_PER_CPU(struct mce, mces_seen); static int cpu_missing; |
ee031c31d x86, mce, cmci: u... |
91 92 93 94 |
/* MCA banks polled by the period polling timer for corrected events */ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL }; |
9b1beaf2b x86, mce: support... |
95 |
static DEFINE_PER_CPU(struct work_struct, mce_work); |
3653ada5d x86, mce: Add wra... |
96 97 98 99 100 |
/* * CPU/chipset specific EDAC code can register a notifier call here to print * MCE errors in a human-readable form. */ ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); |
b5f2fa4ea x86, mce: factor ... |
101 102 103 104 |
/* Do initial initialization of a struct mce */ void mce_setup(struct mce *m) { memset(m, 0, sizeof(struct mce)); |
d620c67fb x86, mce: support... |
105 |
m->cpu = m->extcpu = smp_processor_id(); |
b5f2fa4ea x86, mce: factor ... |
106 |
rdtscll(m->tsc); |
8ee08347c x86, mce: extend ... |
107 108 109 110 |
/* We hope get_seconds stays lockless */ m->time = get_seconds(); m->cpuvendor = boot_cpu_data.x86_vendor; m->cpuid = cpuid_eax(1); |
8ee08347c x86, mce: extend ... |
111 |
m->socketid = cpu_data(m->extcpu).phys_proc_id; |
8ee08347c x86, mce: extend ... |
112 113 |
m->apicid = cpu_data(m->extcpu).initial_apicid; rdmsrl(MSR_IA32_MCG_CAP, m->mcgcap); |
b5f2fa4ea x86, mce: factor ... |
114 |
} |
ea149b36c x86, mce: add bas... |
115 116 |
DEFINE_PER_CPU(struct mce, injectm); EXPORT_PER_CPU_SYMBOL_GPL(injectm); |
1da177e4c Linux-2.6.12-rc2 |
117 118 119 120 121 |
/* * Lockless MCE logging infrastructure. * This avoids deadlocks on printk locks without having to break locks. Also * separate MCEs from kernel messages to avoid bogus bug reports. */ |
231fd906c x86 mce_64.c: mak... |
122 |
static struct mce_log mcelog = { |
f6fb0ac08 x86, mce: store r... |
123 124 125 |
.signature = MCE_LOG_SIGNATURE, .len = MCE_LOG_LEN, .recordlen = sizeof(struct mce), |
d88203d1a x86: whitespace c... |
126 |
}; |
1da177e4c Linux-2.6.12-rc2 |
127 128 129 130 |
void mce_log(struct mce *mce) { unsigned next, entry; |
f0cb54524 x86, MCE: Use not... |
131 |
int ret = 0; |
e9eee03e9 x86, mce: clean u... |
132 |
|
8968f9d3d perf_event, x86, ... |
133 134 |
/* Emit the trace record: */ trace_mce_record(mce); |
f0cb54524 x86, MCE: Use not... |
135 136 137 |
ret = atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, mce); if (ret == NOTIFY_STOP) return; |
1da177e4c Linux-2.6.12-rc2 |
138 |
mce->finished = 0; |
7644143cd [PATCH] x86_64: F... |
139 |
wmb(); |
1da177e4c Linux-2.6.12-rc2 |
140 |
for (;;) { |
f56e8a076 x86/mce: Fix RCU ... |
141 |
entry = rcu_dereference_check_mce(mcelog.next); |
673242c10 [PATCH] x86-64: M... |
142 |
for (;;) { |
696e409db edac_mce: Add an ... |
143 144 |
/* |
e9eee03e9 x86, mce: clean u... |
145 146 147 148 |
* When the buffer fills up discard new entries. * Assume that the earlier errors are the more * interesting ones: */ |
673242c10 [PATCH] x86-64: M... |
149 |
if (entry >= MCE_LOG_LEN) { |
14a02530e x86, mce: trivial... |
150 151 |
set_bit(MCE_OVERFLOW, (unsigned long *)&mcelog.flags); |
673242c10 [PATCH] x86-64: M... |
152 153 |
return; } |
e9eee03e9 x86, mce: clean u... |
154 |
/* Old left over entry. Skip: */ |
673242c10 [PATCH] x86-64: M... |
155 156 157 158 |
if (mcelog.entry[entry].finished) { entry++; continue; } |
7644143cd [PATCH] x86_64: F... |
159 |
break; |
1da177e4c Linux-2.6.12-rc2 |
160 |
} |
1da177e4c Linux-2.6.12-rc2 |
161 162 163 164 165 166 |
smp_rmb(); next = entry + 1; if (cmpxchg(&mcelog.next, entry, next) == entry) break; } memcpy(mcelog.entry + entry, mce, sizeof(struct mce)); |
7644143cd [PATCH] x86_64: F... |
167 |
wmb(); |
1da177e4c Linux-2.6.12-rc2 |
168 |
mcelog.entry[entry].finished = 1; |
7644143cd [PATCH] x86_64: F... |
169 |
wmb(); |
1da177e4c Linux-2.6.12-rc2 |
170 |
|
a0189c70e x86, mce: remove ... |
171 |
mce->finished = 1; |
1020bcbcc x86, mce: rename ... |
172 |
set_bit(0, &mce_need_notify); |
1da177e4c Linux-2.6.12-rc2 |
173 |
} |
093719571 x86, MCE: Drain m... |
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
static void drain_mcelog_buffer(void) { unsigned int next, i, prev = 0; next = rcu_dereference_check_mce(mcelog.next); do { struct mce *m; /* drain what was logged during boot */ for (i = prev; i < next; i++) { unsigned long start = jiffies; unsigned retries = 1; m = &mcelog.entry[i]; while (!m->finished) { if (time_after_eq(jiffies, start + 2*retries)) retries++; cpu_relax(); if (!m->finished && retries >= 4) { pr_err("MCE: skipping error being logged currently! "); break; } } smp_rmb(); atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m); } memset(mcelog.entry + prev, 0, (next - prev) * sizeof(*m)); prev = next; next = cmpxchg(&mcelog.next, prev, 0); } while (next != prev); } |
3653ada5d x86, mce: Add wra... |
211 212 213 |
void mce_register_decode_chain(struct notifier_block *nb) { atomic_notifier_chain_register(&x86_mce_decoder_chain, nb); |
093719571 x86, MCE: Drain m... |
214 |
drain_mcelog_buffer(); |
3653ada5d x86, mce: Add wra... |
215 216 217 218 219 220 221 222 |
} EXPORT_SYMBOL_GPL(mce_register_decode_chain); void mce_unregister_decode_chain(struct notifier_block *nb) { atomic_notifier_chain_unregister(&x86_mce_decoder_chain, nb); } EXPORT_SYMBOL_GPL(mce_unregister_decode_chain); |
77e26cca2 x86, mce: Fix mce... |
223 |
static void print_mce(struct mce *m) |
1da177e4c Linux-2.6.12-rc2 |
224 |
{ |
dffa4b2f6 x86, mce: Drop th... |
225 |
int ret = 0; |
a2d7b0d48 x86, mce: Use HW_... |
226 227 |
pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx ", |
d620c67fb x86, mce: support... |
228 |
m->extcpu, m->mcgstatus, m->bank, m->status); |
f436f8bb7 x86: EDAC: MCE: F... |
229 |
|
65ea5b034 x86: rename the s... |
230 |
if (m->ip) { |
a2d7b0d48 x86, mce: Use HW_... |
231 |
pr_emerg(HW_ERR "RIP%s %02x:<%016Lx> ", |
f436f8bb7 x86: EDAC: MCE: F... |
232 233 |
!(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "", m->cs, m->ip); |
1da177e4c Linux-2.6.12-rc2 |
234 |
if (m->cs == __KERNEL_CS) |
65ea5b034 x86: rename the s... |
235 |
print_symbol("{%s}", m->ip); |
f436f8bb7 x86: EDAC: MCE: F... |
236 237 |
pr_cont(" "); |
1da177e4c Linux-2.6.12-rc2 |
238 |
} |
f436f8bb7 x86: EDAC: MCE: F... |
239 |
|
a2d7b0d48 x86, mce: Use HW_... |
240 |
pr_emerg(HW_ERR "TSC %llx ", m->tsc); |
1da177e4c Linux-2.6.12-rc2 |
241 |
if (m->addr) |
f436f8bb7 x86: EDAC: MCE: F... |
242 |
pr_cont("ADDR %llx ", m->addr); |
1da177e4c Linux-2.6.12-rc2 |
243 |
if (m->misc) |
f436f8bb7 x86: EDAC: MCE: F... |
244 |
pr_cont("MISC %llx ", m->misc); |
549d042df x86, mce: pass mc... |
245 |
|
f436f8bb7 x86: EDAC: MCE: F... |
246 247 |
pr_cont(" "); |
506ed6b53 x86, intel: Outpu... |
248 249 250 251 |
/* * Note this output is parsed by external tools and old fields * should not be changed. */ |
881e23e56 x86, microcode: C... |
252 253 |
pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x ", |
506ed6b53 x86, intel: Outpu... |
254 255 |
m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid, cpu_data(m->extcpu).microcode); |
f436f8bb7 x86: EDAC: MCE: F... |
256 257 258 |
/* * Print out human-readable details about the MCE error, |
fb2531953 mce, edac: Use an... |
259 |
* (if the CPU has an implementation for that) |
f436f8bb7 x86: EDAC: MCE: F... |
260 |
*/ |
dffa4b2f6 x86, mce: Drop th... |
261 262 263 264 265 266 |
ret = atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m); if (ret == NOTIFY_STOP) return; pr_emerg_ratelimited(HW_ERR "Run the above through 'mcelog --ascii' "); |
86503560e x86, mce: print h... |
267 |
} |
f94b61c2c x86, mce: impleme... |
268 269 270 |
#define PANIC_TIMEOUT 5 /* 5 seconds */ static atomic_t mce_paniced; |
bf783f9f7 x86, mce: Fake pa... |
271 272 |
static int fake_panic; static atomic_t mce_fake_paniced; |
f94b61c2c x86, mce: impleme... |
273 274 275 276 |
/* Panic in progress. Enable interrupts and wait for final IPI */ static void wait_for_panic(void) { long timeout = PANIC_TIMEOUT*USEC_PER_SEC; |
f436f8bb7 x86: EDAC: MCE: F... |
277 |
|
f94b61c2c x86, mce: impleme... |
278 279 280 281 |
preempt_disable(); local_irq_enable(); while (timeout-- > 0) udelay(1); |
29b0f591d x86, mce: default... |
282 283 |
if (panic_timeout == 0) panic_timeout = mce_panic_timeout; |
f94b61c2c x86, mce: impleme... |
284 285 |
panic("Panicing machine check CPU died"); } |
bd19a5e6b x86, mce: check e... |
286 |
static void mce_panic(char *msg, struct mce *final, char *exp) |
d88203d1a x86: whitespace c... |
287 |
{ |
482908b49 ACPI, APEI, Use E... |
288 |
int i, apei_err = 0; |
e02e68d31 x86_64: support p... |
289 |
|
bf783f9f7 x86, mce: Fake pa... |
290 291 292 293 294 295 296 |
if (!fake_panic) { /* * Make sure only one CPU runs in machine check panic */ if (atomic_inc_return(&mce_paniced) > 1) wait_for_panic(); barrier(); |
f94b61c2c x86, mce: impleme... |
297 |
|
bf783f9f7 x86, mce: Fake pa... |
298 299 300 301 302 303 304 |
bust_spinlocks(1); console_verbose(); } else { /* Don't log too much for fake panic */ if (atomic_inc_return(&mce_fake_paniced) > 1) return; } |
a0189c70e x86, mce: remove ... |
305 |
/* First print corrected ones that are still unlogged */ |
1da177e4c Linux-2.6.12-rc2 |
306 |
for (i = 0; i < MCE_LOG_LEN; i++) { |
a0189c70e x86, mce: remove ... |
307 |
struct mce *m = &mcelog.entry[i]; |
77e26cca2 x86, mce: Fix mce... |
308 309 |
if (!(m->status & MCI_STATUS_VAL)) continue; |
482908b49 ACPI, APEI, Use E... |
310 |
if (!(m->status & MCI_STATUS_UC)) { |
77e26cca2 x86, mce: Fix mce... |
311 |
print_mce(m); |
482908b49 ACPI, APEI, Use E... |
312 313 314 |
if (!apei_err) apei_err = apei_write_mce(m); } |
a0189c70e x86, mce: remove ... |
315 316 317 318 319 |
} /* Now print uncorrected but with the final one last */ for (i = 0; i < MCE_LOG_LEN; i++) { struct mce *m = &mcelog.entry[i]; if (!(m->status & MCI_STATUS_VAL)) |
1da177e4c Linux-2.6.12-rc2 |
320 |
continue; |
77e26cca2 x86, mce: Fix mce... |
321 322 |
if (!(m->status & MCI_STATUS_UC)) continue; |
482908b49 ACPI, APEI, Use E... |
323 |
if (!final || memcmp(m, final, sizeof(struct mce))) { |
77e26cca2 x86, mce: Fix mce... |
324 |
print_mce(m); |
482908b49 ACPI, APEI, Use E... |
325 326 327 |
if (!apei_err) apei_err = apei_write_mce(m); } |
1da177e4c Linux-2.6.12-rc2 |
328 |
} |
482908b49 ACPI, APEI, Use E... |
329 |
if (final) { |
77e26cca2 x86, mce: Fix mce... |
330 |
print_mce(final); |
482908b49 ACPI, APEI, Use E... |
331 332 333 |
if (!apei_err) apei_err = apei_write_mce(final); } |
3c0797925 x86, mce: switch ... |
334 |
if (cpu_missing) |
a2d7b0d48 x86, mce: Use HW_... |
335 336 |
pr_emerg(HW_ERR "Some CPUs didn't answer in synchronization "); |
bd19a5e6b x86, mce: check e... |
337 |
if (exp) |
a2d7b0d48 x86, mce: Use HW_... |
338 339 |
pr_emerg(HW_ERR "Machine check: %s ", exp); |
bf783f9f7 x86, mce: Fake pa... |
340 341 342 343 344 |
if (!fake_panic) { if (panic_timeout == 0) panic_timeout = mce_panic_timeout; panic(msg); } else |
a2d7b0d48 x86, mce: Use HW_... |
345 346 |
pr_emerg(HW_ERR "Fake kernel panic: %s ", msg); |
d88203d1a x86: whitespace c... |
347 |
} |
1da177e4c Linux-2.6.12-rc2 |
348 |
|
ea149b36c x86, mce: add bas... |
349 350 351 352 |
/* Support code for software error injection */ static int msr_to_offset(u32 msr) { |
0a3aee0da x86: Use this_cpu... |
353 |
unsigned bank = __this_cpu_read(injectm.bank); |
f436f8bb7 x86: EDAC: MCE: F... |
354 |
|
ea149b36c x86, mce: add bas... |
355 356 |
if (msr == rip_msr) return offsetof(struct mce, ip); |
a2d32bcbc x86: mce: macros ... |
357 |
if (msr == MSR_IA32_MCx_STATUS(bank)) |
ea149b36c x86, mce: add bas... |
358 |
return offsetof(struct mce, status); |
a2d32bcbc x86: mce: macros ... |
359 |
if (msr == MSR_IA32_MCx_ADDR(bank)) |
ea149b36c x86, mce: add bas... |
360 |
return offsetof(struct mce, addr); |
a2d32bcbc x86: mce: macros ... |
361 |
if (msr == MSR_IA32_MCx_MISC(bank)) |
ea149b36c x86, mce: add bas... |
362 363 364 365 366 |
return offsetof(struct mce, misc); if (msr == MSR_IA32_MCG_STATUS) return offsetof(struct mce, mcgstatus); return -1; } |
5f8c1a54c x86, mce: add MSR... |
367 368 369 370 |
/* MSR access wrappers used for error injection */ static u64 mce_rdmsrl(u32 msr) { u64 v; |
11868a2dc x86: mce: Use saf... |
371 |
|
0a3aee0da x86: Use this_cpu... |
372 |
if (__this_cpu_read(injectm.finished)) { |
ea149b36c x86, mce: add bas... |
373 |
int offset = msr_to_offset(msr); |
11868a2dc x86: mce: Use saf... |
374 |
|
ea149b36c x86, mce: add bas... |
375 376 377 378 |
if (offset < 0) return 0; return *(u64 *)((char *)&__get_cpu_var(injectm) + offset); } |
11868a2dc x86: mce: Use saf... |
379 380 381 382 383 384 385 386 387 388 389 |
if (rdmsrl_safe(msr, &v)) { WARN_ONCE(1, "mce: Unable to read msr %d! ", msr); /* * Return zero in case the access faulted. This should * not happen normally but can happen if the CPU does * something weird, or if the code is buggy. */ v = 0; } |
5f8c1a54c x86, mce: add MSR... |
390 391 392 393 394 |
return v; } static void mce_wrmsrl(u32 msr, u64 v) { |
0a3aee0da x86: Use this_cpu... |
395 |
if (__this_cpu_read(injectm.finished)) { |
ea149b36c x86, mce: add bas... |
396 |
int offset = msr_to_offset(msr); |
11868a2dc x86: mce: Use saf... |
397 |
|
ea149b36c x86, mce: add bas... |
398 399 400 401 |
if (offset >= 0) *(u64 *)((char *)&__get_cpu_var(injectm) + offset) = v; return; } |
5f8c1a54c x86, mce: add MSR... |
402 403 |
wrmsrl(msr, v); } |
9b1beaf2b x86, mce: support... |
404 |
/* |
b8325c5b1 x86, mce: Introdu... |
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
* Collect all global (w.r.t. this processor) status about this machine * check into our "mce" struct so that we can use it later to assess * the severity of the problem as we read per-bank specific details. */ static inline void mce_gather_info(struct mce *m, struct pt_regs *regs) { mce_setup(m); m->mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); if (regs) { /* * Get the address of the instruction at the time of * the machine check error. */ if (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) { m->ip = regs->ip; m->cs = regs->cs; } /* Use accurate RIP reporting if available. */ if (rip_msr) m->ip = mce_rdmsrl(rip_msr); } } /* |
9b1beaf2b x86, mce: support... |
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
* Simple lockless ring to communicate PFNs from the exception handler with the * process context work function. This is vastly simplified because there's * only a single reader and a single writer. */ #define MCE_RING_SIZE 16 /* we use one entry less */ struct mce_ring { unsigned short start; unsigned short end; unsigned long ring[MCE_RING_SIZE]; }; static DEFINE_PER_CPU(struct mce_ring, mce_ring); /* Runs with CPU affinity in workqueue */ static int mce_ring_empty(void) { struct mce_ring *r = &__get_cpu_var(mce_ring); return r->start == r->end; } static int mce_ring_get(unsigned long *pfn) { struct mce_ring *r; int ret = 0; *pfn = 0; get_cpu(); r = &__get_cpu_var(mce_ring); if (r->start == r->end) goto out; *pfn = r->ring[r->start]; r->start = (r->start + 1) % MCE_RING_SIZE; ret = 1; out: put_cpu(); return ret; } /* Always runs in MCE context with preempt off */ static int mce_ring_add(unsigned long pfn) { struct mce_ring *r = &__get_cpu_var(mce_ring); unsigned next; next = (r->end + 1) % MCE_RING_SIZE; if (next == r->start) return -1; r->ring[r->end] = pfn; wmb(); r->end = next; return 0; } |
88ccbedd9 x86, mce, cmci: a... |
483 |
int mce_available(struct cpuinfo_x86 *c) |
1da177e4c Linux-2.6.12-rc2 |
484 |
{ |
04b2b1a4d x86, mce: rename ... |
485 |
if (mce_disabled) |
5b4408fda x86, mce: don't s... |
486 |
return 0; |
3d1712c91 [PATCH] x86_64: {... |
487 |
return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA); |
1da177e4c Linux-2.6.12-rc2 |
488 |
} |
9b1beaf2b x86, mce: support... |
489 490 491 492 493 494 495 496 |
static void mce_schedule_work(void) { if (!mce_ring_empty()) { struct work_struct *work = &__get_cpu_var(mce_work); if (!work_pending(work)) schedule_work(work); } } |
b77e70bf3 x86, mce: Replace... |
497 498 499 |
DEFINE_PER_CPU(struct irq_work, mce_irq_work); static void mce_irq_work_cb(struct irq_work *entry) |
ccc3c3192 x86, mce: impleme... |
500 |
{ |
9ff36ee96 x86, mce: rename ... |
501 |
mce_notify_irq(); |
9b1beaf2b x86, mce: support... |
502 |
mce_schedule_work(); |
ccc3c3192 x86, mce: impleme... |
503 |
} |
ccc3c3192 x86, mce: impleme... |
504 505 506 507 |
static void mce_report_event(struct pt_regs *regs) { if (regs->flags & (X86_VM_MASK|X86_EFLAGS_IF)) { |
9ff36ee96 x86, mce: rename ... |
508 |
mce_notify_irq(); |
9b1beaf2b x86, mce: support... |
509 510 511 512 513 514 515 |
/* * Triggering the work queue here is just an insurance * policy in case the syscall exit notify handler * doesn't run soon enough or ends up running on the * wrong CPU (can happen when audit sleeps) */ mce_schedule_work(); |
ccc3c3192 x86, mce: impleme... |
516 517 |
return; } |
b77e70bf3 x86, mce: Replace... |
518 |
irq_work_queue(&__get_cpu_var(mce_irq_work)); |
ccc3c3192 x86, mce: impleme... |
519 |
} |
ca84f6969 x86, mce: add MCE... |
520 |
DEFINE_PER_CPU(unsigned, mce_poll_count); |
d88203d1a x86: whitespace c... |
521 |
/* |
b79109c3b x86, mce: separat... |
522 523 524 525 |
* Poll for corrected events or events that happened before reset. * Those are just logged through /dev/mcelog. * * This is executed in standard interrupt context. |
ed7290d0e x86, mce: impleme... |
526 527 528 529 530 531 532 533 534 |
* * Note: spec recommends to panic for fatal unsignalled * errors here. However this would be quite problematic -- * we would need to reimplement the Monarch handling and * it would mess up the exclusion between exception handler * and poll hander -- * so we skip this for now. * These cases should not happen anyways, or only when the CPU * is already totally * confused. In this case it's likely it will * not fully execute the machine check handler either. |
b79109c3b x86, mce: separat... |
535 |
*/ |
ee031c31d x86, mce, cmci: u... |
536 |
void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) |
b79109c3b x86, mce: separat... |
537 538 539 |
{ struct mce m; int i; |
402af0d7c x86, asm: Introdu... |
540 |
percpu_inc(mce_poll_count); |
ca84f6969 x86, mce: add MCE... |
541 |
|
b8325c5b1 x86, mce: Introdu... |
542 |
mce_gather_info(&m, NULL); |
b79109c3b x86, mce: separat... |
543 |
|
b79109c3b x86, mce: separat... |
544 |
for (i = 0; i < banks; i++) { |
cebe18203 x86: mce: Move pe... |
545 |
if (!mce_banks[i].ctl || !test_bit(i, *b)) |
b79109c3b x86, mce: separat... |
546 547 548 549 550 551 552 553 |
continue; m.misc = 0; m.addr = 0; m.bank = i; m.tsc = 0; barrier(); |
a2d32bcbc x86: mce: macros ... |
554 |
m.status = mce_rdmsrl(MSR_IA32_MCx_STATUS(i)); |
b79109c3b x86, mce: separat... |
555 556 557 558 |
if (!(m.status & MCI_STATUS_VAL)) continue; /* |
ed7290d0e x86, mce: impleme... |
559 560 |
* Uncorrected or signalled events are handled by the exception * handler when it is enabled, so don't process those here. |
b79109c3b x86, mce: separat... |
561 562 563 |
* * TBD do the same check for MCI_STATUS_EN here? */ |
ed7290d0e x86, mce: impleme... |
564 565 |
if (!(flags & MCP_UC) && (m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC))) |
b79109c3b x86, mce: separat... |
566 567 568 |
continue; if (m.status & MCI_STATUS_MISCV) |
a2d32bcbc x86: mce: macros ... |
569 |
m.misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i)); |
b79109c3b x86, mce: separat... |
570 |
if (m.status & MCI_STATUS_ADDRV) |
a2d32bcbc x86: mce: macros ... |
571 |
m.addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i)); |
b79109c3b x86, mce: separat... |
572 573 574 575 576 577 578 |
if (!(flags & MCP_TIMESTAMP)) m.tsc = 0; /* * Don't get the IP here because it's unlikely to * have anything to do with the actual error location. */ |
f0cb54524 x86, MCE: Use not... |
579 |
if (!(flags & MCP_DONTLOG) && !mce_dont_log_ce) |
5679af4c1 x86, mce: fix boo... |
580 |
mce_log(&m); |
b79109c3b x86, mce: separat... |
581 582 583 584 |
/* * Clear state for this bank. */ |
a2d32bcbc x86: mce: macros ... |
585 |
mce_wrmsrl(MSR_IA32_MCx_STATUS(i), 0); |
b79109c3b x86, mce: separat... |
586 587 588 589 590 591 |
} /* * Don't clear MCG_STATUS here because it's only defined for * exceptions. */ |
88921be30 x86, mce: synchro... |
592 593 |
sync_core(); |
b79109c3b x86, mce: separat... |
594 |
} |
ea149b36c x86, mce: add bas... |
595 |
EXPORT_SYMBOL_GPL(machine_check_poll); |
b79109c3b x86, mce: separat... |
596 597 |
/* |
bd19a5e6b x86, mce: check e... |
598 599 600 601 602 603 604 605 |
* Do a quick check if any of the events requires a panic. * This decides if we keep the events around or clear them. */ static int mce_no_way_out(struct mce *m, char **msg) { int i; for (i = 0; i < banks; i++) { |
a2d32bcbc x86: mce: macros ... |
606 |
m->status = mce_rdmsrl(MSR_IA32_MCx_STATUS(i)); |
bd19a5e6b x86, mce: check e... |
607 608 609 610 611 612 613 |
if (mce_severity(m, tolerant, msg) >= MCE_PANIC_SEVERITY) return 1; } return 0; } /* |
3c0797925 x86, mce: switch ... |
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 |
* Variable to establish order between CPUs while scanning. * Each CPU spins initially until executing is equal its number. */ static atomic_t mce_executing; /* * Defines order of CPUs on entry. First CPU becomes Monarch. */ static atomic_t mce_callin; /* * Check if a timeout waiting for other CPUs happened. */ static int mce_timed_out(u64 *t) { /* * The others already did panic for some reason. * Bail out like in a timeout. * rmb() to tell the compiler that system_state * might have been modified by someone else. */ rmb(); if (atomic_read(&mce_paniced)) wait_for_panic(); if (!monarch_timeout) goto out; if ((s64)*t < SPINUNIT) { /* CHECKME: Make panic default for 1 too? */ if (tolerant < 1) mce_panic("Timeout synchronizing machine check over CPUs", NULL, NULL); cpu_missing = 1; return 1; } *t -= SPINUNIT; out: touch_nmi_watchdog(); return 0; } /* * The Monarch's reign. The Monarch is the CPU who entered * the machine check handler first. It waits for the others to * raise the exception too and then grades them. When any * error is fatal panic. Only then let the others continue. * * The other CPUs entering the MCE handler will be controlled by the * Monarch. They are called Subjects. * * This way we prevent any potential data corruption in a unrecoverable case * and also makes sure always all CPU's errors are examined. * |
680b6cfd3 x86, mce: CE in l... |
666 |
* Also this detects the case of a machine check event coming from outer |
3c0797925 x86, mce: switch ... |
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 |
* space (not detected by any CPUs) In this case some external agent wants * us to shut down, so panic too. * * The other CPUs might still decide to panic if the handler happens * in a unrecoverable place, but in this case the system is in a semi-stable * state and won't corrupt anything by itself. It's ok to let the others * continue for a bit first. * * All the spin loops have timeouts; when a timeout happens a CPU * typically elects itself to be Monarch. */ static void mce_reign(void) { int cpu; struct mce *m = NULL; int global_worst = 0; char *msg = NULL; char *nmsg = NULL; /* * This CPU is the Monarch and the other CPUs have run * through their handlers. * Grade the severity of the errors of all the CPUs. */ for_each_possible_cpu(cpu) { int severity = mce_severity(&per_cpu(mces_seen, cpu), tolerant, &nmsg); if (severity > global_worst) { msg = nmsg; global_worst = severity; m = &per_cpu(mces_seen, cpu); } } /* * Cannot recover? Panic here then. * This dumps all the mces in the log buffer and stops the * other CPUs. */ if (m && global_worst >= MCE_PANIC_SEVERITY && tolerant < 3) |
ac9603754 x86, mce: make no... |
707 |
mce_panic("Fatal Machine check", m, msg); |
3c0797925 x86, mce: switch ... |
708 709 710 711 712 713 714 715 716 717 718 |
/* * For UC somewhere we let the CPU who detects it handle it. * Also must let continue the others, otherwise the handling * CPU could deadlock on a lock. */ /* * No machine check event found. Must be some external * source or one CPU is hung. Panic. */ |
680b6cfd3 x86, mce: CE in l... |
719 |
if (global_worst <= MCE_KEEP_SEVERITY && tolerant < 3) |
3c0797925 x86, mce: switch ... |
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 |
mce_panic("Machine check from unknown source", NULL, NULL); /* * Now clear all the mces_seen so that they don't reappear on * the next mce. */ for_each_possible_cpu(cpu) memset(&per_cpu(mces_seen, cpu), 0, sizeof(struct mce)); } static atomic_t global_nwo; /* * Start of Monarch synchronization. This waits until all CPUs have * entered the exception handler and then determines if any of them * saw a fatal event that requires panic. Then it executes them * in the entry order. * TBD double check parallel CPU hotunplug */ |
7fb06fc96 x86, mce: cleanup... |
739 |
static int mce_start(int *no_way_out) |
3c0797925 x86, mce: switch ... |
740 |
{ |
7fb06fc96 x86, mce: cleanup... |
741 |
int order; |
3c0797925 x86, mce: switch ... |
742 743 |
int cpus = num_online_cpus(); u64 timeout = (u64)monarch_timeout * NSEC_PER_USEC; |
7fb06fc96 x86, mce: cleanup... |
744 745 |
if (!timeout) return -1; |
3c0797925 x86, mce: switch ... |
746 |
|
7fb06fc96 x86, mce: cleanup... |
747 |
atomic_add(*no_way_out, &global_nwo); |
184e1fdfe x86, mce: fix a r... |
748 749 750 751 |
/* * global_nwo should be updated before mce_callin */ smp_wmb(); |
a95436e44 x86, mce: use ato... |
752 |
order = atomic_inc_return(&mce_callin); |
3c0797925 x86, mce: switch ... |
753 754 755 756 757 758 759 |
/* * Wait for everyone. */ while (atomic_read(&mce_callin) != cpus) { if (mce_timed_out(&timeout)) { atomic_set(&global_nwo, 0); |
7fb06fc96 x86, mce: cleanup... |
760 |
return -1; |
3c0797925 x86, mce: switch ... |
761 762 763 764 765 |
} ndelay(SPINUNIT); } /* |
184e1fdfe x86, mce: fix a r... |
766 767 768 |
* mce_callin should be read before global_nwo */ smp_rmb(); |
3c0797925 x86, mce: switch ... |
769 |
|
7fb06fc96 x86, mce: cleanup... |
770 771 772 773 |
if (order == 1) { /* * Monarch: Starts executing now, the others wait. */ |
3c0797925 x86, mce: switch ... |
774 |
atomic_set(&mce_executing, 1); |
7fb06fc96 x86, mce: cleanup... |
775 776 777 778 779 780 781 782 783 784 785 786 787 788 |
} else { /* * Subject: Now start the scanning loop one by one in * the original callin order. * This way when there are any shared banks it will be * only seen by one CPU before cleared, avoiding duplicates. */ while (atomic_read(&mce_executing) < order) { if (mce_timed_out(&timeout)) { atomic_set(&global_nwo, 0); return -1; } ndelay(SPINUNIT); } |
3c0797925 x86, mce: switch ... |
789 790 791 |
} /* |
7fb06fc96 x86, mce: cleanup... |
792 |
* Cache the global no_way_out state. |
3c0797925 x86, mce: switch ... |
793 |
*/ |
7fb06fc96 x86, mce: cleanup... |
794 795 796 |
*no_way_out = atomic_read(&global_nwo); return order; |
3c0797925 x86, mce: switch ... |
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 |
} /* * Synchronize between CPUs after main scanning loop. * This invokes the bulk of the Monarch processing. */ static int mce_end(int order) { int ret = -1; u64 timeout = (u64)monarch_timeout * NSEC_PER_USEC; if (!timeout) goto reset; if (order < 0) goto reset; /* * Allow others to run. */ atomic_inc(&mce_executing); if (order == 1) { /* CHECKME: Can this race with a parallel hotplug? */ int cpus = num_online_cpus(); /* * Monarch: Wait for everyone to go through their scanning * loops. */ while (atomic_read(&mce_executing) <= cpus) { if (mce_timed_out(&timeout)) goto reset; ndelay(SPINUNIT); } mce_reign(); barrier(); ret = 0; } else { /* * Subject: Wait for Monarch to finish. */ while (atomic_read(&mce_executing) != 0) { if (mce_timed_out(&timeout)) goto reset; ndelay(SPINUNIT); } /* * Don't reset anything. That's done by the Monarch. */ return 0; } /* * Reset all global state. */ reset: atomic_set(&global_nwo, 0); atomic_set(&mce_callin, 0); barrier(); /* * Let others run again. */ atomic_set(&mce_executing, 0); return ret; } |
9b1beaf2b x86, mce: support... |
865 866 867 868 |
/* * Check if the address reported by the CPU is in a format we can parse. * It would be possible to add code for most other cases, but all would * be somewhat complicated (e.g. segment offset would require an instruction |
0d2eb44f6 x86: Fix common m... |
869 |
* parser). So only support physical addresses up to page granuality for now. |
9b1beaf2b x86, mce: support... |
870 871 872 873 874 |
*/ static int mce_usable_address(struct mce *m) { if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV)) return 0; |
2b90e77ea x86, mce: Replace... |
875 |
if (MCI_MISC_ADDR_LSB(m->misc) > PAGE_SHIFT) |
9b1beaf2b x86, mce: support... |
876 |
return 0; |
2b90e77ea x86, mce: Replace... |
877 |
if (MCI_MISC_ADDR_MODE(m->misc) != MCI_MISC_ADDR_PHYS) |
9b1beaf2b x86, mce: support... |
878 879 880 |
return 0; return 1; } |
3c0797925 x86, mce: switch ... |
881 882 883 884 885 886 |
static void mce_clear_state(unsigned long *toclear) { int i; for (i = 0; i < banks; i++) { if (test_bit(i, toclear)) |
a2d32bcbc x86: mce: macros ... |
887 |
mce_wrmsrl(MSR_IA32_MCx_STATUS(i), 0); |
3c0797925 x86, mce: switch ... |
888 889 890 891 |
} } /* |
b79109c3b x86, mce: separat... |
892 893 894 895 896 897 |
* The actual machine check handler. This only handles real * exceptions when something got corrupted coming in through int 18. * * This is executed in NMI context not subject to normal locking rules. This * implies that most kernel services cannot be safely used. Don't even * think about putting a printk in there! |
3c0797925 x86, mce: switch ... |
898 899 900 901 |
* * On Intel systems this is entered on all CPUs in parallel through * MCE broadcast. However some CPUs might be broken beyond repair, * so be always careful when synchronizing with others. |
1da177e4c Linux-2.6.12-rc2 |
902 |
*/ |
e9eee03e9 x86, mce: clean u... |
903 |
void do_machine_check(struct pt_regs *regs, long error_code) |
1da177e4c Linux-2.6.12-rc2 |
904 |
{ |
3c0797925 x86, mce: switch ... |
905 |
struct mce m, *final; |
1da177e4c Linux-2.6.12-rc2 |
906 |
int i; |
3c0797925 x86, mce: switch ... |
907 908 909 910 911 912 |
int worst = 0; int severity; /* * Establish sequential order between the CPUs entering the machine * check handler. */ |
7fb06fc96 x86, mce: cleanup... |
913 |
int order; |
bd78432c8 x86_64: mcelog to... |
914 915 916 917 918 919 920 921 922 923 |
/* * If no_way_out gets set, there is no safe way to recover from this * MCE. If tolerant is cranked up, we'll try anyway. */ int no_way_out = 0; /* * If kill_it gets set, there might be a way to recover from this * error. */ int kill_it = 0; |
b79109c3b x86, mce: separat... |
924 |
DECLARE_BITMAP(toclear, MAX_NR_BANKS); |
bd19a5e6b x86, mce: check e... |
925 |
char *msg = "Unknown"; |
1da177e4c Linux-2.6.12-rc2 |
926 |
|
553f265fe [PATCH] x86_64: D... |
927 |
atomic_inc(&mce_entry); |
402af0d7c x86, asm: Introdu... |
928 |
percpu_inc(mce_exception_count); |
01ca79f14 x86, mce: add mac... |
929 |
|
b79109c3b x86, mce: separat... |
930 |
if (!banks) |
32561696c x86, mce: rename ... |
931 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
932 |
|
b8325c5b1 x86, mce: Introdu... |
933 |
mce_gather_info(&m, regs); |
b5f2fa4ea x86, mce: factor ... |
934 |
|
3c0797925 x86, mce: switch ... |
935 936 |
final = &__get_cpu_var(mces_seen); *final = m; |
680b6cfd3 x86, mce: CE in l... |
937 |
no_way_out = mce_no_way_out(&m, &msg); |
1da177e4c Linux-2.6.12-rc2 |
938 |
barrier(); |
3c0797925 x86, mce: switch ... |
939 |
/* |
ed7290d0e x86, mce: impleme... |
940 941 942 943 944 945 |
* When no restart IP must always kill or panic. */ if (!(m.mcgstatus & MCG_STATUS_RIPV)) kill_it = 1; /* |
3c0797925 x86, mce: switch ... |
946 947 948 949 |
* Go through all the banks in exclusion of the other CPUs. * This way we don't report duplicated events on shared banks * because the first one to see it will clear it. */ |
7fb06fc96 x86, mce: cleanup... |
950 |
order = mce_start(&no_way_out); |
1da177e4c Linux-2.6.12-rc2 |
951 |
for (i = 0; i < banks; i++) { |
b79109c3b x86, mce: separat... |
952 |
__clear_bit(i, toclear); |
cebe18203 x86: mce: Move pe... |
953 |
if (!mce_banks[i].ctl) |
1da177e4c Linux-2.6.12-rc2 |
954 |
continue; |
d88203d1a x86: whitespace c... |
955 956 |
m.misc = 0; |
1da177e4c Linux-2.6.12-rc2 |
957 958 |
m.addr = 0; m.bank = i; |
1da177e4c Linux-2.6.12-rc2 |
959 |
|
a2d32bcbc x86: mce: macros ... |
960 |
m.status = mce_rdmsrl(MSR_IA32_MCx_STATUS(i)); |
1da177e4c Linux-2.6.12-rc2 |
961 962 |
if ((m.status & MCI_STATUS_VAL) == 0) continue; |
b79109c3b x86, mce: separat... |
963 |
/* |
ed7290d0e x86, mce: impleme... |
964 965 |
* Non uncorrected or non signaled errors are handled by * machine_check_poll. Leave them alone, unless this panics. |
b79109c3b x86, mce: separat... |
966 |
*/ |
ed7290d0e x86, mce: impleme... |
967 968 |
if (!(m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC)) && !no_way_out) |
b79109c3b x86, mce: separat... |
969 970 971 972 973 974 |
continue; /* * Set taint even when machine check was not enabled. */ add_taint(TAINT_MACHINE_CHECK); |
ed7290d0e x86, mce: impleme... |
975 |
severity = mce_severity(&m, tolerant, NULL); |
b79109c3b x86, mce: separat... |
976 |
|
ed7290d0e x86, mce: impleme... |
977 978 979 980 981 982 983 984 |
/* * When machine check was for corrected handler don't touch, * unless we're panicing. */ if (severity == MCE_KEEP_SEVERITY && !no_way_out) continue; __set_bit(i, toclear); if (severity == MCE_NO_SEVERITY) { |
b79109c3b x86, mce: separat... |
985 986 987 988 989 |
/* * Machine check event was not enabled. Clear, but * ignore. */ continue; |
1da177e4c Linux-2.6.12-rc2 |
990 |
} |
ed7290d0e x86, mce: impleme... |
991 992 993 994 995 |
/* * Kill on action required. */ if (severity == MCE_AR_SEVERITY) kill_it = 1; |
1da177e4c Linux-2.6.12-rc2 |
996 |
if (m.status & MCI_STATUS_MISCV) |
a2d32bcbc x86: mce: macros ... |
997 |
m.misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i)); |
1da177e4c Linux-2.6.12-rc2 |
998 |
if (m.status & MCI_STATUS_ADDRV) |
a2d32bcbc x86: mce: macros ... |
999 |
m.addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i)); |
1da177e4c Linux-2.6.12-rc2 |
1000 |
|
9b1beaf2b x86, mce: support... |
1001 1002 1003 1004 1005 1006 1007 1008 1009 |
/* * Action optional error. Queue address for later processing. * When the ring overflows we just ignore the AO error. * RED-PEN add some logging mechanism when * usable_address or mce_add_ring fails. * RED-PEN don't ignore overflow for tolerant == 0 */ if (severity == MCE_AO_SEVERITY && mce_usable_address(&m)) mce_ring_add(m.addr >> PAGE_SHIFT); |
b79109c3b x86, mce: separat... |
1010 |
mce_log(&m); |
1da177e4c Linux-2.6.12-rc2 |
1011 |
|
3c0797925 x86, mce: switch ... |
1012 1013 1014 |
if (severity > worst) { *final = m; worst = severity; |
1da177e4c Linux-2.6.12-rc2 |
1015 |
} |
1da177e4c Linux-2.6.12-rc2 |
1016 |
} |
3c0797925 x86, mce: switch ... |
1017 1018 |
if (!no_way_out) mce_clear_state(toclear); |
e9eee03e9 x86, mce: clean u... |
1019 |
/* |
3c0797925 x86, mce: switch ... |
1020 1021 |
* Do most of the synchronization with other CPUs. * When there's any problem use only local no_way_out state. |
e9eee03e9 x86, mce: clean u... |
1022 |
*/ |
3c0797925 x86, mce: switch ... |
1023 1024 |
if (mce_end(order) < 0) no_way_out = worst >= MCE_PANIC_SEVERITY; |
bd78432c8 x86_64: mcelog to... |
1025 1026 1027 |
/* * If we have decided that we just CAN'T continue, and the user |
e9eee03e9 x86, mce: clean u... |
1028 |
* has not set tolerant to an insane level, give up and die. |
3c0797925 x86, mce: switch ... |
1029 1030 1031 |
* * This is mainly used in the case when the system doesn't * support MCE broadcasting or it has been disabled. |
bd78432c8 x86_64: mcelog to... |
1032 1033 |
*/ if (no_way_out && tolerant < 3) |
ac9603754 x86, mce: make no... |
1034 |
mce_panic("Fatal machine check on current CPU", final, msg); |
bd78432c8 x86_64: mcelog to... |
1035 1036 1037 1038 1039 1040 1041 |
/* * If the error seems to be unrecoverable, something should be * done. Try to kill as little as possible. If we can kill just * one task, do that. If the user has set the tolerance very * high, don't try to do anything at all. */ |
bd78432c8 x86_64: mcelog to... |
1042 |
|
ed7290d0e x86, mce: impleme... |
1043 1044 |
if (kill_it && tolerant < 3) force_sig(SIGBUS, current); |
1da177e4c Linux-2.6.12-rc2 |
1045 |
|
e02e68d31 x86_64: support p... |
1046 1047 |
/* notify userspace ASAP */ set_thread_flag(TIF_MCE_NOTIFY); |
3c0797925 x86, mce: switch ... |
1048 1049 |
if (worst > 0) mce_report_event(regs); |
5f8c1a54c x86, mce: add MSR... |
1050 |
mce_wrmsrl(MSR_IA32_MCG_STATUS, 0); |
32561696c x86, mce: rename ... |
1051 |
out: |
553f265fe [PATCH] x86_64: D... |
1052 |
atomic_dec(&mce_entry); |
88921be30 x86, mce: synchro... |
1053 |
sync_core(); |
1da177e4c Linux-2.6.12-rc2 |
1054 |
} |
ea149b36c x86, mce: add bas... |
1055 |
EXPORT_SYMBOL_GPL(do_machine_check); |
1da177e4c Linux-2.6.12-rc2 |
1056 |
|
9b1beaf2b x86, mce: support... |
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 |
/* dummy to break dependency. actual code is in mm/memory-failure.c */ void __attribute__((weak)) memory_failure(unsigned long pfn, int vector) { printk(KERN_ERR "Action optional memory failure at %lx ignored ", pfn); } /* * Called after mce notification in process context. This code * is allowed to sleep. Call the high level VM handler to process * any corrupted pages. * Assume that the work queue code only calls this one at a time * per CPU. * Note we don't disable preemption, so this code might run on the wrong * CPU. In this case the event is picked up by the scheduled work queue. * This is merely a fast path to expedite processing in some common * cases. */ void mce_notify_process(void) { unsigned long pfn; mce_notify_irq(); while (mce_ring_get(&pfn)) memory_failure(pfn, MCE_VECTOR); } static void mce_process_work(struct work_struct *dummy) { mce_notify_process(); } |
15d5f8398 [PATCH] x86: Refa... |
1087 1088 1089 |
#ifdef CONFIG_X86_MCE_INTEL /*** * mce_log_therm_throt_event - Logs the thermal throttling event to mcelog |
676b1855d spelling fixes: a... |
1090 |
* @cpu: The CPU on which the event occurred. |
15d5f8398 [PATCH] x86: Refa... |
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 |
* @status: Event status information * * This function should be called by the thermal interrupt after the * event has been processed and the decision was made to log the event * further. * * The status parameter will be saved to the 'status' field of 'struct mce' * and historically has been the register value of the * MSR_IA32_THERMAL_STATUS (Intel) msr. */ |
b5f2fa4ea x86, mce: factor ... |
1101 |
void mce_log_therm_throt_event(__u64 status) |
15d5f8398 [PATCH] x86: Refa... |
1102 1103 |
{ struct mce m; |
b5f2fa4ea x86, mce: factor ... |
1104 |
mce_setup(&m); |
15d5f8398 [PATCH] x86: Refa... |
1105 1106 |
m.bank = MCE_THERMAL_BANK; m.status = status; |
15d5f8398 [PATCH] x86: Refa... |
1107 1108 1109 |
mce_log(&m); } #endif /* CONFIG_X86_MCE_INTEL */ |
1da177e4c Linux-2.6.12-rc2 |
1110 |
/* |
8a336b0a4 [PATCH] x86-64: D... |
1111 1112 1113 |
* Periodic polling timer for "silent" machine check errors. If the * poller finds an MCE, poll 2x faster. When the poller finds no more * errors, poll 2x slower (up to check_interval seconds). |
1da177e4c Linux-2.6.12-rc2 |
1114 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
1115 |
static int check_interval = 5 * 60; /* 5 minutes */ |
e9eee03e9 x86, mce: clean u... |
1116 |
|
245b2e70e percpu: clean up ... |
1117 |
static DEFINE_PER_CPU(int, mce_next_interval); /* in jiffies */ |
52d168e28 x86, mce: switch ... |
1118 |
static DEFINE_PER_CPU(struct timer_list, mce_timer); |
1da177e4c Linux-2.6.12-rc2 |
1119 |
|
5e09954a9 x86, mce: Fix up ... |
1120 |
static void mce_start_timer(unsigned long data) |
1da177e4c Linux-2.6.12-rc2 |
1121 |
{ |
52d168e28 x86, mce: switch ... |
1122 |
struct timer_list *t = &per_cpu(mce_timer, data); |
6298c512b x86, mce: make po... |
1123 |
int *n; |
52d168e28 x86, mce: switch ... |
1124 1125 |
WARN_ON(smp_processor_id() != data); |
7b543a533 x86: Replace uses... |
1126 |
if (mce_available(__this_cpu_ptr(&cpu_info))) { |
ee031c31d x86, mce, cmci: u... |
1127 1128 |
machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_poll_banks)); |
e9eee03e9 x86, mce: clean u... |
1129 |
} |
1da177e4c Linux-2.6.12-rc2 |
1130 1131 |
/* |
e02e68d31 x86_64: support p... |
1132 1133 |
* Alert userspace if needed. If we logged an MCE, reduce the * polling interval, otherwise increase the polling interval. |
1da177e4c Linux-2.6.12-rc2 |
1134 |
*/ |
245b2e70e percpu: clean up ... |
1135 |
n = &__get_cpu_var(mce_next_interval); |
9ff36ee96 x86, mce: rename ... |
1136 |
if (mce_notify_irq()) |
6298c512b x86, mce: make po... |
1137 |
*n = max(*n/2, HZ/100); |
14a02530e x86, mce: trivial... |
1138 |
else |
6298c512b x86, mce: make po... |
1139 |
*n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ)); |
e02e68d31 x86_64: support p... |
1140 |
|
6298c512b x86, mce: make po... |
1141 |
t->expires = jiffies + *n; |
5be6066a7 x86, mce: percpu ... |
1142 |
add_timer_on(t, smp_processor_id()); |
e02e68d31 x86_64: support p... |
1143 |
} |
9aaef96f6 x86, mce: Do not ... |
1144 1145 1146 1147 1148 1149 1150 1151 |
/* Must not be called in IRQ context where del_timer_sync() can deadlock */ static void mce_timer_delete_all(void) { int cpu; for_each_online_cpu(cpu) del_timer_sync(&per_cpu(mce_timer, cpu)); } |
9bd984058 x86, mce: always ... |
1152 1153 |
static void mce_do_trigger(struct work_struct *work) { |
1020bcbcc x86, mce: rename ... |
1154 |
call_usermodehelper(mce_helper, mce_helper_argv, NULL, UMH_NO_WAIT); |
9bd984058 x86, mce: always ... |
1155 1156 1157 |
} static DECLARE_WORK(mce_trigger_work, mce_do_trigger); |
e02e68d31 x86_64: support p... |
1158 |
/* |
9bd984058 x86, mce: always ... |
1159 1160 1161 |
* Notify the user(s) about new machine check events. * Can be called from interrupt context, but not from machine check/NMI * context. |
e02e68d31 x86_64: support p... |
1162 |
*/ |
9ff36ee96 x86, mce: rename ... |
1163 |
int mce_notify_irq(void) |
e02e68d31 x86_64: support p... |
1164 |
{ |
8457c84d6 x86, mce: replace... |
1165 1166 |
/* Not more than two messages every minute */ static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); |
e02e68d31 x86_64: support p... |
1167 |
clear_thread_flag(TIF_MCE_NOTIFY); |
e9eee03e9 x86, mce: clean u... |
1168 |
|
1020bcbcc x86, mce: rename ... |
1169 |
if (test_and_clear_bit(0, &mce_need_notify)) { |
93b62c3cf x86, mce: Use mce... |
1170 1171 |
/* wake processes polling /dev/mcelog */ wake_up_interruptible(&mce_chrdev_wait); |
9bd984058 x86, mce: always ... |
1172 1173 1174 1175 1176 1177 |
/* * There is no risk of missing notifications because * work_pending is always cleared before the function is * executed. */ |
1020bcbcc x86, mce: rename ... |
1178 |
if (mce_helper[0] && !work_pending(&mce_trigger_work)) |
9bd984058 x86, mce: always ... |
1179 |
schedule_work(&mce_trigger_work); |
e02e68d31 x86_64: support p... |
1180 |
|
8457c84d6 x86, mce: replace... |
1181 |
if (__ratelimit(&ratelimit)) |
a2d7b0d48 x86, mce: Use HW_... |
1182 1183 |
pr_info(HW_ERR "Machine check events logged "); |
e02e68d31 x86_64: support p... |
1184 1185 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
1186 |
} |
e02e68d31 x86_64: support p... |
1187 1188 |
return 0; } |
9ff36ee96 x86, mce: rename ... |
1189 |
EXPORT_SYMBOL_GPL(mce_notify_irq); |
8a336b0a4 [PATCH] x86-64: D... |
1190 |
|
cffd377e5 x86, mce: Fix __i... |
1191 |
static int __cpuinit __mcheck_cpu_mce_banks_init(void) |
cebe18203 x86: mce: Move pe... |
1192 1193 1194 1195 1196 1197 1198 1199 |
{ int i; mce_banks = kzalloc(banks * sizeof(struct mce_bank), GFP_KERNEL); if (!mce_banks) return -ENOMEM; for (i = 0; i < banks; i++) { struct mce_bank *b = &mce_banks[i]; |
11868a2dc x86: mce: Use saf... |
1200 |
|
cebe18203 x86: mce: Move pe... |
1201 1202 1203 1204 1205 |
b->ctl = -1ULL; b->init = 1; } return 0; } |
d88203d1a x86: whitespace c... |
1206 |
/* |
1da177e4c Linux-2.6.12-rc2 |
1207 1208 |
* Initialize Machine Checks for a CPU. */ |
5e09954a9 x86, mce: Fix up ... |
1209 |
static int __cpuinit __mcheck_cpu_cap_init(void) |
1da177e4c Linux-2.6.12-rc2 |
1210 |
{ |
0d7482e3d x86, mce: impleme... |
1211 |
unsigned b; |
e9eee03e9 x86, mce: clean u... |
1212 |
u64 cap; |
1da177e4c Linux-2.6.12-rc2 |
1213 1214 |
rdmsrl(MSR_IA32_MCG_CAP, cap); |
01c6680a5 x86, mce: Cleanup... |
1215 1216 |
b = cap & MCG_BANKCNT_MASK; |
93ae5012a x86: Don't print ... |
1217 1218 1219 |
if (!banks) printk(KERN_INFO "mce: CPU supports %d MCE banks ", b); |
b659294b7 x86, mce: print n... |
1220 |
|
0d7482e3d x86, mce: impleme... |
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 |
if (b > MAX_NR_BANKS) { printk(KERN_WARNING "MCE: Using only %u machine check banks out of %u ", MAX_NR_BANKS, b); b = MAX_NR_BANKS; } /* Don't support asymmetric configurations today */ WARN_ON(banks != 0 && b != banks); banks = b; |
cebe18203 x86: mce: Move pe... |
1232 |
if (!mce_banks) { |
cffd377e5 x86, mce: Fix __i... |
1233 |
int err = __mcheck_cpu_mce_banks_init(); |
11868a2dc x86: mce: Use saf... |
1234 |
|
cebe18203 x86: mce: Move pe... |
1235 1236 |
if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
1237 |
} |
0d7482e3d x86, mce: impleme... |
1238 |
|
94ad84740 [PATCH] x86_64: U... |
1239 |
/* Use accurate RIP reporting if available. */ |
01c6680a5 x86, mce: Cleanup... |
1240 |
if ((cap & MCG_EXT_P) && MCG_EXT_CNT(cap) >= 9) |
94ad84740 [PATCH] x86_64: U... |
1241 |
rip_msr = MSR_IA32_MCG_EIP; |
1da177e4c Linux-2.6.12-rc2 |
1242 |
|
ed7290d0e x86, mce: impleme... |
1243 1244 |
if (cap & MCG_SER_P) mce_ser = 1; |
0d7482e3d x86, mce: impleme... |
1245 1246 |
return 0; } |
5e09954a9 x86, mce: Fix up ... |
1247 |
static void __mcheck_cpu_init_generic(void) |
0d7482e3d x86, mce: impleme... |
1248 |
{ |
e9eee03e9 x86, mce: clean u... |
1249 |
mce_banks_t all_banks; |
0d7482e3d x86, mce: impleme... |
1250 1251 |
u64 cap; int i; |
b79109c3b x86, mce: separat... |
1252 1253 1254 |
/* * Log the machine checks left over from the previous reset. */ |
ee031c31d x86, mce, cmci: u... |
1255 |
bitmap_fill(all_banks, MAX_NR_BANKS); |
5679af4c1 x86, mce: fix boo... |
1256 |
machine_check_poll(MCP_UC|(!mce_bootlog ? MCP_DONTLOG : 0), &all_banks); |
1da177e4c Linux-2.6.12-rc2 |
1257 1258 |
set_in_cr4(X86_CR4_MCE); |
0d7482e3d x86, mce: impleme... |
1259 |
rdmsrl(MSR_IA32_MCG_CAP, cap); |
1da177e4c Linux-2.6.12-rc2 |
1260 1261 1262 1263 |
if (cap & MCG_CTL_P) wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); for (i = 0; i < banks; i++) { |
cebe18203 x86: mce: Move pe... |
1264 |
struct mce_bank *b = &mce_banks[i]; |
11868a2dc x86: mce: Use saf... |
1265 |
|
cebe18203 x86: mce: Move pe... |
1266 |
if (!b->init) |
06b7a7a5e x86, mce: impleme... |
1267 |
continue; |
a2d32bcbc x86: mce: macros ... |
1268 1269 |
wrmsrl(MSR_IA32_MCx_CTL(i), b->ctl); wrmsrl(MSR_IA32_MCx_STATUS(i), 0); |
d88203d1a x86: whitespace c... |
1270 |
} |
1da177e4c Linux-2.6.12-rc2 |
1271 1272 1273 |
} /* Add per CPU specific workarounds here */ |
5e09954a9 x86, mce: Fix up ... |
1274 |
static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) |
d88203d1a x86: whitespace c... |
1275 |
{ |
e412cd257 x86, mce: Don't i... |
1276 1277 1278 1279 1280 |
if (c->x86_vendor == X86_VENDOR_UNKNOWN) { pr_info("MCE: unknown CPU type - not enabling MCE support. "); return -EOPNOTSUPP; } |
1da177e4c Linux-2.6.12-rc2 |
1281 |
/* This should be disabled by the BIOS, but isn't always */ |
911f6a7ba x86-64: extend MC... |
1282 |
if (c->x86_vendor == X86_VENDOR_AMD) { |
e9eee03e9 x86, mce: clean u... |
1283 1284 1285 1286 1287 1288 |
if (c->x86 == 15 && banks > 4) { /* * disable GART TBL walk error reporting, which * trips off incorrectly with the IOMMU & 3ware * & Cerberus: */ |
cebe18203 x86: mce: Move pe... |
1289 |
clear_bit(10, (unsigned long *)&mce_banks[4].ctl); |
e9eee03e9 x86, mce: clean u... |
1290 1291 1292 1293 1294 1295 |
} if (c->x86 <= 17 && mce_bootlog < 0) { /* * Lots of broken BIOS around that don't clear them * by default and leave crap in there. Don't log: */ |
911f6a7ba x86-64: extend MC... |
1296 |
mce_bootlog = 0; |
e9eee03e9 x86, mce: clean u... |
1297 |
} |
2e6f694fd x86, mce: port K7... |
1298 1299 1300 1301 |
/* * Various K7s with broken bank 0 around. Always disable * by default. */ |
203abd67b x86: mce: Handle ... |
1302 |
if (c->x86 == 6 && banks > 0) |
cebe18203 x86: mce: Move pe... |
1303 |
mce_banks[0].ctl = 0; |
1da177e4c Linux-2.6.12-rc2 |
1304 |
} |
e583538f0 [PATCH] x86_64: L... |
1305 |
|
06b7a7a5e x86, mce: impleme... |
1306 1307 1308 1309 1310 1311 1312 1313 1314 |
if (c->x86_vendor == X86_VENDOR_INTEL) { /* * SDM documents that on family 6 bank 0 should not be written * because it aliases to another special BIOS controlled * register. * But it's not aliased anymore on model 0x1a+ * Don't ignore bank 0 completely because there could be a * valid event later, merely don't write CTL0. */ |
cebe18203 x86: mce: Move pe... |
1315 1316 |
if (c->x86 == 6 && c->x86_model < 0x1A && banks > 0) mce_banks[0].init = 0; |
3c0797925 x86, mce: switch ... |
1317 1318 1319 1320 1321 1322 1323 1324 |
/* * All newer Intel systems support MCE broadcasting. Enable * synchronization with a one second timeout. */ if ((c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xe)) && monarch_timeout < 0) monarch_timeout = USEC_PER_SEC; |
c7f6fa441 x86, mce: don't l... |
1325 |
|
e412cd257 x86, mce: Don't i... |
1326 1327 1328 1329 1330 |
/* * There are also broken BIOSes on some Pentium M and * earlier systems: */ if (c->x86 == 6 && c->x86_model <= 13 && mce_bootlog < 0) |
c7f6fa441 x86, mce: don't l... |
1331 |
mce_bootlog = 0; |
06b7a7a5e x86, mce: impleme... |
1332 |
} |
3c0797925 x86, mce: switch ... |
1333 1334 |
if (monarch_timeout < 0) monarch_timeout = 0; |
29b0f591d x86, mce: default... |
1335 1336 |
if (mce_bootlog != 0) mce_panic_timeout = 30; |
e412cd257 x86, mce: Don't i... |
1337 1338 |
return 0; |
d88203d1a x86: whitespace c... |
1339 |
} |
1da177e4c Linux-2.6.12-rc2 |
1340 |
|
3a97fc341 x86, mce: Check t... |
1341 |
static int __cpuinit __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c) |
4efc0670b x86, mce: use 64b... |
1342 1343 |
{ if (c->x86 != 5) |
3a97fc341 x86, mce: Check t... |
1344 |
return 0; |
4efc0670b x86, mce: use 64b... |
1345 1346 |
switch (c->x86_vendor) { case X86_VENDOR_INTEL: |
c69783698 x86, mce: make mc... |
1347 |
intel_p5_mcheck_init(c); |
3a97fc341 x86, mce: Check t... |
1348 |
return 1; |
4efc0670b x86, mce: use 64b... |
1349 1350 1351 |
break; case X86_VENDOR_CENTAUR: winchip_mcheck_init(c); |
3a97fc341 x86, mce: Check t... |
1352 |
return 1; |
4efc0670b x86, mce: use 64b... |
1353 1354 |
break; } |
3a97fc341 x86, mce: Check t... |
1355 1356 |
return 0; |
4efc0670b x86, mce: use 64b... |
1357 |
} |
5e09954a9 x86, mce: Fix up ... |
1358 |
static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) |
1da177e4c Linux-2.6.12-rc2 |
1359 1360 1361 1362 1363 |
{ switch (c->x86_vendor) { case X86_VENDOR_INTEL: mce_intel_feature_init(c); break; |
89b831ef8 [PATCH] x86_64: S... |
1364 1365 1366 |
case X86_VENDOR_AMD: mce_amd_feature_init(c); break; |
1da177e4c Linux-2.6.12-rc2 |
1367 1368 1369 1370 |
default: break; } } |
5e09954a9 x86, mce: Fix up ... |
1371 |
static void __mcheck_cpu_init_timer(void) |
52d168e28 x86, mce: switch ... |
1372 1373 |
{ struct timer_list *t = &__get_cpu_var(mce_timer); |
245b2e70e percpu: clean up ... |
1374 |
int *n = &__get_cpu_var(mce_next_interval); |
52d168e28 x86, mce: switch ... |
1375 |
|
bc09effab x86/mce: Set up t... |
1376 |
setup_timer(t, mce_start_timer, smp_processor_id()); |
62fdac591 x86, mce: Add boo... |
1377 1378 |
if (mce_ignore_ce) return; |
6298c512b x86, mce: make po... |
1379 1380 |
*n = check_interval * HZ; if (!*n) |
52d168e28 x86, mce: switch ... |
1381 |
return; |
6298c512b x86, mce: make po... |
1382 |
t->expires = round_jiffies(jiffies + *n); |
5be6066a7 x86, mce: percpu ... |
1383 |
add_timer_on(t, smp_processor_id()); |
52d168e28 x86, mce: switch ... |
1384 |
} |
9eda8cb3a x86: mce: Move co... |
1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 |
/* Handle unconfigured int18 (should never happen) */ static void unexpected_machine_check(struct pt_regs *regs, long error_code) { printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check). ", smp_processor_id()); } /* Call the installed machine check handler for this CPU setup. */ void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check; |
d88203d1a x86: whitespace c... |
1396 |
/* |
1da177e4c Linux-2.6.12-rc2 |
1397 |
* Called for each booted CPU to set up machine checks. |
e9eee03e9 x86, mce: clean u... |
1398 |
* Must be called with preempt off: |
1da177e4c Linux-2.6.12-rc2 |
1399 |
*/ |
5e09954a9 x86, mce: Fix up ... |
1400 |
void __cpuinit mcheck_cpu_init(struct cpuinfo_x86 *c) |
1da177e4c Linux-2.6.12-rc2 |
1401 |
{ |
4efc0670b x86, mce: use 64b... |
1402 1403 |
if (mce_disabled) return; |
3a97fc341 x86, mce: Check t... |
1404 1405 |
if (__mcheck_cpu_ancient_init(c)) return; |
4efc0670b x86, mce: use 64b... |
1406 |
|
5b4408fda x86, mce: don't s... |
1407 |
if (!mce_available(c)) |
1da177e4c Linux-2.6.12-rc2 |
1408 |
return; |
5e09954a9 x86, mce: Fix up ... |
1409 |
if (__mcheck_cpu_cap_init() < 0 || __mcheck_cpu_apply_quirks(c) < 0) { |
04b2b1a4d x86, mce: rename ... |
1410 |
mce_disabled = 1; |
0d7482e3d x86, mce: impleme... |
1411 1412 |
return; } |
0d7482e3d x86, mce: impleme... |
1413 |
|
5d7279268 x86, mce: use a c... |
1414 |
machine_check_vector = do_machine_check; |
5e09954a9 x86, mce: Fix up ... |
1415 1416 1417 |
__mcheck_cpu_init_generic(); __mcheck_cpu_init_vendor(c); __mcheck_cpu_init_timer(); |
9b1beaf2b x86, mce: support... |
1418 |
INIT_WORK(&__get_cpu_var(mce_work), mce_process_work); |
b77e70bf3 x86, mce: Replace... |
1419 |
init_irq_work(&__get_cpu_var(mce_irq_work), &mce_irq_work_cb); |
1da177e4c Linux-2.6.12-rc2 |
1420 1421 1422 |
} /* |
93b62c3cf x86, mce: Use mce... |
1423 |
* mce_chrdev: Character device /dev/mcelog to read and clear the MCE log. |
1da177e4c Linux-2.6.12-rc2 |
1424 |
*/ |
93b62c3cf x86, mce: Use mce... |
1425 1426 1427 |
static DEFINE_SPINLOCK(mce_chrdev_state_lock); static int mce_chrdev_open_count; /* #times opened */ static int mce_chrdev_open_exclu; /* already open exclusive? */ |
f528e7ba2 x86_64: O_EXCL on... |
1428 |
|
93b62c3cf x86, mce: Use mce... |
1429 |
static int mce_chrdev_open(struct inode *inode, struct file *file) |
f528e7ba2 x86_64: O_EXCL on... |
1430 |
{ |
93b62c3cf x86, mce: Use mce... |
1431 |
spin_lock(&mce_chrdev_state_lock); |
f528e7ba2 x86_64: O_EXCL on... |
1432 |
|
93b62c3cf x86, mce: Use mce... |
1433 1434 1435 |
if (mce_chrdev_open_exclu || (mce_chrdev_open_count && (file->f_flags & O_EXCL))) { spin_unlock(&mce_chrdev_state_lock); |
e9eee03e9 x86, mce: clean u... |
1436 |
|
f528e7ba2 x86_64: O_EXCL on... |
1437 1438 1439 1440 |
return -EBUSY; } if (file->f_flags & O_EXCL) |
93b62c3cf x86, mce: Use mce... |
1441 1442 |
mce_chrdev_open_exclu = 1; mce_chrdev_open_count++; |
f528e7ba2 x86_64: O_EXCL on... |
1443 |
|
93b62c3cf x86, mce: Use mce... |
1444 |
spin_unlock(&mce_chrdev_state_lock); |
f528e7ba2 x86_64: O_EXCL on... |
1445 |
|
bd78432c8 x86_64: mcelog to... |
1446 |
return nonseekable_open(inode, file); |
f528e7ba2 x86_64: O_EXCL on... |
1447 |
} |
93b62c3cf x86, mce: Use mce... |
1448 |
static int mce_chrdev_release(struct inode *inode, struct file *file) |
f528e7ba2 x86_64: O_EXCL on... |
1449 |
{ |
93b62c3cf x86, mce: Use mce... |
1450 |
spin_lock(&mce_chrdev_state_lock); |
f528e7ba2 x86_64: O_EXCL on... |
1451 |
|
93b62c3cf x86, mce: Use mce... |
1452 1453 |
mce_chrdev_open_count--; mce_chrdev_open_exclu = 0; |
f528e7ba2 x86_64: O_EXCL on... |
1454 |
|
93b62c3cf x86, mce: Use mce... |
1455 |
spin_unlock(&mce_chrdev_state_lock); |
f528e7ba2 x86_64: O_EXCL on... |
1456 1457 1458 |
return 0; } |
d88203d1a x86: whitespace c... |
1459 1460 |
static void collect_tscs(void *data) { |
1da177e4c Linux-2.6.12-rc2 |
1461 |
unsigned long *cpu_tsc = (unsigned long *)data; |
d88203d1a x86: whitespace c... |
1462 |
|
1da177e4c Linux-2.6.12-rc2 |
1463 |
rdtscll(cpu_tsc[smp_processor_id()]); |
d88203d1a x86: whitespace c... |
1464 |
} |
1da177e4c Linux-2.6.12-rc2 |
1465 |
|
482908b49 ACPI, APEI, Use E... |
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 |
static int mce_apei_read_done; /* Collect MCE record of previous boot in persistent storage via APEI ERST. */ static int __mce_read_apei(char __user **ubuf, size_t usize) { int rc; u64 record_id; struct mce m; if (usize < sizeof(struct mce)) return -EINVAL; rc = apei_read_mce(&m, &record_id); /* Error or no more MCE record */ if (rc <= 0) { mce_apei_read_done = 1; return rc; } rc = -EFAULT; if (copy_to_user(*ubuf, &m, sizeof(struct mce))) return rc; /* * In fact, we should have cleared the record after that has * been flushed to the disk or sent to network in * /sbin/mcelog, but we have no interface to support that now, * so just clear it to avoid duplication. */ rc = apei_clear_mce(record_id); if (rc) { mce_apei_read_done = 1; return rc; } *ubuf += sizeof(struct mce); return 0; } |
93b62c3cf x86, mce: Use mce... |
1502 1503 |
static ssize_t mce_chrdev_read(struct file *filp, char __user *ubuf, size_t usize, loff_t *off) |
1da177e4c Linux-2.6.12-rc2 |
1504 |
{ |
e9eee03e9 x86, mce: clean u... |
1505 |
char __user *buf = ubuf; |
f0de53bbc [PATCH] x86_64: R... |
1506 |
unsigned long *cpu_tsc; |
ef41df434 x86, mce: fix a r... |
1507 |
unsigned prev, next; |
1da177e4c Linux-2.6.12-rc2 |
1508 |
int i, err; |
6bca67f95 NR_CPUS: Replace ... |
1509 |
cpu_tsc = kmalloc(nr_cpu_ids * sizeof(long), GFP_KERNEL); |
f0de53bbc [PATCH] x86_64: R... |
1510 1511 |
if (!cpu_tsc) return -ENOMEM; |
93b62c3cf x86, mce: Use mce... |
1512 |
mutex_lock(&mce_chrdev_read_mutex); |
482908b49 ACPI, APEI, Use E... |
1513 1514 1515 1516 1517 1518 |
if (!mce_apei_read_done) { err = __mce_read_apei(&buf, usize); if (err || buf != ubuf) goto out; } |
f56e8a076 x86/mce: Fix RCU ... |
1519 |
next = rcu_dereference_check_mce(mcelog.next); |
1da177e4c Linux-2.6.12-rc2 |
1520 1521 |
/* Only supports full reads right now */ |
482908b49 ACPI, APEI, Use E... |
1522 1523 1524 |
err = -EINVAL; if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) goto out; |
1da177e4c Linux-2.6.12-rc2 |
1525 1526 |
err = 0; |
ef41df434 x86, mce: fix a r... |
1527 1528 1529 1530 |
prev = 0; do { for (i = prev; i < next; i++) { unsigned long start = jiffies; |
559faa6be x86, mce: Cleanup... |
1531 |
struct mce *m = &mcelog.entry[i]; |
ef41df434 x86, mce: fix a r... |
1532 |
|
559faa6be x86, mce: Cleanup... |
1533 |
while (!m->finished) { |
ef41df434 x86, mce: fix a r... |
1534 |
if (time_after_eq(jiffies, start + 2)) { |
559faa6be x86, mce: Cleanup... |
1535 |
memset(m, 0, sizeof(*m)); |
ef41df434 x86, mce: fix a r... |
1536 1537 1538 |
goto timeout; } cpu_relax(); |
673242c10 [PATCH] x86-64: M... |
1539 |
} |
ef41df434 x86, mce: fix a r... |
1540 |
smp_rmb(); |
559faa6be x86, mce: Cleanup... |
1541 1542 |
err |= copy_to_user(buf, m, sizeof(*m)); buf += sizeof(*m); |
ef41df434 x86, mce: fix a r... |
1543 1544 |
timeout: ; |
673242c10 [PATCH] x86-64: M... |
1545 |
} |
1da177e4c Linux-2.6.12-rc2 |
1546 |
|
ef41df434 x86, mce: fix a r... |
1547 1548 1549 1550 1551 |
memset(mcelog.entry + prev, 0, (next - prev) * sizeof(struct mce)); prev = next; next = cmpxchg(&mcelog.next, prev, 0); } while (next != prev); |
1da177e4c Linux-2.6.12-rc2 |
1552 |
|
b2b186600 [PATCH] RCU: clea... |
1553 |
synchronize_sched(); |
1da177e4c Linux-2.6.12-rc2 |
1554 |
|
d88203d1a x86: whitespace c... |
1555 1556 1557 1558 |
/* * Collect entries that were still getting written before the * synchronize. */ |
15c8b6c1a on_each_cpu(): ki... |
1559 |
on_each_cpu(collect_tscs, cpu_tsc, 1); |
e9eee03e9 x86, mce: clean u... |
1560 |
|
d88203d1a x86: whitespace c... |
1561 |
for (i = next; i < MCE_LOG_LEN; i++) { |
559faa6be x86, mce: Cleanup... |
1562 1563 1564 1565 |
struct mce *m = &mcelog.entry[i]; if (m->finished && m->tsc < cpu_tsc[m->cpu]) { err |= copy_to_user(buf, m, sizeof(*m)); |
1da177e4c Linux-2.6.12-rc2 |
1566 |
smp_rmb(); |
559faa6be x86, mce: Cleanup... |
1567 1568 |
buf += sizeof(*m); memset(m, 0, sizeof(*m)); |
1da177e4c Linux-2.6.12-rc2 |
1569 |
} |
d88203d1a x86: whitespace c... |
1570 |
} |
482908b49 ACPI, APEI, Use E... |
1571 1572 1573 1574 1575 |
if (err) err = -EFAULT; out: |
93b62c3cf x86, mce: Use mce... |
1576 |
mutex_unlock(&mce_chrdev_read_mutex); |
f0de53bbc [PATCH] x86_64: R... |
1577 |
kfree(cpu_tsc); |
e9eee03e9 x86, mce: clean u... |
1578 |
|
482908b49 ACPI, APEI, Use E... |
1579 |
return err ? err : buf - ubuf; |
1da177e4c Linux-2.6.12-rc2 |
1580 |
} |
93b62c3cf x86, mce: Use mce... |
1581 |
static unsigned int mce_chrdev_poll(struct file *file, poll_table *wait) |
e02e68d31 x86_64: support p... |
1582 |
{ |
93b62c3cf x86, mce: Use mce... |
1583 |
poll_wait(file, &mce_chrdev_wait, wait); |
a4dd99250 rcu: create new r... |
1584 |
if (rcu_access_index(mcelog.next)) |
e02e68d31 x86_64: support p... |
1585 |
return POLLIN | POLLRDNORM; |
482908b49 ACPI, APEI, Use E... |
1586 1587 |
if (!mce_apei_read_done && apei_check_mce()) return POLLIN | POLLRDNORM; |
e02e68d31 x86_64: support p... |
1588 1589 |
return 0; } |
93b62c3cf x86, mce: Use mce... |
1590 1591 |
static long mce_chrdev_ioctl(struct file *f, unsigned int cmd, unsigned long arg) |
1da177e4c Linux-2.6.12-rc2 |
1592 1593 |
{ int __user *p = (int __user *)arg; |
d88203d1a x86: whitespace c... |
1594 |
|
1da177e4c Linux-2.6.12-rc2 |
1595 |
if (!capable(CAP_SYS_ADMIN)) |
d88203d1a x86: whitespace c... |
1596 |
return -EPERM; |
e9eee03e9 x86, mce: clean u... |
1597 |
|
1da177e4c Linux-2.6.12-rc2 |
1598 |
switch (cmd) { |
d88203d1a x86: whitespace c... |
1599 |
case MCE_GET_RECORD_LEN: |
1da177e4c Linux-2.6.12-rc2 |
1600 1601 |
return put_user(sizeof(struct mce), p); case MCE_GET_LOG_LEN: |
d88203d1a x86: whitespace c... |
1602 |
return put_user(MCE_LOG_LEN, p); |
1da177e4c Linux-2.6.12-rc2 |
1603 1604 |
case MCE_GETCLEAR_FLAGS: { unsigned flags; |
d88203d1a x86: whitespace c... |
1605 1606 |
do { |
1da177e4c Linux-2.6.12-rc2 |
1607 |
flags = mcelog.flags; |
d88203d1a x86: whitespace c... |
1608 |
} while (cmpxchg(&mcelog.flags, flags, 0) != flags); |
e9eee03e9 x86, mce: clean u... |
1609 |
|
d88203d1a x86: whitespace c... |
1610 |
return put_user(flags, p); |
1da177e4c Linux-2.6.12-rc2 |
1611 1612 |
} default: |
d88203d1a x86: whitespace c... |
1613 1614 |
return -ENOTTY; } |
1da177e4c Linux-2.6.12-rc2 |
1615 |
} |
66f5ddf30 x86/mce: Make mce... |
1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 |
static ssize_t (*mce_write)(struct file *filp, const char __user *ubuf, size_t usize, loff_t *off); void register_mce_write_callback(ssize_t (*fn)(struct file *filp, const char __user *ubuf, size_t usize, loff_t *off)) { mce_write = fn; } EXPORT_SYMBOL_GPL(register_mce_write_callback); ssize_t mce_chrdev_write(struct file *filp, const char __user *ubuf, size_t usize, loff_t *off) { if (mce_write) return mce_write(filp, ubuf, usize, off); else return -EINVAL; } static const struct file_operations mce_chrdev_ops = { |
93b62c3cf x86, mce: Use mce... |
1637 1638 1639 |
.open = mce_chrdev_open, .release = mce_chrdev_release, .read = mce_chrdev_read, |
66f5ddf30 x86/mce: Make mce... |
1640 |
.write = mce_chrdev_write, |
93b62c3cf x86, mce: Use mce... |
1641 1642 1643 |
.poll = mce_chrdev_poll, .unlocked_ioctl = mce_chrdev_ioctl, .llseek = no_llseek, |
1da177e4c Linux-2.6.12-rc2 |
1644 |
}; |
93b62c3cf x86, mce: Use mce... |
1645 |
static struct miscdevice mce_chrdev_device = { |
1da177e4c Linux-2.6.12-rc2 |
1646 1647 1648 1649 |
MISC_MCELOG_MINOR, "mcelog", &mce_chrdev_ops, }; |
d88203d1a x86: whitespace c... |
1650 |
/* |
62fdac591 x86, mce: Add boo... |
1651 1652 1653 1654 |
* mce=off Disables machine check * mce=no_cmci Disables CMCI * mce=dont_log_ce Clears corrected events silently, no log created for CEs. * mce=ignore_ce Disables polling and CMCI, corrected events are not cleared. |
3c0797925 x86, mce: switch ... |
1655 1656 1657 |
* mce=TOLERANCELEVEL[,monarchtimeout] (number, see above) * monarchtimeout is how long to wait for other CPUs on machine * check, or 0 to not wait |
13503fa91 x86, mce: Cleanup... |
1658 1659 1660 |
* mce=bootlog Log MCEs from before booting. Disabled by default on AMD. * mce=nobootlog Don't log MCEs from before booting. */ |
1da177e4c Linux-2.6.12-rc2 |
1661 1662 |
static int __init mcheck_enable(char *str) { |
e3346fc48 x86, mce: fix "mc... |
1663 |
if (*str == 0) { |
4efc0670b x86, mce: use 64b... |
1664 |
enable_p5_mce(); |
e3346fc48 x86, mce: fix "mc... |
1665 1666 |
return 1; } |
4efc0670b x86, mce: use 64b... |
1667 1668 |
if (*str == '=') str++; |
1da177e4c Linux-2.6.12-rc2 |
1669 |
if (!strcmp(str, "off")) |
04b2b1a4d x86, mce: rename ... |
1670 |
mce_disabled = 1; |
62fdac591 x86, mce: Add boo... |
1671 1672 1673 1674 1675 1676 |
else if (!strcmp(str, "no_cmci")) mce_cmci_disabled = 1; else if (!strcmp(str, "dont_log_ce")) mce_dont_log_ce = 1; else if (!strcmp(str, "ignore_ce")) mce_ignore_ce = 1; |
13503fa91 x86, mce: Cleanup... |
1677 1678 |
else if (!strcmp(str, "bootlog") || !strcmp(str, "nobootlog")) mce_bootlog = (str[0] == 'b'); |
3c0797925 x86, mce: switch ... |
1679 |
else if (isdigit(str[0])) { |
8c566ef5f [PATCH] x86-64: A... |
1680 |
get_option(&str, &tolerant); |
3c0797925 x86, mce: switch ... |
1681 1682 1683 1684 1685 |
if (*str == ',') { ++str; get_option(&str, &monarch_timeout); } } else { |
4efc0670b x86, mce: use 64b... |
1686 1687 |
printk(KERN_INFO "mce argument %s ignored. Please use /sys ", |
13503fa91 x86, mce: Cleanup... |
1688 1689 1690 |
str); return 0; } |
9b41046cd [PATCH] Don't pas... |
1691 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
1692 |
} |
4efc0670b x86, mce: use 64b... |
1693 |
__setup("mce", mcheck_enable); |
1da177e4c Linux-2.6.12-rc2 |
1694 |
|
a2202aa29 x86: Under BIOS c... |
1695 |
int __init mcheck_init(void) |
b33a63636 x86, mce: Add a g... |
1696 |
{ |
a2202aa29 x86: Under BIOS c... |
1697 |
mcheck_intel_therm_init(); |
b33a63636 x86, mce: Add a g... |
1698 1699 |
return 0; } |
b33a63636 x86, mce: Add a g... |
1700 |
|
d88203d1a x86: whitespace c... |
1701 |
/* |
c7cece89f x86, mce: Use mce... |
1702 |
* mce_syscore: PM support |
d88203d1a x86: whitespace c... |
1703 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
1704 |
|
973a2dd1d x86, mce: disable... |
1705 1706 1707 1708 |
/* * Disable machine checks on suspend and shutdown. We can't really handle * them later. */ |
5e09954a9 x86, mce: Fix up ... |
1709 |
static int mce_disable_error_reporting(void) |
973a2dd1d x86, mce: disable... |
1710 1711 |
{ int i; |
06b7a7a5e x86, mce: impleme... |
1712 |
for (i = 0; i < banks; i++) { |
cebe18203 x86: mce: Move pe... |
1713 |
struct mce_bank *b = &mce_banks[i]; |
11868a2dc x86: mce: Use saf... |
1714 |
|
cebe18203 x86: mce: Move pe... |
1715 |
if (b->init) |
a2d32bcbc x86: mce: macros ... |
1716 |
wrmsrl(MSR_IA32_MCx_CTL(i), 0); |
06b7a7a5e x86, mce: impleme... |
1717 |
} |
973a2dd1d x86, mce: disable... |
1718 1719 |
return 0; } |
c7cece89f x86, mce: Use mce... |
1720 |
static int mce_syscore_suspend(void) |
973a2dd1d x86, mce: disable... |
1721 |
{ |
5e09954a9 x86, mce: Fix up ... |
1722 |
return mce_disable_error_reporting(); |
973a2dd1d x86, mce: disable... |
1723 |
} |
c7cece89f x86, mce: Use mce... |
1724 |
static void mce_syscore_shutdown(void) |
973a2dd1d x86, mce: disable... |
1725 |
{ |
f3c6ea1b0 x86: Use syscore_... |
1726 |
mce_disable_error_reporting(); |
973a2dd1d x86, mce: disable... |
1727 |
} |
e9eee03e9 x86, mce: clean u... |
1728 1729 1730 1731 1732 |
/* * On resume clear all MCE state. Don't want to see leftovers from the BIOS. * Only one CPU is active at this time, the others get re-added later using * CPU hotplug: */ |
c7cece89f x86, mce: Use mce... |
1733 |
static void mce_syscore_resume(void) |
1da177e4c Linux-2.6.12-rc2 |
1734 |
{ |
5e09954a9 x86, mce: Fix up ... |
1735 |
__mcheck_cpu_init_generic(); |
7b543a533 x86: Replace uses... |
1736 |
__mcheck_cpu_init_vendor(__this_cpu_ptr(&cpu_info)); |
1da177e4c Linux-2.6.12-rc2 |
1737 |
} |
f3c6ea1b0 x86: Use syscore_... |
1738 |
static struct syscore_ops mce_syscore_ops = { |
c7cece89f x86, mce: Use mce... |
1739 1740 1741 |
.suspend = mce_syscore_suspend, .shutdown = mce_syscore_shutdown, .resume = mce_syscore_resume, |
f3c6ea1b0 x86: Use syscore_... |
1742 |
}; |
c7cece89f x86, mce: Use mce... |
1743 |
/* |
8a25a2fd1 cpu: convert 'cpu... |
1744 |
* mce_device: Sysfs support |
c7cece89f x86, mce: Use mce... |
1745 |
*/ |
52d168e28 x86, mce: switch ... |
1746 1747 |
static void mce_cpu_restart(void *data) { |
7b543a533 x86: Replace uses... |
1748 |
if (!mce_available(__this_cpu_ptr(&cpu_info))) |
33edbf02a x86, mce: don't i... |
1749 |
return; |
5e09954a9 x86, mce: Fix up ... |
1750 1751 |
__mcheck_cpu_init_generic(); __mcheck_cpu_init_timer(); |
52d168e28 x86, mce: switch ... |
1752 |
} |
1da177e4c Linux-2.6.12-rc2 |
1753 |
/* Reinit MCEs after user configuration changes */ |
d88203d1a x86: whitespace c... |
1754 1755 |
static void mce_restart(void) { |
9aaef96f6 x86, mce: Do not ... |
1756 |
mce_timer_delete_all(); |
52d168e28 x86, mce: switch ... |
1757 |
on_each_cpu(mce_cpu_restart, NULL, 1); |
1da177e4c Linux-2.6.12-rc2 |
1758 |
} |
9af43b54a x86, mce: sysfs e... |
1759 |
/* Toggle features for corrected errors */ |
9aaef96f6 x86, mce: Do not ... |
1760 |
static void mce_disable_cmci(void *data) |
9af43b54a x86, mce: sysfs e... |
1761 |
{ |
7b543a533 x86: Replace uses... |
1762 |
if (!mce_available(__this_cpu_ptr(&cpu_info))) |
9af43b54a x86, mce: sysfs e... |
1763 |
return; |
9af43b54a x86, mce: sysfs e... |
1764 1765 1766 1767 1768 |
cmci_clear(); } static void mce_enable_ce(void *all) { |
7b543a533 x86: Replace uses... |
1769 |
if (!mce_available(__this_cpu_ptr(&cpu_info))) |
9af43b54a x86, mce: sysfs e... |
1770 1771 1772 1773 |
return; cmci_reenable(); cmci_recheck(); if (all) |
5e09954a9 x86, mce: Fix up ... |
1774 |
__mcheck_cpu_init_timer(); |
9af43b54a x86, mce: sysfs e... |
1775 |
} |
8a25a2fd1 cpu: convert 'cpu... |
1776 |
static struct bus_type mce_subsys = { |
e9eee03e9 x86, mce: clean u... |
1777 |
.name = "machinecheck", |
8a25a2fd1 cpu: convert 'cpu... |
1778 |
.dev_name = "machinecheck", |
1da177e4c Linux-2.6.12-rc2 |
1779 |
}; |
e032d8077 mce: fix warning ... |
1780 |
struct device *mce_device[CONFIG_NR_CPUS]; |
e9eee03e9 x86, mce: clean u... |
1781 1782 1783 |
__cpuinitdata void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); |
1da177e4c Linux-2.6.12-rc2 |
1784 |
|
8a25a2fd1 cpu: convert 'cpu... |
1785 |
static inline struct mce_bank *attr_to_bank(struct device_attribute *attr) |
cebe18203 x86: mce: Move pe... |
1786 1787 1788 |
{ return container_of(attr, struct mce_bank, attr); } |
0d7482e3d x86, mce: impleme... |
1789 |
|
8a25a2fd1 cpu: convert 'cpu... |
1790 |
static ssize_t show_bank(struct device *s, struct device_attribute *attr, |
0d7482e3d x86, mce: impleme... |
1791 1792 |
char *buf) { |
cebe18203 x86: mce: Move pe... |
1793 1794 |
return sprintf(buf, "%llx ", attr_to_bank(attr)->ctl); |
0d7482e3d x86, mce: impleme... |
1795 |
} |
8a25a2fd1 cpu: convert 'cpu... |
1796 |
static ssize_t set_bank(struct device *s, struct device_attribute *attr, |
9319cec8c x86, mce: use str... |
1797 |
const char *buf, size_t size) |
0d7482e3d x86, mce: impleme... |
1798 |
{ |
9319cec8c x86, mce: use str... |
1799 |
u64 new; |
e9eee03e9 x86, mce: clean u... |
1800 |
|
9319cec8c x86, mce: use str... |
1801 |
if (strict_strtoull(buf, 0, &new) < 0) |
0d7482e3d x86, mce: impleme... |
1802 |
return -EINVAL; |
e9eee03e9 x86, mce: clean u... |
1803 |
|
cebe18203 x86: mce: Move pe... |
1804 |
attr_to_bank(attr)->ctl = new; |
0d7482e3d x86, mce: impleme... |
1805 |
mce_restart(); |
e9eee03e9 x86, mce: clean u... |
1806 |
|
9319cec8c x86, mce: use str... |
1807 |
return size; |
0d7482e3d x86, mce: impleme... |
1808 |
} |
a98f0dd34 [PATCH] x86-64: A... |
1809 |
|
e9eee03e9 x86, mce: clean u... |
1810 |
static ssize_t |
8a25a2fd1 cpu: convert 'cpu... |
1811 |
show_trigger(struct device *s, struct device_attribute *attr, char *buf) |
a98f0dd34 [PATCH] x86-64: A... |
1812 |
{ |
1020bcbcc x86, mce: rename ... |
1813 |
strcpy(buf, mce_helper); |
a98f0dd34 [PATCH] x86-64: A... |
1814 1815 |
strcat(buf, " "); |
1020bcbcc x86, mce: rename ... |
1816 |
return strlen(mce_helper) + 1; |
a98f0dd34 [PATCH] x86-64: A... |
1817 |
} |
8a25a2fd1 cpu: convert 'cpu... |
1818 |
static ssize_t set_trigger(struct device *s, struct device_attribute *attr, |
e9eee03e9 x86, mce: clean u... |
1819 |
const char *buf, size_t siz) |
a98f0dd34 [PATCH] x86-64: A... |
1820 1821 |
{ char *p; |
e9eee03e9 x86, mce: clean u... |
1822 |
|
1020bcbcc x86, mce: rename ... |
1823 1824 |
strncpy(mce_helper, buf, sizeof(mce_helper)); mce_helper[sizeof(mce_helper)-1] = 0; |
1020bcbcc x86, mce: rename ... |
1825 1826 |
p = strchr(mce_helper, ' '); |
e9eee03e9 x86, mce: clean u... |
1827 |
|
e9084ec98 x86, mce: Fix set... |
1828 |
if (p) |
e9eee03e9 x86, mce: clean u... |
1829 |
*p = 0; |
e9084ec98 x86, mce: Fix set... |
1830 |
return strlen(mce_helper) + !!p; |
a98f0dd34 [PATCH] x86-64: A... |
1831 |
} |
8a25a2fd1 cpu: convert 'cpu... |
1832 1833 |
static ssize_t set_ignore_ce(struct device *s, struct device_attribute *attr, |
9af43b54a x86, mce: sysfs e... |
1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 |
const char *buf, size_t size) { u64 new; if (strict_strtoull(buf, 0, &new) < 0) return -EINVAL; if (mce_ignore_ce ^ !!new) { if (new) { /* disable ce features */ |
9aaef96f6 x86, mce: Do not ... |
1844 1845 |
mce_timer_delete_all(); on_each_cpu(mce_disable_cmci, NULL, 1); |
9af43b54a x86, mce: sysfs e... |
1846 1847 1848 1849 1850 1851 1852 1853 1854 |
mce_ignore_ce = 1; } else { /* enable ce features */ mce_ignore_ce = 0; on_each_cpu(mce_enable_ce, (void *)1, 1); } } return size; } |
8a25a2fd1 cpu: convert 'cpu... |
1855 1856 |
static ssize_t set_cmci_disabled(struct device *s, struct device_attribute *attr, |
9af43b54a x86, mce: sysfs e... |
1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 |
const char *buf, size_t size) { u64 new; if (strict_strtoull(buf, 0, &new) < 0) return -EINVAL; if (mce_cmci_disabled ^ !!new) { if (new) { /* disable cmci */ |
9aaef96f6 x86, mce: Do not ... |
1867 |
on_each_cpu(mce_disable_cmci, NULL, 1); |
9af43b54a x86, mce: sysfs e... |
1868 1869 1870 1871 1872 1873 1874 1875 1876 |
mce_cmci_disabled = 1; } else { /* enable cmci */ mce_cmci_disabled = 0; on_each_cpu(mce_enable_ce, NULL, 1); } } return size; } |
8a25a2fd1 cpu: convert 'cpu... |
1877 1878 |
static ssize_t store_int_with_restart(struct device *s, struct device_attribute *attr, |
b56f642d2 x86, mce: use ext... |
1879 1880 |
const char *buf, size_t size) { |
8a25a2fd1 cpu: convert 'cpu... |
1881 |
ssize_t ret = device_store_int(s, attr, buf, size); |
b56f642d2 x86, mce: use ext... |
1882 1883 1884 |
mce_restart(); return ret; } |
8a25a2fd1 cpu: convert 'cpu... |
1885 1886 1887 1888 |
static DEVICE_ATTR(trigger, 0644, show_trigger, set_trigger); static DEVICE_INT_ATTR(tolerant, 0644, tolerant); static DEVICE_INT_ATTR(monarch_timeout, 0644, monarch_timeout); static DEVICE_INT_ATTR(dont_log_ce, 0644, mce_dont_log_ce); |
e9eee03e9 x86, mce: clean u... |
1889 |
|
8a25a2fd1 cpu: convert 'cpu... |
1890 1891 |
static struct dev_ext_attribute dev_attr_check_interval = { __ATTR(check_interval, 0644, device_show_int, store_int_with_restart), |
b56f642d2 x86, mce: use ext... |
1892 1893 |
&check_interval }; |
e9eee03e9 x86, mce: clean u... |
1894 |
|
8a25a2fd1 cpu: convert 'cpu... |
1895 1896 |
static struct dev_ext_attribute dev_attr_ignore_ce = { __ATTR(ignore_ce, 0644, device_show_int, set_ignore_ce), |
9af43b54a x86, mce: sysfs e... |
1897 1898 |
&mce_ignore_ce }; |
8a25a2fd1 cpu: convert 'cpu... |
1899 1900 |
static struct dev_ext_attribute dev_attr_cmci_disabled = { __ATTR(cmci_disabled, 0644, device_show_int, set_cmci_disabled), |
9af43b54a x86, mce: sysfs e... |
1901 1902 |
&mce_cmci_disabled }; |
8a25a2fd1 cpu: convert 'cpu... |
1903 1904 1905 1906 1907 1908 1909 1910 |
static struct device_attribute *mce_device_attrs[] = { &dev_attr_tolerant.attr, &dev_attr_check_interval.attr, &dev_attr_trigger, &dev_attr_monarch_timeout.attr, &dev_attr_dont_log_ce.attr, &dev_attr_ignore_ce.attr, &dev_attr_cmci_disabled.attr, |
a98f0dd34 [PATCH] x86-64: A... |
1911 1912 |
NULL }; |
1da177e4c Linux-2.6.12-rc2 |
1913 |
|
8a25a2fd1 cpu: convert 'cpu... |
1914 |
static cpumask_var_t mce_device_initialized; |
bae19fe03 x86: don't call m... |
1915 |
|
e032d8077 mce: fix warning ... |
1916 1917 1918 1919 |
static void mce_device_release(struct device *dev) { kfree(dev); } |
8a25a2fd1 cpu: convert 'cpu... |
1920 1921 |
/* Per cpu device init. All of the cpus still share the same ctrl bank: */ static __cpuinit int mce_device_create(unsigned int cpu) |
1da177e4c Linux-2.6.12-rc2 |
1922 |
{ |
e032d8077 mce: fix warning ... |
1923 |
struct device *dev; |
1da177e4c Linux-2.6.12-rc2 |
1924 |
int err; |
b1f49f958 x86, mce: fix err... |
1925 |
int i, j; |
92cb7612a x86: convert cpui... |
1926 |
|
903675569 x86: fix cpu-hotp... |
1927 |
if (!mce_available(&boot_cpu_data)) |
91c6d4009 [PATCH] x86_64: C... |
1928 |
return -EIO; |
e032d8077 mce: fix warning ... |
1929 1930 1931 |
dev = kzalloc(sizeof *dev, GFP_KERNEL); if (!dev) return -ENOMEM; |
8a25a2fd1 cpu: convert 'cpu... |
1932 1933 |
dev->id = cpu; dev->bus = &mce_subsys; |
e032d8077 mce: fix warning ... |
1934 |
dev->release = &mce_device_release; |
91c6d4009 [PATCH] x86_64: C... |
1935 |
|
8a25a2fd1 cpu: convert 'cpu... |
1936 |
err = device_register(dev); |
d435d862b cpu hotplug: mce:... |
1937 1938 |
if (err) return err; |
8a25a2fd1 cpu: convert 'cpu... |
1939 1940 |
for (i = 0; mce_device_attrs[i]; i++) { err = device_create_file(dev, mce_device_attrs[i]); |
d435d862b cpu hotplug: mce:... |
1941 1942 1943 |
if (err) goto error; } |
b1f49f958 x86, mce: fix err... |
1944 |
for (j = 0; j < banks; j++) { |
8a25a2fd1 cpu: convert 'cpu... |
1945 |
err = device_create_file(dev, &mce_banks[j].attr); |
0d7482e3d x86, mce: impleme... |
1946 1947 1948 |
if (err) goto error2; } |
8a25a2fd1 cpu: convert 'cpu... |
1949 |
cpumask_set_cpu(cpu, mce_device_initialized); |
e032d8077 mce: fix warning ... |
1950 |
mce_device[cpu] = dev; |
91c6d4009 [PATCH] x86_64: C... |
1951 |
|
d435d862b cpu hotplug: mce:... |
1952 |
return 0; |
0d7482e3d x86, mce: impleme... |
1953 |
error2: |
b1f49f958 x86, mce: fix err... |
1954 |
while (--j >= 0) |
8a25a2fd1 cpu: convert 'cpu... |
1955 |
device_remove_file(dev, &mce_banks[j].attr); |
d435d862b cpu hotplug: mce:... |
1956 |
error: |
cb491fca5 x86, mce: Rename ... |
1957 |
while (--i >= 0) |
8a25a2fd1 cpu: convert 'cpu... |
1958 |
device_remove_file(dev, mce_device_attrs[i]); |
cb491fca5 x86, mce: Rename ... |
1959 |
|
8a25a2fd1 cpu: convert 'cpu... |
1960 |
device_unregister(dev); |
d435d862b cpu hotplug: mce:... |
1961 |
|
91c6d4009 [PATCH] x86_64: C... |
1962 1963 |
return err; } |
8a25a2fd1 cpu: convert 'cpu... |
1964 |
static __cpuinit void mce_device_remove(unsigned int cpu) |
91c6d4009 [PATCH] x86_64: C... |
1965 |
{ |
e032d8077 mce: fix warning ... |
1966 |
struct device *dev = mce_device[cpu]; |
73ca5358a [PATCH] x86_64: i... |
1967 |
int i; |
8a25a2fd1 cpu: convert 'cpu... |
1968 |
if (!cpumask_test_cpu(cpu, mce_device_initialized)) |
bae19fe03 x86: don't call m... |
1969 |
return; |
8a25a2fd1 cpu: convert 'cpu... |
1970 1971 |
for (i = 0; mce_device_attrs[i]; i++) device_remove_file(dev, mce_device_attrs[i]); |
cb491fca5 x86, mce: Rename ... |
1972 |
|
0d7482e3d x86, mce: impleme... |
1973 |
for (i = 0; i < banks; i++) |
8a25a2fd1 cpu: convert 'cpu... |
1974 |
device_remove_file(dev, &mce_banks[i].attr); |
cb491fca5 x86, mce: Rename ... |
1975 |
|
8a25a2fd1 cpu: convert 'cpu... |
1976 1977 |
device_unregister(dev); cpumask_clear_cpu(cpu, mce_device_initialized); |
e032d8077 mce: fix warning ... |
1978 |
mce_device[cpu] = NULL; |
91c6d4009 [PATCH] x86_64: C... |
1979 |
} |
91c6d4009 [PATCH] x86_64: C... |
1980 |
|
d6b75584a x86, mce: disable... |
1981 |
/* Make sure there are no machine checks on offlined CPUs. */ |
767df1bdd x86, mce: Add __c... |
1982 |
static void __cpuinit mce_disable_cpu(void *h) |
d6b75584a x86, mce: disable... |
1983 |
{ |
88ccbedd9 x86, mce, cmci: a... |
1984 |
unsigned long action = *(unsigned long *)h; |
cb491fca5 x86, mce: Rename ... |
1985 |
int i; |
d6b75584a x86, mce: disable... |
1986 |
|
7b543a533 x86: Replace uses... |
1987 |
if (!mce_available(__this_cpu_ptr(&cpu_info))) |
d6b75584a x86, mce: disable... |
1988 |
return; |
767df1bdd x86, mce: Add __c... |
1989 |
|
88ccbedd9 x86, mce, cmci: a... |
1990 1991 |
if (!(action & CPU_TASKS_FROZEN)) cmci_clear(); |
06b7a7a5e x86, mce: impleme... |
1992 |
for (i = 0; i < banks; i++) { |
cebe18203 x86: mce: Move pe... |
1993 |
struct mce_bank *b = &mce_banks[i]; |
11868a2dc x86: mce: Use saf... |
1994 |
|
cebe18203 x86: mce: Move pe... |
1995 |
if (b->init) |
a2d32bcbc x86: mce: macros ... |
1996 |
wrmsrl(MSR_IA32_MCx_CTL(i), 0); |
06b7a7a5e x86, mce: impleme... |
1997 |
} |
d6b75584a x86, mce: disable... |
1998 |
} |
767df1bdd x86, mce: Add __c... |
1999 |
static void __cpuinit mce_reenable_cpu(void *h) |
d6b75584a x86, mce: disable... |
2000 |
{ |
88ccbedd9 x86, mce, cmci: a... |
2001 |
unsigned long action = *(unsigned long *)h; |
e9eee03e9 x86, mce: clean u... |
2002 |
int i; |
d6b75584a x86, mce: disable... |
2003 |
|
7b543a533 x86: Replace uses... |
2004 |
if (!mce_available(__this_cpu_ptr(&cpu_info))) |
d6b75584a x86, mce: disable... |
2005 |
return; |
e9eee03e9 x86, mce: clean u... |
2006 |
|
88ccbedd9 x86, mce, cmci: a... |
2007 2008 |
if (!(action & CPU_TASKS_FROZEN)) cmci_reenable(); |
06b7a7a5e x86, mce: impleme... |
2009 |
for (i = 0; i < banks; i++) { |
cebe18203 x86: mce: Move pe... |
2010 |
struct mce_bank *b = &mce_banks[i]; |
11868a2dc x86: mce: Use saf... |
2011 |
|
cebe18203 x86: mce: Move pe... |
2012 |
if (b->init) |
a2d32bcbc x86: mce: macros ... |
2013 |
wrmsrl(MSR_IA32_MCx_CTL(i), b->ctl); |
06b7a7a5e x86, mce: impleme... |
2014 |
} |
d6b75584a x86, mce: disable... |
2015 |
} |
91c6d4009 [PATCH] x86_64: C... |
2016 |
/* Get notified when a cpu comes on/off. Be hotplug friendly. */ |
e9eee03e9 x86, mce: clean u... |
2017 2018 |
static int __cpuinit mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) |
91c6d4009 [PATCH] x86_64: C... |
2019 2020 |
{ unsigned int cpu = (unsigned long)hcpu; |
52d168e28 x86, mce: switch ... |
2021 |
struct timer_list *t = &per_cpu(mce_timer, cpu); |
91c6d4009 [PATCH] x86_64: C... |
2022 2023 |
switch (action) { |
bae19fe03 x86: don't call m... |
2024 2025 |
case CPU_ONLINE: case CPU_ONLINE_FROZEN: |
8a25a2fd1 cpu: convert 'cpu... |
2026 |
mce_device_create(cpu); |
8735728ef x86 MCE: Fix CPU ... |
2027 2028 |
if (threshold_cpu_callback) threshold_cpu_callback(action, cpu); |
91c6d4009 [PATCH] x86_64: C... |
2029 |
break; |
91c6d4009 [PATCH] x86_64: C... |
2030 |
case CPU_DEAD: |
8bb784428 Add suspend-relat... |
2031 |
case CPU_DEAD_FROZEN: |
8735728ef x86 MCE: Fix CPU ... |
2032 2033 |
if (threshold_cpu_callback) threshold_cpu_callback(action, cpu); |
8a25a2fd1 cpu: convert 'cpu... |
2034 |
mce_device_remove(cpu); |
91c6d4009 [PATCH] x86_64: C... |
2035 |
break; |
52d168e28 x86, mce: switch ... |
2036 2037 2038 |
case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: del_timer_sync(t); |
88ccbedd9 x86, mce, cmci: a... |
2039 |
smp_call_function_single(cpu, mce_disable_cpu, &action, 1); |
52d168e28 x86, mce: switch ... |
2040 2041 2042 |
break; case CPU_DOWN_FAILED: case CPU_DOWN_FAILED_FROZEN: |
fe5ed91dd x86, mce: don't r... |
2043 2044 |
if (!mce_ignore_ce && check_interval) { t->expires = round_jiffies(jiffies + |
245b2e70e percpu: clean up ... |
2045 |
__get_cpu_var(mce_next_interval)); |
fe5ed91dd x86, mce: don't r... |
2046 2047 |
add_timer_on(t, cpu); } |
88ccbedd9 x86, mce, cmci: a... |
2048 2049 2050 2051 2052 |
smp_call_function_single(cpu, mce_reenable_cpu, &action, 1); break; case CPU_POST_DEAD: /* intentionally ignoring frozen here */ cmci_rediscover(cpu); |
52d168e28 x86, mce: switch ... |
2053 |
break; |
91c6d4009 [PATCH] x86_64: C... |
2054 |
} |
bae19fe03 x86: don't call m... |
2055 |
return NOTIFY_OK; |
91c6d4009 [PATCH] x86_64: C... |
2056 |
} |
1e35669d0 x86: fix section ... |
2057 |
static struct notifier_block mce_cpu_notifier __cpuinitdata = { |
91c6d4009 [PATCH] x86_64: C... |
2058 2059 |
.notifier_call = mce_cpu_callback, }; |
cebe18203 x86: mce: Move pe... |
2060 |
static __init void mce_init_banks(void) |
0d7482e3d x86, mce: impleme... |
2061 2062 |
{ int i; |
0d7482e3d x86, mce: impleme... |
2063 |
for (i = 0; i < banks; i++) { |
cebe18203 x86: mce: Move pe... |
2064 |
struct mce_bank *b = &mce_banks[i]; |
8a25a2fd1 cpu: convert 'cpu... |
2065 |
struct device_attribute *a = &b->attr; |
e9eee03e9 x86, mce: clean u... |
2066 |
|
a07e4156a sysfs: Use sysfs_... |
2067 |
sysfs_attr_init(&a->attr); |
cebe18203 x86: mce: Move pe... |
2068 2069 |
a->attr.name = b->attrname; snprintf(b->attrname, ATTR_LEN, "bank%d", i); |
e9eee03e9 x86, mce: clean u... |
2070 2071 2072 2073 |
a->attr.mode = 0644; a->show = show_bank; a->store = set_bank; |
0d7482e3d x86, mce: impleme... |
2074 |
} |
0d7482e3d x86, mce: impleme... |
2075 |
} |
5e09954a9 x86, mce: Fix up ... |
2076 |
static __init int mcheck_init_device(void) |
91c6d4009 [PATCH] x86_64: C... |
2077 2078 2079 |
{ int err; int i = 0; |
1da177e4c Linux-2.6.12-rc2 |
2080 2081 |
if (!mce_available(&boot_cpu_data)) return -EIO; |
0d7482e3d x86, mce: impleme... |
2082 |
|
8a25a2fd1 cpu: convert 'cpu... |
2083 |
zalloc_cpumask_var(&mce_device_initialized, GFP_KERNEL); |
996867d09 cpumask: convert ... |
2084 |
|
cebe18203 x86: mce: Move pe... |
2085 |
mce_init_banks(); |
0d7482e3d x86, mce: impleme... |
2086 |
|
8a25a2fd1 cpu: convert 'cpu... |
2087 |
err = subsys_system_register(&mce_subsys, NULL); |
d435d862b cpu hotplug: mce:... |
2088 2089 |
if (err) return err; |
91c6d4009 [PATCH] x86_64: C... |
2090 2091 |
for_each_online_cpu(i) { |
8a25a2fd1 cpu: convert 'cpu... |
2092 |
err = mce_device_create(i); |
d435d862b cpu hotplug: mce:... |
2093 2094 |
if (err) return err; |
91c6d4009 [PATCH] x86_64: C... |
2095 |
} |
f3c6ea1b0 x86: Use syscore_... |
2096 |
register_syscore_ops(&mce_syscore_ops); |
be6b5a350 [PATCH] cpu hotpl... |
2097 |
register_hotcpu_notifier(&mce_cpu_notifier); |
93b62c3cf x86, mce: Use mce... |
2098 2099 2100 |
/* register character device /dev/mcelog */ misc_register(&mce_chrdev_device); |
e9eee03e9 x86, mce: clean u... |
2101 |
|
1da177e4c Linux-2.6.12-rc2 |
2102 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
2103 |
} |
5e09954a9 x86, mce: Fix up ... |
2104 |
device_initcall(mcheck_init_device); |
a988d334a x86, mce: unify, ... |
2105 |
|
d7c3c9a60 x86, mce: move mc... |
2106 2107 2108 2109 2110 2111 2112 2113 2114 |
/* * Old style boot options parsing. Only for compatibility. */ static int __init mcheck_disable(char *str) { mce_disabled = 1; return 1; } __setup("nomce", mcheck_disable); |
a988d334a x86, mce: unify, ... |
2115 |
|
5be9ed251 x86, mce: Move de... |
2116 2117 |
#ifdef CONFIG_DEBUG_FS struct dentry *mce_get_debugfs_dir(void) |
a988d334a x86, mce: unify, ... |
2118 |
{ |
5be9ed251 x86, mce: Move de... |
2119 |
static struct dentry *dmce; |
a988d334a x86, mce: unify, ... |
2120 |
|
5be9ed251 x86, mce: Move de... |
2121 2122 |
if (!dmce) dmce = debugfs_create_dir("mce", NULL); |
a988d334a x86, mce: unify, ... |
2123 |
|
5be9ed251 x86, mce: Move de... |
2124 2125 |
return dmce; } |
a988d334a x86, mce: unify, ... |
2126 |
|
bf783f9f7 x86, mce: Fake pa... |
2127 2128 2129 2130 2131 2132 2133 2134 |
static void mce_reset(void) { cpu_missing = 0; atomic_set(&mce_fake_paniced, 0); atomic_set(&mce_executing, 0); atomic_set(&mce_callin, 0); atomic_set(&global_nwo, 0); } |
a988d334a x86, mce: unify, ... |
2135 |
|
bf783f9f7 x86, mce: Fake pa... |
2136 2137 2138 2139 |
static int fake_panic_get(void *data, u64 *val) { *val = fake_panic; return 0; |
a988d334a x86, mce: unify, ... |
2140 |
} |
bf783f9f7 x86, mce: Fake pa... |
2141 |
static int fake_panic_set(void *data, u64 val) |
a988d334a x86, mce: unify, ... |
2142 |
{ |
bf783f9f7 x86, mce: Fake pa... |
2143 2144 2145 |
mce_reset(); fake_panic = val; return 0; |
a988d334a x86, mce: unify, ... |
2146 |
} |
a988d334a x86, mce: unify, ... |
2147 |
|
bf783f9f7 x86, mce: Fake pa... |
2148 2149 2150 |
DEFINE_SIMPLE_ATTRIBUTE(fake_panic_fops, fake_panic_get, fake_panic_set, "%llu "); |
d7c3c9a60 x86, mce: move mc... |
2151 |
|
5e09954a9 x86, mce: Fix up ... |
2152 |
static int __init mcheck_debugfs_init(void) |
d7c3c9a60 x86, mce: move mc... |
2153 |
{ |
bf783f9f7 x86, mce: Fake pa... |
2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 |
struct dentry *dmce, *ffake_panic; dmce = mce_get_debugfs_dir(); if (!dmce) return -ENOMEM; ffake_panic = debugfs_create_file("fake_panic", 0444, dmce, NULL, &fake_panic_fops); if (!ffake_panic) return -ENOMEM; return 0; |
d7c3c9a60 x86, mce: move mc... |
2165 |
} |
5e09954a9 x86, mce: Fix up ... |
2166 |
late_initcall(mcheck_debugfs_init); |
5be9ed251 x86, mce: Move de... |
2167 |
#endif |