X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fx86_64%2Fkernel%2Fmce.c;h=86f9fd85016a3cb2046fbfec058acbdd99903d17;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=cf1fe8b7fa5bbb2f248ac6fb956f28f0917bf9d7;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index cf1fe8b7f..86f9fd850 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -31,6 +31,8 @@ static int mce_dont_init; static int tolerant = 1; static int banks; static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL }; +static unsigned long console_logged; +static int notify_user; /* * Lockless MCE logging infrastructure. @@ -43,7 +45,7 @@ struct mce_log mcelog = { MCE_LOG_LEN, }; -static void mce_log(struct mce *mce) +void mce_log(struct mce *mce) { unsigned next, entry; mce->finished = 0; @@ -68,6 +70,9 @@ static void mce_log(struct mce *mce) smp_wmb(); mcelog.entry[entry].finished = 1; smp_wmb(); + + if (!test_and_set_bit(0, &console_logged)) + notify_user = 1; } static void print_mce(struct mce *m) @@ -191,6 +196,8 @@ void do_machine_check(struct pt_regs * regs, long error_code) panicm = m; panicm_found = 1; } + + tainted |= TAINT_MACHINE_CHECK; } /* Never do anything final in the polling timer */ @@ -250,6 +257,19 @@ static void mcheck_timer(void *data) { on_each_cpu(mcheck_check_cpu, NULL, 1, 1); schedule_delayed_work(&mcheck_work, check_interval * HZ); + + /* + * It's ok to read stale data here for notify_user and + * console_logged as we'll simply get the updated versions + * on the next mcheck_timer execution and atomic operations + * on console_logged act as synchronization for notify_user + * writes. + */ + if (notify_user && console_logged) { + notify_user = 0; + clear_bit(0, &console_logged); + printk(KERN_INFO "Machine check events logged\n"); + } } @@ -303,22 +323,34 @@ static void __init mce_cpu_quirks(struct cpuinfo_x86 *c) } } +static void __init mce_cpu_features(struct cpuinfo_x86 *c) +{ + switch (c->x86_vendor) { + case X86_VENDOR_INTEL: + mce_intel_feature_init(c); + break; + default: + break; + } +} + /* * Called for each booted CPU to set up machine checks. * Must be called with preempt off. */ void __init mcheck_init(struct cpuinfo_x86 *c) { - static unsigned long mce_cpus __initdata = 0; + static cpumask_t mce_cpus __initdata = CPU_MASK_NONE; mce_cpu_quirks(c); if (mce_dont_init || - test_and_set_bit(smp_processor_id(), &mce_cpus) || + cpu_test_and_set(smp_processor_id(), mce_cpus) || !mce_available(c)) return; mce_init(NULL); + mce_cpu_features(c); } /* @@ -359,8 +391,7 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff memset(mcelog.entry, 0, next * sizeof(struct mce)); mcelog.next = 0; - smp_wmb(); - + synchronize_kernel(); /* Collect entries that were still getting written before the synchronize. */