blob: 183dc61054295426fcf12262cf94c66ab6df0a0b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Machine check handler.
3 * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs.
4 * Rest from unknown author(s).
5 * 2004 Andi Kleen. Rewrote most of it.
6 */
7
8#include <linux/init.h>
9#include <linux/types.h>
10#include <linux/kernel.h>
11#include <linux/sched.h>
12#include <linux/string.h>
13#include <linux/rcupdate.h>
14#include <linux/kallsyms.h>
15#include <linux/sysdev.h>
16#include <linux/miscdevice.h>
17#include <linux/fs.h>
Andi Kleen91c6d402005-07-28 21:15:39 -070018#include <linux/cpu.h>
19#include <linux/percpu.h>
Andi Kleen8c566ef2005-09-12 18:49:24 +020020#include <linux/ctype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/processor.h>
22#include <asm/msr.h>
23#include <asm/mce.h>
24#include <asm/kdebug.h>
25#include <asm/uaccess.h>
26
27#define MISC_MCELOG_MINOR 227
28#define NR_BANKS 5
29
30static int mce_dont_init;
31
32/* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic,
33 3: never panic or exit (for testing only) */
34static int tolerant = 1;
35static int banks;
36static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
37static unsigned long console_logged;
38static int notify_user;
Andi Kleen94ad8472005-04-16 15:25:09 -070039static int rip_msr;
Andi Kleene5835382005-11-05 17:25:54 +010040static int mce_bootlog = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42/*
43 * Lockless MCE logging infrastructure.
44 * This avoids deadlocks on printk locks without having to break locks. Also
45 * separate MCEs from kernel messages to avoid bogus bug reports.
46 */
47
48struct mce_log mcelog = {
49 MCE_LOG_SIGNATURE,
50 MCE_LOG_LEN,
51};
52
53void mce_log(struct mce *mce)
54{
55 unsigned next, entry;
56 mce->finished = 0;
Mike Waychison76441432005-09-30 00:01:27 +020057 wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 for (;;) {
59 entry = rcu_dereference(mcelog.next);
Mike Waychison76441432005-09-30 00:01:27 +020060 /* The rmb forces the compiler to reload next in each
61 iteration */
62 rmb();
Andi Kleen673242c2005-09-12 18:49:24 +020063 for (;;) {
64 /* When the buffer fills up discard new entries. Assume
65 that the earlier errors are the more interesting. */
66 if (entry >= MCE_LOG_LEN) {
67 set_bit(MCE_OVERFLOW, &mcelog.flags);
68 return;
69 }
70 /* Old left over entry. Skip. */
71 if (mcelog.entry[entry].finished) {
72 entry++;
73 continue;
74 }
Mike Waychison76441432005-09-30 00:01:27 +020075 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 smp_rmb();
78 next = entry + 1;
79 if (cmpxchg(&mcelog.next, entry, next) == entry)
80 break;
81 }
82 memcpy(mcelog.entry + entry, mce, sizeof(struct mce));
Mike Waychison76441432005-09-30 00:01:27 +020083 wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 mcelog.entry[entry].finished = 1;
Mike Waychison76441432005-09-30 00:01:27 +020085 wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
87 if (!test_and_set_bit(0, &console_logged))
88 notify_user = 1;
89}
90
91static void print_mce(struct mce *m)
92{
93 printk(KERN_EMERG "\n"
94 KERN_EMERG
95 "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
96 m->cpu, m->mcgstatus, m->bank, m->status);
97 if (m->rip) {
98 printk(KERN_EMERG
99 "RIP%s %02x:<%016Lx> ",
100 !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
101 m->cs, m->rip);
102 if (m->cs == __KERNEL_CS)
103 print_symbol("{%s}", m->rip);
104 printk("\n");
105 }
106 printk(KERN_EMERG "TSC %Lx ", m->tsc);
107 if (m->addr)
108 printk("ADDR %Lx ", m->addr);
109 if (m->misc)
110 printk("MISC %Lx ", m->misc);
111 printk("\n");
112}
113
114static void mce_panic(char *msg, struct mce *backup, unsigned long start)
115{
116 int i;
117 oops_begin();
118 for (i = 0; i < MCE_LOG_LEN; i++) {
119 unsigned long tsc = mcelog.entry[i].tsc;
120 if (time_before(tsc, start))
121 continue;
122 print_mce(&mcelog.entry[i]);
123 if (backup && mcelog.entry[i].tsc == backup->tsc)
124 backup = NULL;
125 }
126 if (backup)
127 print_mce(backup);
128 if (tolerant >= 3)
129 printk("Fake panic: %s\n", msg);
130 else
131 panic(msg);
132}
133
134static int mce_available(struct cpuinfo_x86 *c)
135{
136 return test_bit(X86_FEATURE_MCE, &c->x86_capability) &&
137 test_bit(X86_FEATURE_MCA, &c->x86_capability);
138}
139
Andi Kleen94ad8472005-04-16 15:25:09 -0700140static inline void mce_get_rip(struct mce *m, struct pt_regs *regs)
141{
142 if (regs && (m->mcgstatus & MCG_STATUS_RIPV)) {
143 m->rip = regs->rip;
144 m->cs = regs->cs;
145 } else {
146 m->rip = 0;
147 m->cs = 0;
148 }
149 if (rip_msr) {
150 /* Assume the RIP in the MSR is exact. Is this true? */
151 m->mcgstatus |= MCG_STATUS_EIPV;
152 rdmsrl(rip_msr, m->rip);
153 m->cs = 0;
154 }
155}
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157/*
158 * The actual machine check handler
159 */
160
161void do_machine_check(struct pt_regs * regs, long error_code)
162{
163 struct mce m, panicm;
164 int nowayout = (tolerant < 1);
165 int kill_it = 0;
166 u64 mcestart = 0;
167 int i;
168 int panicm_found = 0;
169
170 if (regs)
171 notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL);
172 if (!banks)
173 return;
174
175 memset(&m, 0, sizeof(struct mce));
176 m.cpu = hard_smp_processor_id();
177 rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
178 if (!(m.mcgstatus & MCG_STATUS_RIPV))
179 kill_it = 1;
180
181 rdtscll(mcestart);
182 barrier();
183
184 for (i = 0; i < banks; i++) {
185 if (!bank[i])
186 continue;
187
188 m.misc = 0;
189 m.addr = 0;
190 m.bank = i;
191 m.tsc = 0;
192
193 rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
194 if ((m.status & MCI_STATUS_VAL) == 0)
195 continue;
196
197 if (m.status & MCI_STATUS_EN) {
198 /* In theory _OVER could be a nowayout too, but
199 assume any overflowed errors were no fatal. */
200 nowayout |= !!(m.status & MCI_STATUS_PCC);
201 kill_it |= !!(m.status & MCI_STATUS_UC);
202 }
203
204 if (m.status & MCI_STATUS_MISCV)
205 rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc);
206 if (m.status & MCI_STATUS_ADDRV)
207 rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
208
Andi Kleen94ad8472005-04-16 15:25:09 -0700209 mce_get_rip(&m, regs);
Andi Kleend5172f22005-08-07 09:42:07 -0700210 if (error_code >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 rdtscll(m.tsc);
212 wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
Andi Kleend5172f22005-08-07 09:42:07 -0700213 if (error_code != -2)
214 mce_log(&m);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 /* Did this bank cause the exception? */
217 /* Assume that the bank with uncorrectable errors did it,
218 and that there is only a single one. */
219 if ((m.status & MCI_STATUS_UC) && (m.status & MCI_STATUS_EN)) {
220 panicm = m;
221 panicm_found = 1;
222 }
223
Randy Dunlap9f158332005-09-13 01:25:16 -0700224 add_taint(TAINT_MACHINE_CHECK);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 }
226
227 /* Never do anything final in the polling timer */
228 if (!regs)
229 goto out;
230
231 /* If we didn't find an uncorrectable error, pick
232 the last one (shouldn't happen, just being safe). */
233 if (!panicm_found)
234 panicm = m;
235 if (nowayout)
236 mce_panic("Machine check", &panicm, mcestart);
237 if (kill_it) {
238 int user_space = 0;
239
240 if (m.mcgstatus & MCG_STATUS_RIPV)
241 user_space = panicm.rip && (panicm.cs & 3);
242
243 /* When the machine was in user space and the CPU didn't get
244 confused it's normally not necessary to panic, unless you
245 are paranoid (tolerant == 0)
246
247 RED-PEN could be more tolerant for MCEs in idle,
248 but most likely they occur at boot anyways, where
249 it is best to just halt the machine. */
250 if ((!user_space && (panic_on_oops || tolerant < 2)) ||
251 (unsigned)current->pid <= 1)
252 mce_panic("Uncorrected machine check", &panicm, mcestart);
253
254 /* do_exit takes an awful lot of locks and has as
255 slight risk of deadlocking. If you don't want that
256 don't set tolerant >= 2 */
257 if (tolerant < 3)
258 do_exit(SIGBUS);
259 }
260
261 out:
262 /* Last thing done in the machine check exception to clear state. */
263 wrmsrl(MSR_IA32_MCG_STATUS, 0);
264}
265
266/*
267 * Periodic polling timer for "silent" machine check errors.
268 */
269
270static int check_interval = 5 * 60; /* 5 minutes */
271static void mcheck_timer(void *data);
272static DECLARE_WORK(mcheck_work, mcheck_timer, NULL);
273
274static void mcheck_check_cpu(void *info)
275{
276 if (mce_available(&current_cpu_data))
277 do_machine_check(NULL, 0);
278}
279
280static void mcheck_timer(void *data)
281{
282 on_each_cpu(mcheck_check_cpu, NULL, 1, 1);
283 schedule_delayed_work(&mcheck_work, check_interval * HZ);
284
285 /*
286 * It's ok to read stale data here for notify_user and
287 * console_logged as we'll simply get the updated versions
288 * on the next mcheck_timer execution and atomic operations
289 * on console_logged act as synchronization for notify_user
290 * writes.
291 */
292 if (notify_user && console_logged) {
293 notify_user = 0;
294 clear_bit(0, &console_logged);
295 printk(KERN_INFO "Machine check events logged\n");
296 }
297}
298
299
300static __init int periodic_mcheck_init(void)
301{
302 if (check_interval)
303 schedule_delayed_work(&mcheck_work, check_interval*HZ);
304 return 0;
305}
306__initcall(periodic_mcheck_init);
307
308
309/*
310 * Initialize Machine Checks for a CPU.
311 */
312static void mce_init(void *dummy)
313{
314 u64 cap;
315 int i;
316
317 rdmsrl(MSR_IA32_MCG_CAP, cap);
318 banks = cap & 0xff;
319 if (banks > NR_BANKS) {
320 printk(KERN_INFO "MCE: warning: using only %d banks\n", banks);
321 banks = NR_BANKS;
322 }
Andi Kleen94ad8472005-04-16 15:25:09 -0700323 /* Use accurate RIP reporting if available. */
324 if ((cap & (1<<9)) && ((cap >> 16) & 0xff) >= 9)
325 rip_msr = MSR_IA32_MCG_EIP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327 /* Log the machine checks left over from the previous reset.
328 This also clears all registers */
Andi Kleend5172f22005-08-07 09:42:07 -0700329 do_machine_check(NULL, mce_bootlog ? -1 : -2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 set_in_cr4(X86_CR4_MCE);
332
333 if (cap & MCG_CTL_P)
334 wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
335
336 for (i = 0; i < banks; i++) {
337 wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
338 wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
339 }
340}
341
342/* Add per CPU specific workarounds here */
Ashok Raje6982c62005-06-25 14:54:58 -0700343static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
345 /* This should be disabled by the BIOS, but isn't always */
346 if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 15) {
347 /* disable GART TBL walk error reporting, which trips off
348 incorrectly with the IOMMU & 3ware & Cerberus. */
349 clear_bit(10, &bank[4]);
Andi Kleene5835382005-11-05 17:25:54 +0100350 /* Lots of broken BIOS around that don't clear them
351 by default and leave crap in there. Don't log. */
352 mce_bootlog = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 }
Andi Kleene5835382005-11-05 17:25:54 +0100354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
Ashok Raje6982c62005-06-25 14:54:58 -0700357static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358{
359 switch (c->x86_vendor) {
360 case X86_VENDOR_INTEL:
361 mce_intel_feature_init(c);
362 break;
Jacob Shin89b831e2005-11-05 17:25:53 +0100363 case X86_VENDOR_AMD:
364 mce_amd_feature_init(c);
365 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 default:
367 break;
368 }
369}
370
371/*
372 * Called for each booted CPU to set up machine checks.
373 * Must be called with preempt off.
374 */
Ashok Raje6982c62005-06-25 14:54:58 -0700375void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
377 static cpumask_t mce_cpus __initdata = CPU_MASK_NONE;
378
379 mce_cpu_quirks(c);
380
381 if (mce_dont_init ||
382 cpu_test_and_set(smp_processor_id(), mce_cpus) ||
383 !mce_available(c))
384 return;
385
386 mce_init(NULL);
387 mce_cpu_features(c);
388}
389
390/*
391 * Character device to read and clear the MCE log.
392 */
393
394static void collect_tscs(void *data)
395{
396 unsigned long *cpu_tsc = (unsigned long *)data;
397 rdtscll(cpu_tsc[smp_processor_id()]);
398}
399
400static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff_t *off)
401{
Andi Kleenf0de53b2005-04-16 15:25:10 -0700402 unsigned long *cpu_tsc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 static DECLARE_MUTEX(mce_read_sem);
404 unsigned next;
405 char __user *buf = ubuf;
406 int i, err;
407
Andi Kleenf0de53b2005-04-16 15:25:10 -0700408 cpu_tsc = kmalloc(NR_CPUS * sizeof(long), GFP_KERNEL);
409 if (!cpu_tsc)
410 return -ENOMEM;
411
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 down(&mce_read_sem);
413 next = rcu_dereference(mcelog.next);
414
415 /* Only supports full reads right now */
416 if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) {
417 up(&mce_read_sem);
Andi Kleenf0de53b2005-04-16 15:25:10 -0700418 kfree(cpu_tsc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 return -EINVAL;
420 }
421
422 err = 0;
Andi Kleen673242c2005-09-12 18:49:24 +0200423 for (i = 0; i < next; i++) {
424 unsigned long start = jiffies;
425 while (!mcelog.entry[i].finished) {
426 if (!time_before(jiffies, start + 2)) {
427 memset(mcelog.entry + i,0, sizeof(struct mce));
428 continue;
429 }
430 cpu_relax();
431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 smp_rmb();
433 err |= copy_to_user(buf, mcelog.entry + i, sizeof(struct mce));
434 buf += sizeof(struct mce);
435 }
436
437 memset(mcelog.entry, 0, next * sizeof(struct mce));
438 mcelog.next = 0;
439
Paul E. McKenneyb2b18662005-06-25 14:55:38 -0700440 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442 /* Collect entries that were still getting written before the synchronize. */
443
444 on_each_cpu(collect_tscs, cpu_tsc, 1, 1);
445 for (i = next; i < MCE_LOG_LEN; i++) {
446 if (mcelog.entry[i].finished &&
447 mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) {
448 err |= copy_to_user(buf, mcelog.entry+i, sizeof(struct mce));
449 smp_rmb();
450 buf += sizeof(struct mce);
451 memset(&mcelog.entry[i], 0, sizeof(struct mce));
452 }
453 }
454 up(&mce_read_sem);
Andi Kleenf0de53b2005-04-16 15:25:10 -0700455 kfree(cpu_tsc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 return err ? -EFAULT : buf - ubuf;
457}
458
459static int mce_ioctl(struct inode *i, struct file *f,unsigned int cmd, unsigned long arg)
460{
461 int __user *p = (int __user *)arg;
462 if (!capable(CAP_SYS_ADMIN))
463 return -EPERM;
464 switch (cmd) {
465 case MCE_GET_RECORD_LEN:
466 return put_user(sizeof(struct mce), p);
467 case MCE_GET_LOG_LEN:
468 return put_user(MCE_LOG_LEN, p);
469 case MCE_GETCLEAR_FLAGS: {
470 unsigned flags;
471 do {
472 flags = mcelog.flags;
473 } while (cmpxchg(&mcelog.flags, flags, 0) != flags);
474 return put_user(flags, p);
475 }
476 default:
477 return -ENOTTY;
478 }
479}
480
481static struct file_operations mce_chrdev_ops = {
482 .read = mce_read,
483 .ioctl = mce_ioctl,
484};
485
486static struct miscdevice mce_log_device = {
487 MISC_MCELOG_MINOR,
488 "mcelog",
489 &mce_chrdev_ops,
490};
491
492/*
493 * Old style boot options parsing. Only for compatibility.
494 */
495
496static int __init mcheck_disable(char *str)
497{
498 mce_dont_init = 1;
499 return 0;
500}
501
502/* mce=off disables machine check. Note you can reenable it later
Andi Kleend5172f22005-08-07 09:42:07 -0700503 using sysfs.
Andi Kleen8c566ef2005-09-12 18:49:24 +0200504 mce=TOLERANCELEVEL (number, see above)
Andi Kleene5835382005-11-05 17:25:54 +0100505 mce=bootlog Log MCEs from before booting. Disabled by default on AMD.
506 mce=nobootlog Don't log MCEs from before booting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507static int __init mcheck_enable(char *str)
508{
Andi Kleend5172f22005-08-07 09:42:07 -0700509 if (*str == '=')
510 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 if (!strcmp(str, "off"))
512 mce_dont_init = 1;
Andi Kleene5835382005-11-05 17:25:54 +0100513 else if (!strcmp(str, "bootlog") || !strcmp(str,"nobootlog"))
514 mce_bootlog = str[0] == 'b';
Andi Kleen8c566ef2005-09-12 18:49:24 +0200515 else if (isdigit(str[0]))
516 get_option(&str, &tolerant);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 else
518 printk("mce= argument %s ignored. Please use /sys", str);
519 return 0;
520}
521
522__setup("nomce", mcheck_disable);
523__setup("mce", mcheck_enable);
524
525/*
526 * Sysfs support
527 */
528
Andi Kleen413588c2005-09-12 18:49:24 +0200529/* On resume clear all MCE state. Don't want to see leftovers from the BIOS.
530 Only one CPU is active at this time, the others get readded later using
531 CPU hotplug. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532static int mce_resume(struct sys_device *dev)
533{
Andi Kleen413588c2005-09-12 18:49:24 +0200534 mce_init(NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return 0;
536}
537
538/* Reinit MCEs after user configuration changes */
539static void mce_restart(void)
540{
541 if (check_interval)
542 cancel_delayed_work(&mcheck_work);
543 /* Timer race is harmless here */
544 on_each_cpu(mce_init, NULL, 1, 1);
545 if (check_interval)
546 schedule_delayed_work(&mcheck_work, check_interval*HZ);
547}
548
549static struct sysdev_class mce_sysclass = {
550 .resume = mce_resume,
551 set_kset_name("machinecheck"),
552};
553
Andi Kleen91c6d402005-07-28 21:15:39 -0700554static DEFINE_PER_CPU(struct sys_device, device_mce);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556/* Why are there no generic functions for this? */
557#define ACCESSOR(name, var, start) \
558 static ssize_t show_ ## name(struct sys_device *s, char *buf) { \
559 return sprintf(buf, "%lx\n", (unsigned long)var); \
560 } \
561 static ssize_t set_ ## name(struct sys_device *s,const char *buf,size_t siz) { \
562 char *end; \
563 unsigned long new = simple_strtoul(buf, &end, 0); \
564 if (end == buf) return -EINVAL; \
565 var = new; \
566 start; \
567 return end-buf; \
568 } \
569 static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name);
570
571ACCESSOR(bank0ctl,bank[0],mce_restart())
572ACCESSOR(bank1ctl,bank[1],mce_restart())
573ACCESSOR(bank2ctl,bank[2],mce_restart())
574ACCESSOR(bank3ctl,bank[3],mce_restart())
575ACCESSOR(bank4ctl,bank[4],mce_restart())
576ACCESSOR(tolerant,tolerant,)
577ACCESSOR(check_interval,check_interval,mce_restart())
578
Andi Kleen91c6d402005-07-28 21:15:39 -0700579/* Per cpu sysdev init. All of the cpus still share the same ctl bank */
580static __cpuinit int mce_create_device(unsigned int cpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
582 int err;
Andi Kleen91c6d402005-07-28 21:15:39 -0700583 if (!mce_available(&cpu_data[cpu]))
584 return -EIO;
585
586 per_cpu(device_mce,cpu).id = cpu;
587 per_cpu(device_mce,cpu).cls = &mce_sysclass;
588
589 err = sysdev_register(&per_cpu(device_mce,cpu));
590
591 if (!err) {
592 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank0ctl);
593 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank1ctl);
594 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank2ctl);
595 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank3ctl);
596 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank4ctl);
597 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_tolerant);
598 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_check_interval);
599 }
600 return err;
601}
602
603#ifdef CONFIG_HOTPLUG_CPU
604static __cpuinit void mce_remove_device(unsigned int cpu)
605{
606 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank0ctl);
607 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank1ctl);
608 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank2ctl);
609 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank3ctl);
610 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank4ctl);
611 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_tolerant);
612 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_check_interval);
613 sysdev_unregister(&per_cpu(device_mce,cpu));
614}
615#endif
616
617/* Get notified when a cpu comes on/off. Be hotplug friendly. */
618static __cpuinit int
619mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
620{
621 unsigned int cpu = (unsigned long)hcpu;
622
623 switch (action) {
624 case CPU_ONLINE:
625 mce_create_device(cpu);
626 break;
627#ifdef CONFIG_HOTPLUG_CPU
628 case CPU_DEAD:
629 mce_remove_device(cpu);
630 break;
631#endif
632 }
633 return NOTIFY_OK;
634}
635
636static struct notifier_block mce_cpu_notifier = {
637 .notifier_call = mce_cpu_callback,
638};
639
640static __init int mce_init_device(void)
641{
642 int err;
643 int i = 0;
644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (!mce_available(&boot_cpu_data))
646 return -EIO;
647 err = sysdev_class_register(&mce_sysclass);
Andi Kleen91c6d402005-07-28 21:15:39 -0700648
649 for_each_online_cpu(i) {
650 mce_create_device(i);
651 }
652
653 register_cpu_notifier(&mce_cpu_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 misc_register(&mce_log_device);
655 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656}
Andi Kleen91c6d402005-07-28 21:15:39 -0700657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658device_initcall(mce_init_device);