git://git.onelab.eu
/
linux-2.6.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
vserver 1.9.3
[linux-2.6.git]
/
arch
/
x86_64
/
kernel
/
mce.c
diff --git
a/arch/x86_64/kernel/mce.c
b/arch/x86_64/kernel/mce.c
index
3bb678f
..
cf1fe8b
100644
(file)
--- a/
arch/x86_64/kernel/mce.c
+++ b/
arch/x86_64/kernel/mce.c
@@
-24,7
+24,8
@@
#define MISC_MCELOG_MINOR 227
#define NR_BANKS 5
#define MISC_MCELOG_MINOR 227
#define NR_BANKS 5
-static int mce_disabled __initdata;
+static int mce_dont_init;
+
/* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic,
3: never panic or exit (for testing only) */
static int tolerant = 1;
/* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic,
3: never panic or exit (for testing only) */
static int tolerant = 1;
@@
-48,8
+49,7
@@
static void mce_log(struct mce *mce)
mce->finished = 0;
smp_wmb();
for (;;) {
mce->finished = 0;
smp_wmb();
for (;;) {
- entry = mcelog.next;
- read_barrier_depends();
+ entry = rcu_dereference(mcelog.next);
/* When the buffer fills up discard new entries. Assume
that the earlier errors are the more interesting. */
if (entry >= MCE_LOG_LEN) {
/* When the buffer fills up discard new entries. Assume
that the earlier errors are the more interesting. */
if (entry >= MCE_LOG_LEN) {
@@
-72,7
+72,8
@@
static void mce_log(struct mce *mce)
static void print_mce(struct mce *m)
{
static void print_mce(struct mce *m)
{
- printk(KERN_EMERG
+ printk(KERN_EMERG "\n"
+ KERN_EMERG
"CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
m->cpu, m->mcgstatus, m->bank, m->status);
if (m->rip) {
"CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
m->cpu, m->mcgstatus, m->bank, m->status);
if (m->rip) {
@@
-101,7
+102,7
@@
static void mce_panic(char *msg, struct mce *backup, unsigned long start)
if (time_before(tsc, start))
continue;
print_mce(&mcelog.entry[i]);
if (time_before(tsc, start))
continue;
print_mce(&mcelog.entry[i]);
- if (mcelog.entry[i].tsc == backup->tsc)
+ if (
backup &&
mcelog.entry[i].tsc == backup->tsc)
backup = NULL;
}
if (backup)
backup = NULL;
}
if (backup)
@@
-114,9
+115,8
@@
static void mce_panic(char *msg, struct mce *backup, unsigned long start)
static int mce_available(struct cpuinfo_x86 *c)
{
static int mce_available(struct cpuinfo_x86 *c)
{
- return !mce_disabled &&
- test_bit(X86_FEATURE_MCE, &c->x86_capability) &&
- test_bit(X86_FEATURE_MCA, &c->x86_capability);
+ return test_bit(X86_FEATURE_MCE, &c->x86_capability) &&
+ test_bit(X86_FEATURE_MCA, &c->x86_capability);
}
/*
}
/*
@@
-128,8
+128,9
@@
void do_machine_check(struct pt_regs * regs, long error_code)
struct mce m, panicm;
int nowayout = (tolerant < 1);
int kill_it = 0;
struct mce m, panicm;
int nowayout = (tolerant < 1);
int kill_it = 0;
- u64 mcestart;
+ u64 mcestart
= 0
;
int i;
int i;
+ int panicm_found = 0;
if (regs)
notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL);
if (regs)
notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL);
@@
-139,17
+140,11
@@
void do_machine_check(struct pt_regs * regs, long error_code)
memset(&m, 0, sizeof(struct mce));
m.cpu = hard_smp_processor_id();
rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
memset(&m, 0, sizeof(struct mce));
m.cpu = hard_smp_processor_id();
rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
- if (!regs && (m.mcgstatus & MCG_STATUS_MCIP))
- return;
if (!(m.mcgstatus & MCG_STATUS_RIPV))
kill_it = 1;
if (!(m.mcgstatus & MCG_STATUS_RIPV))
kill_it = 1;
- if (regs) {
- m.rip = regs->rip;
- m.cs = regs->cs;
- }
rdtscll(mcestart);
rdtscll(mcestart);
-
mb
();
+
barrier
();
for (i = 0; i < banks; i++) {
if (!bank[i])
for (i = 0; i < banks; i++) {
if (!bank[i])
@@
-157,52
+152,62
@@
void do_machine_check(struct pt_regs * regs, long error_code)
m.misc = 0;
m.addr = 0;
m.misc = 0;
m.addr = 0;
+ m.bank = i;
+ m.tsc = 0;
rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
if ((m.status & MCI_STATUS_VAL) == 0)
continue;
rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
if ((m.status & MCI_STATUS_VAL) == 0)
continue;
- /* Should be implied by the banks check above, but
- check it anyways */
- if ((m.status & MCI_STATUS_EN) == 0)
- continue;
- /* Did this bank cause the exception? */
- /* Assume that the bank with uncorrectable errors did it,
- and that there is only a single one. */
- if (m.status & MCI_STATUS_UC) {
- panicm = m;
- } else {
- m.rip = 0;
- m.cs = 0;
+ if (m.status & MCI_STATUS_EN) {
+ /* In theory _OVER could be a nowayout too, but
+ assume any overflowed errors were no fatal. */
+ nowayout |= !!(m.status & MCI_STATUS_PCC);
+ kill_it |= !!(m.status & MCI_STATUS_UC);
}
}
- /* In theory _OVER could be a nowayout too, but
- assume any overflowed errors were no fatal. */
- nowayout |= !!(m.status & MCI_STATUS_PCC);
- kill_it |= !!(m.status & MCI_STATUS_UC);
- m.bank = i;
-
if (m.status & MCI_STATUS_MISCV)
rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc);
if (m.status & MCI_STATUS_ADDRV)
rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
if (m.status & MCI_STATUS_MISCV)
rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc);
if (m.status & MCI_STATUS_ADDRV)
rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
- rdtscll(m.tsc);
+ if (regs && (m.mcgstatus & MCG_STATUS_RIPV)) {
+ m.rip = regs->rip;
+ m.cs = regs->cs;
+ } else {
+ m.rip = 0;
+ m.cs = 0;
+ }
+
+ if (error_code != -1)
+ rdtscll(m.tsc);
wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
mce_log(&m);
wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
mce_log(&m);
+
+ /* Did this bank cause the exception? */
+ /* Assume that the bank with uncorrectable errors did it,
+ and that there is only a single one. */
+ if ((m.status & MCI_STATUS_UC) && (m.status & MCI_STATUS_EN)) {
+ panicm = m;
+ panicm_found = 1;
+ }
}
}
- wrmsrl(MSR_IA32_MCG_STATUS, 0);
/* Never do anything final in the polling timer */
if (!regs)
/* Never do anything final in the polling timer */
if (!regs)
- return;
+ goto out;
+
+ /* If we didn't find an uncorrectable error, pick
+ the last one (shouldn't happen, just being safe). */
+ if (!panicm_found)
+ panicm = m;
if (nowayout)
if (nowayout)
- mce_panic("Machine check", &m, mcestart);
+ mce_panic("Machine check", &
panic
m, mcestart);
if (kill_it) {
int user_space = 0;
if (m.mcgstatus & MCG_STATUS_RIPV)
if (kill_it) {
int user_space = 0;
if (m.mcgstatus & MCG_STATUS_RIPV)
- user_space =
m.rip && (
m.cs & 3);
+ user_space =
panicm.rip && (panic
m.cs & 3);
/* When the machine was in user space and the CPU didn't get
confused it's normally not necessary to panic, unless you
/* When the machine was in user space and the CPU didn't get
confused it's normally not necessary to panic, unless you
@@
-215,18
+220,15
@@
void do_machine_check(struct pt_regs * regs, long error_code)
(unsigned)current->pid <= 1)
mce_panic("Uncorrected machine check", &panicm, mcestart);
(unsigned)current->pid <= 1)
mce_panic("Uncorrected machine check", &panicm, mcestart);
- /* do_exit takes an awful lot of locks and has as slight risk
- of deadlocking. If you don't want that don't set tolerant >= 2 */
+ /* do_exit takes an awful lot of locks and has as
+ slight risk of deadlocking. If you don't want that
+ don't set tolerant >= 2 */
if (tolerant < 3)
do_exit(SIGBUS);
}
if (tolerant < 3)
do_exit(SIGBUS);
}
-}
-static void mce_clear_all(void)
-{
- int i;
- for (i = 0; i < banks; i++)
- wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
+ out:
+ /* Last thing done in the machine check exception to clear state. */
wrmsrl(MSR_IA32_MCG_STATUS, 0);
}
wrmsrl(MSR_IA32_MCG_STATUS, 0);
}
@@
-269,22
+271,25
@@
static void mce_init(void *dummy)
int i;
rdmsrl(MSR_IA32_MCG_CAP, cap);
int i;
rdmsrl(MSR_IA32_MCG_CAP, cap);
- if (cap & MCG_CTL_P)
- wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
-
banks = cap & 0xff;
if (banks > NR_BANKS) {
printk(KERN_INFO "MCE: warning: using only %d banks\n", banks);
banks = NR_BANKS;
}
banks = cap & 0xff;
if (banks > NR_BANKS) {
printk(KERN_INFO "MCE: warning: using only %d banks\n", banks);
banks = NR_BANKS;
}
- mce_clear_all();
+ /* Log the machine checks left over from the previous reset.
+ This also clears all registers */
+ do_machine_check(NULL, -1);
+
+ set_in_cr4(X86_CR4_MCE);
+
+ if (cap & MCG_CTL_P)
+ wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+
for (i = 0; i < banks; i++) {
wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
}
for (i = 0; i < banks; i++) {
wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
}
-
- set_in_cr4(X86_CR4_MCE);
}
/* Add per CPU specific workarounds here */
}
/* Add per CPU specific workarounds here */
@@
-308,7
+313,9
@@
void __init mcheck_init(struct cpuinfo_x86 *c)
mce_cpu_quirks(c);
mce_cpu_quirks(c);
- if (test_and_set_bit(smp_processor_id(), &mce_cpus) || !mce_available(c))
+ if (mce_dont_init ||
+ test_and_set_bit(smp_processor_id(), &mce_cpus) ||
+ !mce_available(c))
return;
mce_init(NULL);
return;
mce_init(NULL);
@@
-333,9
+340,8
@@
static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff
int i, err;
down(&mce_read_sem);
int i, err;
down(&mce_read_sem);
- next = mcelog.next;
- read_barrier_depends();
-
+ next = rcu_dereference(mcelog.next);
+
/* Only supports full reads right now */
if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) {
up(&mce_read_sem);
/* Only supports full reads right now */
if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) {
up(&mce_read_sem);
@@
-412,15
+418,16
@@
static struct miscdevice mce_log_device = {
static int __init mcheck_disable(char *str)
{
static int __init mcheck_disable(char *str)
{
- mce_d
isabled
= 1;
+ mce_d
ont_init
= 1;
return 0;
}
return 0;
}
-/* mce=off disable machine check */
+/* mce=off disables machine check. Note you can reenable it later
+ using sysfs */
static int __init mcheck_enable(char *str)
{
if (!strcmp(str, "off"))
static int __init mcheck_enable(char *str)
{
if (!strcmp(str, "off"))
- mce_d
isabled
= 1;
+ mce_d
ont_init
= 1;
else
printk("mce= argument %s ignored. Please use /sys", str);
return 0;
else
printk("mce= argument %s ignored. Please use /sys", str);
return 0;
@@
-436,7
+443,6
@@
__setup("mce", mcheck_enable);
/* On resume clear all MCE state. Don't want to see leftovers from the BIOS. */
static int mce_resume(struct sys_device *dev)
{
/* On resume clear all MCE state. Don't want to see leftovers from the BIOS. */
static int mce_resume(struct sys_device *dev)
{
- mce_clear_all();
on_each_cpu(mce_init, NULL, 1, 1);
return 0;
}
on_each_cpu(mce_init, NULL, 1, 1);
return 0;
}
@@
-465,7
+471,7
@@
static struct sys_device device_mce = {
/* Why are there no generic functions for this? */
#define ACCESSOR(name, var, start) \
static ssize_t show_ ## name(struct sys_device *s, char *buf) { \
/* Why are there no generic functions for this? */
#define ACCESSOR(name, var, start) \
static ssize_t show_ ## name(struct sys_device *s, char *buf) { \
- return sprintf(buf, "%l
u
\n", (unsigned long)var); \
+ return sprintf(buf, "%l
x
\n", (unsigned long)var); \
} \
static ssize_t set_ ## name(struct sys_device *s,const char *buf,size_t siz) { \
char *end; \
} \
static ssize_t set_ ## name(struct sys_device *s,const char *buf,size_t siz) { \
char *end; \
@@
-494,7
+500,7
@@
static __init int mce_init_device(void)
if (!err)
err = sysdev_register(&device_mce);
if (!err) {
if (!err)
err = sysdev_register(&device_mce);
if (!err) {
- /* could create per CPU objects, but is not worth it. */
+ /* could create per CPU objects, but i
t i
s not worth it. */
sysdev_create_file(&device_mce, &attr_bank0ctl);
sysdev_create_file(&device_mce, &attr_bank1ctl);
sysdev_create_file(&device_mce, &attr_bank2ctl);
sysdev_create_file(&device_mce, &attr_bank0ctl);
sysdev_create_file(&device_mce, &attr_bank1ctl);
sysdev_create_file(&device_mce, &attr_bank2ctl);