diff options
Diffstat (limited to 'arch/x86_64/kernel/mce.c')
-rw-r--r-- | arch/x86_64/kernel/mce.c | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 8aa56736cde3..969365c0771b 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/cpu.h> | 18 | #include <linux/cpu.h> |
19 | #include <linux/percpu.h> | 19 | #include <linux/percpu.h> |
20 | #include <linux/ctype.h> | ||
20 | #include <asm/processor.h> | 21 | #include <asm/processor.h> |
21 | #include <asm/msr.h> | 22 | #include <asm/msr.h> |
22 | #include <asm/mce.h> | 23 | #include <asm/mce.h> |
@@ -56,15 +57,19 @@ void mce_log(struct mce *mce) | |||
56 | smp_wmb(); | 57 | smp_wmb(); |
57 | for (;;) { | 58 | for (;;) { |
58 | entry = rcu_dereference(mcelog.next); | 59 | entry = rcu_dereference(mcelog.next); |
59 | /* When the buffer fills up discard new entries. Assume | 60 | for (;;) { |
60 | that the earlier errors are the more interesting. */ | 61 | /* When the buffer fills up discard new entries. Assume |
61 | if (entry >= MCE_LOG_LEN) { | 62 | that the earlier errors are the more interesting. */ |
62 | set_bit(MCE_OVERFLOW, &mcelog.flags); | 63 | if (entry >= MCE_LOG_LEN) { |
63 | return; | 64 | set_bit(MCE_OVERFLOW, &mcelog.flags); |
65 | return; | ||
66 | } | ||
67 | /* Old left over entry. Skip. */ | ||
68 | if (mcelog.entry[entry].finished) { | ||
69 | entry++; | ||
70 | continue; | ||
71 | } | ||
64 | } | 72 | } |
65 | /* Old left over entry. Skip. */ | ||
66 | if (mcelog.entry[entry].finished) | ||
67 | continue; | ||
68 | smp_rmb(); | 73 | smp_rmb(); |
69 | next = entry + 1; | 74 | next = entry + 1; |
70 | if (cmpxchg(&mcelog.next, entry, next) == entry) | 75 | if (cmpxchg(&mcelog.next, entry, next) == entry) |
@@ -404,9 +409,15 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff | |||
404 | } | 409 | } |
405 | 410 | ||
406 | err = 0; | 411 | err = 0; |
407 | for (i = 0; i < next; i++) { | 412 | for (i = 0; i < next; i++) { |
408 | if (!mcelog.entry[i].finished) | 413 | unsigned long start = jiffies; |
409 | continue; | 414 | while (!mcelog.entry[i].finished) { |
415 | if (!time_before(jiffies, start + 2)) { | ||
416 | memset(mcelog.entry + i,0, sizeof(struct mce)); | ||
417 | continue; | ||
418 | } | ||
419 | cpu_relax(); | ||
420 | } | ||
410 | smp_rmb(); | 421 | smp_rmb(); |
411 | err |= copy_to_user(buf, mcelog.entry + i, sizeof(struct mce)); | 422 | err |= copy_to_user(buf, mcelog.entry + i, sizeof(struct mce)); |
412 | buf += sizeof(struct mce); | 423 | buf += sizeof(struct mce); |
@@ -479,6 +490,7 @@ static int __init mcheck_disable(char *str) | |||
479 | 490 | ||
480 | /* mce=off disables machine check. Note you can reenable it later | 491 | /* mce=off disables machine check. Note you can reenable it later |
481 | using sysfs. | 492 | using sysfs. |
493 | mce=TOLERANCELEVEL (number, see above) | ||
482 | mce=bootlog Log MCEs from before booting. Disabled by default to work | 494 | mce=bootlog Log MCEs from before booting. Disabled by default to work |
483 | around buggy BIOS that leave bogus MCEs. */ | 495 | around buggy BIOS that leave bogus MCEs. */ |
484 | static int __init mcheck_enable(char *str) | 496 | static int __init mcheck_enable(char *str) |
@@ -489,6 +501,8 @@ static int __init mcheck_enable(char *str) | |||
489 | mce_dont_init = 1; | 501 | mce_dont_init = 1; |
490 | else if (!strcmp(str, "bootlog")) | 502 | else if (!strcmp(str, "bootlog")) |
491 | mce_bootlog = 1; | 503 | mce_bootlog = 1; |
504 | else if (isdigit(str[0])) | ||
505 | get_option(&str, &tolerant); | ||
492 | else | 506 | else |
493 | printk("mce= argument %s ignored. Please use /sys", str); | 507 | printk("mce= argument %s ignored. Please use /sys", str); |
494 | return 0; | 508 | return 0; |
@@ -501,10 +515,12 @@ __setup("mce", mcheck_enable); | |||
501 | * Sysfs support | 515 | * Sysfs support |
502 | */ | 516 | */ |
503 | 517 | ||
504 | /* On resume clear all MCE state. Don't want to see leftovers from the BIOS. */ | 518 | /* On resume clear all MCE state. Don't want to see leftovers from the BIOS. |
519 | Only one CPU is active at this time, the others get readded later using | ||
520 | CPU hotplug. */ | ||
505 | static int mce_resume(struct sys_device *dev) | 521 | static int mce_resume(struct sys_device *dev) |
506 | { | 522 | { |
507 | on_each_cpu(mce_init, NULL, 1, 1); | 523 | mce_init(NULL); |
508 | return 0; | 524 | return 0; |
509 | } | 525 | } |
510 | 526 | ||