diff options
author | Andi Kleen <andi@firstfloor.org> | 2009-05-27 15:56:56 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-06-03 17:40:38 -0400 |
commit | 8ee08347c1e8b5680b3b3ce081e42e97bcaa1abe (patch) | |
tree | a03d22d322c9fa31ee2025e3b120723245a2dc6a /arch/x86 | |
parent | d620c67fb92aa11736112f9a03e31d8e3079c57a (diff) |
x86, mce: extend struct mce user interface with more information.
Experience has shown that struct mce which is used to pass an machine
check to the user space daemon currently a few limitations. Also some
data which is useful to print at panic level is also missing.
This patch addresses most of them. The same information is also
printed out together with mce panic.
struct mce can be painlessly extended in a compatible way, the mcelog
user space code just ignores additional fields with a warning.
- It doesn't provide a wall time timestamp. There have been a few
complaints about that. Fix that by adding a 64bit time_t
- It doesn't provide the exact CPU identification. This makes
it awkward for mcelog to decode the event correctly, especially
when there are variations in the supported MCE codes on different
CPU models or when mcelog is running on a different host after a panic.
Previously the administrator had to specify the correct CPU
when mcelog ran on a different host, but with the more variation
in machine checks now it's better to auto detect that.
It's also useful for more detailed analysis of CPU events.
Pass CPUID 1.EAX and the cpu vendor (as encoded in processor.h) instead.
- Socket ID and initial APIC ID are useful to report because they
allow to identify the failing CPU in some (not all) cases.
This is also especially useful for the panic situation.
This addresses one of the complaints from Thomas Gleixner earlier.
- The MCG capabilities MSR needs to be reported for some advanced
error processing in mcelog
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/mce.h | 10 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 12 |
2 files changed, 20 insertions, 2 deletions
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index b4a04b60b740..ba1f8890cf51 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h | |||
@@ -36,13 +36,19 @@ struct mce { | |||
36 | __u64 mcgstatus; | 36 | __u64 mcgstatus; |
37 | __u64 ip; | 37 | __u64 ip; |
38 | __u64 tsc; /* cpu time stamp counter */ | 38 | __u64 tsc; /* cpu time stamp counter */ |
39 | __u64 res1; /* for future extension */ | 39 | __u64 time; /* wall time_t when error was detected */ |
40 | __u64 res2; /* dito. */ | 40 | __u8 cpuvendor; /* cpu vendor as encoded in system.h */ |
41 | __u8 pad1; | ||
42 | __u16 pad2; | ||
43 | __u32 cpuid; /* CPUID 1 EAX */ | ||
41 | __u8 cs; /* code segment */ | 44 | __u8 cs; /* code segment */ |
42 | __u8 bank; /* machine check bank */ | 45 | __u8 bank; /* machine check bank */ |
43 | __u8 cpu; /* cpu number; obsolete; use extcpu now */ | 46 | __u8 cpu; /* cpu number; obsolete; use extcpu now */ |
44 | __u8 finished; /* entry is valid */ | 47 | __u8 finished; /* entry is valid */ |
45 | __u32 extcpu; /* linux cpu number that detected the error */ | 48 | __u32 extcpu; /* linux cpu number that detected the error */ |
49 | __u32 socketid; /* CPU socket ID */ | ||
50 | __u32 apicid; /* CPU initial apic ID */ | ||
51 | __u64 mcgcap; /* MCGCAP MSR: machine check capabilities of CPU */ | ||
46 | }; | 52 | }; |
47 | 53 | ||
48 | /* | 54 | /* |
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 2c4dd6c422c3..ba68449c22a1 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -96,6 +96,15 @@ void mce_setup(struct mce *m) | |||
96 | memset(m, 0, sizeof(struct mce)); | 96 | memset(m, 0, sizeof(struct mce)); |
97 | m->cpu = m->extcpu = smp_processor_id(); | 97 | m->cpu = m->extcpu = smp_processor_id(); |
98 | rdtscll(m->tsc); | 98 | rdtscll(m->tsc); |
99 | /* We hope get_seconds stays lockless */ | ||
100 | m->time = get_seconds(); | ||
101 | m->cpuvendor = boot_cpu_data.x86_vendor; | ||
102 | m->cpuid = cpuid_eax(1); | ||
103 | #ifdef CONFIG_SMP | ||
104 | m->socketid = cpu_data(m->extcpu).phys_proc_id; | ||
105 | #endif | ||
106 | m->apicid = cpu_data(m->extcpu).initial_apicid; | ||
107 | rdmsrl(MSR_IA32_MCG_CAP, m->mcgcap); | ||
99 | } | 108 | } |
100 | 109 | ||
101 | DEFINE_PER_CPU(struct mce, injectm); | 110 | DEFINE_PER_CPU(struct mce, injectm); |
@@ -173,6 +182,9 @@ static void print_mce(struct mce *m) | |||
173 | if (m->misc) | 182 | if (m->misc) |
174 | printk("MISC %llx ", m->misc); | 183 | printk("MISC %llx ", m->misc); |
175 | printk("\n"); | 184 | printk("\n"); |
185 | printk(KERN_EMERG "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n", | ||
186 | m->cpuvendor, m->cpuid, m->time, m->socketid, | ||
187 | m->apicid); | ||
176 | printk(KERN_EMERG "This is not a software problem!\n"); | 188 | printk(KERN_EMERG "This is not a software problem!\n"); |
177 | printk(KERN_EMERG "Run through mcelog --ascii to decode " | 189 | printk(KERN_EMERG "Run through mcelog --ascii to decode " |
178 | "and contact your hardware vendor\n"); | 190 | "and contact your hardware vendor\n"); |