154558Sbp// SPDX-License-Identifier: GPL-2.0-or-later
266479Sbp/*
354558Sbp * Machine check exception handling CPU-side for power7 and power8
454558Sbp *
554558Sbp * Copyright 2013 IBM Corporation
654558Sbp * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
754558Sbp */
854558Sbp
954558Sbp#undef DEBUG
1054558Sbp#define pr_fmt(fmt) "mce_power: " fmt
1154558Sbp
1254558Sbp#include <linux/types.h>
1354558Sbp#include <linux/ptrace.h>
1454558Sbp#include <linux/extable.h>
1554558Sbp#include <linux/pgtable.h>
1654558Sbp#include <asm/mmu.h>
1754558Sbp#include <asm/mce.h>
1854558Sbp#include <asm/machdep.h>
1954558Sbp#include <asm/pte-walk.h>
2054558Sbp#include <asm/sstep.h>
2154558Sbp#include <asm/exception-64s.h>
2254558Sbp#include <asm/extable.h>
2354558Sbp#include <asm/inst.h>
2454558Sbp
2554558Sbp/*
2654558Sbp * Convert an address related to an mm to a PFN. NOTE: we are in real
2754558Sbp * mode, we could potentially race with page table updates.
2854558Sbp */
2954558Sbpunsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
3054558Sbp{
3156424Sbp	pte_t *ptep, pte;
3254558Sbp	unsigned int shift;
3354558Sbp	unsigned long pfn, flags;
3454558Sbp	struct mm_struct *mm;
3554558Sbp
3654558Sbp	if (user_mode(regs))
3754558Sbp		mm = current->mm;
3854558Sbp	else
3954558Sbp		mm = &init_mm;
4054558Sbp
4154558Sbp	local_irq_save(flags);
4254558Sbp	ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift);
4354558Sbp	if (!ptep) {
4454558Sbp		pfn = ULONG_MAX;
4554558Sbp		goto out;
4654558Sbp	}
4754558Sbp	pte = READ_ONCE(*ptep);
4854558Sbp
4954558Sbp	if (!pte_present(pte) || pte_special(pte)) {
5054558Sbp		pfn = ULONG_MAX;
5154558Sbp		goto out;
5254558Sbp	}
5354558Sbp
5454558Sbp	if (shift <= PAGE_SHIFT)
5554558Sbp		pfn = pte_pfn(pte);
5654558Sbp	else {
5754558Sbp		unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
5854558Sbp		pfn = pte_pfn(__pte(pte_val(pte) | (addr & rpnmask)));
5954558Sbp	}
6054558Sbpout:
6154558Sbp	local_irq_restore(flags);
6254558Sbp	return pfn;
6354558Sbp}
64143196Ssobomax
65143196Ssobomaxstatic bool mce_in_guest(void)
66143196Ssobomax{
67143196Ssobomax#ifdef CONFIG_KVM_BOOK3S_HANDLER
68143196Ssobomax	/*
69143196Ssobomax	 * If machine check is hit when in guest context or low level KVM
70143196Ssobomax	 * code, avoid looking up any translations or making any attempts
71143196Ssobomax	 * to recover, just record the event and pass to KVM.
72143196Ssobomax	 */
7354558Sbp	if (get_paca()->kvm_hstate.in_guest)
7454558Sbp		return true;
7554558Sbp#endif
7654558Sbp	return false;
7754558Sbp}
7854558Sbp
7954558Sbp/* flush SLBs and reload */
8054558Sbp#ifdef CONFIG_PPC_64S_HASH_MMU
8187599Sobrienvoid flush_and_reload_slb(void)
8254558Sbp{
8354558Sbp	if (early_radix_enabled())
8454558Sbp		return;
8554558Sbp
8687599Sobrien	/* Invalidate all SLBs */
8754558Sbp	slb_flush_all_realmode();
8854558Sbp
89147256Sbrooks	/*
90147256Sbrooks	 * This probably shouldn't happen, but it may be possible it's
91121816Sbrooks	 * called in early boot before SLB shadows are allocated.
9254558Sbp	 */
9354558Sbp	if (!get_slb_shadow())
9454558Sbp		return;
9560938Sjake
9654558Sbp	slb_restore_bolted_realmode();
9754558Sbp}
9854558Sbp#endif
9954558Sbp
10060938Sjakevoid flush_erat(void)
10154558Sbp{
10254558Sbp#ifdef CONFIG_PPC_64S_HASH_MMU
10354558Sbp	if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
10459681Sbp		flush_and_reload_slb();
10566479Sbp		return;
10654558Sbp	}
10754558Sbp#endif
10854558Sbp	asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT : : :"memory");
10954558Sbp}
11054558Sbp
11154558Sbp#define MCE_FLUSH_SLB 1
11254558Sbp#define MCE_FLUSH_TLB 2
11354558Sbp#define MCE_FLUSH_ERAT 3
11454558Sbp
11554558Sbpstatic int mce_flush(int what)
11659681Sbp{
11766479Sbp#ifdef CONFIG_PPC_64S_HASH_MMU
11854558Sbp	if (what == MCE_FLUSH_SLB) {
11954558Sbp		flush_and_reload_slb();
12054558Sbp		return 1;
12154558Sbp	}
12254558Sbp#endif
12354558Sbp	if (what == MCE_FLUSH_ERAT) {
12454558Sbp		flush_erat();
12554558Sbp		return 1;
12654558Sbp	}
12754558Sbp	if (what == MCE_FLUSH_TLB) {
128147256Sbrooks		tlbiel_all();
12954558Sbp		return 1;
13054558Sbp	}
13154558Sbp
13254558Sbp	return 0;
13354558Sbp}
13454558Sbp
13554558Sbp#define SRR1_MC_LOADSTORE(srr1)	((srr1) & PPC_BIT(42))
13654558Sbp
13754558Sbpstruct mce_ierror_table {
138152315Sru	unsigned long srr1_mask;
13954558Sbp	unsigned long srr1_value;
14054558Sbp	bool nip_valid; /* nip is a valid indicator of faulting address */
14154558Sbp	unsigned int error_type;
142148887Srwatson	unsigned int error_subtype;
14354558Sbp	unsigned int error_class;
144121816Sbrooks	unsigned int initiator;
14554558Sbp	unsigned int severity;
14654558Sbp	bool sync_error;
14754558Sbp};
14854558Sbp
14954558Sbpstatic const struct mce_ierror_table mce_p7_ierror_table[] = {
15054558Sbp{ 0x00000000001c0000, 0x0000000000040000, true,
15154558Sbp  MCE_ERROR_TYPE_UE,  MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
15254558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
15354558Sbp{ 0x00000000001c0000, 0x0000000000080000, true,
154147256Sbrooks  MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
15554558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
15654558Sbp{ 0x00000000001c0000, 0x00000000000c0000, true,
15754558Sbp  MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
15854558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
159147256Sbrooks{ 0x00000000001c0000, 0x0000000000100000, true,
160147256Sbrooks  MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE, /* BOTH */
161147256Sbrooks  MCE_ECLASS_SOFT_INDETERMINATE,
16254558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
16354558Sbp{ 0x00000000001c0000, 0x0000000000140000, true,
16454558Sbp  MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
16554558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
16654558Sbp{ 0x00000000001c0000, 0x0000000000180000, true,
16754558Sbp  MCE_ERROR_TYPE_UE,  MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
16854558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
16954558Sbp{ 0x00000000001c0000, 0x00000000001c0000, true,
17054558Sbp  MCE_ERROR_TYPE_UE,  MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
17154558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
17254558Sbp{ 0, 0, 0, 0, 0, 0, 0 } };
17354558Sbp
174121816Sbrooksstatic const struct mce_ierror_table mce_p8_ierror_table[] = {
17554558Sbp{ 0x00000000081c0000, 0x0000000000040000, true,
17654558Sbp  MCE_ERROR_TYPE_UE,  MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
17754558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
178121816Sbrooks{ 0x00000000081c0000, 0x0000000000080000, true,
17954558Sbp  MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
18054558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
18154558Sbp{ 0x00000000081c0000, 0x00000000000c0000, true,
182106939Ssam  MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
183106939Ssam  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
184106939Ssam{ 0x00000000081c0000, 0x0000000000100000, true,
18554558Sbp  MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
186121816Sbrooks  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
18754558Sbp{ 0x00000000081c0000, 0x0000000000140000, true,
18854558Sbp  MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
18954558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
19054558Sbp{ 0x00000000081c0000, 0x0000000000180000, true,
19154558Sbp  MCE_ERROR_TYPE_UE,  MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
19254558Sbp  MCE_ECLASS_HARDWARE,
193106939Ssam  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
19454558Sbp{ 0x00000000081c0000, 0x00000000001c0000, true,
19554558Sbp  MCE_ERROR_TYPE_UE,  MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
19654558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
19754558Sbp{ 0x00000000081c0000, 0x0000000008000000, true,
19854558Sbp  MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_IFETCH_TIMEOUT, MCE_ECLASS_HARDWARE,
19954558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
20054558Sbp{ 0x00000000081c0000, 0x0000000008040000, true,
20154558Sbp  MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
20254558Sbp  MCE_ECLASS_HARDWARE,
20354558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
20454558Sbp{ 0, 0, 0, 0, 0, 0, 0 } };
20554558Sbp
20654558Sbpstatic const struct mce_ierror_table mce_p9_ierror_table[] = {
20754558Sbp{ 0x00000000081c0000, 0x0000000000040000, true,
20854558Sbp  MCE_ERROR_TYPE_UE,  MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
20954558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
21054558Sbp{ 0x00000000081c0000, 0x0000000000080000, true,
211130549Smlaier  MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
21254558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
213148887Srwatson{ 0x00000000081c0000, 0x00000000000c0000, true,
214147256Sbrooks  MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
21554558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
21654558Sbp{ 0x00000000081c0000, 0x0000000000100000, true,
21754558Sbp  MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
21854558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
21954558Sbp{ 0x00000000081c0000, 0x0000000000140000, true,
22054558Sbp  MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
221106939Ssam  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
222130549Smlaier{ 0x00000000081c0000, 0x0000000000180000, true,
223130549Smlaier  MCE_ERROR_TYPE_UE,  MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
22459681Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
22559681Sbp{ 0x00000000081c0000, 0x00000000001c0000, true,
22654558Sbp  MCE_ERROR_TYPE_RA,  MCE_RA_ERROR_IFETCH_FOREIGN, MCE_ECLASS_SOFTWARE,
22769152Sjlemon  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
22854558Sbp{ 0x00000000081c0000, 0x0000000008000000, true,
229148887Srwatson  MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_IFETCH_TIMEOUT, MCE_ECLASS_HARDWARE,
23054558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
23154558Sbp{ 0x00000000081c0000, 0x0000000008040000, true,
23254558Sbp  MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
23354558Sbp  MCE_ECLASS_HARDWARE,
23454558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
23554558Sbp{ 0x00000000081c0000, 0x00000000080c0000, true,
23654558Sbp  MCE_ERROR_TYPE_RA,  MCE_RA_ERROR_IFETCH, MCE_ECLASS_SOFTWARE,
23754558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
238111888Sjlemon{ 0x00000000081c0000, 0x0000000008100000, true,
23954558Sbp  MCE_ERROR_TYPE_RA,  MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_SOFTWARE,
240111888Sjlemon  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
241111888Sjlemon{ 0x00000000081c0000, 0x0000000008140000, false,
24254558Sbp  MCE_ERROR_TYPE_RA,  MCE_RA_ERROR_STORE, MCE_ECLASS_HARDWARE,
24354558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_FATAL, false }, /* ASYNC is fatal */
244111888Sjlemon{ 0x00000000081c0000, 0x0000000008180000, false,
245111888Sjlemon  MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_STORE_TIMEOUT,
24654558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_FATAL, false }, /* ASYNC is fatal */
24754558Sbp{ 0x00000000081c0000, 0x00000000081c0000, true, MCE_ECLASS_HARDWARE,
24854558Sbp  MCE_ERROR_TYPE_RA,  MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
249111888Sjlemon  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
250122702Sandre{ 0, 0, 0, 0, 0, 0, 0 } };
251111888Sjlemon
252111888Sjlemonstatic const struct mce_ierror_table mce_p10_ierror_table[] = {
25354558Sbp{ 0x00000000081c0000, 0x0000000000040000, true,
25454558Sbp  MCE_ERROR_TYPE_UE,  MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
255111888Sjlemon  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
256111888Sjlemon{ 0x00000000081c0000, 0x0000000000080000, true,
25754558Sbp  MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
25854558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
259111888Sjlemon{ 0x00000000081c0000, 0x00000000000c0000, true,
260111888Sjlemon  MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
26154558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
262111888Sjlemon{ 0x00000000081c0000, 0x0000000000100000, true,
263111888Sjlemon  MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
26454558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
26554558Sbp{ 0x00000000081c0000, 0x0000000000140000, true,
26654558Sbp  MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
26754558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
268111888Sjlemon{ 0x00000000081c0000, 0x0000000000180000, true,
26954558Sbp  MCE_ERROR_TYPE_UE,  MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
270111888Sjlemon  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
271111888Sjlemon{ 0x00000000081c0000, 0x00000000001c0000, true,
27254558Sbp  MCE_ERROR_TYPE_RA,  MCE_RA_ERROR_IFETCH_FOREIGN, MCE_ECLASS_SOFTWARE,
27354558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
274111888Sjlemon{ 0x00000000081c0000, 0x0000000008080000, true,
27554558Sbp  MCE_ERROR_TYPE_USER,MCE_USER_ERROR_SCV, MCE_ECLASS_SOFTWARE,
276111888Sjlemon  MCE_INITIATOR_CPU,  MCE_SEV_WARNING, true },
27754558Sbp{ 0x00000000081c0000, 0x00000000080c0000, true,
27854558Sbp  MCE_ERROR_TYPE_RA,  MCE_RA_ERROR_IFETCH, MCE_ECLASS_SOFTWARE,
279111888Sjlemon  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
280111888Sjlemon{ 0x00000000081c0000, 0x0000000008100000, true,
28154558Sbp  MCE_ERROR_TYPE_RA,  MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_SOFTWARE,
282111888Sjlemon  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
283111888Sjlemon{ 0x00000000081c0000, 0x0000000008140000, false,
28454558Sbp  MCE_ERROR_TYPE_RA,  MCE_RA_ERROR_STORE, MCE_ECLASS_HARDWARE,
28554558Sbp  MCE_INITIATOR_CPU,  MCE_SEV_FATAL, false }, /* ASYNC is fatal */
28654558Sbp{ 0x00000000081c0000, 0x00000000081c0000, true, MCE_ECLASS_HARDWARE,
28754558Sbp  MCE_ERROR_TYPE_RA,  MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
288111888Sjlemon  MCE_INITIATOR_CPU,  MCE_SEV_SEVERE, true },
28954558Sbp{ 0, 0, 0, 0, 0, 0, 0 } };
290111888Sjlemon
291111888Sjlemonstruct mce_derror_table {
29254558Sbp	unsigned long dsisr_value;
29354558Sbp	bool dar_valid; /* dar is a valid indicator of faulting address */
294111888Sjlemon	unsigned int error_type;
29554558Sbp	unsigned int error_subtype;
296111888Sjlemon	unsigned int error_class;
29754558Sbp	unsigned int initiator;
29854558Sbp	unsigned int severity;
299111888Sjlemon	bool sync_error;
300111888Sjlemon};
30154558Sbp
302111888Sjlemonstatic const struct mce_derror_table mce_p7_derror_table[] = {
303111888Sjlemon{ 0x00008000, false,
30454558Sbp  MCE_ERROR_TYPE_UE,   MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
305111888Sjlemon  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
30654558Sbp{ 0x00004000, true,
30754558Sbp  MCE_ERROR_TYPE_UE,   MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
30854558Sbp  MCE_ECLASS_HARDWARE,
30954558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
31054558Sbp{ 0x00000800, true,
31154558Sbp  MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
31254558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
31371891Sbp{ 0x00000400, true,
31454558Sbp  MCE_ERROR_TYPE_TLB,  MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
31554558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
31654558Sbp{ 0x00000080, true,
31754558Sbp  MCE_ERROR_TYPE_SLB,  MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
318111888Sjlemon  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
31954558Sbp{ 0x00000100, true,
32054558Sbp  MCE_ERROR_TYPE_SLB,  MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
321132778Skan  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
32254558Sbp{ 0x00000040, true,
32354558Sbp  MCE_ERROR_TYPE_SLB,  MCE_SLB_ERROR_INDETERMINATE, /* BOTH */
32454558Sbp  MCE_ECLASS_HARD_INDETERMINATE,
32554558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
32654558Sbp{ 0, false, 0, 0, 0, 0, 0 } };
32754558Sbp
32854558Sbpstatic const struct mce_derror_table mce_p8_derror_table[] = {
32954558Sbp{ 0x00008000, false,
33054558Sbp  MCE_ERROR_TYPE_UE,   MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
33154558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
33254558Sbp{ 0x00004000, true,
33354558Sbp  MCE_ERROR_TYPE_UE,   MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
33454558Sbp  MCE_ECLASS_HARDWARE,
33554558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
33654558Sbp{ 0x00002000, true,
33754558Sbp  MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT, MCE_ECLASS_HARDWARE,
33854558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
33954558Sbp{ 0x00001000, true,
34054558Sbp  MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
34154558Sbp  MCE_ECLASS_HARDWARE,
34254558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
34354558Sbp{ 0x00000800, true,
34454558Sbp  MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
34554558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
34654558Sbp{ 0x00000400, true,
34759681Sbp  MCE_ERROR_TYPE_TLB,  MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
34854558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
34954558Sbp{ 0x00000200, true,
35054558Sbp  MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, /* SECONDARY ERAT */
35154558Sbp  MCE_ECLASS_SOFT_INDETERMINATE,
35254558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
35354558Sbp{ 0x00000080, true,
35454558Sbp  MCE_ERROR_TYPE_SLB,  MCE_SLB_ERROR_MULTIHIT,	/* Before PARITY */
35554558Sbp  MCE_ECLASS_SOFT_INDETERMINATE,
35654558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
35754558Sbp{ 0x00000100, true,
35854558Sbp  MCE_ERROR_TYPE_SLB,  MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
35954558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
36054558Sbp{ 0, false, 0, 0, 0, 0, 0 } };
36154558Sbp
36259681Sbpstatic const struct mce_derror_table mce_p9_derror_table[] = {
36354558Sbp{ 0x00008000, false,
364147256Sbrooks  MCE_ERROR_TYPE_UE,   MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
36554558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
36659681Sbp{ 0x00004000, true,
36754558Sbp  MCE_ERROR_TYPE_UE,   MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
36854558Sbp  MCE_ECLASS_HARDWARE,
36954558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
370123922Ssam{ 0x00002000, true,
37154558Sbp  MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT, MCE_ECLASS_HARDWARE,
37254558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
37354558Sbp{ 0x00001000, true,
37454558Sbp  MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
375111888Sjlemon  MCE_ECLASS_HARDWARE,
376111888Sjlemon  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
37754558Sbp{ 0x00000800, true,
378111888Sjlemon  MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
379111888Sjlemon  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
38054558Sbp{ 0x00000400, true,
38154558Sbp  MCE_ERROR_TYPE_TLB,  MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
382111888Sjlemon  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
383111888Sjlemon{ 0x00000200, false,
384111888Sjlemon  MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE, MCE_ECLASS_SOFTWARE,
385111888Sjlemon  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
386111888Sjlemon{ 0x00000080, true,
38754558Sbp  MCE_ERROR_TYPE_SLB,  MCE_SLB_ERROR_MULTIHIT,	/* Before PARITY */
38854558Sbp  MCE_ECLASS_SOFT_INDETERMINATE,
389111888Sjlemon  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
39054558Sbp{ 0x00000100, true,
391111888Sjlemon  MCE_ERROR_TYPE_SLB,  MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
392111888Sjlemon  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
39354558Sbp{ 0x00000040, true,
39454558Sbp  MCE_ERROR_TYPE_RA,   MCE_RA_ERROR_LOAD, MCE_ECLASS_HARDWARE,
39554558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
39666479Sbp{ 0x00000020, false,
39766479Sbp  MCE_ERROR_TYPE_RA,   MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
39854558Sbp  MCE_ECLASS_HARDWARE,
399121816Sbrooks  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
40059681Sbp{ 0x00000010, false,
40154558Sbp  MCE_ERROR_TYPE_RA,   MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
40254558Sbp  MCE_ECLASS_HARDWARE,
40354558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
40454558Sbp{ 0x00000008, false,
40559681Sbp  MCE_ERROR_TYPE_RA,   MCE_RA_ERROR_LOAD_STORE_FOREIGN, MCE_ECLASS_HARDWARE,
406121816Sbrooks  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
40754558Sbp{ 0, false, 0, 0, 0, 0, 0 } };
40854558Sbp
40954558Sbpstatic const struct mce_derror_table mce_p10_derror_table[] = {
41054558Sbp{ 0x00008000, false,
41159681Sbp  MCE_ERROR_TYPE_UE,   MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
41254558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
41354558Sbp{ 0x00004000, true,
41454558Sbp  MCE_ERROR_TYPE_UE,   MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
41554558Sbp  MCE_ECLASS_HARDWARE,
41654558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
41754558Sbp{ 0x00000800, true,
418111119Simp  MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
41959681Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
42059681Sbp{ 0x00000400, true,
42159681Sbp  MCE_ERROR_TYPE_TLB,  MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
42259681Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
42359681Sbp{ 0x00000200, false,
42459681Sbp  MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE, MCE_ECLASS_SOFTWARE,
42559681Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
42659681Sbp{ 0x00000080, true,
42759681Sbp  MCE_ERROR_TYPE_SLB,  MCE_SLB_ERROR_MULTIHIT,	/* Before PARITY */
42859681Sbp  MCE_ECLASS_SOFT_INDETERMINATE,
42959681Sbp  MCE_INITIATOR_CPU,   MCE_SEV_WARNING, true },
43059681Sbp{ 0x00000100, true,
43159681Sbp  MCE_ERROR_TYPE_SLB,  MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
43259681Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
43354558Sbp{ 0x00000040, true,
43454558Sbp  MCE_ERROR_TYPE_RA,   MCE_RA_ERROR_LOAD, MCE_ECLASS_HARDWARE,
43554558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
43654558Sbp{ 0x00000020, false,
43754558Sbp  MCE_ERROR_TYPE_RA,   MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
43866479Sbp  MCE_ECLASS_HARDWARE,
43954558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
44054558Sbp{ 0x00000010, false,
441111119Simp  MCE_ERROR_TYPE_RA,   MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
44259681Sbp  MCE_ECLASS_HARDWARE,
44359681Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
44459681Sbp{ 0x00000008, false,
44559681Sbp  MCE_ERROR_TYPE_RA,   MCE_RA_ERROR_LOAD_STORE_FOREIGN, MCE_ECLASS_HARDWARE,
44654558Sbp  MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
44754558Sbp{ 0, false, 0, 0, 0, 0, 0 } };
44854558Sbp
44966479Sbpstatic int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr,
45054558Sbp					uint64_t *phys_addr)
45154558Sbp{
45259681Sbp	/*
45354558Sbp	 * Carefully look at the NIP to determine
45459681Sbp	 * the instruction to analyse. Reading the NIP
45554558Sbp	 * in real-mode is tricky and can lead to recursive
45654558Sbp	 * faults
45754558Sbp	 */
45854558Sbp	ppc_inst_t instr;
45954558Sbp	unsigned long pfn, instr_addr;
46054558Sbp	struct instruction_op op;
46154558Sbp	struct pt_regs tmp = *regs;
46254558Sbp
46354558Sbp	pfn = addr_to_pfn(regs, regs->nip);
46454558Sbp	if (pfn != ULONG_MAX) {
46554558Sbp		instr_addr = (pfn << PAGE_SHIFT) + (regs->nip & ~PAGE_MASK);
46654558Sbp		instr = ppc_inst_read((u32 *)instr_addr);
46754558Sbp		if (!analyse_instr(&op, &tmp, instr)) {
46854558Sbp			pfn = addr_to_pfn(regs, op.ea);
46969781Sdwmalone			*addr = op.ea;
470111119Simp			*phys_addr = (pfn << PAGE_SHIFT);
47154558Sbp			return 0;
47254558Sbp		}
473147256Sbrooks		/*
474121816Sbrooks		 * analyse_instr() might fail if the instruction
475147256Sbrooks		 * is not a load/store, although this is unexpected
476154318Srwatson		 * for load/store errors or if we got the NIP
477154318Srwatson		 * wrong
478147256Sbrooks		 */
479154318Srwatson	}
480121816Sbrooks	*addr = 0;
481121816Sbrooks	return -1;
482121816Sbrooks}
483121816Sbrooks
48454558Sbpstatic int mce_handle_ierror(struct pt_regs *regs, unsigned long srr1,
48554558Sbp		const struct mce_ierror_table table[],
48654558Sbp		struct mce_error_info *mce_err, uint64_t *addr,
48754558Sbp		uint64_t *phys_addr)
48854558Sbp{
48954558Sbp	int handled = 0;
49054558Sbp	int i;
49154558Sbp
49254558Sbp	*addr = 0;
49354558Sbp
49454558Sbp	for (i = 0; table[i].srr1_mask; i++) {
49554558Sbp		if ((srr1 & table[i].srr1_mask) != table[i].srr1_value)
496154317Srwatson			continue;
49754558Sbp
49854558Sbp		if (!mce_in_guest()) {
499108172Shsu			/* attempt to correct the error */
50071999Sphk			switch (table[i].error_type) {
50154558Sbp			case MCE_ERROR_TYPE_SLB:
502121816Sbrooks#ifdef CONFIG_PPC_64S_HASH_MMU
50354558Sbp				if (local_paca->in_mce == 1)
504111119Simp					slb_save_contents(local_paca->mce_faulty_slbs);
50554558Sbp#endif
50654558Sbp				handled = mce_flush(MCE_FLUSH_SLB);
50754558Sbp				break;
50854558Sbp			case MCE_ERROR_TYPE_ERAT:
50954558Sbp				handled = mce_flush(MCE_FLUSH_ERAT);
51054558Sbp				break;
51154558Sbp			case MCE_ERROR_TYPE_TLB:
51254558Sbp				handled = mce_flush(MCE_FLUSH_TLB);
51354558Sbp				break;
51454558Sbp			}
51554558Sbp		}
51654558Sbp
51754558Sbp		/* now fill in mce_error_info */
51854558Sbp		mce_err->error_type = table[i].error_type;
51954558Sbp		mce_err->error_class = table[i].error_class;
52054558Sbp		switch (table[i].error_type) {
52154558Sbp		case MCE_ERROR_TYPE_UE:
52254558Sbp			mce_err->u.ue_error_type = table[i].error_subtype;
52354558Sbp			break;
52454558Sbp		case MCE_ERROR_TYPE_SLB:
52554558Sbp			mce_err->u.slb_error_type = table[i].error_subtype;
52654558Sbp			break;
52754558Sbp		case MCE_ERROR_TYPE_ERAT:
52854558Sbp			mce_err->u.erat_error_type = table[i].error_subtype;
52954558Sbp			break;
530108172Shsu		case MCE_ERROR_TYPE_TLB:
53154558Sbp			mce_err->u.tlb_error_type = table[i].error_subtype;
53254558Sbp			break;
53354558Sbp		case MCE_ERROR_TYPE_USER:
534154317Srwatson			mce_err->u.user_error_type = table[i].error_subtype;
53554558Sbp			break;
536147256Sbrooks		case MCE_ERROR_TYPE_RA:
537147256Sbrooks			mce_err->u.ra_error_type = table[i].error_subtype;
538147256Sbrooks			break;
53954558Sbp		case MCE_ERROR_TYPE_LINK:
540147256Sbrooks			mce_err->u.link_error_type = table[i].error_subtype;
54154558Sbp			break;
54254558Sbp		}
54354558Sbp		mce_err->sync_error = table[i].sync_error;
54454558Sbp		mce_err->severity = table[i].severity;
54554558Sbp		mce_err->initiator = table[i].initiator;
54654558Sbp		if (table[i].nip_valid && !mce_in_guest()) {
54754558Sbp			*addr = regs->nip;
54854558Sbp			if (mce_err->sync_error &&
54954558Sbp				table[i].error_type == MCE_ERROR_TYPE_UE) {
55054558Sbp				unsigned long pfn;
55154558Sbp
55254558Sbp				if (get_paca()->in_mce < MAX_MCE_DEPTH) {
55354558Sbp					pfn = addr_to_pfn(regs, regs->nip);
55454558Sbp					if (pfn != ULONG_MAX) {
55554558Sbp						*phys_addr =
55654558Sbp							(pfn << PAGE_SHIFT);
55754558Sbp					}
55854558Sbp				}
55954558Sbp			}
56054558Sbp		}
56154558Sbp		return handled;
56254558Sbp	}
56354558Sbp
56454558Sbp	mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
56554558Sbp	mce_err->error_class = MCE_ECLASS_UNKNOWN;
56654558Sbp	mce_err->severity = MCE_SEV_SEVERE;
56754558Sbp	mce_err->initiator = MCE_INITIATOR_CPU;
56854558Sbp	mce_err->sync_error = true;
56954558Sbp
57054558Sbp	return 0;
57154558Sbp}
57254558Sbp
57354558Sbpstatic int mce_handle_derror(struct pt_regs *regs,
57454558Sbp		const struct mce_derror_table table[],
57554558Sbp		struct mce_error_info *mce_err, uint64_t *addr,
57654558Sbp		uint64_t *phys_addr)
57754558Sbp{
57854558Sbp	uint64_t dsisr = regs->dsisr;
57954558Sbp	int handled = 0;
58054558Sbp	int found = 0;
58154558Sbp	int i;
58254558Sbp
58354558Sbp	*addr = 0;
58454558Sbp
58554558Sbp	for (i = 0; table[i].dsisr_value; i++) {
58654558Sbp		if (!(dsisr & table[i].dsisr_value))
58754558Sbp			continue;
588132199Sphk
58954558Sbp		if (!mce_in_guest()) {
59054558Sbp			/* attempt to correct the error */
59154558Sbp			switch (table[i].error_type) {
59254558Sbp			case MCE_ERROR_TYPE_SLB:
59354558Sbp#ifdef CONFIG_PPC_64S_HASH_MMU
59454558Sbp				if (local_paca->in_mce == 1)
59554558Sbp					slb_save_contents(local_paca->mce_faulty_slbs);
59654558Sbp#endif
59754558Sbp				if (mce_flush(MCE_FLUSH_SLB))
598					handled = 1;
599				break;
600			case MCE_ERROR_TYPE_ERAT:
601				if (mce_flush(MCE_FLUSH_ERAT))
602					handled = 1;
603				break;
604			case MCE_ERROR_TYPE_TLB:
605				if (mce_flush(MCE_FLUSH_TLB))
606					handled = 1;
607				break;
608			}
609		}
610
611		/*
612		 * Attempt to handle multiple conditions, but only return
613		 * one. Ensure uncorrectable errors are first in the table
614		 * to match.
615		 */
616		if (found)
617			continue;
618
619		/* now fill in mce_error_info */
620		mce_err->error_type = table[i].error_type;
621		mce_err->error_class = table[i].error_class;
622		switch (table[i].error_type) {
623		case MCE_ERROR_TYPE_UE:
624			mce_err->u.ue_error_type = table[i].error_subtype;
625			break;
626		case MCE_ERROR_TYPE_SLB:
627			mce_err->u.slb_error_type = table[i].error_subtype;
628			break;
629		case MCE_ERROR_TYPE_ERAT:
630			mce_err->u.erat_error_type = table[i].error_subtype;
631			break;
632		case MCE_ERROR_TYPE_TLB:
633			mce_err->u.tlb_error_type = table[i].error_subtype;
634			break;
635		case MCE_ERROR_TYPE_USER:
636			mce_err->u.user_error_type = table[i].error_subtype;
637			break;
638		case MCE_ERROR_TYPE_RA:
639			mce_err->u.ra_error_type = table[i].error_subtype;
640			break;
641		case MCE_ERROR_TYPE_LINK:
642			mce_err->u.link_error_type = table[i].error_subtype;
643			break;
644		}
645		mce_err->sync_error = table[i].sync_error;
646		mce_err->severity = table[i].severity;
647		mce_err->initiator = table[i].initiator;
648		if (table[i].dar_valid)
649			*addr = regs->dar;
650		else if (mce_err->sync_error && !mce_in_guest() &&
651				table[i].error_type == MCE_ERROR_TYPE_UE) {
652			/*
653			 * We do a maximum of 4 nested MCE calls, see
654			 * kernel/exception-64s.h
655			 */
656			if (get_paca()->in_mce < MAX_MCE_DEPTH)
657				mce_find_instr_ea_and_phys(regs, addr,
658							   phys_addr);
659		}
660		found = 1;
661	}
662
663	if (found)
664		return handled;
665
666	mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
667	mce_err->error_class = MCE_ECLASS_UNKNOWN;
668	mce_err->severity = MCE_SEV_SEVERE;
669	mce_err->initiator = MCE_INITIATOR_CPU;
670	mce_err->sync_error = true;
671
672	return 0;
673}
674
675static long mce_handle_ue_error(struct pt_regs *regs,
676				struct mce_error_info *mce_err)
677{
678	if (mce_in_guest())
679		return 0;
680
681	mce_common_process_ue(regs, mce_err);
682	if (mce_err->ignore_event)
683		return 1;
684
685	/*
686	 * On specific SCOM read via MMIO we may get a machine check
687	 * exception with SRR0 pointing inside opal. If that is the
688	 * case OPAL may have recovery address to re-read SCOM data in
689	 * different way and hence we can recover from this MC.
690	 */
691
692	if (ppc_md.mce_check_early_recovery) {
693		if (ppc_md.mce_check_early_recovery(regs))
694			return 1;
695	}
696
697	return 0;
698}
699
700static long mce_handle_error(struct pt_regs *regs,
701		unsigned long srr1,
702		const struct mce_derror_table dtable[],
703		const struct mce_ierror_table itable[])
704{
705	struct mce_error_info mce_err = { 0 };
706	uint64_t addr, phys_addr = ULONG_MAX;
707	long handled;
708
709	if (SRR1_MC_LOADSTORE(srr1))
710		handled = mce_handle_derror(regs, dtable, &mce_err, &addr,
711				&phys_addr);
712	else
713		handled = mce_handle_ierror(regs, srr1, itable, &mce_err, &addr,
714				&phys_addr);
715
716	if (!handled && mce_err.error_type == MCE_ERROR_TYPE_UE)
717		handled = mce_handle_ue_error(regs, &mce_err);
718
719	save_mce_event(regs, handled, &mce_err, regs->nip, addr, phys_addr);
720
721	return handled;
722}
723
724long __machine_check_early_realmode_p7(struct pt_regs *regs)
725{
726	/* P7 DD1 leaves top bits of DSISR undefined */
727	regs->dsisr &= 0x0000ffff;
728
729	return mce_handle_error(regs, regs->msr,
730			mce_p7_derror_table, mce_p7_ierror_table);
731}
732
733long __machine_check_early_realmode_p8(struct pt_regs *regs)
734{
735	return mce_handle_error(regs, regs->msr,
736			mce_p8_derror_table, mce_p8_ierror_table);
737}
738
739long __machine_check_early_realmode_p9(struct pt_regs *regs)
740{
741	unsigned long srr1 = regs->msr;
742
743	/*
744	 * On POWER9 DD2.1 and below, it's possible to get a machine check
745	 * caused by a paste instruction where only DSISR bit 25 is set. This
746	 * will result in the MCE handler seeing an unknown event and the kernel
747	 * crashing. An MCE that occurs like this is spurious, so we don't need
748	 * to do anything in terms of servicing it. If there is something that
749	 * needs to be serviced, the CPU will raise the MCE again with the
750	 * correct DSISR so that it can be serviced properly. So detect this
751	 * case and mark it as handled.
752	 */
753	if (SRR1_MC_LOADSTORE(regs->msr) && regs->dsisr == 0x02000000)
754		return 1;
755
756	/*
757	 * Async machine check due to bad real address from store or foreign
758	 * link time out comes with the load/store bit (PPC bit 42) set in
759	 * SRR1, but the cause comes in SRR1 not DSISR. Clear bit 42 so we're
760	 * directed to the ierror table so it will find the cause (which
761	 * describes it correctly as a store error).
762	 */
763	if (SRR1_MC_LOADSTORE(srr1) &&
764			((srr1 & 0x081c0000) == 0x08140000 ||
765			 (srr1 & 0x081c0000) == 0x08180000)) {
766		srr1 &= ~PPC_BIT(42);
767	}
768
769	return mce_handle_error(regs, srr1,
770			mce_p9_derror_table, mce_p9_ierror_table);
771}
772
773long __machine_check_early_realmode_p10(struct pt_regs *regs)
774{
775	unsigned long srr1 = regs->msr;
776
777	/*
778	 * Async machine check due to bad real address from store comes with
779	 * the load/store bit (PPC bit 42) set in SRR1, but the cause comes in
780	 * SRR1 not DSISR. Clear bit 42 so we're directed to the ierror table
781	 * so it will find the cause (which describes it correctly as a store
782	 * error).
783	 */
784	if (SRR1_MC_LOADSTORE(srr1) &&
785			(srr1 & 0x081c0000) == 0x08140000) {
786		srr1 &= ~PPC_BIT(42);
787	}
788
789	return mce_handle_error(regs, srr1,
790			mce_p10_derror_table, mce_p10_ierror_table);
791}
792