diff options
author | Tony Luck <tony.luck@intel.com> | 2011-12-13 12:48:13 -0500 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2012-01-03 15:06:45 -0500 |
commit | 85f92694affa7dba7f1978666a69552b5dfc628e (patch) | |
tree | 613ac35ef99bc2500add551cb5e5c405d4ca1894 /arch | |
parent | 7329bbeb92740f35d64a8860ae7837ff4db27fe0 (diff) |
x86/mce: Create helper function to save addr/misc when needed
The MCI_STATUS_MISCV and MCI_STATUS_ADDRV bits in the bank status
registers define whether the MISC and ADDR registers respectively
contain valid data - provide a helper function to check these bits
and read the registers when needed.
In addition, processors that support software error recovery (as
indicated by the MCG_SER_P bit in the MCG_CAP register) may include
some undefined bits in the ADDR register - mask these out.
Acked-by: Borislav Petkov <bp@amd64.org>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 1a08ce5f345f..2f1c200f05e6 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -492,6 +492,27 @@ static void mce_report_event(struct pt_regs *regs) | |||
492 | irq_work_queue(&__get_cpu_var(mce_irq_work)); | 492 | irq_work_queue(&__get_cpu_var(mce_irq_work)); |
493 | } | 493 | } |
494 | 494 | ||
495 | /* | ||
496 | * Read ADDR and MISC registers. | ||
497 | */ | ||
498 | static void mce_read_aux(struct mce *m, int i) | ||
499 | { | ||
500 | if (m->status & MCI_STATUS_MISCV) | ||
501 | m->misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i)); | ||
502 | if (m->status & MCI_STATUS_ADDRV) { | ||
503 | m->addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i)); | ||
504 | |||
505 | /* | ||
506 | * Mask the reported address by the reported granularity. | ||
507 | */ | ||
508 | if (mce_ser && (m->status & MCI_STATUS_MISCV)) { | ||
509 | u8 shift = MCI_MISC_ADDR_LSB(m->misc); | ||
510 | m->addr >>= shift; | ||
511 | m->addr <<= shift; | ||
512 | } | ||
513 | } | ||
514 | } | ||
515 | |||
495 | DEFINE_PER_CPU(unsigned, mce_poll_count); | 516 | DEFINE_PER_CPU(unsigned, mce_poll_count); |
496 | 517 | ||
497 | /* | 518 | /* |
@@ -542,10 +563,7 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) | |||
542 | (m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC))) | 563 | (m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC))) |
543 | continue; | 564 | continue; |
544 | 565 | ||
545 | if (m.status & MCI_STATUS_MISCV) | 566 | mce_read_aux(&m, i); |
546 | m.misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i)); | ||
547 | if (m.status & MCI_STATUS_ADDRV) | ||
548 | m.addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i)); | ||
549 | 567 | ||
550 | if (!(flags & MCP_TIMESTAMP)) | 568 | if (!(flags & MCP_TIMESTAMP)) |
551 | m.tsc = 0; | 569 | m.tsc = 0; |
@@ -981,10 +999,7 @@ void do_machine_check(struct pt_regs *regs, long error_code) | |||
981 | if (severity == MCE_AR_SEVERITY) | 999 | if (severity == MCE_AR_SEVERITY) |
982 | kill_it = 1; | 1000 | kill_it = 1; |
983 | 1001 | ||
984 | if (m.status & MCI_STATUS_MISCV) | 1002 | mce_read_aux(&m, i); |
985 | m.misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i)); | ||
986 | if (m.status & MCI_STATUS_ADDRV) | ||
987 | m.addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i)); | ||
988 | 1003 | ||
989 | /* | 1004 | /* |
990 | * Action optional error. Queue address for later processing. | 1005 | * Action optional error. Queue address for later processing. |