diff options
| -rw-r--r-- | arch/x86_64/kernel/mce.c | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 86f9fd85016a..6ca066424dee 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c | |||
| @@ -33,6 +33,7 @@ static int banks; | |||
| 33 | static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL }; | 33 | static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL }; |
| 34 | static unsigned long console_logged; | 34 | static unsigned long console_logged; |
| 35 | static int notify_user; | 35 | static int notify_user; |
| 36 | static int rip_msr; | ||
| 36 | 37 | ||
| 37 | /* | 38 | /* |
| 38 | * Lockless MCE logging infrastructure. | 39 | * Lockless MCE logging infrastructure. |
| @@ -124,6 +125,23 @@ static int mce_available(struct cpuinfo_x86 *c) | |||
| 124 | test_bit(X86_FEATURE_MCA, &c->x86_capability); | 125 | test_bit(X86_FEATURE_MCA, &c->x86_capability); |
| 125 | } | 126 | } |
| 126 | 127 | ||
| 128 | static inline void mce_get_rip(struct mce *m, struct pt_regs *regs) | ||
| 129 | { | ||
| 130 | if (regs && (m->mcgstatus & MCG_STATUS_RIPV)) { | ||
| 131 | m->rip = regs->rip; | ||
| 132 | m->cs = regs->cs; | ||
| 133 | } else { | ||
| 134 | m->rip = 0; | ||
| 135 | m->cs = 0; | ||
| 136 | } | ||
| 137 | if (rip_msr) { | ||
| 138 | /* Assume the RIP in the MSR is exact. Is this true? */ | ||
| 139 | m->mcgstatus |= MCG_STATUS_EIPV; | ||
| 140 | rdmsrl(rip_msr, m->rip); | ||
| 141 | m->cs = 0; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 127 | /* | 145 | /* |
| 128 | * The actual machine check handler | 146 | * The actual machine check handler |
| 129 | */ | 147 | */ |
| @@ -176,14 +194,7 @@ void do_machine_check(struct pt_regs * regs, long error_code) | |||
| 176 | if (m.status & MCI_STATUS_ADDRV) | 194 | if (m.status & MCI_STATUS_ADDRV) |
| 177 | rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr); | 195 | rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr); |
| 178 | 196 | ||
| 179 | if (regs && (m.mcgstatus & MCG_STATUS_RIPV)) { | 197 | mce_get_rip(&m, regs); |
| 180 | m.rip = regs->rip; | ||
| 181 | m.cs = regs->cs; | ||
| 182 | } else { | ||
| 183 | m.rip = 0; | ||
| 184 | m.cs = 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | if (error_code != -1) | 198 | if (error_code != -1) |
| 188 | rdtscll(m.tsc); | 199 | rdtscll(m.tsc); |
| 189 | wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0); | 200 | wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0); |
| @@ -296,6 +307,9 @@ static void mce_init(void *dummy) | |||
| 296 | printk(KERN_INFO "MCE: warning: using only %d banks\n", banks); | 307 | printk(KERN_INFO "MCE: warning: using only %d banks\n", banks); |
| 297 | banks = NR_BANKS; | 308 | banks = NR_BANKS; |
| 298 | } | 309 | } |
| 310 | /* Use accurate RIP reporting if available. */ | ||
| 311 | if ((cap & (1<<9)) && ((cap >> 16) & 0xff) >= 9) | ||
| 312 | rip_msr = MSR_IA32_MCG_EIP; | ||
| 299 | 313 | ||
| 300 | /* Log the machine checks left over from the previous reset. | 314 | /* Log the machine checks left over from the previous reset. |
| 301 | This also clears all registers */ | 315 | This also clears all registers */ |
