diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-22 20:03:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-22 20:03:40 -0400 |
commit | 7c6582b28a7debef031a8b7e31953c7d45ddb05d (patch) | |
tree | 33104b99d85b7250384a938534ef42853821351e /arch | |
parent | 227ad9bc070db2801a7f586b4d350dd1d8b82e03 (diff) | |
parent | c7cece89f1b00b56276303942f96ec67cf206e1e (diff) |
Merge branch 'x86-mce-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-mce-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
x86, mce: Use mce_sysdev_ prefix to group functions
x86, mce: Use mce_chrdev_ prefix to group functions
x86, mce: Cleanup mce_read()
x86, mce: Cleanup mce_create()/remove_device()
x86, mce: Check the result of ancient_init()
x86, mce: Introduce mce_gather_info()
x86, mce: Replace MCM_ with MCI_MISC_
x86, mce: Replace MCE_SELF_VECTOR by irq_work
x86, mce, severity: Clean up trivial coding style problems
x86, mce, severity: Cleanup severity table
x86, mce, severity: Make formatting a bit more readable
x86, mce, severity: Fix two severities table signatures
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/entry_arch.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/hw_irq.h | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/irq_vectors.h | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/mce.h | 19 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce-severity.c | 152 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 288 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce_amd.c | 10 | ||||
-rw-r--r-- | arch/x86/kernel/entry_64.S | 5 | ||||
-rw-r--r-- | arch/x86/kernel/irqinit.c | 3 |
9 files changed, 251 insertions, 236 deletions
diff --git a/arch/x86/include/asm/entry_arch.h b/arch/x86/include/asm/entry_arch.h index 1cd6d26a0a8d..0baa628e330c 100644 --- a/arch/x86/include/asm/entry_arch.h +++ b/arch/x86/include/asm/entry_arch.h | |||
@@ -53,8 +53,4 @@ BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) | |||
53 | BUILD_INTERRUPT(threshold_interrupt,THRESHOLD_APIC_VECTOR) | 53 | BUILD_INTERRUPT(threshold_interrupt,THRESHOLD_APIC_VECTOR) |
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | #ifdef CONFIG_X86_MCE | ||
57 | BUILD_INTERRUPT(mce_self_interrupt,MCE_SELF_VECTOR) | ||
58 | #endif | ||
59 | |||
60 | #endif | 56 | #endif |
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index bb9efe8706e2..13f5504c76c0 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h | |||
@@ -34,7 +34,6 @@ extern void irq_work_interrupt(void); | |||
34 | extern void spurious_interrupt(void); | 34 | extern void spurious_interrupt(void); |
35 | extern void thermal_interrupt(void); | 35 | extern void thermal_interrupt(void); |
36 | extern void reschedule_interrupt(void); | 36 | extern void reschedule_interrupt(void); |
37 | extern void mce_self_interrupt(void); | ||
38 | 37 | ||
39 | extern void invalidate_interrupt(void); | 38 | extern void invalidate_interrupt(void); |
40 | extern void invalidate_interrupt0(void); | 39 | extern void invalidate_interrupt0(void); |
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 6e976ee3b3ef..6665026ea3ea 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h | |||
@@ -109,11 +109,6 @@ | |||
109 | 109 | ||
110 | #define UV_BAU_MESSAGE 0xf5 | 110 | #define UV_BAU_MESSAGE 0xf5 |
111 | 111 | ||
112 | /* | ||
113 | * Self IPI vector for machine checks | ||
114 | */ | ||
115 | #define MCE_SELF_VECTOR 0xf4 | ||
116 | |||
117 | /* Xen vector callback to receive events in a HVM domain */ | 112 | /* Xen vector callback to receive events in a HVM domain */ |
118 | #define XEN_HVM_EVTCHN_CALLBACK 0xf3 | 113 | #define XEN_HVM_EVTCHN_CALLBACK 0xf3 |
119 | 114 | ||
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 021979a6e23f..716b48af7863 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h | |||
@@ -8,6 +8,7 @@ | |||
8 | * Machine Check support for x86 | 8 | * Machine Check support for x86 |
9 | */ | 9 | */ |
10 | 10 | ||
11 | /* MCG_CAP register defines */ | ||
11 | #define MCG_BANKCNT_MASK 0xff /* Number of Banks */ | 12 | #define MCG_BANKCNT_MASK 0xff /* Number of Banks */ |
12 | #define MCG_CTL_P (1ULL<<8) /* MCG_CTL register available */ | 13 | #define MCG_CTL_P (1ULL<<8) /* MCG_CTL register available */ |
13 | #define MCG_EXT_P (1ULL<<9) /* Extended registers available */ | 14 | #define MCG_EXT_P (1ULL<<9) /* Extended registers available */ |
@@ -17,10 +18,12 @@ | |||
17 | #define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT) | 18 | #define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT) |
18 | #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ | 19 | #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ |
19 | 20 | ||
21 | /* MCG_STATUS register defines */ | ||
20 | #define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */ | 22 | #define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */ |
21 | #define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */ | 23 | #define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */ |
22 | #define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */ | 24 | #define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */ |
23 | 25 | ||
26 | /* MCi_STATUS register defines */ | ||
24 | #define MCI_STATUS_VAL (1ULL<<63) /* valid error */ | 27 | #define MCI_STATUS_VAL (1ULL<<63) /* valid error */ |
25 | #define MCI_STATUS_OVER (1ULL<<62) /* previous errors lost */ | 28 | #define MCI_STATUS_OVER (1ULL<<62) /* previous errors lost */ |
26 | #define MCI_STATUS_UC (1ULL<<61) /* uncorrected error */ | 29 | #define MCI_STATUS_UC (1ULL<<61) /* uncorrected error */ |
@@ -31,12 +34,14 @@ | |||
31 | #define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */ | 34 | #define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */ |
32 | #define MCI_STATUS_AR (1ULL<<55) /* Action required */ | 35 | #define MCI_STATUS_AR (1ULL<<55) /* Action required */ |
33 | 36 | ||
34 | /* MISC register defines */ | 37 | /* MCi_MISC register defines */ |
35 | #define MCM_ADDR_SEGOFF 0 /* segment offset */ | 38 | #define MCI_MISC_ADDR_LSB(m) ((m) & 0x3f) |
36 | #define MCM_ADDR_LINEAR 1 /* linear address */ | 39 | #define MCI_MISC_ADDR_MODE(m) (((m) >> 6) & 7) |
37 | #define MCM_ADDR_PHYS 2 /* physical address */ | 40 | #define MCI_MISC_ADDR_SEGOFF 0 /* segment offset */ |
38 | #define MCM_ADDR_MEM 3 /* memory address */ | 41 | #define MCI_MISC_ADDR_LINEAR 1 /* linear address */ |
39 | #define MCM_ADDR_GENERIC 7 /* generic */ | 42 | #define MCI_MISC_ADDR_PHYS 2 /* physical address */ |
43 | #define MCI_MISC_ADDR_MEM 3 /* memory address */ | ||
44 | #define MCI_MISC_ADDR_GENERIC 7 /* generic */ | ||
40 | 45 | ||
41 | /* CTL2 register defines */ | 46 | /* CTL2 register defines */ |
42 | #define MCI_CTL2_CMCI_EN (1ULL << 30) | 47 | #define MCI_CTL2_CMCI_EN (1ULL << 30) |
@@ -144,7 +149,7 @@ static inline void enable_p5_mce(void) {} | |||
144 | 149 | ||
145 | void mce_setup(struct mce *m); | 150 | void mce_setup(struct mce *m); |
146 | void mce_log(struct mce *m); | 151 | void mce_log(struct mce *m); |
147 | DECLARE_PER_CPU(struct sys_device, mce_dev); | 152 | DECLARE_PER_CPU(struct sys_device, mce_sysdev); |
148 | 153 | ||
149 | /* | 154 | /* |
150 | * Maximum banks number. | 155 | * Maximum banks number. |
diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index 1e8d66c1336a..7395d5f4272d 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c | |||
@@ -43,61 +43,105 @@ static struct severity { | |||
43 | unsigned char covered; | 43 | unsigned char covered; |
44 | char *msg; | 44 | char *msg; |
45 | } severities[] = { | 45 | } severities[] = { |
46 | #define KERNEL .context = IN_KERNEL | 46 | #define MCESEV(s, m, c...) { .sev = MCE_ ## s ## _SEVERITY, .msg = m, ## c } |
47 | #define USER .context = IN_USER | 47 | #define KERNEL .context = IN_KERNEL |
48 | #define SER .ser = SER_REQUIRED | 48 | #define USER .context = IN_USER |
49 | #define NOSER .ser = NO_SER | 49 | #define SER .ser = SER_REQUIRED |
50 | #define SEV(s) .sev = MCE_ ## s ## _SEVERITY | 50 | #define NOSER .ser = NO_SER |
51 | #define BITCLR(x, s, m, r...) { .mask = x, .result = 0, SEV(s), .msg = m, ## r } | 51 | #define BITCLR(x) .mask = x, .result = 0 |
52 | #define BITSET(x, s, m, r...) { .mask = x, .result = x, SEV(s), .msg = m, ## r } | 52 | #define BITSET(x) .mask = x, .result = x |
53 | #define MCGMASK(x, res, s, m, r...) \ | 53 | #define MCGMASK(x, y) .mcgmask = x, .mcgres = y |
54 | { .mcgmask = x, .mcgres = res, SEV(s), .msg = m, ## r } | 54 | #define MASK(x, y) .mask = x, .result = y |
55 | #define MASK(x, y, s, m, r...) \ | ||
56 | { .mask = x, .result = y, SEV(s), .msg = m, ## r } | ||
57 | #define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S) | 55 | #define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S) |
58 | #define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR) | 56 | #define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR) |
59 | #define MCACOD 0xffff | 57 | #define MCACOD 0xffff |
60 | 58 | ||
61 | BITCLR(MCI_STATUS_VAL, NO, "Invalid"), | 59 | MCESEV( |
62 | BITCLR(MCI_STATUS_EN, NO, "Not enabled"), | 60 | NO, "Invalid", |
63 | BITSET(MCI_STATUS_PCC, PANIC, "Processor context corrupt"), | 61 | BITCLR(MCI_STATUS_VAL) |
62 | ), | ||
63 | MCESEV( | ||
64 | NO, "Not enabled", | ||
65 | BITCLR(MCI_STATUS_EN) | ||
66 | ), | ||
67 | MCESEV( | ||
68 | PANIC, "Processor context corrupt", | ||
69 | BITSET(MCI_STATUS_PCC) | ||
70 | ), | ||
64 | /* When MCIP is not set something is very confused */ | 71 | /* When MCIP is not set something is very confused */ |
65 | MCGMASK(MCG_STATUS_MCIP, 0, PANIC, "MCIP not set in MCA handler"), | 72 | MCESEV( |
73 | PANIC, "MCIP not set in MCA handler", | ||
74 | MCGMASK(MCG_STATUS_MCIP, 0) | ||
75 | ), | ||
66 | /* Neither return not error IP -- no chance to recover -> PANIC */ | 76 | /* Neither return not error IP -- no chance to recover -> PANIC */ |
67 | MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0, PANIC, | 77 | MCESEV( |
68 | "Neither restart nor error IP"), | 78 | PANIC, "Neither restart nor error IP", |
69 | MCGMASK(MCG_STATUS_RIPV, 0, PANIC, "In kernel and no restart IP", | 79 | MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0) |
70 | KERNEL), | 80 | ), |
71 | BITCLR(MCI_STATUS_UC, KEEP, "Corrected error", NOSER), | 81 | MCESEV( |
72 | MASK(MCI_STATUS_OVER|MCI_STATUS_UC|MCI_STATUS_EN, MCI_STATUS_UC, SOME, | 82 | PANIC, "In kernel and no restart IP", |
73 | "Spurious not enabled", SER), | 83 | KERNEL, MCGMASK(MCG_STATUS_RIPV, 0) |
84 | ), | ||
85 | MCESEV( | ||
86 | KEEP, "Corrected error", | ||
87 | NOSER, BITCLR(MCI_STATUS_UC) | ||
88 | ), | ||
74 | 89 | ||
75 | /* ignore OVER for UCNA */ | 90 | /* ignore OVER for UCNA */ |
76 | MASK(MCI_UC_SAR, MCI_STATUS_UC, KEEP, | 91 | MCESEV( |
77 | "Uncorrected no action required", SER), | 92 | KEEP, "Uncorrected no action required", |
78 | MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_UC|MCI_STATUS_AR, PANIC, | 93 | SER, MASK(MCI_UC_SAR, MCI_STATUS_UC) |
79 | "Illegal combination (UCNA with AR=1)", SER), | 94 | ), |
80 | MASK(MCI_STATUS_S, 0, KEEP, "Non signalled machine check", SER), | 95 | MCESEV( |
96 | PANIC, "Illegal combination (UCNA with AR=1)", | ||
97 | SER, | ||
98 | MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_UC|MCI_STATUS_AR) | ||
99 | ), | ||
100 | MCESEV( | ||
101 | KEEP, "Non signalled machine check", | ||
102 | SER, BITCLR(MCI_STATUS_S) | ||
103 | ), | ||
81 | 104 | ||
82 | /* AR add known MCACODs here */ | 105 | /* AR add known MCACODs here */ |
83 | MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_OVER|MCI_UC_SAR, PANIC, | 106 | MCESEV( |
84 | "Action required with lost events", SER), | 107 | PANIC, "Action required with lost events", |
85 | MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_SAR, PANIC, | 108 | SER, BITSET(MCI_STATUS_OVER|MCI_UC_SAR) |
86 | "Action required; unknown MCACOD", SER), | 109 | ), |
110 | MCESEV( | ||
111 | PANIC, "Action required: unknown MCACOD", | ||
112 | SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_SAR) | ||
113 | ), | ||
87 | 114 | ||
88 | /* known AO MCACODs: */ | 115 | /* known AO MCACODs: */ |
89 | MASK(MCI_UC_SAR|MCI_STATUS_OVER|0xfff0, MCI_UC_S|0xc0, AO, | 116 | MCESEV( |
90 | "Action optional: memory scrubbing error", SER), | 117 | AO, "Action optional: memory scrubbing error", |
91 | MASK(MCI_UC_SAR|MCI_STATUS_OVER|MCACOD, MCI_UC_S|0x17a, AO, | 118 | SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|0xfff0, MCI_UC_S|0x00c0) |
92 | "Action optional: last level cache writeback error", SER), | 119 | ), |
93 | 120 | MCESEV( | |
94 | MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S, SOME, | 121 | AO, "Action optional: last level cache writeback error", |
95 | "Action optional unknown MCACOD", SER), | 122 | SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_S|0x017a) |
96 | MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S|MCI_STATUS_OVER, SOME, | 123 | ), |
97 | "Action optional with lost events", SER), | 124 | MCESEV( |
98 | BITSET(MCI_STATUS_UC|MCI_STATUS_OVER, PANIC, "Overflowed uncorrected"), | 125 | SOME, "Action optional: unknown MCACOD", |
99 | BITSET(MCI_STATUS_UC, UC, "Uncorrected"), | 126 | SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S) |
100 | BITSET(0, SOME, "No match") /* always matches. keep at end */ | 127 | ), |
128 | MCESEV( | ||
129 | SOME, "Action optional with lost events", | ||
130 | SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_OVER|MCI_UC_S) | ||
131 | ), | ||
132 | |||
133 | MCESEV( | ||
134 | PANIC, "Overflowed uncorrected", | ||
135 | BITSET(MCI_STATUS_OVER|MCI_STATUS_UC) | ||
136 | ), | ||
137 | MCESEV( | ||
138 | UC, "Uncorrected", | ||
139 | BITSET(MCI_STATUS_UC) | ||
140 | ), | ||
141 | MCESEV( | ||
142 | SOME, "No match", | ||
143 | BITSET(0) | ||
144 | ) /* always matches. keep at end */ | ||
101 | }; | 145 | }; |
102 | 146 | ||
103 | /* | 147 | /* |
@@ -112,15 +156,15 @@ static int error_context(struct mce *m) | |||
112 | return IN_KERNEL; | 156 | return IN_KERNEL; |
113 | } | 157 | } |
114 | 158 | ||
115 | int mce_severity(struct mce *a, int tolerant, char **msg) | 159 | int mce_severity(struct mce *m, int tolerant, char **msg) |
116 | { | 160 | { |
117 | enum context ctx = error_context(a); | 161 | enum context ctx = error_context(m); |
118 | struct severity *s; | 162 | struct severity *s; |
119 | 163 | ||
120 | for (s = severities;; s++) { | 164 | for (s = severities;; s++) { |
121 | if ((a->status & s->mask) != s->result) | 165 | if ((m->status & s->mask) != s->result) |
122 | continue; | 166 | continue; |
123 | if ((a->mcgstatus & s->mcgmask) != s->mcgres) | 167 | if ((m->mcgstatus & s->mcgmask) != s->mcgres) |
124 | continue; | 168 | continue; |
125 | if (s->ser == SER_REQUIRED && !mce_ser) | 169 | if (s->ser == SER_REQUIRED && !mce_ser) |
126 | continue; | 170 | continue; |
@@ -197,15 +241,15 @@ static const struct file_operations severities_coverage_fops = { | |||
197 | 241 | ||
198 | static int __init severities_debugfs_init(void) | 242 | static int __init severities_debugfs_init(void) |
199 | { | 243 | { |
200 | struct dentry *dmce = NULL, *fseverities_coverage = NULL; | 244 | struct dentry *dmce, *fsev; |
201 | 245 | ||
202 | dmce = mce_get_debugfs_dir(); | 246 | dmce = mce_get_debugfs_dir(); |
203 | if (dmce == NULL) | 247 | if (!dmce) |
204 | goto err_out; | 248 | goto err_out; |
205 | fseverities_coverage = debugfs_create_file("severities-coverage", | 249 | |
206 | 0444, dmce, NULL, | 250 | fsev = debugfs_create_file("severities-coverage", 0444, dmce, NULL, |
207 | &severities_coverage_fops); | 251 | &severities_coverage_fops); |
208 | if (fseverities_coverage == NULL) | 252 | if (!fsev) |
209 | goto err_out; | 253 | goto err_out; |
210 | 254 | ||
211 | return 0; | 255 | return 0; |
@@ -214,4 +258,4 @@ err_out: | |||
214 | return -ENOMEM; | 258 | return -ENOMEM; |
215 | } | 259 | } |
216 | late_initcall(severities_debugfs_init); | 260 | late_initcall(severities_debugfs_init); |
217 | #endif | 261 | #endif /* CONFIG_DEBUG_FS */ |
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index ff1ae9b6464d..08363b042122 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -10,7 +10,6 @@ | |||
10 | #include <linux/thread_info.h> | 10 | #include <linux/thread_info.h> |
11 | #include <linux/capability.h> | 11 | #include <linux/capability.h> |
12 | #include <linux/miscdevice.h> | 12 | #include <linux/miscdevice.h> |
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/ratelimit.h> | 13 | #include <linux/ratelimit.h> |
15 | #include <linux/kallsyms.h> | 14 | #include <linux/kallsyms.h> |
16 | #include <linux/rcupdate.h> | 15 | #include <linux/rcupdate.h> |
@@ -38,23 +37,20 @@ | |||
38 | #include <linux/mm.h> | 37 | #include <linux/mm.h> |
39 | #include <linux/debugfs.h> | 38 | #include <linux/debugfs.h> |
40 | #include <linux/edac_mce.h> | 39 | #include <linux/edac_mce.h> |
40 | #include <linux/irq_work.h> | ||
41 | 41 | ||
42 | #include <asm/processor.h> | 42 | #include <asm/processor.h> |
43 | #include <asm/hw_irq.h> | ||
44 | #include <asm/apic.h> | ||
45 | #include <asm/idle.h> | ||
46 | #include <asm/ipi.h> | ||
47 | #include <asm/mce.h> | 43 | #include <asm/mce.h> |
48 | #include <asm/msr.h> | 44 | #include <asm/msr.h> |
49 | 45 | ||
50 | #include "mce-internal.h" | 46 | #include "mce-internal.h" |
51 | 47 | ||
52 | static DEFINE_MUTEX(mce_read_mutex); | 48 | static DEFINE_MUTEX(mce_chrdev_read_mutex); |
53 | 49 | ||
54 | #define rcu_dereference_check_mce(p) \ | 50 | #define rcu_dereference_check_mce(p) \ |
55 | rcu_dereference_index_check((p), \ | 51 | rcu_dereference_index_check((p), \ |
56 | rcu_read_lock_sched_held() || \ | 52 | rcu_read_lock_sched_held() || \ |
57 | lockdep_is_held(&mce_read_mutex)) | 53 | lockdep_is_held(&mce_chrdev_read_mutex)) |
58 | 54 | ||
59 | #define CREATE_TRACE_POINTS | 55 | #define CREATE_TRACE_POINTS |
60 | #include <trace/events/mce.h> | 56 | #include <trace/events/mce.h> |
@@ -94,7 +90,8 @@ static unsigned long mce_need_notify; | |||
94 | static char mce_helper[128]; | 90 | static char mce_helper[128]; |
95 | static char *mce_helper_argv[2] = { mce_helper, NULL }; | 91 | static char *mce_helper_argv[2] = { mce_helper, NULL }; |
96 | 92 | ||
97 | static DECLARE_WAIT_QUEUE_HEAD(mce_wait); | 93 | static DECLARE_WAIT_QUEUE_HEAD(mce_chrdev_wait); |
94 | |||
98 | static DEFINE_PER_CPU(struct mce, mces_seen); | 95 | static DEFINE_PER_CPU(struct mce, mces_seen); |
99 | static int cpu_missing; | 96 | static int cpu_missing; |
100 | 97 | ||
@@ -373,6 +370,31 @@ static void mce_wrmsrl(u32 msr, u64 v) | |||
373 | } | 370 | } |
374 | 371 | ||
375 | /* | 372 | /* |
373 | * Collect all global (w.r.t. this processor) status about this machine | ||
374 | * check into our "mce" struct so that we can use it later to assess | ||
375 | * the severity of the problem as we read per-bank specific details. | ||
376 | */ | ||
377 | static inline void mce_gather_info(struct mce *m, struct pt_regs *regs) | ||
378 | { | ||
379 | mce_setup(m); | ||
380 | |||
381 | m->mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); | ||
382 | if (regs) { | ||
383 | /* | ||
384 | * Get the address of the instruction at the time of | ||
385 | * the machine check error. | ||
386 | */ | ||
387 | if (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) { | ||
388 | m->ip = regs->ip; | ||
389 | m->cs = regs->cs; | ||
390 | } | ||
391 | /* Use accurate RIP reporting if available. */ | ||
392 | if (rip_msr) | ||
393 | m->ip = mce_rdmsrl(rip_msr); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | /* | ||
376 | * Simple lockless ring to communicate PFNs from the exception handler with the | 398 | * Simple lockless ring to communicate PFNs from the exception handler with the |
377 | * process context work function. This is vastly simplified because there's | 399 | * process context work function. This is vastly simplified because there's |
378 | * only a single reader and a single writer. | 400 | * only a single reader and a single writer. |
@@ -443,40 +465,13 @@ static void mce_schedule_work(void) | |||
443 | } | 465 | } |
444 | } | 466 | } |
445 | 467 | ||
446 | /* | 468 | DEFINE_PER_CPU(struct irq_work, mce_irq_work); |
447 | * Get the address of the instruction at the time of the machine check | ||
448 | * error. | ||
449 | */ | ||
450 | static inline void mce_get_rip(struct mce *m, struct pt_regs *regs) | ||
451 | { | ||
452 | |||
453 | if (regs && (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV))) { | ||
454 | m->ip = regs->ip; | ||
455 | m->cs = regs->cs; | ||
456 | } else { | ||
457 | m->ip = 0; | ||
458 | m->cs = 0; | ||
459 | } | ||
460 | if (rip_msr) | ||
461 | m->ip = mce_rdmsrl(rip_msr); | ||
462 | } | ||
463 | 469 | ||
464 | #ifdef CONFIG_X86_LOCAL_APIC | 470 | static void mce_irq_work_cb(struct irq_work *entry) |
465 | /* | ||
466 | * Called after interrupts have been reenabled again | ||
467 | * when a MCE happened during an interrupts off region | ||
468 | * in the kernel. | ||
469 | */ | ||
470 | asmlinkage void smp_mce_self_interrupt(struct pt_regs *regs) | ||
471 | { | 471 | { |
472 | ack_APIC_irq(); | ||
473 | exit_idle(); | ||
474 | irq_enter(); | ||
475 | mce_notify_irq(); | 472 | mce_notify_irq(); |
476 | mce_schedule_work(); | 473 | mce_schedule_work(); |
477 | irq_exit(); | ||
478 | } | 474 | } |
479 | #endif | ||
480 | 475 | ||
481 | static void mce_report_event(struct pt_regs *regs) | 476 | static void mce_report_event(struct pt_regs *regs) |
482 | { | 477 | { |
@@ -492,29 +487,7 @@ static void mce_report_event(struct pt_regs *regs) | |||
492 | return; | 487 | return; |
493 | } | 488 | } |
494 | 489 | ||
495 | #ifdef CONFIG_X86_LOCAL_APIC | 490 | irq_work_queue(&__get_cpu_var(mce_irq_work)); |
496 | /* | ||
497 | * Without APIC do not notify. The event will be picked | ||
498 | * up eventually. | ||
499 | */ | ||
500 | if (!cpu_has_apic) | ||
501 | return; | ||
502 | |||
503 | /* | ||
504 | * When interrupts are disabled we cannot use | ||
505 | * kernel services safely. Trigger an self interrupt | ||
506 | * through the APIC to instead do the notification | ||
507 | * after interrupts are reenabled again. | ||
508 | */ | ||
509 | apic->send_IPI_self(MCE_SELF_VECTOR); | ||
510 | |||
511 | /* | ||
512 | * Wait for idle afterwards again so that we don't leave the | ||
513 | * APIC in a non idle state because the normal APIC writes | ||
514 | * cannot exclude us. | ||
515 | */ | ||
516 | apic_wait_icr_idle(); | ||
517 | #endif | ||
518 | } | 491 | } |
519 | 492 | ||
520 | DEFINE_PER_CPU(unsigned, mce_poll_count); | 493 | DEFINE_PER_CPU(unsigned, mce_poll_count); |
@@ -541,9 +514,8 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) | |||
541 | 514 | ||
542 | percpu_inc(mce_poll_count); | 515 | percpu_inc(mce_poll_count); |
543 | 516 | ||
544 | mce_setup(&m); | 517 | mce_gather_info(&m, NULL); |
545 | 518 | ||
546 | m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); | ||
547 | for (i = 0; i < banks; i++) { | 519 | for (i = 0; i < banks; i++) { |
548 | if (!mce_banks[i].ctl || !test_bit(i, *b)) | 520 | if (!mce_banks[i].ctl || !test_bit(i, *b)) |
549 | continue; | 521 | continue; |
@@ -879,9 +851,9 @@ static int mce_usable_address(struct mce *m) | |||
879 | { | 851 | { |
880 | if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV)) | 852 | if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV)) |
881 | return 0; | 853 | return 0; |
882 | if ((m->misc & 0x3f) > PAGE_SHIFT) | 854 | if (MCI_MISC_ADDR_LSB(m->misc) > PAGE_SHIFT) |
883 | return 0; | 855 | return 0; |
884 | if (((m->misc >> 6) & 7) != MCM_ADDR_PHYS) | 856 | if (MCI_MISC_ADDR_MODE(m->misc) != MCI_MISC_ADDR_PHYS) |
885 | return 0; | 857 | return 0; |
886 | return 1; | 858 | return 1; |
887 | } | 859 | } |
@@ -942,9 +914,8 @@ void do_machine_check(struct pt_regs *regs, long error_code) | |||
942 | if (!banks) | 914 | if (!banks) |
943 | goto out; | 915 | goto out; |
944 | 916 | ||
945 | mce_setup(&m); | 917 | mce_gather_info(&m, regs); |
946 | 918 | ||
947 | m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); | ||
948 | final = &__get_cpu_var(mces_seen); | 919 | final = &__get_cpu_var(mces_seen); |
949 | *final = m; | 920 | *final = m; |
950 | 921 | ||
@@ -1028,7 +999,6 @@ void do_machine_check(struct pt_regs *regs, long error_code) | |||
1028 | if (severity == MCE_AO_SEVERITY && mce_usable_address(&m)) | 999 | if (severity == MCE_AO_SEVERITY && mce_usable_address(&m)) |
1029 | mce_ring_add(m.addr >> PAGE_SHIFT); | 1000 | mce_ring_add(m.addr >> PAGE_SHIFT); |
1030 | 1001 | ||
1031 | mce_get_rip(&m, regs); | ||
1032 | mce_log(&m); | 1002 | mce_log(&m); |
1033 | 1003 | ||
1034 | if (severity > worst) { | 1004 | if (severity > worst) { |
@@ -1190,7 +1160,8 @@ int mce_notify_irq(void) | |||
1190 | clear_thread_flag(TIF_MCE_NOTIFY); | 1160 | clear_thread_flag(TIF_MCE_NOTIFY); |
1191 | 1161 | ||
1192 | if (test_and_clear_bit(0, &mce_need_notify)) { | 1162 | if (test_and_clear_bit(0, &mce_need_notify)) { |
1193 | wake_up_interruptible(&mce_wait); | 1163 | /* wake processes polling /dev/mcelog */ |
1164 | wake_up_interruptible(&mce_chrdev_wait); | ||
1194 | 1165 | ||
1195 | /* | 1166 | /* |
1196 | * There is no risk of missing notifications because | 1167 | * There is no risk of missing notifications because |
@@ -1363,18 +1334,23 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) | |||
1363 | return 0; | 1334 | return 0; |
1364 | } | 1335 | } |
1365 | 1336 | ||
1366 | static void __cpuinit __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c) | 1337 | static int __cpuinit __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c) |
1367 | { | 1338 | { |
1368 | if (c->x86 != 5) | 1339 | if (c->x86 != 5) |
1369 | return; | 1340 | return 0; |
1341 | |||
1370 | switch (c->x86_vendor) { | 1342 | switch (c->x86_vendor) { |
1371 | case X86_VENDOR_INTEL: | 1343 | case X86_VENDOR_INTEL: |
1372 | intel_p5_mcheck_init(c); | 1344 | intel_p5_mcheck_init(c); |
1345 | return 1; | ||
1373 | break; | 1346 | break; |
1374 | case X86_VENDOR_CENTAUR: | 1347 | case X86_VENDOR_CENTAUR: |
1375 | winchip_mcheck_init(c); | 1348 | winchip_mcheck_init(c); |
1349 | return 1; | ||
1376 | break; | 1350 | break; |
1377 | } | 1351 | } |
1352 | |||
1353 | return 0; | ||
1378 | } | 1354 | } |
1379 | 1355 | ||
1380 | static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) | 1356 | static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) |
@@ -1428,7 +1404,8 @@ void __cpuinit mcheck_cpu_init(struct cpuinfo_x86 *c) | |||
1428 | if (mce_disabled) | 1404 | if (mce_disabled) |
1429 | return; | 1405 | return; |
1430 | 1406 | ||
1431 | __mcheck_cpu_ancient_init(c); | 1407 | if (__mcheck_cpu_ancient_init(c)) |
1408 | return; | ||
1432 | 1409 | ||
1433 | if (!mce_available(c)) | 1410 | if (!mce_available(c)) |
1434 | return; | 1411 | return; |
@@ -1444,44 +1421,45 @@ void __cpuinit mcheck_cpu_init(struct cpuinfo_x86 *c) | |||
1444 | __mcheck_cpu_init_vendor(c); | 1421 | __mcheck_cpu_init_vendor(c); |
1445 | __mcheck_cpu_init_timer(); | 1422 | __mcheck_cpu_init_timer(); |
1446 | INIT_WORK(&__get_cpu_var(mce_work), mce_process_work); | 1423 | INIT_WORK(&__get_cpu_var(mce_work), mce_process_work); |
1447 | 1424 | init_irq_work(&__get_cpu_var(mce_irq_work), &mce_irq_work_cb); | |
1448 | } | 1425 | } |
1449 | 1426 | ||
1450 | /* | 1427 | /* |
1451 | * Character device to read and clear the MCE log. | 1428 | * mce_chrdev: Character device /dev/mcelog to read and clear the MCE log. |
1452 | */ | 1429 | */ |
1453 | 1430 | ||
1454 | static DEFINE_SPINLOCK(mce_state_lock); | 1431 | static DEFINE_SPINLOCK(mce_chrdev_state_lock); |
1455 | static int open_count; /* #times opened */ | 1432 | static int mce_chrdev_open_count; /* #times opened */ |
1456 | static int open_exclu; /* already open exclusive? */ | 1433 | static int mce_chrdev_open_exclu; /* already open exclusive? */ |
1457 | 1434 | ||
1458 | static int mce_open(struct inode *inode, struct file *file) | 1435 | static int mce_chrdev_open(struct inode *inode, struct file *file) |
1459 | { | 1436 | { |
1460 | spin_lock(&mce_state_lock); | 1437 | spin_lock(&mce_chrdev_state_lock); |
1461 | 1438 | ||
1462 | if (open_exclu || (open_count && (file->f_flags & O_EXCL))) { | 1439 | if (mce_chrdev_open_exclu || |
1463 | spin_unlock(&mce_state_lock); | 1440 | (mce_chrdev_open_count && (file->f_flags & O_EXCL))) { |
1441 | spin_unlock(&mce_chrdev_state_lock); | ||
1464 | 1442 | ||
1465 | return -EBUSY; | 1443 | return -EBUSY; |
1466 | } | 1444 | } |
1467 | 1445 | ||
1468 | if (file->f_flags & O_EXCL) | 1446 | if (file->f_flags & O_EXCL) |
1469 | open_exclu = 1; | 1447 | mce_chrdev_open_exclu = 1; |
1470 | open_count++; | 1448 | mce_chrdev_open_count++; |
1471 | 1449 | ||
1472 | spin_unlock(&mce_state_lock); | 1450 | spin_unlock(&mce_chrdev_state_lock); |
1473 | 1451 | ||
1474 | return nonseekable_open(inode, file); | 1452 | return nonseekable_open(inode, file); |
1475 | } | 1453 | } |
1476 | 1454 | ||
1477 | static int mce_release(struct inode *inode, struct file *file) | 1455 | static int mce_chrdev_release(struct inode *inode, struct file *file) |
1478 | { | 1456 | { |
1479 | spin_lock(&mce_state_lock); | 1457 | spin_lock(&mce_chrdev_state_lock); |
1480 | 1458 | ||
1481 | open_count--; | 1459 | mce_chrdev_open_count--; |
1482 | open_exclu = 0; | 1460 | mce_chrdev_open_exclu = 0; |
1483 | 1461 | ||
1484 | spin_unlock(&mce_state_lock); | 1462 | spin_unlock(&mce_chrdev_state_lock); |
1485 | 1463 | ||
1486 | return 0; | 1464 | return 0; |
1487 | } | 1465 | } |
@@ -1530,8 +1508,8 @@ static int __mce_read_apei(char __user **ubuf, size_t usize) | |||
1530 | return 0; | 1508 | return 0; |
1531 | } | 1509 | } |
1532 | 1510 | ||
1533 | static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, | 1511 | static ssize_t mce_chrdev_read(struct file *filp, char __user *ubuf, |
1534 | loff_t *off) | 1512 | size_t usize, loff_t *off) |
1535 | { | 1513 | { |
1536 | char __user *buf = ubuf; | 1514 | char __user *buf = ubuf; |
1537 | unsigned long *cpu_tsc; | 1515 | unsigned long *cpu_tsc; |
@@ -1542,7 +1520,7 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, | |||
1542 | if (!cpu_tsc) | 1520 | if (!cpu_tsc) |
1543 | return -ENOMEM; | 1521 | return -ENOMEM; |
1544 | 1522 | ||
1545 | mutex_lock(&mce_read_mutex); | 1523 | mutex_lock(&mce_chrdev_read_mutex); |
1546 | 1524 | ||
1547 | if (!mce_apei_read_done) { | 1525 | if (!mce_apei_read_done) { |
1548 | err = __mce_read_apei(&buf, usize); | 1526 | err = __mce_read_apei(&buf, usize); |
@@ -1562,19 +1540,18 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, | |||
1562 | do { | 1540 | do { |
1563 | for (i = prev; i < next; i++) { | 1541 | for (i = prev; i < next; i++) { |
1564 | unsigned long start = jiffies; | 1542 | unsigned long start = jiffies; |
1543 | struct mce *m = &mcelog.entry[i]; | ||
1565 | 1544 | ||
1566 | while (!mcelog.entry[i].finished) { | 1545 | while (!m->finished) { |
1567 | if (time_after_eq(jiffies, start + 2)) { | 1546 | if (time_after_eq(jiffies, start + 2)) { |
1568 | memset(mcelog.entry + i, 0, | 1547 | memset(m, 0, sizeof(*m)); |
1569 | sizeof(struct mce)); | ||
1570 | goto timeout; | 1548 | goto timeout; |
1571 | } | 1549 | } |
1572 | cpu_relax(); | 1550 | cpu_relax(); |
1573 | } | 1551 | } |
1574 | smp_rmb(); | 1552 | smp_rmb(); |
1575 | err |= copy_to_user(buf, mcelog.entry + i, | 1553 | err |= copy_to_user(buf, m, sizeof(*m)); |
1576 | sizeof(struct mce)); | 1554 | buf += sizeof(*m); |
1577 | buf += sizeof(struct mce); | ||
1578 | timeout: | 1555 | timeout: |
1579 | ; | 1556 | ; |
1580 | } | 1557 | } |
@@ -1594,13 +1571,13 @@ timeout: | |||
1594 | on_each_cpu(collect_tscs, cpu_tsc, 1); | 1571 | on_each_cpu(collect_tscs, cpu_tsc, 1); |
1595 | 1572 | ||
1596 | for (i = next; i < MCE_LOG_LEN; i++) { | 1573 | for (i = next; i < MCE_LOG_LEN; i++) { |
1597 | if (mcelog.entry[i].finished && | 1574 | struct mce *m = &mcelog.entry[i]; |
1598 | mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) { | 1575 | |
1599 | err |= copy_to_user(buf, mcelog.entry+i, | 1576 | if (m->finished && m->tsc < cpu_tsc[m->cpu]) { |
1600 | sizeof(struct mce)); | 1577 | err |= copy_to_user(buf, m, sizeof(*m)); |
1601 | smp_rmb(); | 1578 | smp_rmb(); |
1602 | buf += sizeof(struct mce); | 1579 | buf += sizeof(*m); |
1603 | memset(&mcelog.entry[i], 0, sizeof(struct mce)); | 1580 | memset(m, 0, sizeof(*m)); |
1604 | } | 1581 | } |
1605 | } | 1582 | } |
1606 | 1583 | ||
@@ -1608,15 +1585,15 @@ timeout: | |||
1608 | err = -EFAULT; | 1585 | err = -EFAULT; |
1609 | 1586 | ||
1610 | out: | 1587 | out: |
1611 | mutex_unlock(&mce_read_mutex); | 1588 | mutex_unlock(&mce_chrdev_read_mutex); |
1612 | kfree(cpu_tsc); | 1589 | kfree(cpu_tsc); |
1613 | 1590 | ||
1614 | return err ? err : buf - ubuf; | 1591 | return err ? err : buf - ubuf; |
1615 | } | 1592 | } |
1616 | 1593 | ||
1617 | static unsigned int mce_poll(struct file *file, poll_table *wait) | 1594 | static unsigned int mce_chrdev_poll(struct file *file, poll_table *wait) |
1618 | { | 1595 | { |
1619 | poll_wait(file, &mce_wait, wait); | 1596 | poll_wait(file, &mce_chrdev_wait, wait); |
1620 | if (rcu_access_index(mcelog.next)) | 1597 | if (rcu_access_index(mcelog.next)) |
1621 | return POLLIN | POLLRDNORM; | 1598 | return POLLIN | POLLRDNORM; |
1622 | if (!mce_apei_read_done && apei_check_mce()) | 1599 | if (!mce_apei_read_done && apei_check_mce()) |
@@ -1624,7 +1601,8 @@ static unsigned int mce_poll(struct file *file, poll_table *wait) | |||
1624 | return 0; | 1601 | return 0; |
1625 | } | 1602 | } |
1626 | 1603 | ||
1627 | static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | 1604 | static long mce_chrdev_ioctl(struct file *f, unsigned int cmd, |
1605 | unsigned long arg) | ||
1628 | { | 1606 | { |
1629 | int __user *p = (int __user *)arg; | 1607 | int __user *p = (int __user *)arg; |
1630 | 1608 | ||
@@ -1652,16 +1630,16 @@ static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
1652 | 1630 | ||
1653 | /* Modified in mce-inject.c, so not static or const */ | 1631 | /* Modified in mce-inject.c, so not static or const */ |
1654 | struct file_operations mce_chrdev_ops = { | 1632 | struct file_operations mce_chrdev_ops = { |
1655 | .open = mce_open, | 1633 | .open = mce_chrdev_open, |
1656 | .release = mce_release, | 1634 | .release = mce_chrdev_release, |
1657 | .read = mce_read, | 1635 | .read = mce_chrdev_read, |
1658 | .poll = mce_poll, | 1636 | .poll = mce_chrdev_poll, |
1659 | .unlocked_ioctl = mce_ioctl, | 1637 | .unlocked_ioctl = mce_chrdev_ioctl, |
1660 | .llseek = no_llseek, | 1638 | .llseek = no_llseek, |
1661 | }; | 1639 | }; |
1662 | EXPORT_SYMBOL_GPL(mce_chrdev_ops); | 1640 | EXPORT_SYMBOL_GPL(mce_chrdev_ops); |
1663 | 1641 | ||
1664 | static struct miscdevice mce_log_device = { | 1642 | static struct miscdevice mce_chrdev_device = { |
1665 | MISC_MCELOG_MINOR, | 1643 | MISC_MCELOG_MINOR, |
1666 | "mcelog", | 1644 | "mcelog", |
1667 | &mce_chrdev_ops, | 1645 | &mce_chrdev_ops, |
@@ -1719,7 +1697,7 @@ int __init mcheck_init(void) | |||
1719 | } | 1697 | } |
1720 | 1698 | ||
1721 | /* | 1699 | /* |
1722 | * Sysfs support | 1700 | * mce_syscore: PM support |
1723 | */ | 1701 | */ |
1724 | 1702 | ||
1725 | /* | 1703 | /* |
@@ -1739,12 +1717,12 @@ static int mce_disable_error_reporting(void) | |||
1739 | return 0; | 1717 | return 0; |
1740 | } | 1718 | } |
1741 | 1719 | ||
1742 | static int mce_suspend(void) | 1720 | static int mce_syscore_suspend(void) |
1743 | { | 1721 | { |
1744 | return mce_disable_error_reporting(); | 1722 | return mce_disable_error_reporting(); |
1745 | } | 1723 | } |
1746 | 1724 | ||
1747 | static void mce_shutdown(void) | 1725 | static void mce_syscore_shutdown(void) |
1748 | { | 1726 | { |
1749 | mce_disable_error_reporting(); | 1727 | mce_disable_error_reporting(); |
1750 | } | 1728 | } |
@@ -1754,18 +1732,22 @@ static void mce_shutdown(void) | |||
1754 | * Only one CPU is active at this time, the others get re-added later using | 1732 | * Only one CPU is active at this time, the others get re-added later using |
1755 | * CPU hotplug: | 1733 | * CPU hotplug: |
1756 | */ | 1734 | */ |
1757 | static void mce_resume(void) | 1735 | static void mce_syscore_resume(void) |
1758 | { | 1736 | { |
1759 | __mcheck_cpu_init_generic(); | 1737 | __mcheck_cpu_init_generic(); |
1760 | __mcheck_cpu_init_vendor(__this_cpu_ptr(&cpu_info)); | 1738 | __mcheck_cpu_init_vendor(__this_cpu_ptr(&cpu_info)); |
1761 | } | 1739 | } |
1762 | 1740 | ||
1763 | static struct syscore_ops mce_syscore_ops = { | 1741 | static struct syscore_ops mce_syscore_ops = { |
1764 | .suspend = mce_suspend, | 1742 | .suspend = mce_syscore_suspend, |
1765 | .shutdown = mce_shutdown, | 1743 | .shutdown = mce_syscore_shutdown, |
1766 | .resume = mce_resume, | 1744 | .resume = mce_syscore_resume, |
1767 | }; | 1745 | }; |
1768 | 1746 | ||
1747 | /* | ||
1748 | * mce_sysdev: Sysfs support | ||
1749 | */ | ||
1750 | |||
1769 | static void mce_cpu_restart(void *data) | 1751 | static void mce_cpu_restart(void *data) |
1770 | { | 1752 | { |
1771 | del_timer_sync(&__get_cpu_var(mce_timer)); | 1753 | del_timer_sync(&__get_cpu_var(mce_timer)); |
@@ -1801,11 +1783,11 @@ static void mce_enable_ce(void *all) | |||
1801 | __mcheck_cpu_init_timer(); | 1783 | __mcheck_cpu_init_timer(); |
1802 | } | 1784 | } |
1803 | 1785 | ||
1804 | static struct sysdev_class mce_sysclass = { | 1786 | static struct sysdev_class mce_sysdev_class = { |
1805 | .name = "machinecheck", | 1787 | .name = "machinecheck", |
1806 | }; | 1788 | }; |
1807 | 1789 | ||
1808 | DEFINE_PER_CPU(struct sys_device, mce_dev); | 1790 | DEFINE_PER_CPU(struct sys_device, mce_sysdev); |
1809 | 1791 | ||
1810 | __cpuinitdata | 1792 | __cpuinitdata |
1811 | void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); | 1793 | void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); |
@@ -1934,7 +1916,7 @@ static struct sysdev_ext_attribute attr_cmci_disabled = { | |||
1934 | &mce_cmci_disabled | 1916 | &mce_cmci_disabled |
1935 | }; | 1917 | }; |
1936 | 1918 | ||
1937 | static struct sysdev_attribute *mce_attrs[] = { | 1919 | static struct sysdev_attribute *mce_sysdev_attrs[] = { |
1938 | &attr_tolerant.attr, | 1920 | &attr_tolerant.attr, |
1939 | &attr_check_interval.attr, | 1921 | &attr_check_interval.attr, |
1940 | &attr_trigger, | 1922 | &attr_trigger, |
@@ -1945,66 +1927,67 @@ static struct sysdev_attribute *mce_attrs[] = { | |||
1945 | NULL | 1927 | NULL |
1946 | }; | 1928 | }; |
1947 | 1929 | ||
1948 | static cpumask_var_t mce_dev_initialized; | 1930 | static cpumask_var_t mce_sysdev_initialized; |
1949 | 1931 | ||
1950 | /* Per cpu sysdev init. All of the cpus still share the same ctrl bank: */ | 1932 | /* Per cpu sysdev init. All of the cpus still share the same ctrl bank: */ |
1951 | static __cpuinit int mce_create_device(unsigned int cpu) | 1933 | static __cpuinit int mce_sysdev_create(unsigned int cpu) |
1952 | { | 1934 | { |
1935 | struct sys_device *sysdev = &per_cpu(mce_sysdev, cpu); | ||
1953 | int err; | 1936 | int err; |
1954 | int i, j; | 1937 | int i, j; |
1955 | 1938 | ||
1956 | if (!mce_available(&boot_cpu_data)) | 1939 | if (!mce_available(&boot_cpu_data)) |
1957 | return -EIO; | 1940 | return -EIO; |
1958 | 1941 | ||
1959 | memset(&per_cpu(mce_dev, cpu).kobj, 0, sizeof(struct kobject)); | 1942 | memset(&sysdev->kobj, 0, sizeof(struct kobject)); |
1960 | per_cpu(mce_dev, cpu).id = cpu; | 1943 | sysdev->id = cpu; |
1961 | per_cpu(mce_dev, cpu).cls = &mce_sysclass; | 1944 | sysdev->cls = &mce_sysdev_class; |
1962 | 1945 | ||
1963 | err = sysdev_register(&per_cpu(mce_dev, cpu)); | 1946 | err = sysdev_register(sysdev); |
1964 | if (err) | 1947 | if (err) |
1965 | return err; | 1948 | return err; |
1966 | 1949 | ||
1967 | for (i = 0; mce_attrs[i]; i++) { | 1950 | for (i = 0; mce_sysdev_attrs[i]; i++) { |
1968 | err = sysdev_create_file(&per_cpu(mce_dev, cpu), mce_attrs[i]); | 1951 | err = sysdev_create_file(sysdev, mce_sysdev_attrs[i]); |
1969 | if (err) | 1952 | if (err) |
1970 | goto error; | 1953 | goto error; |
1971 | } | 1954 | } |
1972 | for (j = 0; j < banks; j++) { | 1955 | for (j = 0; j < banks; j++) { |
1973 | err = sysdev_create_file(&per_cpu(mce_dev, cpu), | 1956 | err = sysdev_create_file(sysdev, &mce_banks[j].attr); |
1974 | &mce_banks[j].attr); | ||
1975 | if (err) | 1957 | if (err) |
1976 | goto error2; | 1958 | goto error2; |
1977 | } | 1959 | } |
1978 | cpumask_set_cpu(cpu, mce_dev_initialized); | 1960 | cpumask_set_cpu(cpu, mce_sysdev_initialized); |
1979 | 1961 | ||
1980 | return 0; | 1962 | return 0; |
1981 | error2: | 1963 | error2: |
1982 | while (--j >= 0) | 1964 | while (--j >= 0) |
1983 | sysdev_remove_file(&per_cpu(mce_dev, cpu), &mce_banks[j].attr); | 1965 | sysdev_remove_file(sysdev, &mce_banks[j].attr); |
1984 | error: | 1966 | error: |
1985 | while (--i >= 0) | 1967 | while (--i >= 0) |
1986 | sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]); | 1968 | sysdev_remove_file(sysdev, mce_sysdev_attrs[i]); |
1987 | 1969 | ||
1988 | sysdev_unregister(&per_cpu(mce_dev, cpu)); | 1970 | sysdev_unregister(sysdev); |
1989 | 1971 | ||
1990 | return err; | 1972 | return err; |
1991 | } | 1973 | } |
1992 | 1974 | ||
1993 | static __cpuinit void mce_remove_device(unsigned int cpu) | 1975 | static __cpuinit void mce_sysdev_remove(unsigned int cpu) |
1994 | { | 1976 | { |
1977 | struct sys_device *sysdev = &per_cpu(mce_sysdev, cpu); | ||
1995 | int i; | 1978 | int i; |
1996 | 1979 | ||
1997 | if (!cpumask_test_cpu(cpu, mce_dev_initialized)) | 1980 | if (!cpumask_test_cpu(cpu, mce_sysdev_initialized)) |
1998 | return; | 1981 | return; |
1999 | 1982 | ||
2000 | for (i = 0; mce_attrs[i]; i++) | 1983 | for (i = 0; mce_sysdev_attrs[i]; i++) |
2001 | sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]); | 1984 | sysdev_remove_file(sysdev, mce_sysdev_attrs[i]); |
2002 | 1985 | ||
2003 | for (i = 0; i < banks; i++) | 1986 | for (i = 0; i < banks; i++) |
2004 | sysdev_remove_file(&per_cpu(mce_dev, cpu), &mce_banks[i].attr); | 1987 | sysdev_remove_file(sysdev, &mce_banks[i].attr); |
2005 | 1988 | ||
2006 | sysdev_unregister(&per_cpu(mce_dev, cpu)); | 1989 | sysdev_unregister(sysdev); |
2007 | cpumask_clear_cpu(cpu, mce_dev_initialized); | 1990 | cpumask_clear_cpu(cpu, mce_sysdev_initialized); |
2008 | } | 1991 | } |
2009 | 1992 | ||
2010 | /* Make sure there are no machine checks on offlined CPUs. */ | 1993 | /* Make sure there are no machine checks on offlined CPUs. */ |
@@ -2054,7 +2037,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) | |||
2054 | switch (action) { | 2037 | switch (action) { |
2055 | case CPU_ONLINE: | 2038 | case CPU_ONLINE: |
2056 | case CPU_ONLINE_FROZEN: | 2039 | case CPU_ONLINE_FROZEN: |
2057 | mce_create_device(cpu); | 2040 | mce_sysdev_create(cpu); |
2058 | if (threshold_cpu_callback) | 2041 | if (threshold_cpu_callback) |
2059 | threshold_cpu_callback(action, cpu); | 2042 | threshold_cpu_callback(action, cpu); |
2060 | break; | 2043 | break; |
@@ -2062,7 +2045,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) | |||
2062 | case CPU_DEAD_FROZEN: | 2045 | case CPU_DEAD_FROZEN: |
2063 | if (threshold_cpu_callback) | 2046 | if (threshold_cpu_callback) |
2064 | threshold_cpu_callback(action, cpu); | 2047 | threshold_cpu_callback(action, cpu); |
2065 | mce_remove_device(cpu); | 2048 | mce_sysdev_remove(cpu); |
2066 | break; | 2049 | break; |
2067 | case CPU_DOWN_PREPARE: | 2050 | case CPU_DOWN_PREPARE: |
2068 | case CPU_DOWN_PREPARE_FROZEN: | 2051 | case CPU_DOWN_PREPARE_FROZEN: |
@@ -2116,27 +2099,28 @@ static __init int mcheck_init_device(void) | |||
2116 | if (!mce_available(&boot_cpu_data)) | 2099 | if (!mce_available(&boot_cpu_data)) |
2117 | return -EIO; | 2100 | return -EIO; |
2118 | 2101 | ||
2119 | zalloc_cpumask_var(&mce_dev_initialized, GFP_KERNEL); | 2102 | zalloc_cpumask_var(&mce_sysdev_initialized, GFP_KERNEL); |
2120 | 2103 | ||
2121 | mce_init_banks(); | 2104 | mce_init_banks(); |
2122 | 2105 | ||
2123 | err = sysdev_class_register(&mce_sysclass); | 2106 | err = sysdev_class_register(&mce_sysdev_class); |
2124 | if (err) | 2107 | if (err) |
2125 | return err; | 2108 | return err; |
2126 | 2109 | ||
2127 | for_each_online_cpu(i) { | 2110 | for_each_online_cpu(i) { |
2128 | err = mce_create_device(i); | 2111 | err = mce_sysdev_create(i); |
2129 | if (err) | 2112 | if (err) |
2130 | return err; | 2113 | return err; |
2131 | } | 2114 | } |
2132 | 2115 | ||
2133 | register_syscore_ops(&mce_syscore_ops); | 2116 | register_syscore_ops(&mce_syscore_ops); |
2134 | register_hotcpu_notifier(&mce_cpu_notifier); | 2117 | register_hotcpu_notifier(&mce_cpu_notifier); |
2135 | misc_register(&mce_log_device); | 2118 | |
2119 | /* register character device /dev/mcelog */ | ||
2120 | misc_register(&mce_chrdev_device); | ||
2136 | 2121 | ||
2137 | return err; | 2122 | return err; |
2138 | } | 2123 | } |
2139 | |||
2140 | device_initcall(mcheck_init_device); | 2124 | device_initcall(mcheck_init_device); |
2141 | 2125 | ||
2142 | /* | 2126 | /* |
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index bb0adad35143..f5474218cffe 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c | |||
@@ -548,7 +548,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) | |||
548 | if (!b) | 548 | if (!b) |
549 | goto out; | 549 | goto out; |
550 | 550 | ||
551 | err = sysfs_create_link(&per_cpu(mce_dev, cpu).kobj, | 551 | err = sysfs_create_link(&per_cpu(mce_sysdev, cpu).kobj, |
552 | b->kobj, name); | 552 | b->kobj, name); |
553 | if (err) | 553 | if (err) |
554 | goto out; | 554 | goto out; |
@@ -571,7 +571,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) | |||
571 | goto out; | 571 | goto out; |
572 | } | 572 | } |
573 | 573 | ||
574 | b->kobj = kobject_create_and_add(name, &per_cpu(mce_dev, cpu).kobj); | 574 | b->kobj = kobject_create_and_add(name, &per_cpu(mce_sysdev, cpu).kobj); |
575 | if (!b->kobj) | 575 | if (!b->kobj) |
576 | goto out_free; | 576 | goto out_free; |
577 | 577 | ||
@@ -591,7 +591,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) | |||
591 | if (i == cpu) | 591 | if (i == cpu) |
592 | continue; | 592 | continue; |
593 | 593 | ||
594 | err = sysfs_create_link(&per_cpu(mce_dev, i).kobj, | 594 | err = sysfs_create_link(&per_cpu(mce_sysdev, i).kobj, |
595 | b->kobj, name); | 595 | b->kobj, name); |
596 | if (err) | 596 | if (err) |
597 | goto out; | 597 | goto out; |
@@ -669,7 +669,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank) | |||
669 | #ifdef CONFIG_SMP | 669 | #ifdef CONFIG_SMP |
670 | /* sibling symlink */ | 670 | /* sibling symlink */ |
671 | if (shared_bank[bank] && b->blocks->cpu != cpu) { | 671 | if (shared_bank[bank] && b->blocks->cpu != cpu) { |
672 | sysfs_remove_link(&per_cpu(mce_dev, cpu).kobj, name); | 672 | sysfs_remove_link(&per_cpu(mce_sysdev, cpu).kobj, name); |
673 | per_cpu(threshold_banks, cpu)[bank] = NULL; | 673 | per_cpu(threshold_banks, cpu)[bank] = NULL; |
674 | 674 | ||
675 | return; | 675 | return; |
@@ -681,7 +681,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank) | |||
681 | if (i == cpu) | 681 | if (i == cpu) |
682 | continue; | 682 | continue; |
683 | 683 | ||
684 | sysfs_remove_link(&per_cpu(mce_dev, i).kobj, name); | 684 | sysfs_remove_link(&per_cpu(mce_sysdev, i).kobj, name); |
685 | per_cpu(threshold_banks, i)[bank] = NULL; | 685 | per_cpu(threshold_banks, i)[bank] = NULL; |
686 | } | 686 | } |
687 | 687 | ||
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index d130b20a6b90..37e895a1c74d 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -984,11 +984,6 @@ apicinterrupt THRESHOLD_APIC_VECTOR \ | |||
984 | apicinterrupt THERMAL_APIC_VECTOR \ | 984 | apicinterrupt THERMAL_APIC_VECTOR \ |
985 | thermal_interrupt smp_thermal_interrupt | 985 | thermal_interrupt smp_thermal_interrupt |
986 | 986 | ||
987 | #ifdef CONFIG_X86_MCE | ||
988 | apicinterrupt MCE_SELF_VECTOR \ | ||
989 | mce_self_interrupt smp_mce_self_interrupt | ||
990 | #endif | ||
991 | |||
992 | #ifdef CONFIG_SMP | 987 | #ifdef CONFIG_SMP |
993 | apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \ | 988 | apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \ |
994 | call_function_single_interrupt smp_call_function_single_interrupt | 989 | call_function_single_interrupt smp_call_function_single_interrupt |
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index f470e4ef993e..f09d4bbe2d2d 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c | |||
@@ -272,9 +272,6 @@ static void __init apic_intr_init(void) | |||
272 | #ifdef CONFIG_X86_MCE_THRESHOLD | 272 | #ifdef CONFIG_X86_MCE_THRESHOLD |
273 | alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); | 273 | alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); |
274 | #endif | 274 | #endif |
275 | #if defined(CONFIG_X86_MCE) && defined(CONFIG_X86_LOCAL_APIC) | ||
276 | alloc_intr_gate(MCE_SELF_VECTOR, mce_self_interrupt); | ||
277 | #endif | ||
278 | 275 | ||
279 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) | 276 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) |
280 | /* self generated IPI for local APIC timer */ | 277 | /* self generated IPI for local APIC timer */ |