diff options
author | Andi Kleen <ak@suse.de> | 2005-04-16 18:25:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:25:09 -0400 |
commit | 94ad84740fb3fe6c2112e60bc71a256c2815479d (patch) | |
tree | f9725aa273ebbfd40253a90b4d6ae1d5564e7a9f /arch/x86_64 | |
parent | 1c1734090ebcd31e479798b3af4c260ae09bf3a4 (diff) |
[PATCH] x86_64: Use the extended RIP MSR for machine check reporting if available.
They are rumoured to be much more reliable than the RIP in the stack frame on
P4s.
This is a borderline case because the code is very simple. Please note there
are no plans to add support for all the MCE register MSRs.
Cc: <venkatesh.pallipadi@intel.com>
Cc: <racing.guo@intel.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64')
-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 */ |