Release 4.14 arch/x86/kernel/cpu/mcheck/mce.c
/*
* Machine check handler.
*
* K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs.
* Rest from unknown author(s).
* 2004 Andi Kleen. Rewrote most of it.
* Copyright 2008 Intel Corporation
* Author: Andi Kleen
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/thread_info.h>
#include <linux/capability.h>
#include <linux/miscdevice.h>
#include <linux/ratelimit.h>
#include <linux/kallsyms.h>
#include <linux/rcupdate.h>
#include <linux/kobject.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
#include <linux/kernel.h>
#include <linux/percpu.h>
#include <linux/string.h>
#include <linux/device.h>
#include <linux/syscore_ops.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/sched.h>
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/poll.h>
#include <linux/nmi.h>
#include <linux/cpu.h>
#include <linux/ras.h>
#include <linux/smp.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/debugfs.h>
#include <linux/irq_work.h>
#include <linux/export.h>
#include <linux/jump_label.h>
#include <asm/intel-family.h>
#include <asm/processor.h>
#include <asm/traps.h>
#include <asm/tlbflush.h>
#include <asm/mce.h>
#include <asm/msr.h>
#include <asm/reboot.h>
#include <asm/set_memory.h>
#include "mce-internal.h"
static DEFINE_MUTEX(mce_log_mutex);
#define CREATE_TRACE_POINTS
#include <trace/events/mce.h>
#define SPINUNIT 100
/* 100ns */
DEFINE_PER_CPU(unsigned, mce_exception_count);
struct mce_bank *mce_banks __read_mostly;
struct mce_vendor_flags mce_flags __read_mostly;
struct mca_config mca_cfg __read_mostly = {
.bootlog = -1,
/*
* Tolerant levels:
* 0: always panic on uncorrected errors, log corrected errors
* 1: panic or SIGBUS on uncorrected errors, log corrected errors
* 2: SIGBUS or log uncorrected errors (if possible), log corr. errors
* 3: never panic or SIGBUS, log all errors (for testing only)
*/
.tolerant = 1,
.monarch_timeout = -1
};
static DEFINE_PER_CPU(struct mce, mces_seen);
static unsigned long mce_need_notify;
static int cpu_missing;
/*
* MCA banks polled by the period polling timer for corrected events.
* With Intel CMCI, this only has MCA banks which do not support CMCI (if any).
*/
DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
[0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
};
/*
* MCA banks controlled through firmware first for corrected errors.
* This is a global list of banks for which we won't enable CMCI and we
* won't poll. Firmware controls these banks and is responsible for
* reporting corrected errors through GHES. Uncorrected/recoverable
* errors are still notified through a machine check.
*/
mce_banks_t mce_banks_ce_disabled;
static struct work_struct mce_work;
static struct irq_work mce_irq_work;
static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs);
/*
* CPU/chipset specific EDAC code can register a notifier call here to print
* MCE errors in a human-readable form.
*/
BLOCKING_NOTIFIER_HEAD(x86_mce_decoder_chain);
/* Do initial initialization of a struct mce */
void mce_setup(struct mce *m)
{
memset(m, 0, sizeof(struct mce));
m->cpu = m->extcpu = smp_processor_id();
/* We hope get_seconds stays lockless */
m->time = get_seconds();
m->cpuvendor = boot_cpu_data.x86_vendor;
m->cpuid = cpuid_eax(1);
m->socketid = cpu_data(m->extcpu).phys_proc_id;
m->apicid = cpu_data(m->extcpu).initial_apicid;
rdmsrl(MSR_IA32_MCG_CAP, m->mcgcap);
if (this_cpu_has(X86_FEATURE_INTEL_PPIN))
rdmsrl(MSR_PPIN, m->ppin);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 94 | 85.45% | 3 | 75.00% |
Tony Luck | 16 | 14.55% | 1 | 25.00% |
Total | 110 | 100.00% | 4 | 100.00% |
DEFINE_PER_CPU(struct mce, injectm);
EXPORT_PER_CPU_SYMBOL_GPL(injectm);
void mce_log(struct mce *m)
{
if (!mce_gen_pool_add(m))
irq_work_queue(&mce_irq_work);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chen Gong | 10 | 41.67% | 1 | 20.00% |
Andi Kleen | 9 | 37.50% | 2 | 40.00% |
Borislav Petkov | 5 | 20.83% | 2 | 40.00% |
Total | 24 | 100.00% | 5 | 100.00% |
void mce_inject_log(struct mce *m)
{
mutex_lock(&mce_log_mutex);
mce_log(m);
mutex_unlock(&mce_log_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 25 | 92.59% | 2 | 66.67% |
Tony Luck | 2 | 7.41% | 1 | 33.33% |
Total | 27 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(mce_inject_log);
static struct notifier_block mce_srao_nb;
/*
* We run the default notifier if we have only the SRAO, the first and the
* default notifier registered. I.e., the mandatory NUM_DEFAULT_NOTIFIERS
* notifiers registered on the chain.
*/
#define NUM_DEFAULT_NOTIFIERS 3
static atomic_t num_notifiers;
void mce_register_decode_chain(struct notifier_block *nb)
{
if (WARN_ON(nb->priority > MCE_PRIO_MCELOG && nb->priority < MCE_PRIO_EDAC))
return;
atomic_inc(&num_notifiers);
blocking_notifier_chain_register(&x86_mce_decoder_chain, nb);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 34 | 80.95% | 4 | 66.67% |
Chen Gong | 7 | 16.67% | 1 | 16.67% |
Linus Torvalds | 1 | 2.38% | 1 | 16.67% |
Total | 42 | 100.00% | 6 | 100.00% |
EXPORT_SYMBOL_GPL(mce_register_decode_chain);
void mce_unregister_decode_chain(struct notifier_block *nb)
{
atomic_dec(&num_notifiers);
blocking_notifier_chain_unregister(&x86_mce_decoder_chain, nb);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 23 | 95.83% | 2 | 66.67% |
Vishal Verma | 1 | 4.17% | 1 | 33.33% |
Total | 24 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(mce_unregister_decode_chain);
static inline u32 ctl_reg(int bank)
{
return MSR_IA32_MCx_CTL(bank);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yazen Ghannam | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
static inline u32 status_reg(int bank)
{
return MSR_IA32_MCx_STATUS(bank);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yazen Ghannam | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
static inline u32 addr_reg(int bank)
{
return MSR_IA32_MCx_ADDR(bank);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yazen Ghannam | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
static inline u32 misc_reg(int bank)
{
return MSR_IA32_MCx_MISC(bank);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yazen Ghannam | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
static inline u32 smca_ctl_reg(int bank)
{
return MSR_AMD64_SMCA_MCx_CTL(bank);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yazen Ghannam | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
static inline u32 smca_status_reg(int bank)
{
return MSR_AMD64_SMCA_MCx_STATUS(bank);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yazen Ghannam | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
static inline u32 smca_addr_reg(int bank)
{
return MSR_AMD64_SMCA_MCx_ADDR(bank);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yazen Ghannam | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
static inline u32 smca_misc_reg(int bank)
{
return MSR_AMD64_SMCA_MCx_MISC(bank);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yazen Ghannam | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
struct mca_msr_regs msr_ops = {
.ctl = ctl_reg,
.status = status_reg,
.addr = addr_reg,
.misc = misc_reg
};
static void __print_mce(struct mce *m)
{
pr_emerg(HW_ERR "CPU %d: Machine Check%s: %Lx Bank %d: %016Lx\n",
m->extcpu,
(m->mcgstatus & MCG_STATUS_MCIP ? " Exception" : ""),
m->mcgstatus, m->bank, m->status);
if (m->ip) {
pr_emerg(HW_ERR "RIP%s %02x:<%016Lx> ",
!(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
m->cs, m->ip);
if (m->cs == __KERNEL_CS)
print_symbol("{%s}", m->ip);
pr_cont("\n");
}
pr_emerg(HW_ERR "TSC %llx ", m->tsc);
if (m->addr)
pr_cont("ADDR %llx ", m->addr);
if (m->misc)
pr_cont("MISC %llx ", m->misc);
if (mce_flags.smca) {
if (m->synd)
pr_cont("SYND %llx ", m->synd);
if (m->ipid)
pr_cont("IPID %llx ", m->ipid);
}
pr_cont("\n");
/*
* Note this output is parsed by external tools and old fields
* should not be changed.
*/
pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n",
m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
cpu_data(m->extcpu).microcode);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 135 | 61.09% | 10 | 55.56% |
Yazen Ghannam | 38 | 17.19% | 1 | 5.56% |
Borislav Petkov | 16 | 7.24% | 2 | 11.11% |
Andrew Morton | 14 | 6.33% | 1 | 5.56% |
Ingo Molnar | 8 | 3.62% | 1 | 5.56% |
H. Peter Anvin | 6 | 2.71% | 2 | 11.11% |
Huang Ying | 4 | 1.81% | 1 | 5.56% |
Total | 221 | 100.00% | 18 | 100.00% |
static void print_mce(struct mce *m)
{
__print_mce(m);
pr_emerg_ratelimited(HW_ERR "Run the above through 'mcelog --ascii'\n");
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 21 | 95.45% | 2 | 66.67% |
Andi Kleen | 1 | 4.55% | 1 | 33.33% |
Total | 22 | 100.00% | 3 | 100.00% |
#define PANIC_TIMEOUT 5
/* 5 seconds */
static atomic_t mce_panicked;
static int fake_panic;
static atomic_t mce_fake_panicked;
/* Panic in progress. Enable interrupts and wait for final IPI */
static void wait_for_panic(void)
{
long timeout = PANIC_TIMEOUT*USEC_PER_SEC;
preempt_disable();
local_irq_enable();
while (timeout-- > 0)
udelay(1);
if (panic_timeout == 0)
panic_timeout = mca_cfg.panic_timeout;
panic("Panicing machine check CPU died");
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 47 | 94.00% | 2 | 66.67% |
Borislav Petkov | 3 | 6.00% | 1 | 33.33% |
Total | 50 | 100.00% | 3 | 100.00% |
static void mce_panic(const char *msg, struct mce *final, char *exp)
{
int apei_err = 0;
struct llist_node *pending;
struct mce_evt_llist *l;
if (!fake_panic) {
/*
* Make sure only one CPU runs in machine check panic
*/
if (atomic_inc_return(&mce_panicked) > 1)
wait_for_panic();
barrier();
bust_spinlocks(1);
console_verbose();
} else {
/* Don't log too much for fake panic */
if (atomic_inc_return(&mce_fake_panicked) > 1)
return;
}
pending = mce_gen_pool_prepare_records();
/* First print corrected ones that are still unlogged */
llist_for_each_entry(l, pending, llnode) {
struct mce *m = &l->mce;
if (!(m->status & MCI_STATUS_UC)) {
print_mce(m);
if (!apei_err)
apei_err = apei_write_mce(m);
}
}
/* Now print uncorrected but with the final one last */
llist_for_each_entry(l, pending, llnode) {
struct mce *m = &l->mce;
if (!(m->status & MCI_STATUS_UC))
continue;
if (!final || mce_cmp(m, final)) {
print_mce(m);
if (!apei_err)
apei_err = apei_write_mce(m);
}
}
if (final) {
print_mce(final);
if (!apei_err)
apei_err = apei_write_mce(final);
}
if (cpu_missing)
pr_emerg(HW_ERR "Some CPUs didn't answer in synchronization\n");
if (exp)
pr_emerg(HW_ERR "Machine check: %s\n", exp);
if (!fake_panic) {
if (panic_timeout == 0)
panic_timeout = mca_cfg.panic_timeout;
panic(msg);
} else
pr_emerg(HW_ERR "Fake kernel panic: %s\n", msg);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 136 | 48.57% | 10 | 52.63% |
Huang Ying | 85 | 30.36% | 3 | 15.79% |
Tony Luck | 38 | 13.57% | 1 | 5.26% |
Hidetoshi Seto | 14 | 5.00% | 1 | 5.26% |
Borislav Petkov | 6 | 2.14% | 3 | 15.79% |
Andrew Lutomirski | 1 | 0.36% | 1 | 5.26% |
Total | 280 | 100.00% | 19 | 100.00% |
/* Support code for software error injection */
static int msr_to_offset(u32 msr)
{
unsigned bank = __this_cpu_read(injectm.bank);
if (msr == mca_cfg.rip_msr)
return offsetof(struct mce, ip);
if (msr == msr_ops.status(bank))
return offsetof(struct mce, status);
if (msr == msr_ops.addr(bank))
return offsetof(struct mce, addr);
if (msr == msr_ops.misc(bank))
return offsetof(struct mce, misc);
if (msr == MSR_IA32_MCG_STATUS)
return offsetof(struct mce, mcgstatus);
return -1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 103 | 89.57% | 2 | 40.00% |
Yazen Ghannam | 9 | 7.83% | 1 | 20.00% |
Borislav Petkov | 2 | 1.74% | 1 | 20.00% |
Tejun Heo | 1 | 0.87% | 1 | 20.00% |
Total | 115 | 100.00% | 5 | 100.00% |
/* MSR access wrappers used for error injection */
static u64 mce_rdmsrl(u32 msr)
{
u64 v;
if (__this_cpu_read(injectm.finished)) {
int offset = msr_to_offset(msr);
if (offset < 0)
return 0;
return *(u64 *)((char *)this_cpu_ptr(&injectm) + offset);
}
if (rdmsrl_safe(msr, &v)) {
WARN_ONCE(1, "mce: Unable to read MSR 0x%x!\n", msr);
/*
* Return zero in case the access faulted. This should
* not happen normally but can happen if the CPU does
* something weird, or if the code is buggy.
*/
v = 0;
}
return v;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 65 | 73.03% | 2 | 33.33% |
Ingo Molnar | 19 | 21.35% | 1 | 16.67% |
Tejun Heo | 2 | 2.25% | 1 | 16.67% |
Christoph Lameter | 2 | 2.25% | 1 | 16.67% |
Borislav Petkov | 1 | 1.12% | 1 | 16.67% |
Total | 89 | 100.00% | 6 | 100.00% |
static void mce_wrmsrl(u32 msr, u64 v)
{
if (__this_cpu_read(injectm.finished)) {
int offset = msr_to_offset(msr);
if (offset >= 0)
*(u64 *)((char *)this_cpu_ptr(&injectm) + offset) = v;
return;
}
wrmsrl(msr, v);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 62 | 93.94% | 2 | 50.00% |
Christoph Lameter | 2 | 3.03% | 1 | 25.00% |
Tejun Heo | 2 | 3.03% | 1 | 25.00% |
Total | 66 | 100.00% | 4 | 100.00% |
/*
* Collect all global (w.r.t. this processor) status about this machine
* check into our "mce" struct so that we can use it later to assess
* the severity of the problem as we read per-bank specific details.
*/
static inline void mce_gather_info(struct mce *m, struct pt_regs *regs)
{
mce_setup(m);
m->mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS);
if (regs) {
/*
* Get the address of the instruction at the time of
* the machine check error.
*/
if (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) {
m->ip = regs->ip;
m->cs = regs->cs;
/*
* When in VM86 mode make the cs look like ring 3
* always. This is a lie, but it's better than passing
* the additional vm86 bit around everywhere.
*/
if (v8086_mode(regs))
m->cs |= 3;
}
/* Use accurate RIP reporting if available. */
if (mca_cfg.rip_msr)
m->ip = mce_rdmsrl(mca_cfg.rip_msr);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hidetoshi Seto | 82 | 82.00% | 1 | 33.33% |
Andi Kleen | 14 | 14.00% | 1 | 33.33% |
Borislav Petkov | 4 | 4.00% | 1 | 33.33% |
Total | 100 | 100.00% | 3 | 100.00% |
int mce_available(struct cpuinfo_x86 *c)
{
if (mca_cfg.disabled)
return 0;
return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 25 | 73.53% | 3 | 60.00% |
Akinobu Mita | 6 | 17.65% | 1 | 20.00% |
Borislav Petkov | 3 | 8.82% | 1 | 20.00% |
Total | 34 | 100.00% | 5 | 100.00% |
static void mce_schedule_work(void)
{
if (!mce_gen_pool_empty())
schedule_work(&mce_work);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 15 | 75.00% | 1 | 25.00% |
Chen Gong | 2 | 10.00% | 1 | 25.00% |
Tejun Heo | 2 | 10.00% | 1 | 25.00% |
Christoph Lameter | 1 | 5.00% | 1 | 25.00% |
Total | 20 | 100.00% | 4 | 100.00% |
static void mce_irq_work_cb(struct irq_work *entry)
{
mce_schedule_work();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 10 | 71.43% | 2 | 66.67% |
Hidetoshi Seto | 4 | 28.57% | 1 | 33.33% |
Total | 14 | 100.00% | 3 | 100.00% |
static void mce_report_event(struct pt_regs *regs)
{
if (regs->flags & (X86_VM_MASK|X86_EFLAGS_IF)) {
mce_notify_irq();
/*
* Triggering the work queue here is just an insurance
* policy in case the syscall exit notify handler
* doesn't run soon enough or ends up running on the
* wrong CPU (can happen when audit sleeps)
*/
mce_schedule_work();
return;
}
irq_work_queue(&mce_irq_work);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 34 | 87.18% | 3 | 60.00% |
Hidetoshi Seto | 4 | 10.26% | 1 | 20.00% |
Christoph Lameter | 1 | 2.56% | 1 | 20.00% |
Total | 39 | 100.00% | 5 | 100.00% |
/*
* Check if the address reported by the CPU is in a format we can parse.
* It would be possible to add code for most other cases, but all would
* be somewhat complicated (e.g. segment offset would require an instruction
* parser). So only support physical addresses up to page granuality for now.
*/
static int mce_usable_address(struct mce *m)
{
if (!(m->status & MCI_STATUS_ADDRV))
return 0;
/* Checks after this one are Intel-specific: */
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
return 1;
if (!(m->status & MCI_STATUS_MISCV))
return 0;
if (MCI_MISC_ADDR_LSB(m->misc) > PAGE_SHIFT)
return 0;
if (MCI_MISC_ADDR_MODE(m->misc) != MCI_MISC_ADDR_PHYS)
return 0;
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 82 | 100.00% | 2 | 100.00% |
Total | 82 | 100.00% | 2 | 100.00% |
bool mce_is_memory_error(struct mce *m)
{
if (m->cpuvendor == X86_VENDOR_AMD) {
/* ErrCodeExt[20:16] */
u8 xec = (m->status >> 16) & 0x1f;
return (xec == 0x0 || xec == 0x8);
} else if (m->cpuvendor == X86_VENDOR_INTEL) {
/*
* Intel SDM Volume 3B - 15.9.2 Compound Error Codes
*
* Bit 7 of the MCACOD field of IA32_MCi_STATUS is used for
* indicating a memory error. Bit 8 is used for indicating a
* cache hierarchy error. The combination of bit 2 and bit 3
* is used for indicating a `generic' cache hierarchy error
* But we can't just blindly check the above bits, because if
* bit 11 is set, then it is a bus/interconnect error - and
* either way the above bits just gives more detail on what
* bus/interconnect error happened. Note that bit 12 can be
* ignored, as it's the "filter" bit.
*/
return (m->status & 0xef80) == BIT(7) ||
(m->status & 0xef00) == BIT(8) ||
(m->status & 0xeffc) == 0xc;
}
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 86 | 88.66% | 2 | 66.67% |
Chen Gong | 11 | 11.34% | 1 | 33.33% |
Total | 97 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(mce_is_memory_error);
static bool cec_add_mce(struct mce *m)
{
if (!m)
return false;
/* We eat only correctable DRAM errors with usable addresses. */
if (mce_is_memory_error(m) &&
!(m->status & MCI_STATUS_UC) &&
mce_usable_address(m))
if (!cec_add_elem(m->addr >> PAGE_SHIFT))
return true;
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 40 | 67.80% | 3 | 60.00% |
Chen Gong | 18 | 30.51% | 1 | 20.00% |
Andi Kleen | 1 | 1.69% | 1 | 20.00% |
Total | 59 | 100.00% | 5 | 100.00% |
static int mce_first_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct mce *m = (struct mce *)data;
if (!m)
return NOTIFY_DONE;
if (cec_add_mce(m))
return NOTIFY_STOP;
/* Emit the trace record: */
trace_mce_record(m);
set_bit(0, &mce_need_notify);
mce_notify_irq();
return NOTIFY_DONE;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 66 | 95.65% | 3 | 75.00% |
Andi Kleen | 3 | 4.35% | 1 | 25.00% |
Total | 69 | 100.00% | 4 | 100.00% |
static struct notifier_block first_nb = {
.notifier_call = mce_first_notifier,
.priority = MCE_PRIO_FIRST,
};
static int srao_decode_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct mce *mce = (struct mce *)data;
unsigned long pfn;
if (!mce)
return NOTIFY_DONE;
if (mce_usable_address(mce) && (mce->severity == MCE_AO_SEVERITY)) {
pfn = mce->addr >> PAGE_SHIFT;
memory_failure(pfn, MCE_VECTOR, 0);
}
return NOTIFY_OK;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chen Gong | 74 | 92.50% | 1 | 33.33% |
Andi Kleen | 3 | 3.75% | 1 | 33.33% |
Borislav Petkov | 3 | 3.75% | 1 | 33.33% |
Total | 80 | 100.00% | 3 | 100.00% |
static struct notifier_block mce_srao_nb = {
.notifier_call = srao_decode_notifier,
.priority = MCE_PRIO_SRAO,
};
static int mce_default_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct mce *m = (struct mce *)data;
if (!m)
return NOTIFY_DONE;
if (atomic_read(&num_notifiers) > NUM_DEFAULT_NOTIFIERS)
return NOTIFY_DONE;
__print_mce(m);
return NOTIFY_DONE;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 60 | 100.00% | 2 | 100.00% |
Total | 60 | 100.00% | 2 | 100.00% |
static struct notifier_block mce_default_nb = {
.notifier_call = mce_default_notifier,
/* lowest prio, we want it to run last. */
.priority = MCE_PRIO_LOWEST,
};
/*
* Read ADDR and MISC registers.
*/
static void mce_read_aux(struct mce *m, int i)
{
if (m->status & MCI_STATUS_MISCV)
m->misc = mce_rdmsrl(msr_ops.misc(i));
if (m->status & MCI_STATUS_ADDRV) {
m->addr = mce_rdmsrl(msr_ops.addr(i));
/*
* Mask the reported address by the reported granularity.
*/
if (mca_cfg.ser && (m->status & MCI_STATUS_MISCV)) {
u8 shift = MCI_MISC_ADDR_LSB(m->misc);
m->addr >>= shift;
m->addr <<= shift;
}
/*
* Extract [55:<lsb>] where lsb is the least significant
* *valid* bit of the address bits.
*/
if (mce_flags.smca) {
u8 lsb = (m->addr >> 56) & 0x3f;
m->addr &= GENMASK_ULL(55, lsb);
}
}
if (mce_flags.smca) {
m->ipid = mce_rdmsrl(MSR_AMD64_SMCA_MCx_IPID(i));
if (m->status & MCI_STATUS_SYNDV)
m->synd = mce_rdmsrl(MSR_AMD64_SMCA_MCx_SYND(i));
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tony Luck | 90 | 52.33% | 1 | 16.67% |
Yazen Ghannam | 79 | 45.93% | 4 | 66.67% |
Borislav Petkov | 3 | 1.74% | 1 | 16.67% |
Total | 172 | 100.00% | 6 | 100.00% |
DEFINE_PER_CPU(unsigned, mce_poll_count);
/*
* Poll for corrected events or events that happened before reset.
* Those are just logged through /dev/mcelog.
*
* This is executed in standard interrupt context.
*
* Note: spec recommends to panic for fatal unsignalled
* errors here. However this would be quite problematic --
* we would need to reimplement the Monarch handling and
* it would mess up the exclusion between exception handler
* and poll hander -- * so we skip this for now.
* These cases should not happen anyways, or only when the CPU
* is already totally * confused. In this case it's likely it will
* not fully execute the machine check handler either.
*/
bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
{
bool error_seen = false;
struct mce m;
int i;
this_cpu_inc(mce_poll_count);
mce_gather_info(&m, NULL);
if (flags & MCP_TIMESTAMP)
m.tsc = rdtsc();
for (i = 0; i < mca_cfg.banks; i++) {
if (!mce_banks[i].ctl || !test_bit(i, *b))
continue;
m.misc = 0;
m.addr = 0;
m.bank = i;
barrier();
m.status = mce_rdmsrl(msr_ops.status(i));
if (!(m.status & MCI_STATUS_VAL))
continue;
/*
* Uncorrected or signalled events are handled by the exception
* handler when it is enabled, so don't process those here.
*
* TBD do the same check for MCI_STATUS_EN here?
*/
if (!(flags & MCP_UC) &&
(m.status & (mca_cfg.ser ? MCI_STATUS_S : MCI_STATUS_UC)))
continue;
error_seen = true;
mce_read_aux(&m, i);
m.severity = mce_severity(&m, mca_cfg.tolerant, NULL, false);
/*
* Don't get the IP here because it's unlikely to
* have anything to do with the actual error location.
*/
if (!(flags & MCP_DONTLOG) && !mca_cfg.dont_log_ce)
mce_log(&m);
else if (mce_usable_address(&m)) {
/*
* Although we skipped logging this, we still want
* to take action. Add to the pool so the registered
* notifiers will see it.
*/
if (!mce_gen_pool_add(&m))
mce_schedule_work();
}
/*
* Clear state for this bank.
*/
mce_wrmsrl(msr_ops.status(i), 0);
}
/*
* Don't clear MCG_STATUS here because it's only defined for
* exceptions.
*/
sync_core();
return error_seen;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 163 | 63.42% | 9 | 39.13% |
Borislav Petkov | 30 | 11.67% | 6 | 26.09% |
Tony Luck | 27 | 10.51% | 2 | 8.70% |
Chen Yucong | 23 | 8.95% | 1 | 4.35% |
Yazen Ghannam | 8 | 3.11% | 2 | 8.70% |
Hidetoshi Seto | 5 | 1.95% | 2 | 8.70% |
Alex Shi | 1 | 0.39% | 1 | 4.35% |
Total | 257 | 100.00% | 23 | 100.00% |
EXPORT_SYMBOL_GPL(machine_check_poll);
/*
* Do a quick check if any of the events requires a panic.
* This decides if we keep the events around or clear them.
*/
static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
struct pt_regs *regs)
{
int i, ret = 0;
char *tmp;
for (i = 0; i < mca_cfg.banks; i++) {
m->status = mce_rdmsrl(msr_ops.status(i));
if (m->status & MCI_STATUS_VAL) {
__set_bit(i, validp);
if (quirk_no_way_out)
quirk_no_way_out(i, m, regs);
}
if (mce_severity(m, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) {
*msg = tmp;
ret = 1;
}
}
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 60 | 46.15% | 3 | 33.33% |
Tony Luck | 48 | 36.92% | 2 | 22.22% |
Borislav Petkov | 17 | 13.08% | 2 | 22.22% |
Yazen Ghannam | 3 | 2.31% | 1 | 11.11% |
Chen Yucong | 2 | 1.54% | 1 | 11.11% |
Total | 130 | 100.00% | 9 | 100.00% |
/*
* Variable to establish order between CPUs while scanning.
* Each CPU spins initially until executing is equal its number.
*/
static atomic_t mce_executing;
/*
* Defines order of CPUs on entry. First CPU becomes Monarch.
*/
static atomic_t mce_callin;
/*
* Check if a timeout waiting for other CPUs happened.
*/
static int mce_timed_out(u64 *t, const char *msg)
{
/*
* The others already did panic for some reason.
* Bail out like in a timeout.
* rmb() to tell the compiler that system_state
* might have been modified by someone else.
*/
rmb();
if (atomic_read(&mce_panicked))
wait_for_panic();
if (!mca_cfg.monarch_timeout)
goto out;
if ((s64)*t < SPINUNIT) {
if (mca_cfg.tolerant <= 1)
mce_panic(msg, NULL, NULL);
cpu_missing = 1;
return 1;
}
*t -= SPINUNIT;
out:
touch_nmi_watchdog();
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 77 | 86.52% | 1 | 16.67% |
Borislav Petkov | 6 | 6.74% | 4 | 66.67% |
Andrew Lutomirski | 6 | 6.74% | 1 | 16.67% |
Total | 89 | 100.00% | 6 | 100.00% |
/*
* The Monarch's reign. The Monarch is the CPU who entered
* the machine check handler first. It waits for the others to
* raise the exception too and then grades them. When any
* error is fatal panic. Only then let the others continue.
*
* The other CPUs entering the MCE handler will be controlled by the
* Monarch. They are called Subjects.
*
* This way we prevent any potential data corruption in a unrecoverable case
* and also makes sure always all CPU's errors are examined.
*
* Also this detects the case of a machine check event coming from outer
* space (not detected by any CPUs) In this case some external agent wants
* us to shut down, so panic too.
*
* The other CPUs might still decide to panic if the handler happens
* in a unrecoverable place, but in this case the system is in a semi-stable
* state and won't corrupt anything by itself. It's ok to let the others
* continue for a bit first.
*
* All the spin loops have timeouts; when a timeout happens a CPU
* typically elects itself to be Monarch.
*/
static void mce_reign(void)
{
int cpu;
struct mce *m = NULL;
int global_worst = 0;
char *msg = NULL;
char *nmsg = NULL;
/*
* This CPU is the Monarch and the other CPUs have run
* through their handlers.
* Grade the severity of the errors of all the CPUs.
*/
for_each_possible_cpu(cpu) {
int severity = mce_severity(&per_cpu(mces_seen, cpu),
mca_cfg.tolerant,
&nmsg, true);
if (severity > global_worst) {
msg = nmsg;
global_worst = severity;
m = &per_cpu(mces_seen, cpu);
}
}
/*
* Cannot recover? Panic here then.
* This dumps all the mces in the log buffer and stops the
* other CPUs.
*/
if (m && global_worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3)
mce_panic("Fatal machine check", m, msg);
/*
* For UC somewhere we let the CPU who detects it handle it.
* Also must let continue the others, otherwise the handling
* CPU could deadlock on a lock.
*/
/*
* No machine check event found. Must be some external
* source or one CPU is hung. Panic.
*/
if (global_worst <= MCE_KEEP_SEVERITY && mca_cfg.tolerant < 3)
mce_panic("Fatal machine check from unknown source", NULL, NULL);
/*
* Now clear all the mces_seen so that they don't reappear on
* the next mce.
*/
for_each_possible_cpu(cpu)
memset(&per_cpu(mces_seen, cpu), 0, sizeof(struct mce));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 149 | 91.98% | 1 | 20.00% |
Borislav Petkov | 6 | 3.70% | 1 | 20.00% |
Hidetoshi Seto | 3 | 1.85% | 1 | 20.00% |
Chen Yucong | 2 | 1.23% | 1 | 20.00% |
Derek Che | 2 | 1.23% | 1 | 20.00% |
Total | 162 | 100.00% | 5 | 100.00% |
static atomic_t global_nwo;
/*
* Start of Monarch synchronization. This waits until all CPUs have
* entered the exception handler and then determines if any of them
* saw a fatal event that requires panic. Then it executes them
* in the entry order.
* TBD double check parallel CPU hotunplug
*/
static int mce_start(int *no_way_out)
{
int order;
int cpus = num_online_cpus();
u64 timeout = (u64)mca_cfg.monarch_timeout * NSEC_PER_USEC;
if (!timeout)
return -1;
atomic_add(*no_way_out, &global_nwo);
/*
* Rely on the implied barrier below, such that global_nwo
* is updated before mce_callin.
*/
order = atomic_inc_return(&mce_callin);
/*
* Wait for everyone.
*/
while (atomic_read(&mce_callin) != cpus) {
if (mce_timed_out(&timeout,
"Timeout: Not all CPUs entered broadcast exception handler")) {
atomic_set(&global_nwo, 0);
return -1;
}
ndelay(SPINUNIT);
}
/*
* mce_callin should be read before global_nwo
*/
smp_rmb();
if (order == 1) {
/*
* Monarch: Starts executing now, the others wait.
*/
atomic_set(&mce_executing, 1);
} else {
/*
* Subject: Now start the scanning loop one by one in
* the original callin order.
* This way when there are any shared banks it will be
* only seen by one CPU before cleared, avoiding duplicates.
*/
while (atomic_read(&mce_executing) < order) {
if (mce_timed_out(&timeout,
"Timeout: Subject CPUs unable to finish machine check processing")) {
atomic_set(&global_nwo, 0);
return -1;
}
ndelay(SPINUNIT);
}
}
/*
* Cache the global no_way_out state.
*/
*no_way_out = atomic_read(&global_nwo);
return order;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 138 | 77.09% | 1 | 14.29% |
Hidetoshi Seto | 22 | 12.29% | 1 | 14.29% |
Huang Ying | 11 | 6.15% | 1 | 14.29% |
Andrew Lutomirski | 4 | 2.23% | 1 | 14.29% |
Borislav Petkov | 3 | 1.68% | 2 | 28.57% |
Davidlohr Bueso A | 1 | 0.56% | 1 | 14.29% |
Total | 179 | 100.00% | 7 | 100.00% |
/*
* Synchronize between CPUs after main scanning loop.
* This invokes the bulk of the Monarch processing.
*/
static int mce_end(int order)
{
int ret = -1;
u64 timeout = (u64)mca_cfg.monarch_timeout * NSEC_PER_USEC;
if (!timeout)
goto reset;
if (order < 0)
goto reset;
/*
* Allow others to run.
*/
atomic_inc(&mce_executing);
if (order == 1) {
/* CHECKME: Can this race with a parallel hotplug? */
int cpus = num_online_cpus();
/*
* Monarch: Wait for everyone to go through their scanning
* loops.
*/
while (atomic_read(&mce_executing) <= cpus) {
if (mce_timed_out(&timeout,
"Timeout: Monarch CPU unable to finish machine check processing"))
goto reset;
ndelay(SPINUNIT);
}
mce_reign();
barrier();
ret = 0;
} else {
/*
* Subject: Wait for Monarch to finish.
*/
while (atomic_read(&mce_executing) != 0) {
if (mce_timed_out(&timeout,
"Timeout: Monarch CPU did not finish machine check processing"))
goto reset;
ndelay(SPINUNIT);
}
/*
* Don't reset anything. That's done by the Monarch.
*/
return 0;
}
/*
* Reset all global state.
*/
reset:
atomic_set(&global_nwo, 0);
atomic_set(&mce_callin, 0);
barrier();
/*
* Let others run again.
*/
atomic_set(&mce_executing, 0);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 173 | 96.65% | 1 | 33.33% |
Andrew Lutomirski | 4 | 2.23% | 1 | 33.33% |
Borislav Petkov | 2 | 1.12% | 1 | 33.33% |
Total | 179 | 100.00% | 3 | 100.00% |
static void mce_clear_state(unsigned long *toclear)
{
int i;
for (i = 0; i < mca_cfg.banks; i++) {
if (test_bit(i, toclear))
mce_wrmsrl(msr_ops.status(i), 0);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 47 | 90.38% | 3 | 60.00% |
Yazen Ghannam | 3 | 5.77% | 1 | 20.00% |
Borislav Petkov | 2 | 3.85% | 1 | 20.00% |
Total | 52 | 100.00% | 5 | 100.00% |
static int do_memory_failure(struct mce *m)
{
int flags = MF_ACTION_REQUIRED;
int ret;
pr_err("Uncorrected hardware memory error in user-access at %llx", m->addr);
if (!(m->mcgstatus & MCG_STATUS_RIPV))
flags |= MF_MUST_KILL;
ret = memory_failure(m->addr >> PAGE_SHIFT, MCE_VECTOR, flags);
if (ret)
pr_err("Memory error not recovered");
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tony Luck | 70 | 100.00% | 1 | 100.00% |
Total | 70 | 100.00% | 1 | 100.00% |
#if defined(arch_unmap_kpfn) && defined(CONFIG_MEMORY_FAILURE)
void arch_unmap_kpfn(unsigned long pfn)
{
unsigned long decoy_addr;
/*
* Unmap this page from the kernel 1:1 mappings to make sure
* we don't log more errors because of speculative access to
* the page.
* We would like to just call:
* set_memory_np((unsigned long)pfn_to_kaddr(pfn), 1);
* but doing that would radically increase the odds of a
* speculative access to the posion page because we'd have
* the virtual address of the kernel 1:1 mapping sitting
* around in registers.
* Instead we get tricky. We create a non-canonical address
* that looks just like the one we want, but has bit 63 flipped.
* This relies on set_memory_np() not checking whether we passed
* a legal address.
*/
/*
* Build time check to see if we have a spare virtual bit. Don't want
* to leave this until run time because most developers don't have a
* system that can exercise this code path. This will only become a
* problem if/when we move beyond 5-level page tables.
*
* Hard code "9" here because cpp doesn't grok ilog2(PTRS_PER_PGD)
*/
#if PGDIR_SHIFT + 9 < 63
decoy_addr = (pfn << PAGE_SHIFT) + (PAGE_OFFSET ^ BIT(63));
#else
#error "no unused virtual bit available"
#endif
if (set_memory_np(decoy_addr, 1))
pr_warn("Could not invalidate pfn=0x%lx from 1:1 map\n", pfn);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tony Luck | 62 | 100.00% | 1 | 100.00% |
Total | 62 | 100.00% | 1 | 100.00% |
#endif
/*
* The actual machine check handler. This only handles real
* exceptions when something got corrupted coming in through int 18.
*
* This is executed in NMI context not subject to normal locking rules. This
* implies that most kernel services cannot be safely used. Don't even
* think about putting a printk in there!
*
* On Intel systems this is entered on all CPUs in parallel through
* MCE broadcast. However some CPUs might be broken beyond repair,
* so be always careful when synchronizing with others.
*/
void do_machine_check(struct pt_regs *regs, long error_code)
{
struct mca_config *cfg = &mca_cfg;
struct mce m, *final;
int i;
int worst = 0;
int severity;
/*
* Establish sequential order between the CPUs entering the machine
* check handler.
*/
int order = -1;
/*
* If no_way_out gets set, there is no safe way to recover from this
* MCE. If mca_cfg.tolerant is cranked up, we'll try anyway.
*/
int no_way_out = 0;
/*
* If kill_it gets set, there might be a way to recover from this
* error.
*/
int kill_it = 0;
DECLARE_BITMAP(toclear, MAX_NR_BANKS);
DECLARE_BITMAP(valid_banks, MAX_NR_BANKS);
char *msg = "Unknown";
/*
* MCEs are always local on AMD. Same is determined by MCG_STATUS_LMCES
* on Intel.
*/
int lmce = 1;
int cpu = smp_processor_id();
/*
* Cases where we avoid rendezvous handler timeout:
* 1) If this CPU is offline.
*
* 2) If crashing_cpu was set, e.g. we're entering kdump and we need to
* skip those CPUs which remain looping in the 1st kernel - see
* crash_nmi_callback().
*
* Note: there still is a small window between kexec-ing and the new,
* kdump kernel establishing a new #MC handler where a broadcasted MCE
* might not get handled properly.
*/
if (cpu_is_offline(cpu) ||
(crashing_cpu != -1 && crashing_cpu != cpu)) {
u64 mcgstatus;
mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS);
if (mcgstatus & MCG_STATUS_RIPV) {
mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);
return;
}
}
ist_enter(regs);
this_cpu_inc(mce_exception_count);
if (!cfg->banks)
goto out;
mce_gather_info(&m, regs);
m.tsc = rdtsc();
final = this_cpu_ptr(&mces_seen);
*final = m;
memset(valid_banks, 0, sizeof(valid_banks));
no_way_out = mce_no_way_out(&m, &msg, valid_banks, regs);
barrier();
/*
* When no restart IP might need to kill or panic.
* Assume the worst for now, but if we find the
* severity is MCE_AR_SEVERITY we have other options.
*/
if (!(m.mcgstatus & MCG_STATUS_RIPV))
kill_it = 1;
/*
* Check if this MCE is signaled to only this logical processor,
* on Intel only.
*/
if (m.cpuvendor == X86_VENDOR_INTEL)
lmce = m.mcgstatus & MCG_STATUS_LMCES;
/*
* Go through all banks in exclusion of the other CPUs. This way we
* don't report duplicated events on shared banks because the first one
* to see it will clear it. If this is a Local MCE, then no need to
* perform rendezvous.
*/
if (!lmce)
order = mce_start(&no_way_out);
for (i = 0; i < cfg->banks; i++) {
__clear_bit(i, toclear);
if (!test_bit(i, valid_banks))
continue;
if (!mce_banks[i].ctl)
continue;
m.misc = 0;
m.addr = 0;
m.bank = i;
m.status = mce_rdmsrl(msr_ops.status(i));
if ((m.status & MCI_STATUS_VAL) == 0)
continue;
/*
* Non uncorrected or non signaled errors are handled by
* machine_check_poll. Leave them alone, unless this panics.
*/
if (!(m.status & (cfg->ser ? MCI_STATUS_S : MCI_STATUS_UC)) &&
!no_way_out)
continue;
/*
* Set taint even when machine check was not enabled.
*/
add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
severity = mce_severity(&m, cfg->tolerant, NULL, true);
/*
* When machine check was for corrected/deferred handler don't
* touch, unless we're panicing.
*/
if ((severity == MCE_KEEP_SEVERITY ||
severity == MCE_UCNA_SEVERITY) && !no_way_out)
continue;
__set_bit(i, toclear);
if (severity == MCE_NO_SEVERITY) {
/*
* Machine check event was not enabled. Clear, but
* ignore.
*/
continue;
}
mce_read_aux(&m, i);
/* assuming valid severity level != 0 */
m.severity = severity;
mce_log(&m);
if (severity > worst) {
*final = m;
worst = severity;
}
}
/* mce_clear_state will clear *final, save locally for use later */
m = *final;
if (!no_way_out)
mce_clear_state(toclear);
/*
* Do most of the synchronization with other CPUs.
* When there's any problem use only local no_way_out state.
*/
if (!lmce) {
if (mce_end(order) < 0)
no_way_out = worst >= MCE_PANIC_SEVERITY;
} else {
/*
* Local MCE skipped calling mce_reign()
* If we found a fatal error, we need to panic here.
*/
if (worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3)
mce_panic("Machine check from unknown source",
NULL, NULL);
}
/*
* If tolerant is at an insane level we drop requests to kill
* processes and continue even when there is no way out.
*/
if (cfg->tolerant == 3)
kill_it = 0;
else if (no_way_out)
mce_panic("Fatal machine check on current CPU", &m, msg);
if (worst > 0)
mce_report_event(regs);
mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);
out:
sync_core();
if (worst != MCE_AR_SEVERITY && !kill_it)
goto out_ist;
/* Fault was in user mode and we need to take some action */
if ((m.cs & 3) == 3) {
ist_begin_non_atomic(regs);
local_irq_enable();
if (kill_it || do_memory_failure(&m))
force_sig(SIGBUS, current);
local_irq_disable();
ist_end_non_atomic();
} else {
if (!fixup_exception(regs, X86_TRAP_MC))
mce_panic("Failed kernel mode recovery", &m, NULL);
}
out_ist:
ist_exit(regs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 319 | 47.19% | 23 | 46.94% |
Tony Luck | 140 | 20.71% | 6 | 12.24% |
Ashok Raj | 78 | 11.54% | 2 | 4.08% |
Borislav Petkov | 27 | 3.99% | 3 | 6.12% |
Yazen Ghannam | 23 | 3.40% | 2 | 4.08% |
Xunlei Pang | 19 | 2.81% | 1 | 2.04% |
Tim Hockin | 16 | 2.37% | 1 | 2.04% |
Hidetoshi Seto | 16 | 2.37% | 3 | 6.12% |
Andrew Lutomirski | 10 | 1.48% | 1 | 2.04% |
Chen Yucong | 9 | 1.33% | 1 | 2.04% |
Chen Gong | 6 | 0.89% | 1 | 2.04% |
Andrew Morton | 4 | 0.59% | 1 | 2.04% |
Ingo Molnar | 4 | 0.59% | 1 | 2.04% |
Christoph Lameter | 2 | 0.30% | 1 | 2.04% |
Rusty Russell | 2 | 0.30% | 1 | 2.04% |
Alex Shi | 1 | 0.15% | 1 | 2.04% |
Total | 676 | 100.00% | 49 | 100.00% |
EXPORT_SYMBOL_GPL(do_machine_check);
#ifndef CONFIG_MEMORY_FAILURE
int memory_failure(unsigned long pfn, int vector, int flags)
{
/* mce_severity() should not hand us an ACTION_REQUIRED error */
BUG_ON(flags & MF_ACTION_REQUIRED);
pr_err("Uncorrected memory error in page 0x%lx ignored\n"
"Rebuild kernel with CONFIG_MEMORY_FAILURE=y for smarter handling\n",
pfn);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tony Luck | 20 | 58.82% | 2 | 50.00% |
Andi Kleen | 13 | 38.24% | 1 | 25.00% |
Joe Perches | 1 | 2.94% | 1 | 25.00% |
Total | 34 | 100.00% | 4 | 100.00% |
#endif
/*
* Periodic polling timer for "silent" machine check errors. If the
* poller finds an MCE, poll 2x faster. When the poller finds no more
* errors, poll 2x slower (up to check_interval seconds).
*/
static unsigned long check_interval = INITIAL_CHECK_INTERVAL;
static DEFINE_PER_CPU(unsigned long, mce_next_interval); /* in jiffies */
static DEFINE_PER_CPU(struct timer_list, mce_timer);
static unsigned long mce_adjust_timer_default(unsigned long interval)
{
return interval;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chen Gong | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
static unsigned long (*mce_adjust_timer)(unsigned long interval) = mce_adjust_timer_default;
static void __start_timer(struct timer_list *t, unsigned long interval)
{
unsigned long when = jiffies + interval;
unsigned long flags;
local_irq_save(flags);
if (!timer_pending(t) || time_before(when, t->expires))
mod_timer(t, round_jiffies(when));
local_irq_restore(flags);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 47 | 73.44% | 1 | 25.00% |
Chen Gong | 13 | 20.31% | 1 | 25.00% |
Thomas Gleixner | 4 | 6.25% | 2 | 50.00% |
Total | 64 | 100.00% | 4 | 100.00% |
static void mce_timer_fn(unsigned long data)
{
struct timer_list *t = this_cpu_ptr(&mce_timer);
int cpu = smp_processor_id();
unsigned long iv;
WARN_ON(cpu != data);
iv = __this_cpu_read(mce_next_interval);
if (mce_available(this_cpu_ptr(&cpu_info))) {
machine_check_poll(0, this_cpu_ptr(&mce_poll_banks));
if (mce_intel_cmci_poll()) {
iv = mce_adjust_timer(iv);
goto done;
}
}
/*
* Alert userspace if needed. If we logged an MCE, reduce the polling
* interval, otherwise increase the polling interval.
*/
if (mce_notify_irq())
iv = max(iv / 2, (unsigned long) HZ/100);
else
iv = min(iv * 2, round_jiffies_relative(check_interval * HZ));
done:
__this_cpu_write(mce_next_interval, iv);
__start_timer(t, iv);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 45 | 31.69% | 6 | 28.57% |
Borislav Petkov | 32 | 22.54% | 2 | 9.52% |
Tim Hockin | 22 | 15.49% | 2 | 9.52% |
Thomas Gleixner | 21 | 14.79% | 2 | 9.52% |
Chen Gong | 6 | 4.23% | 3 | 14.29% |
Christoph Lameter | 5 | 3.52% | 1 | 4.76% |
Zwane Mwaikambo | 3 | 2.11% | 1 | 4.76% |
Tejun Heo | 3 | 2.11% | 1 | 4.76% |
Venkatesh Pallipadi | 3 | 2.11% | 1 | 4.76% |
Hidetoshi Seto | 1 | 0.70% | 1 | 4.76% |
Ingo Molnar | 1 | 0.70% | 1 | 4.76% |
Total | 142 | 100.00% | 21 | 100.00% |
/*
* Ensure that the timer is firing in @interval from now.
*/
void mce_timer_kick(unsigned long interval)
{
struct timer_list *t = this_cpu_ptr(&mce_timer);
unsigned long iv = __this_cpu_read(mce_next_interval);
__start_timer(t, interval);
if (interval < iv)
__this_cpu_write(mce_next_interval, interval);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chen Gong | 45 | 91.84% | 1 | 25.00% |
Christoph Lameter | 2 | 4.08% | 1 | 25.00% |
Thomas Gleixner | 1 | 2.04% | 1 | 25.00% |
Borislav Petkov | 1 | 2.04% | 1 | 25.00% |
Total | 49 | 100.00% | 4 | 100.00% |
/* Must not be called in IRQ context where del_timer_sync() can deadlock */
static void mce_timer_delete_all(void)
{
int cpu;
for_each_online_cpu(cpu)
del_timer_sync(&per_cpu(mce_timer, cpu));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hidetoshi Seto | 26 | 100.00% | 1 | 100.00% |
Total | 26 | 100.00% | 1 | 100.00% |
/*
* Notify the user(s) about new machine check events.
* Can be called from interrupt context, but not from machine check/NMI
* context.
*/
int mce_notify_irq(void)
{
/* Not more than two messages every minute */
static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2);
if (test_and_clear_bit(0, &mce_need_notify)) {
mce_work_trigger();
if (__ratelimit(&ratelimit))
pr_info(HW_ERR "Machine check events logged\n");
return 1;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tim Hockin | 23 | 41.82% | 2 | 22.22% |
Andi Kleen | 18 | 32.73% | 3 | 33.33% |
Zwane Mwaikambo | 9 | 16.36% | 1 | 11.11% |
Tony Luck | 2 | 3.64% | 1 | 11.11% |
Huang Ying | 2 | 3.64% | 1 | 11.11% |
Hidetoshi Seto | 1 | 1.82% | 1 | 11.11% |
Total | 55 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL_GPL(mce_notify_irq);
static int __mcheck_cpu_mce_banks_init(void)
{
int i;
u8 num_banks = mca_cfg.banks;
mce_banks = kzalloc(num_banks * sizeof(struct mce_bank), GFP_KERNEL);
if (!mce_banks)
return -ENOMEM;
for (i = 0; i < num_banks; i++) {
struct mce_bank *b = &mce_banks[i];
b->ctl = -1ULL;
b->init = 1;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 74 | 88.10% | 1 | 33.33% |
Borislav Petkov | 9 | 10.71% | 1 | 33.33% |
Hidetoshi Seto | 1 | 1.19% | 1 | 33.33% |
Total | 84 | 100.00% | 3 | 100.00% |
/*
* Initialize Machine Checks for a CPU.
*/
static int __mcheck_cpu_cap_init(void)
{
unsigned b;
u64 cap;
rdmsrl(MSR_IA32_MCG_CAP, cap);
b = cap & MCG_BANKCNT_MASK;
if (!mca_cfg.banks)
pr_info("CPU supports %d MCE banks\n", b);
if (b > MAX_NR_BANKS) {
pr_warn("Using only %u machine check banks out of %u\n",
MAX_NR_BANKS, b);
b = MAX_NR_BANKS;
}
/* Don't support asymmetric configurations today */
WARN_ON(mca_cfg.banks != 0 && b != mca_cfg.banks);
mca_cfg.banks = b;
if (!mce_banks) {
int err = __mcheck_cpu_mce_banks_init();
if (err)
return err;
}
/* Use accurate RIP reporting if available. */
if ((cap & MCG_EXT_P) && MCG_EXT_CNT(cap) >= 9)
mca_cfg.rip_msr = MSR_IA32_MCG_EIP;
if (cap & MCG_SER_P)
mca_cfg.ser = true;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 100 | 70.92% | 7 | 38.89% |
Borislav Petkov | 15 | 10.64% | 4 | 22.22% |
Ingo Molnar | 8 | 5.67% | 2 | 11.11% |
Thomas Gleixner | 5 | 3.55% | 1 | 5.56% |
Roland Dreier | 5 | 3.55% | 1 | 5.56% |
Joe Perches | 4 | 2.84% | 1 | 5.56% |
Daniel Rahn | 3 | 2.13% | 1 | 5.56% |
Hidetoshi Seto | 1 | 0.71% | 1 | 5.56% |
Total | 141 | 100.00% | 18 | 100.00% |
static void __mcheck_cpu_init_generic(void)
{
enum mcp_flags m_fl = 0;
mce_banks_t all_banks;
u64 cap;
if (!mca_cfg.bootlog)
m_fl = MCP_DONTLOG;
/*
* Log the machine checks left over from the previous reset.
*/
bitmap_fill(all_banks, MAX_NR_BANKS);
machine_check_poll(MCP_UC | m_fl, &all_banks);
cr4_set_bits(X86_CR4_MCE);
rdmsrl(MSR_IA32_MCG_CAP, cap);
if (cap & MCG_CTL_P)
wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 52 | 68.42% | 6 | 54.55% |
Borislav Petkov | 19 | 25.00% | 2 | 18.18% |
Ingo Molnar | 3 | 3.95% | 1 | 9.09% |
Andrew Lutomirski | 1 | 1.32% | 1 | 9.09% |
Aravind Gopalakrishnan | 1 | 1.32% | 1 | 9.09% |
Total | 76 | 100.00% | 11 | 100.00% |
static void __mcheck_cpu_init_clear_banks(void)
{
int i;
for (i = 0; i < mca_cfg.banks; i++) {
struct mce_bank *b = &mce_banks[i];
if (!b->init)
continue;
wrmsrl(msr_ops.ctl(i), b->ctl);
wrmsrl(msr_ops.status(i), 0);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 49 | 67.12% | 5 | 55.56% |
Aravind Gopalakrishnan | 10 | 13.70% | 1 | 11.11% |
Yazen Ghannam | 6 | 8.22% | 1 | 11.11% |
Venkatesh Pallipadi | 6 | 8.22% | 1 | 11.11% |
Borislav Petkov | 2 | 2.74% | 1 | 11.11% |
Total | 73 | 100.00% | 9 | 100.00% |
/*
* During IFU recovery Sandy Bridge -EP4S processors set the RIPV and
* EIPV bits in MCG_STATUS to zero on the affected logical processor (SDM
* Vol 3B Table 15-20). But this confuses both the code that determines
* whether the machine check occurred in kernel or user mode, and also
* the severity assessment code. Pretend that EIPV was set, and take the
* ip/cs values from the pt_regs that mce_gather_info() ignored earlier.
*/
static void quirk_sandybridge_ifu(int bank, struct mce *m, struct pt_regs *regs)
{
if (bank != 0)
return;
if ((m->mcgstatus & (MCG_STATUS_EIPV|MCG_STATUS_RIPV)) != 0)
return;
if ((m->status & (MCI_STATUS_OVER|MCI_STATUS_UC|
MCI_STATUS_EN|MCI_STATUS_MISCV|MCI_STATUS_ADDRV|
MCI_STATUS_PCC|MCI_STATUS_S|MCI_STATUS_AR|
MCACOD)) !=
(MCI_STATUS_UC|MCI_STATUS_EN|
MCI_STATUS_MISCV|MCI_STATUS_ADDRV|MCI_STATUS_S|
MCI_STATUS_AR|MCACOD_INSTR))
return;
m->mcgstatus |= MCG_STATUS_EIPV;
m->ip = regs->ip;
m->cs = regs->cs;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tony Luck | 110 | 100.00% | 1 | 100.00% |
Total | 110 | 100.00% | 1 | 100.00% |
/* Add per CPU specific workarounds here */
static int __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
{
struct mca_config *cfg = &mca_cfg;
if (c->x86_vendor == X86_VENDOR_UNKNOWN) {
pr_info("unknown CPU type - not enabling MCE support\n");
return -EOPNOTSUPP;
}
/* This should be disabled by the BIOS, but isn't always */
if (c->x86_vendor == X86_VENDOR_AMD) {
if (c->x86 == 15 && cfg->banks > 4) {
/*
* disable GART TBL walk error reporting, which
* trips off incorrectly with the IOMMU & 3ware
* & Cerberus:
*/
clear_bit(10, (unsigned long *)&mce_banks[4].ctl);
}
if (c->x86 < 0x11 && cfg->bootlog < 0) {
/*
* Lots of broken BIOS around that don't clear them
* by default and leave crap in there. Don't log:
*/
cfg->bootlog = 0;
}
/*
* Various K7s with broken bank 0 around. Always disable
* by default.
*/
if (c->x86 == 6 && cfg->banks > 0)
mce_banks[0].ctl = 0;
/*
* overflow_recov is supported for F15h Models 00h-0fh
* even though we don't have a CPUID bit for it.
*/
if (c->x86 == 0x15 && c->x86_model <= 0xf)
mce_flags.overflow_recov = 1;
/*
* Turn off MC4_MISC thresholding banks on those models since
* they're not supported there.
*/
if (c->x86 == 0x15 &&
(c->x86_model >= 0x10 && c->x86_model <= 0x1f)) {
int i;
u64 hwcr;
bool need_toggle;
u32 msrs[] = {
0x00000413, /* MC4_MISC0 */
0xc0000408, /* MC4_MISC1 */
};
rdmsrl(MSR_K7_HWCR, hwcr);
/* McStatusWrEn has to be set */
need_toggle = !(hwcr & BIT(18));
if (need_toggle)
wrmsrl(MSR_K7_HWCR, hwcr | BIT(18));
/* Clear CntP bit safely */
for (i = 0; i < ARRAY_SIZE(msrs); i++)
msr_clear_bit(msrs[i], 62);
/* restore old settings */
if (need_toggle)
wrmsrl(MSR_K7_HWCR, hwcr);
}
}
if (c->x86_vendor == X86_VENDOR_INTEL) {
/*
* SDM documents that on family 6 bank 0 should not be written
* because it aliases to another special BIOS controlled
* register.
* But it's not aliased anymore on model 0x1a+
* Don't ignore bank 0 completely because there could be a
* valid event later, merely don't write CTL0.
*/
if (c->x86 == 6 && c->x86_model < 0x1A && cfg->banks > 0)
mce_banks[0].init = 0;
/*
* All newer Intel systems support MCE broadcasting. Enable
* synchronization with a one second timeout.
*/
if ((c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xe)) &&
cfg->monarch_timeout < 0)
cfg->monarch_timeout = USEC_PER_SEC;
/*
* There are also broken BIOSes on some Pentium M and
* earlier systems:
*/
if (c->x86 == 6 && c->x86_model <= 13 && cfg->bootlog < 0)
cfg->bootlog = 0;
if (c->x86 == 6 && c->x86_model == 45)
quirk_no_way_out = quirk_sandybridge_ifu;
}
if (cfg->monarch_timeout < 0)
cfg->monarch_timeout = 0;
if (cfg->bootlog != 0)
cfg->panic_timeout = 30;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 161 | 37.70% | 6 | 24.00% |
Andi Kleen | 160 | 37.47% | 9 | 36.00% |
Ingo Molnar | 30 | 7.03% | 2 | 8.00% |
Aravind Gopalakrishnan | 22 | 5.15% | 2 | 8.00% |
Bartlomiej Zolnierkiewicz | 19 | 4.45% | 1 | 4.00% |
Tony Luck | 18 | 4.22% | 1 | 4.00% |
Jan Beulich | 13 | 3.04% | 1 | 4.00% |
Jesse Larrew | 2 | 0.47% | 1 | 4.00% |
Yazen Ghannam | 1 | 0.23% | 1 | 4.00% |
Joe Perches | 1 | 0.23% | 1 | 4.00% |
Total | 427 | 100.00% | 25 | 100.00% |
static int __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c)
{
if (c->x86 != 5)
return 0;
switch (c->x86_vendor) {
case X86_VENDOR_INTEL:
intel_p5_mcheck_init(c);
return 1;
break;
case X86_VENDOR_CENTAUR:
winchip_mcheck_init(c);
return 1;
break;
default:
return 0;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 43 | 70.49% | 1 | 25.00% |
Hidetoshi Seto | 13 | 21.31% | 1 | 25.00% |
Borislav Petkov | 5 | 8.20% | 2 | 50.00% |
Total | 61 | 100.00% | 4 | 100.00% |
/*
* Init basic CPU features needed for early decoding of MCEs.
*/
static void __mcheck_cpu_init_early(struct cpuinfo_x86 *c)
{
if (c->x86_vendor == X86_VENDOR_AMD) {
mce_flags.overflow_recov = !!cpu_has(c, X86_FEATURE_OVERFLOW_RECOV);
mce_flags.succor = !!cpu_has(c, X86_FEATURE_SUCCOR);
mce_flags.smca = !!cpu_has(c, X86_FEATURE_SMCA);
if (mce_flags.smca) {
msr_ops.ctl = smca_ctl_reg;
msr_ops.status = smca_status_reg;
msr_ops.addr = smca_addr_reg;
msr_ops.misc = smca_misc_reg;
}
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yazen Ghannam | 50 | 54.35% | 3 | 37.50% |
Aravind Gopalakrishnan | 28 | 30.43% | 3 | 37.50% |
Zwane Mwaikambo | 13 | 14.13% | 1 | 12.50% |
Jacob Shin | 1 | 1.09% | 1 | 12.50% |
Total | 92 | 100.00% | 8 | 100.00% |
static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c)
{
switch (c->x86_vendor) {
case X86_VENDOR_INTEL:
mce_intel_feature_init(c);
mce_adjust_timer = cmci_intel_adjust_timer;
break;
case X86_VENDOR_AMD: {
mce_amd_feature_init(c);
break;
}
default:
break;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Yazen Ghannam | 34 | 75.56% | 1 | 20.00% |
Aravind Gopalakrishnan | 6 | 13.33% | 2 | 40.00% |
Zwane Mwaikambo | 4 | 8.89% | 1 | 20.00% |
Jacob Shin | 1 | 2.22% | 1 | 20.00% |
Total | 45 | 100.00% | 5 | 100.00% |
static void __mcheck_cpu_clear_vendor(struct cpuinfo_x86 *c)
{
switch (c->x86_vendor) {
case X86_VENDOR_INTEL:
mce_intel_feature_clear(c);
break;
default:
break;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ashok Raj | 30 | 100.00% | 1 | 100.00% |
Total | 30 | 100.00% | 1 | 100.00% |
static void mce_start_timer(struct timer_list *t)
{
unsigned long iv = check_interval * HZ;
if (mca_cfg.ignore_ce || !iv)
return;
this_cpu_write(mce_next_interval, iv);
__start_timer(t, iv);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 21 | 48.84% | 2 | 22.22% |
Thomas Gleixner | 15 | 34.88% | 4 | 44.44% |
Borislav Petkov | 6 | 13.95% | 2 | 22.22% |
Hidetoshi Seto | 1 | 2.33% | 1 | 11.11% |
Total | 43 | 100.00% | 9 | 100.00% |
static void __mcheck_cpu_setup_timer(void)
{
struct timer_list *t = this_cpu_ptr(&mce_timer);
unsigned int cpu = smp_processor_id();
setup_pinned_timer(t, mce_timer_fn, cpu);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sebastian Andrzej Siewior | 35 | 100.00% | 1 | 100.00% |
Total | 35 | 100.00% | 1 | 100.00% |
static void __mcheck_cpu_init_timer(void)
{
struct timer_list *t = this_cpu_ptr(&mce_timer);
unsigned int cpu = smp_processor_id();
setup_pinned_timer(t, mce_timer_fn, cpu);
mce_start_timer(t);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Gleixner | 38 | 95.00% | 2 | 66.67% |
Christoph Lameter | 2 | 5.00% | 1 | 33.33% |
Total | 40 | 100.00% | 3 | 100.00% |
/* Handle unconfigured int18 (should never happen) */
static void unexpected_machine_check(struct pt_regs *regs, long error_code)
{
pr_err("CPU#%d: Unexpected int18 (Machine Check)\n",
smp_processor_id());
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 20 | 90.91% | 1 | 50.00% |
Joe Perches | 2 | 9.09% | 1 | 50.00% |
Total | 22 | 100.00% | 2 | 100.00% |
/* Call the installed machine check handler for this CPU setup. */
void (*machine_check_vector)(struct pt_regs *, long error_code) =
unexpected_machine_check;
/*
* Called for each booted CPU to set up machine checks.
* Must be called with preempt off:
*/
void mcheck_cpu_init(struct cpuinfo_x86 *c)
{
if (mca_cfg.disabled)
return;
if (__mcheck_cpu_ancient_init(c))
return;
if (!mce_available(c))
return;
if (__mcheck_cpu_cap_init() < 0 || __mcheck_cpu_apply_quirks(c) < 0) {
mca_cfg.disabled = true;
return;
}
if (mce_gen_pool_init()) {
mca_cfg.disabled = true;
pr_emerg("Couldn't allocate MCE records pool!\n");
return;
}
machine_check_vector = do_machine_check;
__mcheck_cpu_init_early(c);
__mcheck_cpu_init_generic();
__mcheck_cpu_init_vendor(c);
__mcheck_cpu_init_clear_banks();
__mcheck_cpu_setup_timer();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 42 | 42.42% | 6 | 40.00% |
Chen Gong | 19 | 19.19% | 1 | 6.67% |
Tony Luck | 12 | 12.12% | 2 | 13.33% |
Borislav Petkov | 11 | 11.11% | 2 | 13.33% |
Ingo Molnar | 6 | 6.06% | 1 | 6.67% |
Hidetoshi Seto | 4 | 4.04% | 1 | 6.67% |
Zwane Mwaikambo | 4 | 4.04% | 1 | 6.67% |
Yazen Ghannam | 1 | 1.01% | 1 | 6.67% |
Total | 99 | 100.00% | 15 | 100.00% |
/*
* Called for each booted CPU to clear some machine checks opt-ins
*/
void mcheck_cpu_clear(struct cpuinfo_x86 *c)
{
if (mca_cfg.disabled)
return;
if (!mce_available(c))
return;
/*
* Possibly to clear general settings generic to x86
* __mcheck_cpu_clear_generic(c);
*/
__mcheck_cpu_clear_vendor(c);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tony Luck | 32 | 100.00% | 2 | 100.00% |
Total | 32 | 100.00% | 2 | 100.00% |
static void __mce_disable_bank(void *arg)
{
int bank = *((int *)arg);
__clear_bit(bank, this_cpu_ptr(mce_poll_banks));
cmci_disable_bank(bank);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Naveen N. Rao | 36 | 97.30% | 1 | 50.00% |
Christoph Lameter | 1 | 2.70% | 1 | 50.00% |
Total | 37 | 100.00% | 2 | 100.00% |
void mce_disable_bank(int bank)
{
if (bank >= mca_cfg.banks) {
pr_warn(FW_BUG
"Ignoring request to disable invalid MCA bank %d.\n",
bank);
return;
}
set_bit(bank, mce_banks_ce_disabled);
on_each_cpu(__mce_disable_bank, &bank, 1);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Naveen N. Rao | 44 | 100.00% | 1 | 100.00% |
Total | 44 | 100.00% | 1 | 100.00% |
/*
* mce=off Disables machine check
* mce=no_cmci Disables CMCI
* mce=no_lmce Disables LMCE
* mce=dont_log_ce Clears corrected events silently, no log created for CEs.
* mce=ignore_ce Disables polling and CMCI, corrected events are not cleared.
* mce=TOLERANCELEVEL[,monarchtimeout] (number, see above)
* monarchtimeout is how long to wait for other CPUs on machine
* check, or 0 to not wait
* mce=bootlog Log MCEs from before booting. Disabled by default on AMD Fam10h
and older.
* mce=nobootlog Don't log MCEs from before booting.
* mce=bios_cmci_threshold Don't program the CMCI threshold
* mce=recovery force enable memcpy_mcsafe()
*/
static int __init mcheck_enable(char *str)
{
struct mca_config *cfg = &mca_cfg;
if (*str == 0) {
enable_p5_mce();
return 1;
}
if (*str == '=')
str++;
if (!strcmp(str, "off"))
cfg->disabled = true;
else if (!strcmp(str, "no_cmci"))
cfg->cmci_disabled = true;
else if (!strcmp(str, "no_lmce"))
cfg->lmce_disabled = true;
else if (!strcmp(str, "dont_log_ce"))
cfg->dont_log_ce = true;
else if (!strcmp(str, "ignore_ce"))
cfg->ignore_ce = true;
else if (!strcmp(str, "bootlog") || !strcmp(str, "nobootlog"))
cfg->bootlog = (str[0] == 'b');
else if (!strcmp(str, "bios_cmci_threshold"))
cfg->bios_cmci_threshold = true;
else if (!strcmp(str, "recovery"))
cfg->recovery = true;
else if (isdigit(str[0])) {
if (get_option(&str, &cfg->tolerant) == 2)
get_option(&str, &(cfg->monarch_timeout));
} else {
pr_info("mce argument %s ignored. Please use /sys\n", str);
return 0;
}
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 111 | 44.22% | 8 | 38.10% |
Hidetoshi Seto | 50 | 19.92% | 2 | 9.52% |
Borislav Petkov | 37 | 14.74% | 4 | 19.05% |
Tony Luck | 17 | 6.77% | 1 | 4.76% |
Naveen N. Rao | 13 | 5.18% | 1 | 4.76% |
Ashok Raj | 13 | 5.18% | 1 | 4.76% |
Bartlomiej Zolnierkiewicz | 5 | 1.99% | 1 | 4.76% |
Xie XiuQi | 3 | 1.20% | 1 | 4.76% |
Joe Perches | 1 | 0.40% | 1 | 4.76% |
Hirofumi Ogawa | 1 | 0.40% | 1 | 4.76% |
Total | 251 | 100.00% | 21 | 100.00% |
__setup("mce", mcheck_enable);
int __init mcheck_init(void)
{
mcheck_intel_therm_init();
mce_register_decode_chain(&first_nb);
mce_register_decode_chain(&mce_srao_nb);
mce_register_decode_chain(&mce_default_nb);
mcheck_vendor_init_severity();
INIT_WORK(&mce_work, mce_gen_pool_process);
init_irq_work(&mce_irq_work, mce_irq_work_cb);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Borislav Petkov | 24 | 47.06% | 4 | 50.00% |
Chen Gong | 21 | 41.18% | 2 | 25.00% |
Aravind Gopalakrishnan | 3 | 5.88% | 1 | 12.50% |
Yong Wang | 3 | 5.88% | 1 | 12.50% |
Total | 51 | 100.00% | 8 | 100.00% |
/*
* mce_syscore: PM support
*/
/*
* Disable machine checks on suspend and shutdown. We can't really handle
* them later.
*/
static void mce_disable_error_reporting(void)
{
int i;
for (i = 0; i < mca_cfg.banks; i++) {
struct mce_bank *b = &mce_banks[i];
if (b->init)
wrmsrl(msr_ops.ctl(i), 0);
}
return;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 49 | 84.48% | 4 | 50.00% |
Yazen Ghannam | 3 | 5.17% | 1 | 12.50% |
Ashok Raj | 3 | 5.17% | 1 | 12.50% |
Borislav Petkov | 3 | 5.17% | 2 | 25.00% |
Total | 58 | 100.00% | 8 | 100.00% |
static void vendor_disable_error_reporting(void)
{
/*
* Don't clear on Intel or AMD CPUs. Some of these MSRs are socket-wide.
* Disabling them for just a single offlined CPU is bad, since it will
* inhibit reporting for all shared resources on the socket like the
* last level cache (LLC), the integrated memory controller (iMC), etc.
*/
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ||
boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
return;
mce_disable_error_reporting();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ashok Raj | 19 | 70.37% | 1 | 33.33% |
Yazen Ghannam | 7 | 25.93% | 1 | 33.33% |
Andi Kleen | 1 | 3.70% | 1 | 33.33% |
Total | 27 | 100.00% | 3 | 100.00% |
static int mce_syscore_suspend(void)
{
vendor_disable_error_reporting();
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 8 | 57.14% | 1 | 25.00% |
Ashok Raj | 4 | 28.57% | 1 | 25.00% |
Hidetoshi Seto | 1 | 7.14% | 1 | 25.00% |
Rafael J. Wysocki | 1 | 7.14% | 1 | 25.00% |
Total | 14 | 100.00% | 4 | 100.00% |
static void mce_syscore_shutdown(void)
{
vendor_disable_error_reporting();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 6 | 54.55% | 1 | 25.00% |
Rafael J. Wysocki | 3 | 27.27% | 1 | 25.00% |
Ashok Raj | 1 | 9.09% | 1 | 25.00% |
Hidetoshi Seto | 1 | 9.09% | 1 | 25.00% |
Total | 11 | 100.00% | 4 | 100.00% |
/*
* On resume clear all MCE state. Don't want to see leftovers from the BIOS.
* Only one CPU is active at this time, the others get re-added later using
* CPU hotplug:
*/
static void mce_syscore_resume(void)
{
__mcheck_cpu_init_generic();
__mcheck_cpu_init_vendor(raw_cpu_ptr(&cpu_info));
__mcheck_cpu_init_clear_banks();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 10 | 43.48% | 2 | 22.22% |
Tejun Heo | 3 | 13.04% | 1 | 11.11% |
Aravind Gopalakrishnan | 3 | 13.04% | 1 | 11.11% |
Borislav Petkov | 2 | 8.70% | 1 | 11.11% |
Rafael J. Wysocki | 2 | 8.70% | 1 | 11.11% |
Christoph Lameter | 1 | 4.35% | 1 | 11.11% |
Thomas Gleixner | 1 | 4.35% | 1 | 11.11% |
Hidetoshi Seto | 1 | 4.35% | 1 | 11.11% |
Total | 23 | 100.00% | 9 | 100.00% |
static struct syscore_ops mce_syscore_ops = {
.suspend = mce_syscore_suspend,
.shutdown = mce_syscore_shutdown,
.resume = mce_syscore_resume,
};
/*
* mce_device: Sysfs support
*/
static void mce_cpu_restart(void *data)
{
if (!mce_available(raw_cpu_ptr(&cpu_info)))
return;
__mcheck_cpu_init_generic();
__mcheck_cpu_init_clear_banks();
__mcheck_cpu_init_timer();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 20 | 62.50% | 3 | 33.33% |
Tejun Heo | 3 | 9.38% | 1 | 11.11% |
Aravind Gopalakrishnan | 3 | 9.38% | 1 | 11.11% |
Hidetoshi Seto | 2 | 6.25% | 1 | 11.11% |
Borislav Petkov | 2 | 6.25% | 1 | 11.11% |
Thomas Gleixner | 1 | 3.12% | 1 | 11.11% |
Christoph Lameter | 1 | 3.12% | 1 | 11.11% |
Total | 32 | 100.00% | 9 | 100.00% |
/* Reinit MCEs after user configuration changes */
static void mce_restart(void)
{
mce_timer_delete_all();
on_each_cpu(mce_cpu_restart, NULL, 1);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 16 | 80.00% | 3 | 60.00% |
Hidetoshi Seto | 3 | 15.00% | 1 | 20.00% |
Venkatesh Pallipadi | 1 | 5.00% | 1 | 20.00% |
Total | 20 | 100.00% | 5 | 100.00% |
/* Toggle features for corrected errors */
static void mce_disable_cmci(void *data)
{
if (!mce_available(raw_cpu_ptr(&cpu_info)))
return;
cmci_clear();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hidetoshi Seto | 22 | 84.62% | 2 | 50.00% |
Tejun Heo | 3 | 11.54% | 1 | 25.00% |
Christoph Lameter | 1 | 3.85% | 1 | 25.00% |
Total | 26 | 100.00% | 4 | 100.00% |
static void mce_enable_ce(void *all)
{
if (!mce_available(raw_cpu_ptr(&cpu_info)))
return;
cmci_reenable();
cmci_recheck();
if (all)
__mcheck_cpu_init_timer();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hidetoshi Seto | 31 | 86.11% | 1 | 25.00% |
Tejun Heo | 3 | 8.33% | 1 | 25.00% |
Christoph Lameter | 1 | 2.78% | 1 | 25.00% |
Borislav Petkov | 1 | 2.78% | 1 | 25.00% |
Total | 36 | 100.00% | 4 | 100.00% |
static struct bus_type mce_subsys = {
.name = "machinecheck",
.dev_name = "machinecheck",
};
DEFINE_PER_CPU(struct device *, mce_device);
static inline struct mce_bank *attr_to_bank(struct device_attribute *attr)
{
return container_of(attr, struct mce_bank, attr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 24 | 96.00% | 2 | 66.67% |
Kay Sievers | 1 | 4.00% | 1 | 33.33% |
Total | 25 | 100.00% | 3 | 100.00% |
static ssize_t show_bank(struct device *s, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%llx\n", attr_to_bank(attr)->ctl);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 29 | 82.86% | 4 | 57.14% |
David Shaohua Li | 3 | 8.57% | 1 | 14.29% |
Kay Sievers | 2 | 5.71% | 1 | 14.29% |
H. Peter Anvin | 1 | 2.86% | 1 | 14.29% |
Total | 35 | 100.00% | 7 | 100.00% |
static ssize_t set_bank(struct device *s, struct device_attribute *attr,
const char *buf, size_t size)
{
u64 new;
if (kstrtou64(buf, 0, &new) < 0)
return -EINVAL;
attr_to_bank(attr)->ctl = new;
mce_restart();
return size;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 47 | 78.33% | 2 | 40.00% |
Hidetoshi Seto | 10 | 16.67% | 1 | 20.00% |
Kay Sievers | 2 | 3.33% | 1 | 20.00% |
Daniel Walter | 1 | 1.67% | 1 | 20.00% |
Total | 60 | 100.00% | 5 | 100.00% |
static ssize_t set_ignore_ce(struct device *s,
struct device_attribute *attr,
const char *buf, size_t size)
{
u64 new;
if (kstrtou64(buf, 0, &new) < 0)
return -EINVAL;
if (mca_cfg.ignore_ce ^ !!new) {
if (new) {
/* disable ce features */
mce_timer_delete_all();
on_each_cpu(mce_disable_cmci, NULL, 1);
mca_cfg.ignore_ce = true;
} else {
/* enable ce features */
mca_cfg.ignore_ce = false;
on_each_cpu(mce_enable_ce, (void *)1, 1);
}
}
return size;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hidetoshi Seto | 94 | 87.04% | 2 | 40.00% |
Borislav Petkov | 11 | 10.19% | 1 | 20.00% |
Kay Sievers | 2 | 1.85% | 1 | 20.00% |
Daniel Walter | 1 | 0.93% | 1 | 20.00% |
Total | 108 | 100.00% | 5 | 100.00% |
static ssize_t set_cmci_disabled(struct device *s,
struct device_attribute *attr,
const char *buf, size_t size)
{
u64 new;
if (kstrtou64(buf, 0, &new) < 0)
return -EINVAL;
if (mca_cfg.cmci_disabled ^ !!new) {
if (new) {
/* disable cmci */
on_each_cpu(mce_disable_cmci, NULL, 1);
mca_cfg.cmci_disabled = true;
} else {
/* enable cmci */
mca_cfg.cmci_disabled = false;
on_each_cpu(mce_enable_ce, NULL, 1);
}
}
return size;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hidetoshi Seto | 87 | 86.14% | 2 | 40.00% |
Borislav Petkov | 11 | 10.89% | 1 | 20.00% |
Kay Sievers | 2 | 1.98% | 1 | 20.00% |
Daniel Walter | 1 | 0.99% | 1 | 20.00% |
Total | 101 | 100.00% | 5 | 100.00% |
static ssize_t store_int_with_restart(struct device *s,
struct device_attribute *attr,
const char *buf, size_t size)
{
ssize_t ret = device_store_int(s, attr, buf, size);
mce_restart();
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 41 | 93.18% | 1 | 50.00% |
Kay Sievers | 3 | 6.82% | 1 | 50.00% |
Total | 44 | 100.00% | 2 | 100.00% |
static DEVICE_INT_ATTR(tolerant, 0644, mca_cfg.tolerant);
static DEVICE_INT_ATTR(monarch_timeout, 0644, mca_cfg.monarch_timeout);
static DEVICE_BOOL_ATTR(dont_log_ce, 0644, mca_cfg.dont_log_ce);
static struct dev_ext_attribute dev_attr_check_interval = {
__ATTR(check_interval, 0644, device_show_int, store_int_with_restart),
&check_interval
};
static struct dev_ext_attribute dev_attr_ignore_ce = {
__ATTR(ignore_ce, 0644, device_show_bool, set_ignore_ce),
&mca_cfg.ignore_ce
};
static struct dev_ext_attribute dev_attr_cmci_disabled = {
__ATTR(cmci_disabled, 0644, device_show_bool, set_cmci_disabled),
&mca_cfg.cmci_disabled
};
static struct device_attribute *mce_device_attrs[] = {
&dev_attr_tolerant.attr,
&dev_attr_check_interval.attr,
#ifdef CONFIG_X86_MCELOG_LEGACY
&dev_attr_trigger,
#endif
&dev_attr_monarch_timeout.attr,
&dev_attr_dont_log_ce.attr,
&dev_attr_ignore_ce.attr,
&dev_attr_cmci_disabled.attr,
NULL
};
static cpumask_var_t mce_device_initialized;
static void mce_device_release(struct device *dev)
{
kfree(dev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
/* Per cpu device init. All of the cpus still share the same ctrl bank: */
static int mce_device_create(unsigned int cpu)
{
struct device *dev;
int err;
int i, j;
if (!mce_available(&boot_cpu_data))
return -EIO;
dev = per_cpu(mce_device, cpu);
if (dev)
return 0;
dev = kzalloc(sizeof *dev, GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->id = cpu;
dev->bus = &mce_subsys;
dev->release = &mce_device_release;
err = device_register(dev);
if (err) {
put_device(dev);
return err;
}
for (i = 0; mce_device_attrs[i]; i++) {
err = device_create_file(dev, mce_device_attrs[i]);
if (err)
goto error;
}
for (j = 0; j < mca_cfg.banks; j++) {
err = device_create_file(dev, &mce_banks[j].attr);
if (err)
goto error2;
}
cpumask_set_cpu(cpu, mce_device_initialized);
per_cpu(mce_device, cpu) = dev;
return 0;
error2:
while (--j >= 0)
device_remove_file(dev, &mce_banks[j].attr);
error:
while (--i >= 0)
device_remove_file(dev, mce_device_attrs[i]);
device_unregister(dev);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 102 | 40.00% | 7 | 35.00% |
Akinobu Mita | 36 | 14.12% | 1 | 5.00% |
Greg Kroah-Hartman | 31 | 12.16% | 2 | 10.00% |
Kay Sievers | 24 | 9.41% | 1 | 5.00% |
David Shaohua Li | 17 | 6.67% | 1 | 5.00% |
Sebastian Andrzej Siewior | 16 | 6.27% | 1 | 5.00% |
Hidetoshi Seto | 13 | 5.10% | 2 | 10.00% |
Levente Kurusa | 7 | 2.75% | 1 | 5.00% |
Andreas Herrmann | 6 | 2.35% | 2 | 10.00% |
Borislav Petkov | 2 | 0.78% | 1 | 5.00% |
Rusty Russell | 1 | 0.39% | 1 | 5.00% |
Total | 255 | 100.00% | 20 | 100.00% |
static void mce_device_remove(unsigned int cpu)
{
struct device *dev = per_cpu(mce_device, cpu);
int i;
if (!cpumask_test_cpu(cpu, mce_device_initialized))
return;
for (i = 0; mce_device_attrs[i]; i++)
device_remove_file(dev, mce_device_attrs[i]);
for (i = 0; i < mca_cfg.banks; i++)
device_remove_file(dev, &mce_banks[i].attr);
device_unregister(dev);
cpumask_clear_cpu(cpu, mce_device_initialized);
per_cpu(mce_device, cpu) = NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 42 | 38.53% | 5 | 38.46% |
David Shaohua Li | 17 | 15.60% | 1 | 7.69% |
Andreas Herrmann | 14 | 12.84% | 1 | 7.69% |
Kay Sievers | 14 | 12.84% | 1 | 7.69% |
Greg Kroah-Hartman | 13 | 11.93% | 2 | 15.38% |
Hidetoshi Seto | 5 | 4.59% | 1 | 7.69% |
Rusty Russell | 2 | 1.83% | 1 | 7.69% |
Borislav Petkov | 2 | 1.83% | 1 | 7.69% |
Total | 109 | 100.00% | 13 | 100.00% |
/* Make sure there are no machine checks on offlined CPUs. */
static void mce_disable_cpu(void)
{
if (!mce_available(raw_cpu_ptr(&cpu_info)))
return;
if (!cpuhp_tasks_frozen)
cmci_clear();
vendor_disable_error_reporting();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 25 | 78.12% | 2 | 33.33% |
Tejun Heo | 3 | 9.38% | 1 | 16.67% |
Ashok Raj | 2 | 6.25% | 1 | 16.67% |
Sebastian Andrzej Siewior | 1 | 3.12% | 1 | 16.67% |
Christoph Lameter | 1 | 3.12% | 1 | 16.67% |
Total | 32 | 100.00% | 6 | 100.00% |
static void mce_reenable_cpu(void)
{
int i;
if (!mce_available(raw_cpu_ptr(&cpu_info)))
return;
if (!cpuhp_tasks_frozen)
cmci_reenable();
for (i = 0; i < mca_cfg.banks; i++) {
struct mce_bank *b = &mce_banks[i];
if (b->init)
wrmsrl(msr_ops.ctl(i), b->ctl);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 67 | 83.75% | 5 | 45.45% |
Yazen Ghannam | 3 | 3.75% | 1 | 9.09% |
Tejun Heo | 3 | 3.75% | 1 | 9.09% |
Ingo Molnar | 3 | 3.75% | 1 | 9.09% |
Borislav Petkov | 2 | 2.50% | 1 | 9.09% |
Sebastian Andrzej Siewior | 1 | 1.25% | 1 | 9.09% |
Christoph Lameter | 1 | 1.25% | 1 | 9.09% |
Total | 80 | 100.00% | 11 | 100.00% |
static int mce_cpu_dead(unsigned int cpu)
{
mce_intel_hcpu_update(cpu);
/* intentionally ignoring frozen here */
if (!cpuhp_tasks_frozen)
cmci_rediscover();
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sebastian Andrzej Siewior | 19 | 70.37% | 2 | 66.67% |
Andi Kleen | 8 | 29.63% | 1 | 33.33% |
Total | 27 | 100.00% | 3 | 100.00% |
static int mce_cpu_online(unsigned int cpu)
{
struct timer_list *t = this_cpu_ptr(&mce_timer);
int ret;
mce_device_create(cpu);
ret = mce_threshold_create_device(cpu);
if (ret) {
mce_device_remove(cpu);
return ret;
}
mce_reenable_cpu();
mce_start_timer(t);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sebastian Andrzej Siewior | 25 | 40.98% | 3 | 30.00% |
Andi Kleen | 23 | 37.70% | 3 | 30.00% |
Rafael J. Wysocki | 7 | 11.48% | 1 | 10.00% |
Thomas Gleixner | 2 | 3.28% | 1 | 10.00% |
Kay Sievers | 2 | 3.28% | 1 | 10.00% |
Borislav Petkov | 2 | 3.28% | 1 | 10.00% |
Total | 61 | 100.00% | 10 | 100.00% |
static int mce_cpu_pre_down(unsigned int cpu)
{
struct timer_list *t = this_cpu_ptr(&mce_timer);
mce_disable_cpu();
del_timer_sync(t);
mce_threshold_remove_device(cpu);
mce_device_remove(cpu);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sebastian Andrzej Siewior | 20 | 47.62% | 2 | 28.57% |
Andi Kleen | 10 | 23.81% | 2 | 28.57% |
Chen Gong | 6 | 14.29% | 1 | 14.29% |
Thomas Gleixner | 6 | 14.29% | 2 | 28.57% |
Total | 42 | 100.00% | 7 | 100.00% |
static __init void mce_init_banks(void)
{
int i;
for (i = 0; i < mca_cfg.banks; i++) {
struct mce_bank *b = &mce_banks[i];
struct device_attribute *a = &b->attr;
sysfs_attr_init(&a->attr);
a->attr.name = b->attrname;
snprintf(b->attrname, ATTR_LEN, "bank%d", i);
a->attr.mode = 0644;
a->show = show_bank;
a->store = set_bank;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 90 | 89.11% | 2 | 40.00% |
Eric W. Biedermann | 8 | 7.92% | 1 | 20.00% |
Borislav Petkov | 2 | 1.98% | 1 | 20.00% |
Kay Sievers | 1 | 0.99% | 1 | 20.00% |
Total | 101 | 100.00% | 5 | 100.00% |
static __init int mcheck_init_device(void)
{
int err;
if (!mce_available(&boot_cpu_data)) {
err = -EIO;
goto err_out;
}
if (!zalloc_cpumask_var(&mce_device_initialized, GFP_KERNEL)) {
err = -ENOMEM;
goto err_out;
}
mce_init_banks();
err = subsys_system_register(&mce_subsys, NULL);
if (err)
goto err_out_mem;
err = cpuhp_setup_state(CPUHP_X86_MCE_DEAD, "x86/mce:dead", NULL,
mce_cpu_dead);
if (err)
goto err_out_mem;
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/mce:online",
mce_cpu_online, mce_cpu_pre_down);
if (err < 0)
goto err_out_online;
register_syscore_ops(&mce_syscore_ops);
return 0;
err_out_online:
cpuhp_remove_state(CPUHP_X86_MCE_DEAD);
err_out_mem:
free_cpumask_var(mce_device_initialized);
err_out:
pr_err("Unable to init MCE device (rc: %d)\n", err);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Mathieu Souchaud | 48 | 32.21% | 1 | 7.14% |
Andi Kleen | 38 | 25.50% | 4 | 28.57% |
Sebastian Andrzej Siewior | 29 | 19.46% | 2 | 14.29% |
Akinobu Mita | 14 | 9.40% | 1 | 7.14% |
Rafael J. Wysocki | 6 | 4.03% | 1 | 7.14% |
Rusty Russell | 6 | 4.03% | 1 | 7.14% |
Kay Sievers | 5 | 3.36% | 1 | 7.14% |
Borislav Petkov | 1 | 0.67% | 1 | 7.14% |
Tony Luck | 1 | 0.67% | 1 | 7.14% |
Yinghai Lu | 1 | 0.67% | 1 | 7.14% |
Total | 149 | 100.00% | 14 | 100.00% |
device_initcall_sync(mcheck_init_device);
/*
* Old style boot options parsing. Only for compatibility.
*/
static int __init mcheck_disable(char *str)
{
mca_cfg.disabled = true;
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ingo Molnar | 15 | 75.00% | 1 | 33.33% |
Borislav Petkov | 4 | 20.00% | 1 | 33.33% |
Andi Kleen | 1 | 5.00% | 1 | 33.33% |
Total | 20 | 100.00% | 3 | 100.00% |
__setup("nomce", mcheck_disable);
#ifdef CONFIG_DEBUG_FS
struct dentry *mce_get_debugfs_dir(void)
{
static struct dentry *dmce;
if (!dmce)
dmce = debugfs_create_dir("mce", NULL);
return dmce;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Huang Ying | 22 | 68.75% | 1 | 50.00% |
Ingo Molnar | 10 | 31.25% | 1 | 50.00% |
Total | 32 | 100.00% | 2 | 100.00% |
static void mce_reset(void)
{
cpu_missing = 0;
atomic_set(&mce_fake_panicked, 0);
atomic_set(&mce_executing, 0);
atomic_set(&mce_callin, 0);
atomic_set(&global_nwo, 0);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Huang Ying | 28 | 63.64% | 1 | 25.00% |
Ingo Molnar | 15 | 34.09% | 2 | 50.00% |
Borislav Petkov | 1 | 2.27% | 1 | 25.00% |
Total | 44 | 100.00% | 4 | 100.00% |
static int fake_panic_get(void *data, u64 *val)
{
*val = fake_panic;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Huang Ying | 13 | 59.09% | 1 | 50.00% |
Ingo Molnar | 9 | 40.91% | 1 | 50.00% |
Total | 22 | 100.00% | 2 | 100.00% |
static int fake_panic_set(void *data, u64 val)
{
mce_reset();
fake_panic = val;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Huang Ying | 21 | 91.30% | 1 | 50.00% |
Ingo Molnar | 2 | 8.70% | 1 | 50.00% |
Total | 23 | 100.00% | 2 | 100.00% |
DEFINE_SIMPLE_ATTRIBUTE(fake_panic_fops, fake_panic_get,
fake_panic_set, "%llu\n");
static int __init mcheck_debugfs_init(void)
{
struct dentry *dmce, *ffake_panic;
dmce = mce_get_debugfs_dir();
if (!dmce)
return -ENOMEM;
ffake_panic = debugfs_create_file("fake_panic", 0444, dmce, NULL,
&fake_panic_fops);
if (!ffake_panic)
return -ENOMEM;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Huang Ying | 47 | 79.66% | 1 | 33.33% |
Ingo Molnar | 11 | 18.64% | 1 | 33.33% |
Borislav Petkov | 1 | 1.69% | 1 | 33.33% |
Total | 59 | 100.00% | 3 | 100.00% |
#else
static int __init mcheck_debugfs_init(void) { return -EINVAL; }
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chen Gong | 12 | 92.31% | 1 | 50.00% |
Borislav Petkov | 1 | 7.69% | 1 | 50.00% |
Total | 13 | 100.00% | 2 | 100.00% |
#endif
DEFINE_STATIC_KEY_FALSE(mcsafe_key);
EXPORT_SYMBOL_GPL(mcsafe_key);
static int __init mcheck_late_init(void)
{
if (mca_cfg.recovery)
static_branch_inc(&mcsafe_key);
mcheck_debugfs_init();
cec_init();
/*
* Flush out everything that has been logged during early boot, now that
* everything has been initialized (workqueues, decoders, ...).
*/
mce_schedule_work();
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chen Gong | 19 | 55.88% | 1 | 33.33% |
Tony Luck | 12 | 35.29% | 1 | 33.33% |
Borislav Petkov | 3 | 8.82% | 1 | 33.33% |
Total | 34 | 100.00% | 3 | 100.00% |
late_initcall(mcheck_late_init);
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 3569 | 41.42% | 70 | 26.72% |
Borislav Petkov | 1115 | 12.94% | 36 | 13.74% |
Tony Luck | 789 | 9.16% | 15 | 5.73% |
Hidetoshi Seto | 590 | 6.85% | 20 | 7.63% |
Yazen Ghannam | 424 | 4.92% | 12 | 4.58% |
Chen Gong | 334 | 3.88% | 7 | 2.67% |
Huang Ying | 255 | 2.96% | 5 | 1.91% |
Ingo Molnar | 180 | 2.09% | 7 | 2.67% |
Ashok Raj | 150 | 1.74% | 5 | 1.91% |
Sebastian Andrzej Siewior | 146 | 1.69% | 5 | 1.91% |
Thomas Gleixner | 99 | 1.15% | 8 | 3.05% |
Naveen N. Rao | 98 | 1.14% | 3 | 1.15% |
Kay Sievers | 94 | 1.09% | 2 | 0.76% |
Aravind Gopalakrishnan | 81 | 0.94% | 7 | 2.67% |
Tim Hockin | 70 | 0.81% | 3 | 1.15% |
Greg Kroah-Hartman | 67 | 0.78% | 2 | 0.76% |
Akinobu Mita | 56 | 0.65% | 2 | 0.76% |
Mathieu Souchaud | 48 | 0.56% | 1 | 0.38% |
David Shaohua Li | 42 | 0.49% | 1 | 0.38% |
Rafael J. Wysocki | 41 | 0.48% | 2 | 0.76% |
Chen Yucong | 36 | 0.42% | 2 | 0.76% |
Zwane Mwaikambo | 33 | 0.38% | 2 | 0.76% |
Andrew Lutomirski | 32 | 0.37% | 3 | 1.15% |
Tejun Heo | 31 | 0.36% | 4 | 1.53% |
Bartlomiej Zolnierkiewicz | 24 | 0.28% | 2 | 0.76% |
Christoph Lameter | 24 | 0.28% | 1 | 0.38% |
Andreas Herrmann | 22 | 0.26% | 2 | 0.76% |
Xunlei Pang | 22 | 0.26% | 1 | 0.38% |
Andrew Morton | 18 | 0.21% | 2 | 0.76% |
Joe Perches | 16 | 0.19% | 1 | 0.38% |
Dave Jones | 14 | 0.16% | 1 | 0.38% |
Jan Beulich | 13 | 0.15% | 1 | 0.38% |
Rusty Russell | 12 | 0.14% | 2 | 0.76% |
Venkatesh Pallipadi | 10 | 0.12% | 2 | 0.76% |
Eric W. Biedermann | 8 | 0.09% | 1 | 0.38% |
Levente Kurusa | 7 | 0.08% | 1 | 0.38% |
H. Peter Anvin | 7 | 0.08% | 2 | 0.76% |
Roland Dreier | 5 | 0.06% | 1 | 0.38% |
Yong Wang | 3 | 0.03% | 1 | 0.38% |
Paul Gortmaker | 3 | 0.03% | 1 | 0.38% |
Daniel Rahn | 3 | 0.03% | 1 | 0.38% |
Daniel Walter | 3 | 0.03% | 1 | 0.38% |
Xie XiuQi | 3 | 0.03% | 1 | 0.38% |
Randy Dunlap | 2 | 0.02% | 1 | 0.38% |
Jesse Larrew | 2 | 0.02% | 1 | 0.38% |
Vishal Verma | 2 | 0.02% | 1 | 0.38% |
Derek Che | 2 | 0.02% | 1 | 0.38% |
Jacob Shin | 2 | 0.02% | 1 | 0.38% |
Alex Shi | 2 | 0.02% | 1 | 0.38% |
Arnd Bergmann | 2 | 0.02% | 1 | 0.38% |
Yinghai Lu | 2 | 0.02% | 2 | 0.76% |
Linus Torvalds | 1 | 0.01% | 1 | 0.38% |
Hirofumi Ogawa | 1 | 0.01% | 1 | 0.38% |
Davidlohr Bueso A | 1 | 0.01% | 1 | 0.38% |
Liu Jinsong | 1 | 0.01% | 1 | 0.38% |
Total | 8617 | 100.00% | 262 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.