Skip to content

Commit

Permalink
Merge branch 'ras-core-for-linus' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/tip/tip

Pull RAS updates from Ingo Molnar:
 "Various x86 MCE fixes and small enhancements"

* 'ras-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/mce: Make usable address checks Intel-only
  x86/mce: Add the missing memory error check on AMD
  x86/RAS: Remove mce.usable_addr
  x86/mce: Do not enter deferred errors into the generic pool twice
  • Loading branch information
torvalds committed Jan 11, 2016
2 parents 5cb52b5 + feab21f commit 4bd20db
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 41 deletions.
2 changes: 1 addition & 1 deletion arch/x86/include/uapi/asm/mce.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct mce {
__u8 cpuvendor; /* cpu vendor as encoded in system.h */
__u8 inject_flags; /* software inject flags */
__u8 severity;
__u8 usable_addr;
__u8 pad;
__u32 cpuid; /* CPUID 1 EAX */
__u8 cs; /* code segment */
__u8 bank; /* machine check bank */
Expand Down
82 changes: 42 additions & 40 deletions arch/x86/kernel/cpu/mcheck/mce.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ 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);
static int mce_usable_address(struct mce *m);

/*
* CPU/chipset specific EDAC code can register a notifier call here to print
Expand Down Expand Up @@ -475,6 +474,28 @@ static void mce_report_event(struct pt_regs *regs)
irq_work_queue(&mce_irq_work);
}

/*
* 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_MISCV) || !(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 (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;
}

static int srao_decode_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
Expand All @@ -484,7 +505,7 @@ static int srao_decode_notifier(struct notifier_block *nb, unsigned long val,
if (!mce)
return NOTIFY_DONE;

if (mce->usable_addr && (mce->severity == MCE_AO_SEVERITY)) {
if (mce_usable_address(mce) && (mce->severity == MCE_AO_SEVERITY)) {
pfn = mce->addr >> PAGE_SHIFT;
memory_failure(pfn, MCE_VECTOR, 0);
}
Expand Down Expand Up @@ -522,10 +543,10 @@ static bool memory_error(struct mce *m)
struct cpuinfo_x86 *c = &boot_cpu_data;

if (c->x86_vendor == X86_VENDOR_AMD) {
/*
* coming soon
*/
return false;
/* ErrCodeExt[20:16] */
u8 xec = (m->status >> 16) & 0x1f;

return (xec == 0x0 || xec == 0x8);
} else if (c->x86_vendor == X86_VENDOR_INTEL) {
/*
* Intel SDM Volume 3B - 15.9.2 Compound Error Codes
Expand Down Expand Up @@ -567,7 +588,7 @@ DEFINE_PER_CPU(unsigned, mce_poll_count);
*/
bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
{
bool error_logged = false;
bool error_seen = false;
struct mce m;
int severity;
int i;
Expand Down Expand Up @@ -601,34 +622,33 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
(m.status & (mca_cfg.ser ? MCI_STATUS_S : MCI_STATUS_UC)))
continue;

error_seen = true;

mce_read_aux(&m, i);

if (!(flags & MCP_TIMESTAMP))
m.tsc = 0;

severity = mce_severity(&m, mca_cfg.tolerant, NULL, false);

/*
* In the cases where we don't have a valid address after all,
* do not add it into the ring buffer.
*/
if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m)) {
if (m.status & MCI_STATUS_ADDRV) {
if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m))
if (m.status & MCI_STATUS_ADDRV)
m.severity = severity;
m.usable_addr = mce_usable_address(&m);

if (!mce_gen_pool_add(&m))
mce_schedule_work();
}
}

/*
* 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) {
error_logged = true;
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();
}

/*
Expand All @@ -644,7 +664,7 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)

sync_core();

return error_logged;
return error_seen;
}
EXPORT_SYMBOL_GPL(machine_check_poll);

Expand Down Expand Up @@ -931,23 +951,6 @@ static int mce_end(int order)
return ret;
}

/*
* 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_MISCV) || !(m->status & MCI_STATUS_ADDRV))
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;
}

static void mce_clear_state(unsigned long *toclear)
{
int i;
Expand Down Expand Up @@ -1100,7 +1103,6 @@ void do_machine_check(struct pt_regs *regs, long error_code)

/* assuming valid severity level != 0 */
m.severity = severity;
m.usable_addr = mce_usable_address(&m);

mce_log(&m);

Expand Down

0 comments on commit 4bd20db

Please sign in to comment.