xref: /openbmc/linux/arch/x86/kernel/cpu/mce/internal.h (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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