Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/kernel/cpu/mce/internal.h
26516 views
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_hw_err err;
30
};
31
32
void mce_gen_pool_process(struct work_struct *__unused);
33
bool mce_gen_pool_empty(void);
34
bool mce_gen_pool_add(struct mce_hw_err *err);
35
bool 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
void mce_prep_record_common(struct mce *m);
265
void mce_prep_record_per_cpu(unsigned int cpu, struct mce *m);
266
267
#ifdef CONFIG_X86_MCE_AMD
268
extern bool amd_filter_mce(struct mce *m);
269
bool amd_mce_usable_address(struct mce *m);
270
271
/*
272
* If MCA_CONFIG[McaLsbInStatusSupported] is set, extract ErrAddr in bits
273
* [56:0] of MCA_STATUS, else in bits [55:0] of MCA_ADDR.
274
*/
275
static __always_inline void smca_extract_err_addr(struct mce *m)
276
{
277
u8 lsb;
278
279
if (!mce_flags.smca)
280
return;
281
282
if (this_cpu_ptr(mce_banks_array)[m->bank].lsb_in_status) {
283
lsb = (m->status >> 24) & 0x3f;
284
285
m->addr &= GENMASK_ULL(56, lsb);
286
287
return;
288
}
289
290
lsb = (m->addr >> 56) & 0x3f;
291
292
m->addr &= GENMASK_ULL(55, lsb);
293
}
294
295
#else
296
static inline bool amd_filter_mce(struct mce *m) { return false; }
297
static inline bool amd_mce_usable_address(struct mce *m) { return false; }
298
static inline void smca_extract_err_addr(struct mce *m) { }
299
#endif
300
301
#ifdef CONFIG_X86_ANCIENT_MCE
302
void intel_p5_mcheck_init(struct cpuinfo_x86 *c);
303
void winchip_mcheck_init(struct cpuinfo_x86 *c);
304
noinstr void pentium_machine_check(struct pt_regs *regs);
305
noinstr void winchip_machine_check(struct pt_regs *regs);
306
static inline void enable_p5_mce(void) { mce_p5_enabled = 1; }
307
#else
308
static __always_inline void intel_p5_mcheck_init(struct cpuinfo_x86 *c) {}
309
static __always_inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {}
310
static __always_inline void enable_p5_mce(void) {}
311
static __always_inline void pentium_machine_check(struct pt_regs *regs) {}
312
static __always_inline void winchip_machine_check(struct pt_regs *regs) {}
313
#endif
314
315
noinstr u64 mce_rdmsrq(u32 msr);
316
317
static __always_inline u32 mca_msr_reg(int bank, enum mca_msr reg)
318
{
319
if (cpu_feature_enabled(X86_FEATURE_SMCA)) {
320
switch (reg) {
321
case MCA_CTL: return MSR_AMD64_SMCA_MCx_CTL(bank);
322
case MCA_ADDR: return MSR_AMD64_SMCA_MCx_ADDR(bank);
323
case MCA_MISC: return MSR_AMD64_SMCA_MCx_MISC(bank);
324
case MCA_STATUS: return MSR_AMD64_SMCA_MCx_STATUS(bank);
325
}
326
}
327
328
switch (reg) {
329
case MCA_CTL: return MSR_IA32_MCx_CTL(bank);
330
case MCA_ADDR: return MSR_IA32_MCx_ADDR(bank);
331
case MCA_MISC: return MSR_IA32_MCx_MISC(bank);
332
case MCA_STATUS: return MSR_IA32_MCx_STATUS(bank);
333
}
334
335
return 0;
336
}
337
338
extern void (*mc_poll_banks)(void);
339
#endif /* __X86_MCE_INTERNAL_H__ */
340
341