1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef __X86_MCE_INTERNAL_H__ |
3 | #define __X86_MCE_INTERNAL_H__ |
4 | |
5 | #undef pr_fmt |
6 | #define pr_fmt(fmt) "mce: " fmt |
7 | |
8 | #include <linux/device.h> |
9 | #include <asm/mce.h> |
10 | |
11 | enum severity_level { |
12 | MCE_NO_SEVERITY, |
13 | MCE_DEFERRED_SEVERITY, |
14 | MCE_UCNA_SEVERITY = MCE_DEFERRED_SEVERITY, |
15 | MCE_KEEP_SEVERITY, |
16 | MCE_SOME_SEVERITY, |
17 | MCE_AO_SEVERITY, |
18 | MCE_UC_SEVERITY, |
19 | MCE_AR_SEVERITY, |
20 | MCE_PANIC_SEVERITY, |
21 | }; |
22 | |
23 | extern struct blocking_notifier_head x86_mce_decoder_chain; |
24 | |
25 | #define INITIAL_CHECK_INTERVAL 5 * 60 /* 5 minutes */ |
26 | |
27 | struct mce_evt_llist { |
28 | struct llist_node llnode; |
29 | struct mce mce; |
30 | }; |
31 | |
32 | void mce_gen_pool_process(struct work_struct *__unused); |
33 | bool mce_gen_pool_empty(void); |
34 | int mce_gen_pool_add(struct mce *mce); |
35 | int mce_gen_pool_init(void); |
36 | struct llist_node *mce_gen_pool_prepare_records(void); |
37 | |
38 | int mce_severity(struct mce *a, struct pt_regs *regs, char **msg, bool is_excp); |
39 | struct dentry *mce_get_debugfs_dir(void); |
40 | |
41 | extern mce_banks_t mce_banks_ce_disabled; |
42 | |
43 | #ifdef CONFIG_X86_MCE_INTEL |
44 | void mce_intel_handle_storm(int bank, bool on); |
45 | void cmci_disable_bank(int bank); |
46 | void intel_init_cmci(void); |
47 | void intel_init_lmce(void); |
48 | void intel_clear_lmce(void); |
49 | bool intel_filter_mce(struct mce *m); |
50 | bool intel_mce_usable_address(struct mce *m); |
51 | #else |
52 | static inline void mce_intel_handle_storm(int bank, bool on) { } |
53 | static inline void cmci_disable_bank(int bank) { } |
54 | static inline void intel_init_cmci(void) { } |
55 | static inline void intel_init_lmce(void) { } |
56 | static inline void intel_clear_lmce(void) { } |
57 | static inline bool intel_filter_mce(struct mce *m) { return false; } |
58 | static inline bool intel_mce_usable_address(struct mce *m) { return false; } |
59 | #endif |
60 | |
61 | void mce_timer_kick(bool storm); |
62 | |
63 | #ifdef CONFIG_X86_MCE_THRESHOLD |
64 | void cmci_storm_begin(unsigned int bank); |
65 | void cmci_storm_end(unsigned int bank); |
66 | void mce_track_storm(struct mce *mce); |
67 | void mce_inherit_storm(unsigned int bank); |
68 | bool mce_get_storm_mode(void); |
69 | void mce_set_storm_mode(bool storm); |
70 | #else |
71 | static inline void cmci_storm_begin(unsigned int bank) {} |
72 | static inline void cmci_storm_end(unsigned int bank) {} |
73 | static inline void mce_track_storm(struct mce *mce) {} |
74 | static inline void mce_inherit_storm(unsigned int bank) {} |
75 | static inline bool mce_get_storm_mode(void) { return false; } |
76 | static inline void mce_set_storm_mode(bool storm) {} |
77 | #endif |
78 | |
79 | /* |
80 | * history: Bitmask tracking errors occurrence. Each set bit |
81 | * represents an error seen. |
82 | * |
83 | * timestamp: Last time (in jiffies) that the bank was polled. |
84 | * in_storm_mode: Is this bank in storm mode? |
85 | * poll_only: Bank does not support CMCI, skip storm tracking. |
86 | */ |
87 | struct storm_bank { |
88 | u64 history; |
89 | u64 timestamp; |
90 | bool in_storm_mode; |
91 | bool poll_only; |
92 | }; |
93 | |
94 | #define NUM_HISTORY_BITS (sizeof(u64) * BITS_PER_BYTE) |
95 | |
96 | /* How many errors within the history buffer mark the start of a storm. */ |
97 | #define STORM_BEGIN_THRESHOLD 5 |
98 | |
99 | /* |
100 | * How many polls of machine check bank without an error before declaring |
101 | * the storm is over. Since it is tracked by the bitmasks in the history |
102 | * field of struct storm_bank the mask is 30 bits [0 ... 29]. |
103 | */ |
104 | #define STORM_END_POLL_THRESHOLD 29 |
105 | |
106 | /* |
107 | * banks: per-cpu, per-bank details |
108 | * stormy_bank_count: count of MC banks in storm state |
109 | * poll_mode: CPU is in poll mode |
110 | */ |
111 | struct mca_storm_desc { |
112 | struct storm_bank banks[MAX_NR_BANKS]; |
113 | u8 stormy_bank_count; |
114 | bool poll_mode; |
115 | }; |
116 | |
117 | DECLARE_PER_CPU(struct mca_storm_desc, storm_desc); |
118 | |
119 | #ifdef CONFIG_ACPI_APEI |
120 | int apei_write_mce(struct mce *m); |
121 | ssize_t apei_read_mce(struct mce *m, u64 *record_id); |
122 | int apei_check_mce(void); |
123 | int apei_clear_mce(u64 record_id); |
124 | #else |
125 | static inline int apei_write_mce(struct mce *m) |
126 | { |
127 | return -EINVAL; |
128 | } |
129 | static inline ssize_t apei_read_mce(struct mce *m, u64 *record_id) |
130 | { |
131 | return 0; |
132 | } |
133 | static inline int apei_check_mce(void) |
134 | { |
135 | return 0; |
136 | } |
137 | static inline int apei_clear_mce(u64 record_id) |
138 | { |
139 | return -EINVAL; |
140 | } |
141 | #endif |
142 | |
143 | /* |
144 | * We consider records to be equivalent if bank+status+addr+misc all match. |
145 | * This is only used when the system is going down because of a fatal error |
146 | * to avoid cluttering the console log with essentially repeated information. |
147 | * In normal processing all errors seen are logged. |
148 | */ |
149 | static inline bool mce_cmp(struct mce *m1, struct mce *m2) |
150 | { |
151 | return m1->bank != m2->bank || |
152 | m1->status != m2->status || |
153 | m1->addr != m2->addr || |
154 | m1->misc != m2->misc; |
155 | } |
156 | |
157 | extern struct device_attribute dev_attr_trigger; |
158 | |
159 | #ifdef CONFIG_X86_MCELOG_LEGACY |
160 | void mce_work_trigger(void); |
161 | void mce_register_injector_chain(struct notifier_block *nb); |
162 | void mce_unregister_injector_chain(struct notifier_block *nb); |
163 | #else |
164 | static inline void mce_work_trigger(void) { } |
165 | static inline void mce_register_injector_chain(struct notifier_block *nb) { } |
166 | static inline void mce_unregister_injector_chain(struct notifier_block *nb) { } |
167 | #endif |
168 | |
169 | struct mca_config { |
170 | __u64 lmce_disabled : 1, |
171 | disabled : 1, |
172 | ser : 1, |
173 | recovery : 1, |
174 | bios_cmci_threshold : 1, |
175 | /* Proper #MC exception handler is set */ |
176 | initialized : 1, |
177 | __reserved : 58; |
178 | |
179 | bool dont_log_ce; |
180 | bool cmci_disabled; |
181 | bool ignore_ce; |
182 | bool print_all; |
183 | |
184 | int monarch_timeout; |
185 | int panic_timeout; |
186 | u32 rip_msr; |
187 | s8 bootlog; |
188 | }; |
189 | |
190 | extern struct mca_config mca_cfg; |
191 | DECLARE_PER_CPU_READ_MOSTLY(unsigned int, mce_num_banks); |
192 | |
193 | struct mce_vendor_flags { |
194 | /* |
195 | * Indicates that overflow conditions are not fatal, when set. |
196 | */ |
197 | __u64 overflow_recov : 1, |
198 | |
199 | /* |
200 | * (AMD) SUCCOR stands for S/W UnCorrectable error COntainment and |
201 | * Recovery. It indicates support for data poisoning in HW and deferred |
202 | * error interrupts. |
203 | */ |
204 | succor : 1, |
205 | |
206 | /* |
207 | * (AMD) SMCA: This bit indicates support for Scalable MCA which expands |
208 | * the register space for each MCA bank and also increases number of |
209 | * banks. Also, to accommodate the new banks and registers, the MCA |
210 | * register space is moved to a new MSR range. |
211 | */ |
212 | smca : 1, |
213 | |
214 | /* Zen IFU quirk */ |
215 | zen_ifu_quirk : 1, |
216 | |
217 | /* AMD-style error thresholding banks present. */ |
218 | amd_threshold : 1, |
219 | |
220 | /* Pentium, family 5-style MCA */ |
221 | p5 : 1, |
222 | |
223 | /* Centaur Winchip C6-style MCA */ |
224 | winchip : 1, |
225 | |
226 | /* SandyBridge IFU quirk */ |
227 | snb_ifu_quirk : 1, |
228 | |
229 | /* Skylake, Cascade Lake, Cooper Lake REP;MOVS* quirk */ |
230 | skx_repmov_quirk : 1, |
231 | |
232 | __reserved_0 : 55; |
233 | }; |
234 | |
235 | extern struct mce_vendor_flags mce_flags; |
236 | |
237 | struct mce_bank { |
238 | /* subevents to enable */ |
239 | u64 ctl; |
240 | |
241 | /* initialise bank? */ |
242 | __u64 init : 1, |
243 | |
244 | /* |
245 | * (AMD) MCA_CONFIG[McaLsbInStatusSupported]: When set, this bit indicates |
246 | * the LSB field is found in MCA_STATUS and not in MCA_ADDR. |
247 | */ |
248 | lsb_in_status : 1, |
249 | |
250 | __reserved_1 : 62; |
251 | }; |
252 | |
253 | DECLARE_PER_CPU_READ_MOSTLY(struct mce_bank[MAX_NR_BANKS], mce_banks_array); |
254 | |
255 | enum mca_msr { |
256 | MCA_CTL, |
257 | MCA_STATUS, |
258 | MCA_ADDR, |
259 | MCA_MISC, |
260 | }; |
261 | |
262 | /* Decide whether to add MCE record to MCE event pool or filter it out. */ |
263 | extern bool filter_mce(struct mce *m); |
264 | |
265 | #ifdef CONFIG_X86_MCE_AMD |
266 | extern bool amd_filter_mce(struct mce *m); |
267 | bool amd_mce_usable_address(struct mce *m); |
268 | |
269 | /* |
270 | * If MCA_CONFIG[McaLsbInStatusSupported] is set, extract ErrAddr in bits |
271 | * [56:0] of MCA_STATUS, else in bits [55:0] of MCA_ADDR. |
272 | */ |
273 | static __always_inline void (struct mce *m) |
274 | { |
275 | u8 lsb; |
276 | |
277 | if (!mce_flags.smca) |
278 | return; |
279 | |
280 | if (this_cpu_ptr(mce_banks_array)[m->bank].lsb_in_status) { |
281 | lsb = (m->status >> 24) & 0x3f; |
282 | |
283 | m->addr &= GENMASK_ULL(56, lsb); |
284 | |
285 | return; |
286 | } |
287 | |
288 | lsb = (m->addr >> 56) & 0x3f; |
289 | |
290 | m->addr &= GENMASK_ULL(55, lsb); |
291 | } |
292 | |
293 | #else |
294 | static inline bool amd_filter_mce(struct mce *m) { return false; } |
295 | static inline bool amd_mce_usable_address(struct mce *m) { return false; } |
296 | static inline void smca_extract_err_addr(struct mce *m) { } |
297 | #endif |
298 | |
299 | #ifdef CONFIG_X86_ANCIENT_MCE |
300 | void intel_p5_mcheck_init(struct cpuinfo_x86 *c); |
301 | void winchip_mcheck_init(struct cpuinfo_x86 *c); |
302 | noinstr void pentium_machine_check(struct pt_regs *regs); |
303 | noinstr void winchip_machine_check(struct pt_regs *regs); |
304 | static inline void enable_p5_mce(void) { mce_p5_enabled = 1; } |
305 | #else |
306 | static __always_inline void intel_p5_mcheck_init(struct cpuinfo_x86 *c) {} |
307 | static __always_inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {} |
308 | static __always_inline void enable_p5_mce(void) {} |
309 | static __always_inline void pentium_machine_check(struct pt_regs *regs) {} |
310 | static __always_inline void winchip_machine_check(struct pt_regs *regs) {} |
311 | #endif |
312 | |
313 | noinstr u64 mce_rdmsrl(u32 msr); |
314 | |
315 | static __always_inline u32 mca_msr_reg(int bank, enum mca_msr reg) |
316 | { |
317 | if (cpu_feature_enabled(X86_FEATURE_SMCA)) { |
318 | switch (reg) { |
319 | case MCA_CTL: return MSR_AMD64_SMCA_MCx_CTL(bank); |
320 | case MCA_ADDR: return MSR_AMD64_SMCA_MCx_ADDR(bank); |
321 | case MCA_MISC: return MSR_AMD64_SMCA_MCx_MISC(bank); |
322 | case MCA_STATUS: return MSR_AMD64_SMCA_MCx_STATUS(bank); |
323 | } |
324 | } |
325 | |
326 | switch (reg) { |
327 | case MCA_CTL: return MSR_IA32_MCx_CTL(bank); |
328 | case MCA_ADDR: return MSR_IA32_MCx_ADDR(bank); |
329 | case MCA_MISC: return MSR_IA32_MCx_MISC(bank); |
330 | case MCA_STATUS: return MSR_IA32_MCx_STATUS(bank); |
331 | } |
332 | |
333 | return 0; |
334 | } |
335 | |
336 | extern void (*mc_poll_banks)(void); |
337 | #endif /* __X86_MCE_INTERNAL_H__ */ |
338 | |