121afaf18SBorislav Petkov /* SPDX-License-Identifier: GPL-2.0 */
221afaf18SBorislav Petkov #ifndef __X86_MCE_INTERNAL_H__
321afaf18SBorislav Petkov #define __X86_MCE_INTERNAL_H__
421afaf18SBorislav Petkov
53bfaf95cSBorislav Petkov #undef pr_fmt
63bfaf95cSBorislav Petkov #define pr_fmt(fmt) "mce: " fmt
73bfaf95cSBorislav Petkov
821afaf18SBorislav Petkov #include <linux/device.h>
921afaf18SBorislav Petkov #include <asm/mce.h>
1021afaf18SBorislav Petkov
1121afaf18SBorislav Petkov enum severity_level {
1221afaf18SBorislav Petkov MCE_NO_SEVERITY,
1321afaf18SBorislav Petkov MCE_DEFERRED_SEVERITY,
1421afaf18SBorislav Petkov MCE_UCNA_SEVERITY = MCE_DEFERRED_SEVERITY,
1521afaf18SBorislav Petkov MCE_KEEP_SEVERITY,
1621afaf18SBorislav Petkov MCE_SOME_SEVERITY,
1721afaf18SBorislav Petkov MCE_AO_SEVERITY,
1821afaf18SBorislav Petkov MCE_UC_SEVERITY,
1921afaf18SBorislav Petkov MCE_AR_SEVERITY,
2021afaf18SBorislav Petkov MCE_PANIC_SEVERITY,
2121afaf18SBorislav Petkov };
2221afaf18SBorislav Petkov
2321afaf18SBorislav Petkov extern struct blocking_notifier_head x86_mce_decoder_chain;
2421afaf18SBorislav Petkov
2521afaf18SBorislav Petkov #define INITIAL_CHECK_INTERVAL 5 * 60 /* 5 minutes */
2621afaf18SBorislav Petkov
2721afaf18SBorislav Petkov struct mce_evt_llist {
2821afaf18SBorislav Petkov struct llist_node llnode;
2921afaf18SBorislav Petkov struct mce mce;
3021afaf18SBorislav Petkov };
3121afaf18SBorislav Petkov
3221afaf18SBorislav Petkov void mce_gen_pool_process(struct work_struct *__unused);
3321afaf18SBorislav Petkov bool mce_gen_pool_empty(void);
3421afaf18SBorislav Petkov int mce_gen_pool_add(struct mce *mce);
3521afaf18SBorislav Petkov int mce_gen_pool_init(void);
3621afaf18SBorislav Petkov struct llist_node *mce_gen_pool_prepare_records(void);
3721afaf18SBorislav Petkov
387f1b8e0dSBorislav Petkov int mce_severity(struct mce *a, struct pt_regs *regs, char **msg, bool is_excp);
3921afaf18SBorislav Petkov struct dentry *mce_get_debugfs_dir(void);
4021afaf18SBorislav Petkov
4121afaf18SBorislav Petkov extern mce_banks_t mce_banks_ce_disabled;
4221afaf18SBorislav Petkov
4321afaf18SBorislav Petkov #ifdef CONFIG_X86_MCE_INTEL
4421afaf18SBorislav Petkov unsigned long cmci_intel_adjust_timer(unsigned long interval);
4521afaf18SBorislav Petkov bool mce_intel_cmci_poll(void);
4621afaf18SBorislav Petkov void mce_intel_hcpu_update(unsigned long cpu);
4721afaf18SBorislav Petkov void cmci_disable_bank(int bank);
485a3d56a0STony W Wang-oc void intel_init_cmci(void);
4970f0c230STony W Wang-oc void intel_init_lmce(void);
5070f0c230STony W Wang-oc void intel_clear_lmce(void);
512976908eSPrarit Bhargava bool intel_filter_mce(struct mce *m);
5221afaf18SBorislav Petkov #else
5321afaf18SBorislav Petkov # define cmci_intel_adjust_timer mce_adjust_timer_default
mce_intel_cmci_poll(void)5421afaf18SBorislav Petkov static inline bool mce_intel_cmci_poll(void) { return false; }
mce_intel_hcpu_update(unsigned long cpu)5521afaf18SBorislav Petkov static inline void mce_intel_hcpu_update(unsigned long cpu) { }
cmci_disable_bank(int bank)5621afaf18SBorislav Petkov static inline void cmci_disable_bank(int bank) { }
intel_init_cmci(void)575a3d56a0STony W Wang-oc static inline void intel_init_cmci(void) { }
intel_init_lmce(void)5870f0c230STony W Wang-oc static inline void intel_init_lmce(void) { }
intel_clear_lmce(void)5970f0c230STony W Wang-oc static inline void intel_clear_lmce(void) { }
intel_filter_mce(struct mce * m)60083b32d6SThomas Gleixner static inline bool intel_filter_mce(struct mce *m) { return false; }
6121afaf18SBorislav Petkov #endif
6221afaf18SBorislav Petkov
6321afaf18SBorislav Petkov void mce_timer_kick(unsigned long interval);
6421afaf18SBorislav Petkov
6521afaf18SBorislav Petkov #ifdef CONFIG_ACPI_APEI
6621afaf18SBorislav Petkov int apei_write_mce(struct mce *m);
6721afaf18SBorislav Petkov ssize_t apei_read_mce(struct mce *m, u64 *record_id);
6821afaf18SBorislav Petkov int apei_check_mce(void);
6921afaf18SBorislav Petkov int apei_clear_mce(u64 record_id);
7021afaf18SBorislav Petkov #else
apei_write_mce(struct mce * m)7121afaf18SBorislav Petkov static inline int apei_write_mce(struct mce *m)
7221afaf18SBorislav Petkov {
7321afaf18SBorislav Petkov return -EINVAL;
7421afaf18SBorislav Petkov }
apei_read_mce(struct mce * m,u64 * record_id)7521afaf18SBorislav Petkov static inline ssize_t apei_read_mce(struct mce *m, u64 *record_id)
7621afaf18SBorislav Petkov {
7721afaf18SBorislav Petkov return 0;
7821afaf18SBorislav Petkov }
apei_check_mce(void)7921afaf18SBorislav Petkov static inline int apei_check_mce(void)
8021afaf18SBorislav Petkov {
8121afaf18SBorislav Petkov return 0;
8221afaf18SBorislav Petkov }
apei_clear_mce(u64 record_id)8321afaf18SBorislav Petkov static inline int apei_clear_mce(u64 record_id)
8421afaf18SBorislav Petkov {
8521afaf18SBorislav Petkov return -EINVAL;
8621afaf18SBorislav Petkov }
8721afaf18SBorislav Petkov #endif
8821afaf18SBorislav Petkov
8921afaf18SBorislav Petkov /*
9021afaf18SBorislav Petkov * We consider records to be equivalent if bank+status+addr+misc all match.
9121afaf18SBorislav Petkov * This is only used when the system is going down because of a fatal error
9221afaf18SBorislav Petkov * to avoid cluttering the console log with essentially repeated information.
9321afaf18SBorislav Petkov * In normal processing all errors seen are logged.
9421afaf18SBorislav Petkov */
mce_cmp(struct mce * m1,struct mce * m2)9521afaf18SBorislav Petkov static inline bool mce_cmp(struct mce *m1, struct mce *m2)
9621afaf18SBorislav Petkov {
9721afaf18SBorislav Petkov return m1->bank != m2->bank ||
9821afaf18SBorislav Petkov m1->status != m2->status ||
9921afaf18SBorislav Petkov m1->addr != m2->addr ||
10021afaf18SBorislav Petkov m1->misc != m2->misc;
10121afaf18SBorislav Petkov }
10221afaf18SBorislav Petkov
10321afaf18SBorislav Petkov extern struct device_attribute dev_attr_trigger;
10421afaf18SBorislav Petkov
10521afaf18SBorislav Petkov #ifdef CONFIG_X86_MCELOG_LEGACY
10621afaf18SBorislav Petkov void mce_work_trigger(void);
10721afaf18SBorislav Petkov void mce_register_injector_chain(struct notifier_block *nb);
10821afaf18SBorislav Petkov void mce_unregister_injector_chain(struct notifier_block *nb);
10921afaf18SBorislav Petkov #else
mce_work_trigger(void)11021afaf18SBorislav Petkov static inline void mce_work_trigger(void) { }
mce_register_injector_chain(struct notifier_block * nb)11121afaf18SBorislav Petkov static inline void mce_register_injector_chain(struct notifier_block *nb) { }
mce_unregister_injector_chain(struct notifier_block * nb)11221afaf18SBorislav Petkov static inline void mce_unregister_injector_chain(struct notifier_block *nb) { }
11321afaf18SBorislav Petkov #endif
11421afaf18SBorislav Petkov
11521afaf18SBorislav Petkov struct mca_config {
11621afaf18SBorislav Petkov __u64 lmce_disabled : 1,
11721afaf18SBorislav Petkov disabled : 1,
11821afaf18SBorislav Petkov ser : 1,
11921afaf18SBorislav Petkov recovery : 1,
12021afaf18SBorislav Petkov bios_cmci_threshold : 1,
121cbe1de16SBorislav Petkov /* Proper #MC exception handler is set */
122cbe1de16SBorislav Petkov initialized : 1,
123cbe1de16SBorislav Petkov __reserved : 58;
12421afaf18SBorislav Petkov
12515802468SBorislav Petkov bool dont_log_ce;
12615802468SBorislav Petkov bool cmci_disabled;
12715802468SBorislav Petkov bool ignore_ce;
12815802468SBorislav Petkov bool print_all;
12915802468SBorislav Petkov
13021afaf18SBorislav Petkov int monarch_timeout;
13121afaf18SBorislav Petkov int panic_timeout;
13221afaf18SBorislav Petkov u32 rip_msr;
13315802468SBorislav Petkov s8 bootlog;
13421afaf18SBorislav Petkov };
13521afaf18SBorislav Petkov
13621afaf18SBorislav Petkov extern struct mca_config mca_cfg;
137c7d314f3SYazen Ghannam DECLARE_PER_CPU_READ_MOSTLY(unsigned int, mce_num_banks);
13821afaf18SBorislav Petkov
13921afaf18SBorislav Petkov struct mce_vendor_flags {
14021afaf18SBorislav Petkov /*
14121afaf18SBorislav Petkov * Indicates that overflow conditions are not fatal, when set.
14221afaf18SBorislav Petkov */
14321afaf18SBorislav Petkov __u64 overflow_recov : 1,
14421afaf18SBorislav Petkov
14521afaf18SBorislav Petkov /*
14621afaf18SBorislav Petkov * (AMD) SUCCOR stands for S/W UnCorrectable error COntainment and
14721afaf18SBorislav Petkov * Recovery. It indicates support for data poisoning in HW and deferred
14821afaf18SBorislav Petkov * error interrupts.
14921afaf18SBorislav Petkov */
15021afaf18SBorislav Petkov succor : 1,
15121afaf18SBorislav Petkov
15221afaf18SBorislav Petkov /*
15321afaf18SBorislav Petkov * (AMD) SMCA: This bit indicates support for Scalable MCA which expands
15421afaf18SBorislav Petkov * the register space for each MCA bank and also increases number of
15521afaf18SBorislav Petkov * banks. Also, to accommodate the new banks and registers, the MCA
15621afaf18SBorislav Petkov * register space is moved to a new MSR range.
15721afaf18SBorislav Petkov */
15821afaf18SBorislav Petkov smca : 1,
15921afaf18SBorislav Petkov
160*4240e2ebSYazen Ghannam /* Zen IFU quirk */
161*4240e2ebSYazen Ghannam zen_ifu_quirk : 1,
162*4240e2ebSYazen Ghannam
163c9bf318fSThomas Gleixner /* AMD-style error thresholding banks present. */
164c9bf318fSThomas Gleixner amd_threshold : 1,
165c9bf318fSThomas Gleixner
166cbe1de16SBorislav Petkov /* Pentium, family 5-style MCA */
167cbe1de16SBorislav Petkov p5 : 1,
168cbe1de16SBorislav Petkov
169cbe1de16SBorislav Petkov /* Centaur Winchip C6-style MCA */
170cbe1de16SBorislav Petkov winchip : 1,
171cbe1de16SBorislav Petkov
172cc466666SBorislav Petkov /* SandyBridge IFU quirk */
173cc466666SBorislav Petkov snb_ifu_quirk : 1,
174cc466666SBorislav Petkov
1758ca97812SJue Wang /* Skylake, Cascade Lake, Cooper Lake REP;MOVS* quirk */
1768ca97812SJue Wang skx_repmov_quirk : 1,
1778ca97812SJue Wang
178*4240e2ebSYazen Ghannam __reserved_0 : 55;
17921afaf18SBorislav Petkov };
18021afaf18SBorislav Petkov
18121afaf18SBorislav Petkov extern struct mce_vendor_flags mce_flags;
18221afaf18SBorislav Petkov
183fcd343a2SSmita Koralahalli struct mce_bank {
184fcd343a2SSmita Koralahalli /* subevents to enable */
185fcd343a2SSmita Koralahalli u64 ctl;
186fcd343a2SSmita Koralahalli
187fcd343a2SSmita Koralahalli /* initialise bank? */
188fcd343a2SSmita Koralahalli __u64 init : 1,
189fcd343a2SSmita Koralahalli
190fcd343a2SSmita Koralahalli /*
191fcd343a2SSmita Koralahalli * (AMD) MCA_CONFIG[McaLsbInStatusSupported]: When set, this bit indicates
192fcd343a2SSmita Koralahalli * the LSB field is found in MCA_STATUS and not in MCA_ADDR.
193fcd343a2SSmita Koralahalli */
194fcd343a2SSmita Koralahalli lsb_in_status : 1,
195fcd343a2SSmita Koralahalli
196fcd343a2SSmita Koralahalli __reserved_1 : 62;
197fcd343a2SSmita Koralahalli };
198fcd343a2SSmita Koralahalli
199fcd343a2SSmita Koralahalli DECLARE_PER_CPU_READ_MOSTLY(struct mce_bank[MAX_NR_BANKS], mce_banks_array);
200fcd343a2SSmita Koralahalli
2018121b8f9SBorislav Petkov enum mca_msr {
2028121b8f9SBorislav Petkov MCA_CTL,
2038121b8f9SBorislav Petkov MCA_STATUS,
2048121b8f9SBorislav Petkov MCA_ADDR,
2058121b8f9SBorislav Petkov MCA_MISC,
20621afaf18SBorislav Petkov };
20721afaf18SBorislav Petkov
20845d4b7b9SYazen Ghannam /* Decide whether to add MCE record to MCE event pool or filter it out. */
20945d4b7b9SYazen Ghannam extern bool filter_mce(struct mce *m);
21045d4b7b9SYazen Ghannam
21171a84402SYazen Ghannam #ifdef CONFIG_X86_MCE_AMD
21271a84402SYazen Ghannam extern bool amd_filter_mce(struct mce *m);
2132117654eSSmita Koralahalli
214fcd343a2SSmita Koralahalli /*
215fcd343a2SSmita Koralahalli * If MCA_CONFIG[McaLsbInStatusSupported] is set, extract ErrAddr in bits
216fcd343a2SSmita Koralahalli * [56:0] of MCA_STATUS, else in bits [55:0] of MCA_ADDR.
217fcd343a2SSmita Koralahalli */
smca_extract_err_addr(struct mce * m)2182117654eSSmita Koralahalli static __always_inline void smca_extract_err_addr(struct mce *m)
2192117654eSSmita Koralahalli {
2202117654eSSmita Koralahalli u8 lsb;
2212117654eSSmita Koralahalli
2222117654eSSmita Koralahalli if (!mce_flags.smca)
2232117654eSSmita Koralahalli return;
2242117654eSSmita Koralahalli
225fcd343a2SSmita Koralahalli if (this_cpu_ptr(mce_banks_array)[m->bank].lsb_in_status) {
226fcd343a2SSmita Koralahalli lsb = (m->status >> 24) & 0x3f;
227fcd343a2SSmita Koralahalli
228fcd343a2SSmita Koralahalli m->addr &= GENMASK_ULL(56, lsb);
229fcd343a2SSmita Koralahalli
230fcd343a2SSmita Koralahalli return;
231fcd343a2SSmita Koralahalli }
232fcd343a2SSmita Koralahalli
2332117654eSSmita Koralahalli lsb = (m->addr >> 56) & 0x3f;
2342117654eSSmita Koralahalli
2352117654eSSmita Koralahalli m->addr &= GENMASK_ULL(55, lsb);
2362117654eSSmita Koralahalli }
2372117654eSSmita Koralahalli
23871a84402SYazen Ghannam #else
amd_filter_mce(struct mce * m)239083b32d6SThomas Gleixner static inline bool amd_filter_mce(struct mce *m) { return false; }
smca_extract_err_addr(struct mce * m)2402117654eSSmita Koralahalli static inline void smca_extract_err_addr(struct mce *m) { }
24171a84402SYazen Ghannam #endif
24271a84402SYazen Ghannam
243cbe1de16SBorislav Petkov #ifdef CONFIG_X86_ANCIENT_MCE
244cbe1de16SBorislav Petkov void intel_p5_mcheck_init(struct cpuinfo_x86 *c);
245cbe1de16SBorislav Petkov void winchip_mcheck_init(struct cpuinfo_x86 *c);
246cbe1de16SBorislav Petkov noinstr void pentium_machine_check(struct pt_regs *regs);
247cbe1de16SBorislav Petkov noinstr void winchip_machine_check(struct pt_regs *regs);
enable_p5_mce(void)248cbe1de16SBorislav Petkov static inline void enable_p5_mce(void) { mce_p5_enabled = 1; }
249cbe1de16SBorislav Petkov #else
intel_p5_mcheck_init(struct cpuinfo_x86 * c)250554eec0bSBorislav Petkov (AMD) static __always_inline void intel_p5_mcheck_init(struct cpuinfo_x86 *c) {}
winchip_mcheck_init(struct cpuinfo_x86 * c)251554eec0bSBorislav Petkov (AMD) static __always_inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {}
enable_p5_mce(void)252554eec0bSBorislav Petkov (AMD) static __always_inline void enable_p5_mce(void) {}
pentium_machine_check(struct pt_regs * regs)253554eec0bSBorislav Petkov (AMD) static __always_inline void pentium_machine_check(struct pt_regs *regs) {}
winchip_machine_check(struct pt_regs * regs)254554eec0bSBorislav Petkov (AMD) static __always_inline void winchip_machine_check(struct pt_regs *regs) {}
255cbe1de16SBorislav Petkov #endif
256cbe1de16SBorislav Petkov
25788f66a42SBorislav Petkov noinstr u64 mce_rdmsrl(u32 msr);
25888f66a42SBorislav Petkov
mca_msr_reg(int bank,enum mca_msr reg)259f11445baSBorislav Petkov static __always_inline u32 mca_msr_reg(int bank, enum mca_msr reg)
260f11445baSBorislav Petkov {
261891e465aSSmita Koralahalli if (cpu_feature_enabled(X86_FEATURE_SMCA)) {
262f11445baSBorislav Petkov switch (reg) {
263f11445baSBorislav Petkov case MCA_CTL: return MSR_AMD64_SMCA_MCx_CTL(bank);
264f11445baSBorislav Petkov case MCA_ADDR: return MSR_AMD64_SMCA_MCx_ADDR(bank);
265f11445baSBorislav Petkov case MCA_MISC: return MSR_AMD64_SMCA_MCx_MISC(bank);
266f11445baSBorislav Petkov case MCA_STATUS: return MSR_AMD64_SMCA_MCx_STATUS(bank);
267f11445baSBorislav Petkov }
268f11445baSBorislav Petkov }
269f11445baSBorislav Petkov
270f11445baSBorislav Petkov switch (reg) {
271f11445baSBorislav Petkov case MCA_CTL: return MSR_IA32_MCx_CTL(bank);
272f11445baSBorislav Petkov case MCA_ADDR: return MSR_IA32_MCx_ADDR(bank);
273f11445baSBorislav Petkov case MCA_MISC: return MSR_IA32_MCx_MISC(bank);
274f11445baSBorislav Petkov case MCA_STATUS: return MSR_IA32_MCx_STATUS(bank);
275f11445baSBorislav Petkov }
276f11445baSBorislav Petkov
277f11445baSBorislav Petkov return 0;
278f11445baSBorislav Petkov }
279f11445baSBorislav Petkov
280c3629dd7SBorislav Petkov (AMD) extern void (*mc_poll_banks)(void);
28121afaf18SBorislav Petkov #endif /* __X86_MCE_INTERNAL_H__ */
282