diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-04-08 06:31:17 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-05-28 12:24:09 -0400 |
commit | e9eee03e99d519599eb615c3e251d5f6cc4be57d (patch) | |
tree | a6db26923fe4b3e570513725a963880c1b74d50c /arch/x86 | |
parent | 13503fa9137d9708d52214e9506c671dbf2fbdce (diff) |
x86, mce: clean up mce_64.c
This file has been modified many times along the years, by multiple
authors, so the general style and structure has diverged in a number
of areas making this file hard to read.
So fix the coding style match that of the rest of the x86 arch code.
[ Impact: cleanup ]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce_64.c | 247 |
1 files changed, 149 insertions, 98 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce_64.c b/arch/x86/kernel/cpu/mcheck/mce_64.c index 77effb55afe7..1491246c4d69 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_64.c | |||
@@ -1,46 +1,47 @@ | |||
1 | /* | 1 | /* |
2 | * Machine check handler. | 2 | * Machine check handler. |
3 | * | ||
3 | * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs. | 4 | * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs. |
4 | * Rest from unknown author(s). | 5 | * Rest from unknown author(s). |
5 | * 2004 Andi Kleen. Rewrote most of it. | 6 | * 2004 Andi Kleen. Rewrote most of it. |
6 | * Copyright 2008 Intel Corporation | 7 | * Copyright 2008 Intel Corporation |
7 | * Author: Andi Kleen | 8 | * Author: Andi Kleen |
8 | */ | 9 | */ |
9 | 10 | #include <linux/thread_info.h> | |
10 | #include <linux/init.h> | 11 | #include <linux/capability.h> |
11 | #include <linux/types.h> | 12 | #include <linux/miscdevice.h> |
12 | #include <linux/kernel.h> | 13 | #include <linux/ratelimit.h> |
13 | #include <linux/sched.h> | 14 | #include <linux/kallsyms.h> |
15 | #include <linux/rcupdate.h> | ||
14 | #include <linux/smp_lock.h> | 16 | #include <linux/smp_lock.h> |
17 | #include <linux/kobject.h> | ||
18 | #include <linux/kdebug.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/percpu.h> | ||
15 | #include <linux/string.h> | 21 | #include <linux/string.h> |
16 | #include <linux/rcupdate.h> | ||
17 | #include <linux/kallsyms.h> | ||
18 | #include <linux/sysdev.h> | 22 | #include <linux/sysdev.h> |
19 | #include <linux/miscdevice.h> | ||
20 | #include <linux/fs.h> | ||
21 | #include <linux/capability.h> | ||
22 | #include <linux/cpu.h> | ||
23 | #include <linux/percpu.h> | ||
24 | #include <linux/poll.h> | ||
25 | #include <linux/thread_info.h> | ||
26 | #include <linux/ctype.h> | 23 | #include <linux/ctype.h> |
27 | #include <linux/kmod.h> | 24 | #include <linux/sched.h> |
28 | #include <linux/kdebug.h> | ||
29 | #include <linux/kobject.h> | ||
30 | #include <linux/sysfs.h> | 25 | #include <linux/sysfs.h> |
31 | #include <linux/ratelimit.h> | 26 | #include <linux/types.h> |
27 | #include <linux/init.h> | ||
28 | #include <linux/kmod.h> | ||
29 | #include <linux/poll.h> | ||
30 | #include <linux/cpu.h> | ||
31 | #include <linux/fs.h> | ||
32 | |||
32 | #include <asm/processor.h> | 33 | #include <asm/processor.h> |
33 | #include <asm/msr.h> | ||
34 | #include <asm/mce.h> | ||
35 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
36 | #include <asm/smp.h> | ||
37 | #include <asm/idle.h> | 35 | #include <asm/idle.h> |
36 | #include <asm/mce.h> | ||
37 | #include <asm/msr.h> | ||
38 | #include <asm/smp.h> | ||
38 | 39 | ||
39 | #define MISC_MCELOG_MINOR 227 | 40 | #define MISC_MCELOG_MINOR 227 |
40 | 41 | ||
41 | atomic_t mce_entry; | 42 | atomic_t mce_entry; |
42 | 43 | ||
43 | static int mce_dont_init; | 44 | static int mce_dont_init; |
44 | 45 | ||
45 | /* | 46 | /* |
46 | * Tolerant levels: | 47 | * Tolerant levels: |
@@ -49,16 +50,16 @@ static int mce_dont_init; | |||
49 | * 2: SIGBUS or log uncorrected errors (if possible), log corrected errors | 50 | * 2: SIGBUS or log uncorrected errors (if possible), log corrected errors |
50 | * 3: never panic or SIGBUS, log all errors (for testing only) | 51 | * 3: never panic or SIGBUS, log all errors (for testing only) |
51 | */ | 52 | */ |
52 | static int tolerant = 1; | 53 | static int tolerant = 1; |
53 | static int banks; | 54 | static int banks; |
54 | static u64 *bank; | 55 | static u64 *bank; |
55 | static unsigned long notify_user; | 56 | static unsigned long notify_user; |
56 | static int rip_msr; | 57 | static int rip_msr; |
57 | static int mce_bootlog = -1; | 58 | static int mce_bootlog = -1; |
58 | static atomic_t mce_events; | 59 | static atomic_t mce_events; |
59 | 60 | ||
60 | static char trigger[128]; | 61 | static char trigger[128]; |
61 | static char *trigger_argv[2] = { trigger, NULL }; | 62 | static char *trigger_argv[2] = { trigger, NULL }; |
62 | 63 | ||
63 | static DECLARE_WAIT_QUEUE_HEAD(mce_wait); | 64 | static DECLARE_WAIT_QUEUE_HEAD(mce_wait); |
64 | 65 | ||
@@ -89,19 +90,23 @@ static struct mce_log mcelog = { | |||
89 | void mce_log(struct mce *mce) | 90 | void mce_log(struct mce *mce) |
90 | { | 91 | { |
91 | unsigned next, entry; | 92 | unsigned next, entry; |
93 | |||
92 | atomic_inc(&mce_events); | 94 | atomic_inc(&mce_events); |
93 | mce->finished = 0; | 95 | mce->finished = 0; |
94 | wmb(); | 96 | wmb(); |
95 | for (;;) { | 97 | for (;;) { |
96 | entry = rcu_dereference(mcelog.next); | 98 | entry = rcu_dereference(mcelog.next); |
97 | for (;;) { | 99 | for (;;) { |
98 | /* When the buffer fills up discard new entries. Assume | 100 | /* |
99 | that the earlier errors are the more interesting. */ | 101 | * When the buffer fills up discard new entries. |
102 | * Assume that the earlier errors are the more | ||
103 | * interesting ones: | ||
104 | */ | ||
100 | if (entry >= MCE_LOG_LEN) { | 105 | if (entry >= MCE_LOG_LEN) { |
101 | set_bit(MCE_OVERFLOW, (unsigned long *)&mcelog.flags); | 106 | set_bit(MCE_OVERFLOW, (unsigned long *)&mcelog.flags); |
102 | return; | 107 | return; |
103 | } | 108 | } |
104 | /* Old left over entry. Skip. */ | 109 | /* Old left over entry. Skip: */ |
105 | if (mcelog.entry[entry].finished) { | 110 | if (mcelog.entry[entry].finished) { |
106 | entry++; | 111 | entry++; |
107 | continue; | 112 | continue; |
@@ -264,12 +269,12 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) | |||
264 | * implies that most kernel services cannot be safely used. Don't even | 269 | * implies that most kernel services cannot be safely used. Don't even |
265 | * think about putting a printk in there! | 270 | * think about putting a printk in there! |
266 | */ | 271 | */ |
267 | void do_machine_check(struct pt_regs * regs, long error_code) | 272 | void do_machine_check(struct pt_regs *regs, long error_code) |
268 | { | 273 | { |
269 | struct mce m, panicm; | 274 | struct mce m, panicm; |
275 | int panicm_found = 0; | ||
270 | u64 mcestart = 0; | 276 | u64 mcestart = 0; |
271 | int i; | 277 | int i; |
272 | int panicm_found = 0; | ||
273 | /* | 278 | /* |
274 | * If no_way_out gets set, there is no safe way to recover from this | 279 | * If no_way_out gets set, there is no safe way to recover from this |
275 | * MCE. If tolerant is cranked up, we'll try anyway. | 280 | * MCE. If tolerant is cranked up, we'll try anyway. |
@@ -293,6 +298,7 @@ void do_machine_check(struct pt_regs * regs, long error_code) | |||
293 | mce_setup(&m); | 298 | mce_setup(&m); |
294 | 299 | ||
295 | rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus); | 300 | rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus); |
301 | |||
296 | /* if the restart IP is not valid, we're done for */ | 302 | /* if the restart IP is not valid, we're done for */ |
297 | if (!(m.mcgstatus & MCG_STATUS_RIPV)) | 303 | if (!(m.mcgstatus & MCG_STATUS_RIPV)) |
298 | no_way_out = 1; | 304 | no_way_out = 1; |
@@ -356,23 +362,29 @@ void do_machine_check(struct pt_regs * regs, long error_code) | |||
356 | mce_get_rip(&m, regs); | 362 | mce_get_rip(&m, regs); |
357 | mce_log(&m); | 363 | mce_log(&m); |
358 | 364 | ||
359 | /* Did this bank cause the exception? */ | 365 | /* |
360 | /* Assume that the bank with uncorrectable errors did it, | 366 | * Did this bank cause the exception? |
361 | and that there is only a single one. */ | 367 | * |
362 | if ((m.status & MCI_STATUS_UC) && (m.status & MCI_STATUS_EN)) { | 368 | * Assume that the bank with uncorrectable errors did it, |
369 | * and that there is only a single one: | ||
370 | */ | ||
371 | if ((m.status & MCI_STATUS_UC) && | ||
372 | (m.status & MCI_STATUS_EN)) { | ||
363 | panicm = m; | 373 | panicm = m; |
364 | panicm_found = 1; | 374 | panicm_found = 1; |
365 | } | 375 | } |
366 | } | 376 | } |
367 | 377 | ||
368 | /* If we didn't find an uncorrectable error, pick | 378 | /* |
369 | the last one (shouldn't happen, just being safe). */ | 379 | * If we didn't find an uncorrectable error, pick |
380 | * the last one (shouldn't happen, just being safe). | ||
381 | */ | ||
370 | if (!panicm_found) | 382 | if (!panicm_found) |
371 | panicm = m; | 383 | panicm = m; |
372 | 384 | ||
373 | /* | 385 | /* |
374 | * If we have decided that we just CAN'T continue, and the user | 386 | * If we have decided that we just CAN'T continue, and the user |
375 | * has not set tolerant to an insane level, give up and die. | 387 | * has not set tolerant to an insane level, give up and die. |
376 | */ | 388 | */ |
377 | if (no_way_out && tolerant < 3) | 389 | if (no_way_out && tolerant < 3) |
378 | mce_panic("Machine check", &panicm, mcestart); | 390 | mce_panic("Machine check", &panicm, mcestart); |
@@ -451,10 +463,9 @@ void mce_log_therm_throt_event(__u64 status) | |||
451 | * poller finds an MCE, poll 2x faster. When the poller finds no more | 463 | * poller finds an MCE, poll 2x faster. When the poller finds no more |
452 | * errors, poll 2x slower (up to check_interval seconds). | 464 | * errors, poll 2x slower (up to check_interval seconds). |
453 | */ | 465 | */ |
454 | |||
455 | static int check_interval = 5 * 60; /* 5 minutes */ | 466 | static int check_interval = 5 * 60; /* 5 minutes */ |
467 | |||
456 | static DEFINE_PER_CPU(int, next_interval); /* in jiffies */ | 468 | static DEFINE_PER_CPU(int, next_interval); /* in jiffies */ |
457 | static void mcheck_timer(unsigned long); | ||
458 | static DEFINE_PER_CPU(struct timer_list, mce_timer); | 469 | static DEFINE_PER_CPU(struct timer_list, mce_timer); |
459 | 470 | ||
460 | static void mcheck_timer(unsigned long data) | 471 | static void mcheck_timer(unsigned long data) |
@@ -464,9 +475,10 @@ static void mcheck_timer(unsigned long data) | |||
464 | 475 | ||
465 | WARN_ON(smp_processor_id() != data); | 476 | WARN_ON(smp_processor_id() != data); |
466 | 477 | ||
467 | if (mce_available(¤t_cpu_data)) | 478 | if (mce_available(¤t_cpu_data)) { |
468 | machine_check_poll(MCP_TIMESTAMP, | 479 | machine_check_poll(MCP_TIMESTAMP, |
469 | &__get_cpu_var(mce_poll_banks)); | 480 | &__get_cpu_var(mce_poll_banks)); |
481 | } | ||
470 | 482 | ||
471 | /* | 483 | /* |
472 | * Alert userspace if needed. If we logged an MCE, reduce the | 484 | * Alert userspace if needed. If we logged an MCE, reduce the |
@@ -501,6 +513,7 @@ int mce_notify_user(void) | |||
501 | static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); | 513 | static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); |
502 | 514 | ||
503 | clear_thread_flag(TIF_MCE_NOTIFY); | 515 | clear_thread_flag(TIF_MCE_NOTIFY); |
516 | |||
504 | if (test_and_clear_bit(0, ¬ify_user)) { | 517 | if (test_and_clear_bit(0, ¬ify_user)) { |
505 | wake_up_interruptible(&mce_wait); | 518 | wake_up_interruptible(&mce_wait); |
506 | 519 | ||
@@ -520,9 +533,10 @@ int mce_notify_user(void) | |||
520 | return 0; | 533 | return 0; |
521 | } | 534 | } |
522 | 535 | ||
523 | /* see if the idle task needs to notify userspace */ | 536 | /* see if the idle task needs to notify userspace: */ |
524 | static int | 537 | static int |
525 | mce_idle_callback(struct notifier_block *nfb, unsigned long action, void *junk) | 538 | mce_idle_callback(struct notifier_block *nfb, unsigned long action, |
539 | void *unused) | ||
526 | { | 540 | { |
527 | /* IDLE_END should be safe - interrupts are back on */ | 541 | /* IDLE_END should be safe - interrupts are back on */ |
528 | if (action == IDLE_END && test_thread_flag(TIF_MCE_NOTIFY)) | 542 | if (action == IDLE_END && test_thread_flag(TIF_MCE_NOTIFY)) |
@@ -532,7 +546,7 @@ mce_idle_callback(struct notifier_block *nfb, unsigned long action, void *junk) | |||
532 | } | 546 | } |
533 | 547 | ||
534 | static struct notifier_block mce_idle_notifier = { | 548 | static struct notifier_block mce_idle_notifier = { |
535 | .notifier_call = mce_idle_callback, | 549 | .notifier_call = mce_idle_callback, |
536 | }; | 550 | }; |
537 | 551 | ||
538 | static __init int periodic_mcheck_init(void) | 552 | static __init int periodic_mcheck_init(void) |
@@ -547,8 +561,8 @@ __initcall(periodic_mcheck_init); | |||
547 | */ | 561 | */ |
548 | static int mce_cap_init(void) | 562 | static int mce_cap_init(void) |
549 | { | 563 | { |
550 | u64 cap; | ||
551 | unsigned b; | 564 | unsigned b; |
565 | u64 cap; | ||
552 | 566 | ||
553 | rdmsrl(MSR_IA32_MCG_CAP, cap); | 567 | rdmsrl(MSR_IA32_MCG_CAP, cap); |
554 | b = cap & 0xff; | 568 | b = cap & 0xff; |
@@ -578,9 +592,9 @@ static int mce_cap_init(void) | |||
578 | 592 | ||
579 | static void mce_init(void *dummy) | 593 | static void mce_init(void *dummy) |
580 | { | 594 | { |
595 | mce_banks_t all_banks; | ||
581 | u64 cap; | 596 | u64 cap; |
582 | int i; | 597 | int i; |
583 | mce_banks_t all_banks; | ||
584 | 598 | ||
585 | /* | 599 | /* |
586 | * Log the machine checks left over from the previous reset. | 600 | * Log the machine checks left over from the previous reset. |
@@ -605,14 +619,21 @@ static void mce_cpu_quirks(struct cpuinfo_x86 *c) | |||
605 | { | 619 | { |
606 | /* This should be disabled by the BIOS, but isn't always */ | 620 | /* This should be disabled by the BIOS, but isn't always */ |
607 | if (c->x86_vendor == X86_VENDOR_AMD) { | 621 | if (c->x86_vendor == X86_VENDOR_AMD) { |
608 | if (c->x86 == 15 && banks > 4) | 622 | if (c->x86 == 15 && banks > 4) { |
609 | /* disable GART TBL walk error reporting, which trips off | 623 | /* |
610 | incorrectly with the IOMMU & 3ware & Cerberus. */ | 624 | * disable GART TBL walk error reporting, which |
625 | * trips off incorrectly with the IOMMU & 3ware | ||
626 | * & Cerberus: | ||
627 | */ | ||
611 | clear_bit(10, (unsigned long *)&bank[4]); | 628 | clear_bit(10, (unsigned long *)&bank[4]); |
612 | if(c->x86 <= 17 && mce_bootlog < 0) | 629 | } |
613 | /* Lots of broken BIOS around that don't clear them | 630 | if (c->x86 <= 17 && mce_bootlog < 0) { |
614 | by default and leave crap in there. Don't log. */ | 631 | /* |
632 | * Lots of broken BIOS around that don't clear them | ||
633 | * by default and leave crap in there. Don't log: | ||
634 | */ | ||
615 | mce_bootlog = 0; | 635 | mce_bootlog = 0; |
636 | } | ||
616 | } | 637 | } |
617 | 638 | ||
618 | } | 639 | } |
@@ -646,7 +667,7 @@ static void mce_init_timer(void) | |||
646 | 667 | ||
647 | /* | 668 | /* |
648 | * Called for each booted CPU to set up machine checks. | 669 | * Called for each booted CPU to set up machine checks. |
649 | * Must be called with preempt off. | 670 | * Must be called with preempt off: |
650 | */ | 671 | */ |
651 | void __cpuinit mcheck_init(struct cpuinfo_x86 *c) | 672 | void __cpuinit mcheck_init(struct cpuinfo_x86 *c) |
652 | { | 673 | { |
@@ -669,8 +690,8 @@ void __cpuinit mcheck_init(struct cpuinfo_x86 *c) | |||
669 | */ | 690 | */ |
670 | 691 | ||
671 | static DEFINE_SPINLOCK(mce_state_lock); | 692 | static DEFINE_SPINLOCK(mce_state_lock); |
672 | static int open_count; /* #times opened */ | 693 | static int open_count; /* #times opened */ |
673 | static int open_exclu; /* already open exclusive? */ | 694 | static int open_exclu; /* already open exclusive? */ |
674 | 695 | ||
675 | static int mce_open(struct inode *inode, struct file *file) | 696 | static int mce_open(struct inode *inode, struct file *file) |
676 | { | 697 | { |
@@ -680,6 +701,7 @@ static int mce_open(struct inode *inode, struct file *file) | |||
680 | if (open_exclu || (open_count && (file->f_flags & O_EXCL))) { | 701 | if (open_exclu || (open_count && (file->f_flags & O_EXCL))) { |
681 | spin_unlock(&mce_state_lock); | 702 | spin_unlock(&mce_state_lock); |
682 | unlock_kernel(); | 703 | unlock_kernel(); |
704 | |||
683 | return -EBUSY; | 705 | return -EBUSY; |
684 | } | 706 | } |
685 | 707 | ||
@@ -712,13 +734,14 @@ static void collect_tscs(void *data) | |||
712 | rdtscll(cpu_tsc[smp_processor_id()]); | 734 | rdtscll(cpu_tsc[smp_processor_id()]); |
713 | } | 735 | } |
714 | 736 | ||
737 | static DEFINE_MUTEX(mce_read_mutex); | ||
738 | |||
715 | static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, | 739 | static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, |
716 | loff_t *off) | 740 | loff_t *off) |
717 | { | 741 | { |
742 | char __user *buf = ubuf; | ||
718 | unsigned long *cpu_tsc; | 743 | unsigned long *cpu_tsc; |
719 | static DEFINE_MUTEX(mce_read_mutex); | ||
720 | unsigned prev, next; | 744 | unsigned prev, next; |
721 | char __user *buf = ubuf; | ||
722 | int i, err; | 745 | int i, err; |
723 | 746 | ||
724 | cpu_tsc = kmalloc(nr_cpu_ids * sizeof(long), GFP_KERNEL); | 747 | cpu_tsc = kmalloc(nr_cpu_ids * sizeof(long), GFP_KERNEL); |
@@ -732,6 +755,7 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, | |||
732 | if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) { | 755 | if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) { |
733 | mutex_unlock(&mce_read_mutex); | 756 | mutex_unlock(&mce_read_mutex); |
734 | kfree(cpu_tsc); | 757 | kfree(cpu_tsc); |
758 | |||
735 | return -EINVAL; | 759 | return -EINVAL; |
736 | } | 760 | } |
737 | 761 | ||
@@ -770,6 +794,7 @@ timeout: | |||
770 | * synchronize. | 794 | * synchronize. |
771 | */ | 795 | */ |
772 | on_each_cpu(collect_tscs, cpu_tsc, 1); | 796 | on_each_cpu(collect_tscs, cpu_tsc, 1); |
797 | |||
773 | for (i = next; i < MCE_LOG_LEN; i++) { | 798 | for (i = next; i < MCE_LOG_LEN; i++) { |
774 | if (mcelog.entry[i].finished && | 799 | if (mcelog.entry[i].finished && |
775 | mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) { | 800 | mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) { |
@@ -782,6 +807,7 @@ timeout: | |||
782 | } | 807 | } |
783 | mutex_unlock(&mce_read_mutex); | 808 | mutex_unlock(&mce_read_mutex); |
784 | kfree(cpu_tsc); | 809 | kfree(cpu_tsc); |
810 | |||
785 | return err ? -EFAULT : buf - ubuf; | 811 | return err ? -EFAULT : buf - ubuf; |
786 | } | 812 | } |
787 | 813 | ||
@@ -799,6 +825,7 @@ static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
799 | 825 | ||
800 | if (!capable(CAP_SYS_ADMIN)) | 826 | if (!capable(CAP_SYS_ADMIN)) |
801 | return -EPERM; | 827 | return -EPERM; |
828 | |||
802 | switch (cmd) { | 829 | switch (cmd) { |
803 | case MCE_GET_RECORD_LEN: | 830 | case MCE_GET_RECORD_LEN: |
804 | return put_user(sizeof(struct mce), p); | 831 | return put_user(sizeof(struct mce), p); |
@@ -810,6 +837,7 @@ static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
810 | do { | 837 | do { |
811 | flags = mcelog.flags; | 838 | flags = mcelog.flags; |
812 | } while (cmpxchg(&mcelog.flags, flags, 0) != flags); | 839 | } while (cmpxchg(&mcelog.flags, flags, 0) != flags); |
840 | |||
813 | return put_user(flags, p); | 841 | return put_user(flags, p); |
814 | } | 842 | } |
815 | default: | 843 | default: |
@@ -818,11 +846,11 @@ static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
818 | } | 846 | } |
819 | 847 | ||
820 | static const struct file_operations mce_chrdev_ops = { | 848 | static const struct file_operations mce_chrdev_ops = { |
821 | .open = mce_open, | 849 | .open = mce_open, |
822 | .release = mce_release, | 850 | .release = mce_release, |
823 | .read = mce_read, | 851 | .read = mce_read, |
824 | .poll = mce_poll, | 852 | .poll = mce_poll, |
825 | .unlocked_ioctl = mce_ioctl, | 853 | .unlocked_ioctl = mce_ioctl, |
826 | }; | 854 | }; |
827 | 855 | ||
828 | static struct miscdevice mce_log_device = { | 856 | static struct miscdevice mce_log_device = { |
@@ -891,13 +919,16 @@ static int mce_shutdown(struct sys_device *dev) | |||
891 | return mce_disable(); | 919 | return mce_disable(); |
892 | } | 920 | } |
893 | 921 | ||
894 | /* On resume clear all MCE state. Don't want to see leftovers from the BIOS. | 922 | /* |
895 | Only one CPU is active at this time, the others get readded later using | 923 | * On resume clear all MCE state. Don't want to see leftovers from the BIOS. |
896 | CPU hotplug. */ | 924 | * Only one CPU is active at this time, the others get re-added later using |
925 | * CPU hotplug: | ||
926 | */ | ||
897 | static int mce_resume(struct sys_device *dev) | 927 | static int mce_resume(struct sys_device *dev) |
898 | { | 928 | { |
899 | mce_init(NULL); | 929 | mce_init(NULL); |
900 | mce_cpu_features(¤t_cpu_data); | 930 | mce_cpu_features(¤t_cpu_data); |
931 | |||
901 | return 0; | 932 | return 0; |
902 | } | 933 | } |
903 | 934 | ||
@@ -916,14 +947,16 @@ static void mce_restart(void) | |||
916 | } | 947 | } |
917 | 948 | ||
918 | static struct sysdev_class mce_sysclass = { | 949 | static struct sysdev_class mce_sysclass = { |
919 | .suspend = mce_suspend, | 950 | .suspend = mce_suspend, |
920 | .shutdown = mce_shutdown, | 951 | .shutdown = mce_shutdown, |
921 | .resume = mce_resume, | 952 | .resume = mce_resume, |
922 | .name = "machinecheck", | 953 | .name = "machinecheck", |
923 | }; | 954 | }; |
924 | 955 | ||
925 | DEFINE_PER_CPU(struct sys_device, device_mce); | 956 | DEFINE_PER_CPU(struct sys_device, device_mce); |
926 | void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu) __cpuinitdata; | 957 | |
958 | __cpuinitdata | ||
959 | void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); | ||
927 | 960 | ||
928 | /* Why are there no generic functions for this? */ | 961 | /* Why are there no generic functions for this? */ |
929 | #define ACCESSOR(name, var, start) \ | 962 | #define ACCESSOR(name, var, start) \ |
@@ -937,9 +970,12 @@ void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu) __cpuinit | |||
937 | const char *buf, size_t siz) { \ | 970 | const char *buf, size_t siz) { \ |
938 | char *end; \ | 971 | char *end; \ |
939 | unsigned long new = simple_strtoul(buf, &end, 0); \ | 972 | unsigned long new = simple_strtoul(buf, &end, 0); \ |
940 | if (end == buf) return -EINVAL; \ | 973 | \ |
974 | if (end == buf) \ | ||
975 | return -EINVAL; \ | ||
941 | var = new; \ | 976 | var = new; \ |
942 | start; \ | 977 | start; \ |
978 | \ | ||
943 | return end-buf; \ | 979 | return end-buf; \ |
944 | } \ | 980 | } \ |
945 | static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name); | 981 | static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name); |
@@ -950,6 +986,7 @@ static ssize_t show_bank(struct sys_device *s, struct sysdev_attribute *attr, | |||
950 | char *buf) | 986 | char *buf) |
951 | { | 987 | { |
952 | u64 b = bank[attr - bank_attrs]; | 988 | u64 b = bank[attr - bank_attrs]; |
989 | |||
953 | return sprintf(buf, "%llx\n", b); | 990 | return sprintf(buf, "%llx\n", b); |
954 | } | 991 | } |
955 | 992 | ||
@@ -958,15 +995,18 @@ static ssize_t set_bank(struct sys_device *s, struct sysdev_attribute *attr, | |||
958 | { | 995 | { |
959 | char *end; | 996 | char *end; |
960 | u64 new = simple_strtoull(buf, &end, 0); | 997 | u64 new = simple_strtoull(buf, &end, 0); |
998 | |||
961 | if (end == buf) | 999 | if (end == buf) |
962 | return -EINVAL; | 1000 | return -EINVAL; |
1001 | |||
963 | bank[attr - bank_attrs] = new; | 1002 | bank[attr - bank_attrs] = new; |
964 | mce_restart(); | 1003 | mce_restart(); |
1004 | |||
965 | return end-buf; | 1005 | return end-buf; |
966 | } | 1006 | } |
967 | 1007 | ||
968 | static ssize_t show_trigger(struct sys_device *s, struct sysdev_attribute *attr, | 1008 | static ssize_t |
969 | char *buf) | 1009 | show_trigger(struct sys_device *s, struct sysdev_attribute *attr, char *buf) |
970 | { | 1010 | { |
971 | strcpy(buf, trigger); | 1011 | strcpy(buf, trigger); |
972 | strcat(buf, "\n"); | 1012 | strcat(buf, "\n"); |
@@ -974,21 +1014,27 @@ static ssize_t show_trigger(struct sys_device *s, struct sysdev_attribute *attr, | |||
974 | } | 1014 | } |
975 | 1015 | ||
976 | static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr, | 1016 | static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr, |
977 | const char *buf,size_t siz) | 1017 | const char *buf, size_t siz) |
978 | { | 1018 | { |
979 | char *p; | 1019 | char *p; |
980 | int len; | 1020 | int len; |
1021 | |||
981 | strncpy(trigger, buf, sizeof(trigger)); | 1022 | strncpy(trigger, buf, sizeof(trigger)); |
982 | trigger[sizeof(trigger)-1] = 0; | 1023 | trigger[sizeof(trigger)-1] = 0; |
983 | len = strlen(trigger); | 1024 | len = strlen(trigger); |
984 | p = strchr(trigger, '\n'); | 1025 | p = strchr(trigger, '\n'); |
985 | if (*p) *p = 0; | 1026 | |
1027 | if (*p) | ||
1028 | *p = 0; | ||
1029 | |||
986 | return len; | 1030 | return len; |
987 | } | 1031 | } |
988 | 1032 | ||
989 | static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger); | 1033 | static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger); |
990 | static SYSDEV_INT_ATTR(tolerant, 0644, tolerant); | 1034 | static SYSDEV_INT_ATTR(tolerant, 0644, tolerant); |
991 | ACCESSOR(check_interval,check_interval,mce_restart()) | 1035 | |
1036 | ACCESSOR(check_interval, check_interval, mce_restart()) | ||
1037 | |||
992 | static struct sysdev_attribute *mce_attributes[] = { | 1038 | static struct sysdev_attribute *mce_attributes[] = { |
993 | &attr_tolerant.attr, &attr_check_interval, &attr_trigger, | 1039 | &attr_tolerant.attr, &attr_check_interval, &attr_trigger, |
994 | NULL | 1040 | NULL |
@@ -996,7 +1042,7 @@ static struct sysdev_attribute *mce_attributes[] = { | |||
996 | 1042 | ||
997 | static cpumask_var_t mce_device_initialized; | 1043 | static cpumask_var_t mce_device_initialized; |
998 | 1044 | ||
999 | /* Per cpu sysdev init. All of the cpus still share the same ctl bank */ | 1045 | /* Per cpu sysdev init. All of the cpus still share the same ctrl bank: */ |
1000 | static __cpuinit int mce_create_device(unsigned int cpu) | 1046 | static __cpuinit int mce_create_device(unsigned int cpu) |
1001 | { | 1047 | { |
1002 | int err; | 1048 | int err; |
@@ -1006,15 +1052,15 @@ static __cpuinit int mce_create_device(unsigned int cpu) | |||
1006 | return -EIO; | 1052 | return -EIO; |
1007 | 1053 | ||
1008 | memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject)); | 1054 | memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject)); |
1009 | per_cpu(device_mce,cpu).id = cpu; | 1055 | per_cpu(device_mce, cpu).id = cpu; |
1010 | per_cpu(device_mce,cpu).cls = &mce_sysclass; | 1056 | per_cpu(device_mce, cpu).cls = &mce_sysclass; |
1011 | 1057 | ||
1012 | err = sysdev_register(&per_cpu(device_mce,cpu)); | 1058 | err = sysdev_register(&per_cpu(device_mce, cpu)); |
1013 | if (err) | 1059 | if (err) |
1014 | return err; | 1060 | return err; |
1015 | 1061 | ||
1016 | for (i = 0; mce_attributes[i]; i++) { | 1062 | for (i = 0; mce_attributes[i]; i++) { |
1017 | err = sysdev_create_file(&per_cpu(device_mce,cpu), | 1063 | err = sysdev_create_file(&per_cpu(device_mce, cpu), |
1018 | mce_attributes[i]); | 1064 | mce_attributes[i]); |
1019 | if (err) | 1065 | if (err) |
1020 | goto error; | 1066 | goto error; |
@@ -1035,10 +1081,10 @@ error2: | |||
1035 | } | 1081 | } |
1036 | error: | 1082 | error: |
1037 | while (--i >= 0) { | 1083 | while (--i >= 0) { |
1038 | sysdev_remove_file(&per_cpu(device_mce,cpu), | 1084 | sysdev_remove_file(&per_cpu(device_mce, cpu), |
1039 | mce_attributes[i]); | 1085 | mce_attributes[i]); |
1040 | } | 1086 | } |
1041 | sysdev_unregister(&per_cpu(device_mce,cpu)); | 1087 | sysdev_unregister(&per_cpu(device_mce, cpu)); |
1042 | 1088 | ||
1043 | return err; | 1089 | return err; |
1044 | } | 1090 | } |
@@ -1051,12 +1097,12 @@ static __cpuinit void mce_remove_device(unsigned int cpu) | |||
1051 | return; | 1097 | return; |
1052 | 1098 | ||
1053 | for (i = 0; mce_attributes[i]; i++) | 1099 | for (i = 0; mce_attributes[i]; i++) |
1054 | sysdev_remove_file(&per_cpu(device_mce,cpu), | 1100 | sysdev_remove_file(&per_cpu(device_mce, cpu), |
1055 | mce_attributes[i]); | 1101 | mce_attributes[i]); |
1056 | for (i = 0; i < banks; i++) | 1102 | for (i = 0; i < banks; i++) |
1057 | sysdev_remove_file(&per_cpu(device_mce, cpu), | 1103 | sysdev_remove_file(&per_cpu(device_mce, cpu), |
1058 | &bank_attrs[i]); | 1104 | &bank_attrs[i]); |
1059 | sysdev_unregister(&per_cpu(device_mce,cpu)); | 1105 | sysdev_unregister(&per_cpu(device_mce, cpu)); |
1060 | cpumask_clear_cpu(cpu, mce_device_initialized); | 1106 | cpumask_clear_cpu(cpu, mce_device_initialized); |
1061 | } | 1107 | } |
1062 | 1108 | ||
@@ -1076,11 +1122,12 @@ static void mce_disable_cpu(void *h) | |||
1076 | 1122 | ||
1077 | static void mce_reenable_cpu(void *h) | 1123 | static void mce_reenable_cpu(void *h) |
1078 | { | 1124 | { |
1079 | int i; | ||
1080 | unsigned long action = *(unsigned long *)h; | 1125 | unsigned long action = *(unsigned long *)h; |
1126 | int i; | ||
1081 | 1127 | ||
1082 | if (!mce_available(¤t_cpu_data)) | 1128 | if (!mce_available(¤t_cpu_data)) |
1083 | return; | 1129 | return; |
1130 | |||
1084 | if (!(action & CPU_TASKS_FROZEN)) | 1131 | if (!(action & CPU_TASKS_FROZEN)) |
1085 | cmci_reenable(); | 1132 | cmci_reenable(); |
1086 | for (i = 0; i < banks; i++) | 1133 | for (i = 0; i < banks; i++) |
@@ -1088,8 +1135,8 @@ static void mce_reenable_cpu(void *h) | |||
1088 | } | 1135 | } |
1089 | 1136 | ||
1090 | /* Get notified when a cpu comes on/off. Be hotplug friendly. */ | 1137 | /* Get notified when a cpu comes on/off. Be hotplug friendly. */ |
1091 | static int __cpuinit mce_cpu_callback(struct notifier_block *nfb, | 1138 | static int __cpuinit |
1092 | unsigned long action, void *hcpu) | 1139 | mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) |
1093 | { | 1140 | { |
1094 | unsigned int cpu = (unsigned long)hcpu; | 1141 | unsigned int cpu = (unsigned long)hcpu; |
1095 | struct timer_list *t = &per_cpu(mce_timer, cpu); | 1142 | struct timer_list *t = &per_cpu(mce_timer, cpu); |
@@ -1142,12 +1189,14 @@ static __init int mce_init_banks(void) | |||
1142 | 1189 | ||
1143 | for (i = 0; i < banks; i++) { | 1190 | for (i = 0; i < banks; i++) { |
1144 | struct sysdev_attribute *a = &bank_attrs[i]; | 1191 | struct sysdev_attribute *a = &bank_attrs[i]; |
1145 | a->attr.name = kasprintf(GFP_KERNEL, "bank%d", i); | 1192 | |
1193 | a->attr.name = kasprintf(GFP_KERNEL, "bank%d", i); | ||
1146 | if (!a->attr.name) | 1194 | if (!a->attr.name) |
1147 | goto nomem; | 1195 | goto nomem; |
1148 | a->attr.mode = 0644; | 1196 | |
1149 | a->show = show_bank; | 1197 | a->attr.mode = 0644; |
1150 | a->store = set_bank; | 1198 | a->show = show_bank; |
1199 | a->store = set_bank; | ||
1151 | } | 1200 | } |
1152 | return 0; | 1201 | return 0; |
1153 | 1202 | ||
@@ -1156,6 +1205,7 @@ nomem: | |||
1156 | kfree(bank_attrs[i].attr.name); | 1205 | kfree(bank_attrs[i].attr.name); |
1157 | kfree(bank_attrs); | 1206 | kfree(bank_attrs); |
1158 | bank_attrs = NULL; | 1207 | bank_attrs = NULL; |
1208 | |||
1159 | return -ENOMEM; | 1209 | return -ENOMEM; |
1160 | } | 1210 | } |
1161 | 1211 | ||
@@ -1185,6 +1235,7 @@ static __init int mce_init_device(void) | |||
1185 | 1235 | ||
1186 | register_hotcpu_notifier(&mce_cpu_notifier); | 1236 | register_hotcpu_notifier(&mce_cpu_notifier); |
1187 | misc_register(&mce_log_device); | 1237 | misc_register(&mce_log_device); |
1238 | |||
1188 | return err; | 1239 | return err; |
1189 | } | 1240 | } |
1190 | 1241 | ||