11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2e22a2274SMahesh Salgaonkar /*
3e22a2274SMahesh Salgaonkar * Machine check exception handling CPU-side for power7 and power8
4e22a2274SMahesh Salgaonkar *
5e22a2274SMahesh Salgaonkar * Copyright 2013 IBM Corporation
6e22a2274SMahesh Salgaonkar * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
7e22a2274SMahesh Salgaonkar */
8e22a2274SMahesh Salgaonkar
9e22a2274SMahesh Salgaonkar #undef DEBUG
10e22a2274SMahesh Salgaonkar #define pr_fmt(fmt) "mce_power: " fmt
11e22a2274SMahesh Salgaonkar
12e22a2274SMahesh Salgaonkar #include <linux/types.h>
13e22a2274SMahesh Salgaonkar #include <linux/ptrace.h>
14895e3dceSBalbir Singh #include <linux/extable.h>
1565fddcfcSMike Rapoport #include <linux/pgtable.h>
16e22a2274SMahesh Salgaonkar #include <asm/mmu.h>
17e22a2274SMahesh Salgaonkar #include <asm/mce.h>
1855672ecfSMahesh Salgaonkar #include <asm/machdep.h>
19ba41e1e1SBalbir Singh #include <asm/pte-walk.h>
20ba41e1e1SBalbir Singh #include <asm/sstep.h>
21ba41e1e1SBalbir Singh #include <asm/exception-64s.h>
22895e3dceSBalbir Singh #include <asm/extable.h>
2394afd069SJordan Niethe #include <asm/inst.h>
24ba41e1e1SBalbir Singh
25ba41e1e1SBalbir Singh /*
26ba41e1e1SBalbir Singh * Convert an address related to an mm to a PFN. NOTE: we are in real
27ba41e1e1SBalbir Singh * mode, we could potentially race with page table updates.
28ba41e1e1SBalbir Singh */
addr_to_pfn(struct pt_regs * regs,unsigned long addr)297f177f98SGanesh Goudar unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
30ba41e1e1SBalbir Singh {
310da81b65SAneesh Kumar K.V pte_t *ptep, pte;
3299ead78aSBalbir Singh unsigned int shift;
33d9101bfaSAneesh Kumar K.V unsigned long pfn, flags;
34ba41e1e1SBalbir Singh struct mm_struct *mm;
35ba41e1e1SBalbir Singh
36ba41e1e1SBalbir Singh if (user_mode(regs))
37ba41e1e1SBalbir Singh mm = current->mm;
38ba41e1e1SBalbir Singh else
39ba41e1e1SBalbir Singh mm = &init_mm;
40ba41e1e1SBalbir Singh
41ba41e1e1SBalbir Singh local_irq_save(flags);
4299ead78aSBalbir Singh ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift);
430da81b65SAneesh Kumar K.V if (!ptep) {
440da81b65SAneesh Kumar K.V pfn = ULONG_MAX;
450da81b65SAneesh Kumar K.V goto out;
460da81b65SAneesh Kumar K.V }
470da81b65SAneesh Kumar K.V pte = READ_ONCE(*ptep);
4899ead78aSBalbir Singh
490da81b65SAneesh Kumar K.V if (!pte_present(pte) || pte_special(pte)) {
50d9101bfaSAneesh Kumar K.V pfn = ULONG_MAX;
51d9101bfaSAneesh Kumar K.V goto out;
5299ead78aSBalbir Singh }
5399ead78aSBalbir Singh
54d9101bfaSAneesh Kumar K.V if (shift <= PAGE_SHIFT)
550da81b65SAneesh Kumar K.V pfn = pte_pfn(pte);
56d9101bfaSAneesh Kumar K.V else {
57d9101bfaSAneesh Kumar K.V unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
580da81b65SAneesh Kumar K.V pfn = pte_pfn(__pte(pte_val(pte) | (addr & rpnmask)));
59d9101bfaSAneesh Kumar K.V }
60d9101bfaSAneesh Kumar K.V out:
61d9101bfaSAneesh Kumar K.V local_irq_restore(flags);
62d9101bfaSAneesh Kumar K.V return pfn;
63ba41e1e1SBalbir Singh }
64e22a2274SMahesh Salgaonkar
mce_in_guest(void)650ce23826SNicholas Piggin static bool mce_in_guest(void)
660ce23826SNicholas Piggin {
670ce23826SNicholas Piggin #ifdef CONFIG_KVM_BOOK3S_HANDLER
680ce23826SNicholas Piggin /*
690ce23826SNicholas Piggin * If machine check is hit when in guest context or low level KVM
700ce23826SNicholas Piggin * code, avoid looking up any translations or making any attempts
710ce23826SNicholas Piggin * to recover, just record the event and pass to KVM.
720ce23826SNicholas Piggin */
730ce23826SNicholas Piggin if (get_paca()->kvm_hstate.in_guest)
740ce23826SNicholas Piggin return true;
750ce23826SNicholas Piggin #endif
760ce23826SNicholas Piggin return false;
770ce23826SNicholas Piggin }
780ce23826SNicholas Piggin
79e22a2274SMahesh Salgaonkar /* flush SLBs and reload */
80387e220aSNicholas Piggin #ifdef CONFIG_PPC_64S_HASH_MMU
flush_and_reload_slb(void)81a43c1590SMahesh Salgaonkar void flush_and_reload_slb(void)
82e22a2274SMahesh Salgaonkar {
83e7e81847SNicholas Piggin if (early_radix_enabled())
84e22a2274SMahesh Salgaonkar return;
85e22a2274SMahesh Salgaonkar
86310dce62SNicholas Piggin /* Invalidate all SLBs */
87310dce62SNicholas Piggin slb_flush_all_realmode();
88310dce62SNicholas Piggin
89e7e81847SNicholas Piggin /*
90e7e81847SNicholas Piggin * This probably shouldn't happen, but it may be possible it's
91e7e81847SNicholas Piggin * called in early boot before SLB shadows are allocated.
92e7e81847SNicholas Piggin */
93e7e81847SNicholas Piggin if (!get_slb_shadow())
94e7e81847SNicholas Piggin return;
95e22a2274SMahesh Salgaonkar
96e7e81847SNicholas Piggin slb_restore_bolted_realmode();
97e22a2274SMahesh Salgaonkar }
98caca285eSAneesh Kumar K.V #endif
99e22a2274SMahesh Salgaonkar
flush_erat(void)10082f70a05SNicholas Piggin void flush_erat(void)
1017b9f71f9SNicholas Piggin {
102387e220aSNicholas Piggin #ifdef CONFIG_PPC_64S_HASH_MMU
103bc276ecbSNicholas Piggin if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
104bc276ecbSNicholas Piggin flush_and_reload_slb();
105bc276ecbSNicholas Piggin return;
106bc276ecbSNicholas Piggin }
107bc276ecbSNicholas Piggin #endif
108fe7946ceSNicholas Piggin asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT : : :"memory");
1097b9f71f9SNicholas Piggin }
1107b9f71f9SNicholas Piggin
1117b9f71f9SNicholas Piggin #define MCE_FLUSH_SLB 1
1127b9f71f9SNicholas Piggin #define MCE_FLUSH_TLB 2
1137b9f71f9SNicholas Piggin #define MCE_FLUSH_ERAT 3
1147b9f71f9SNicholas Piggin
mce_flush(int what)1157b9f71f9SNicholas Piggin static int mce_flush(int what)
1167b9f71f9SNicholas Piggin {
117387e220aSNicholas Piggin #ifdef CONFIG_PPC_64S_HASH_MMU
1187b9f71f9SNicholas Piggin if (what == MCE_FLUSH_SLB) {
1197b9f71f9SNicholas Piggin flush_and_reload_slb();
1207b9f71f9SNicholas Piggin return 1;
1217b9f71f9SNicholas Piggin }
1227b9f71f9SNicholas Piggin #endif
1237b9f71f9SNicholas Piggin if (what == MCE_FLUSH_ERAT) {
1247b9f71f9SNicholas Piggin flush_erat();
1257b9f71f9SNicholas Piggin return 1;
1267b9f71f9SNicholas Piggin }
1277b9f71f9SNicholas Piggin if (what == MCE_FLUSH_TLB) {
128d4748276SNicholas Piggin tlbiel_all();
1297b9f71f9SNicholas Piggin return 1;
1307b9f71f9SNicholas Piggin }
1317b9f71f9SNicholas Piggin
1327b9f71f9SNicholas Piggin return 0;
1337b9f71f9SNicholas Piggin }
1347b9f71f9SNicholas Piggin
135755309beSNicholas Piggin #define SRR1_MC_LOADSTORE(srr1) ((srr1) & PPC_BIT(42))
13658c8d17fSNicholas Piggin
137631bc46cSNicholas Piggin struct mce_ierror_table {
138631bc46cSNicholas Piggin unsigned long srr1_mask;
139631bc46cSNicholas Piggin unsigned long srr1_value;
140631bc46cSNicholas Piggin bool nip_valid; /* nip is a valid indicator of faulting address */
141631bc46cSNicholas Piggin unsigned int error_type;
142631bc46cSNicholas Piggin unsigned int error_subtype;
14350dbabe0SMahesh Salgaonkar unsigned int error_class;
144631bc46cSNicholas Piggin unsigned int initiator;
145631bc46cSNicholas Piggin unsigned int severity;
146cda6618dSMahesh Salgaonkar bool sync_error;
147631bc46cSNicholas Piggin };
148631bc46cSNicholas Piggin
149631bc46cSNicholas Piggin static const struct mce_ierror_table mce_p7_ierror_table[] = {
150631bc46cSNicholas Piggin { 0x00000000001c0000, 0x0000000000040000, true,
15150dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
152cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
153631bc46cSNicholas Piggin { 0x00000000001c0000, 0x0000000000080000, true,
15450dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
155cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
156631bc46cSNicholas Piggin { 0x00000000001c0000, 0x00000000000c0000, true,
15750dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
158cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
159631bc46cSNicholas Piggin { 0x00000000001c0000, 0x0000000000100000, true,
160631bc46cSNicholas Piggin MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE, /* BOTH */
16150dbabe0SMahesh Salgaonkar MCE_ECLASS_SOFT_INDETERMINATE,
162cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
163631bc46cSNicholas Piggin { 0x00000000001c0000, 0x0000000000140000, true,
16450dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
165cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
166631bc46cSNicholas Piggin { 0x00000000001c0000, 0x0000000000180000, true,
16750dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
168cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
169631bc46cSNicholas Piggin { 0x00000000001c0000, 0x00000000001c0000, true,
17050dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
171cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
172cda6618dSMahesh Salgaonkar { 0, 0, 0, 0, 0, 0, 0 } };
173631bc46cSNicholas Piggin
174631bc46cSNicholas Piggin static const struct mce_ierror_table mce_p8_ierror_table[] = {
175c7e790c5SNicholas Piggin { 0x00000000081c0000, 0x0000000000040000, true,
17650dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
177cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
178c7e790c5SNicholas Piggin { 0x00000000081c0000, 0x0000000000080000, true,
17950dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
180cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
181c7e790c5SNicholas Piggin { 0x00000000081c0000, 0x00000000000c0000, true,
18250dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
183cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
184c7e790c5SNicholas Piggin { 0x00000000081c0000, 0x0000000000100000, true,
18550dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
186cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
187c7e790c5SNicholas Piggin { 0x00000000081c0000, 0x0000000000140000, true,
18850dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
189cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
190c7e790c5SNicholas Piggin { 0x00000000081c0000, 0x0000000000180000, true,
191631bc46cSNicholas Piggin MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
19250dbabe0SMahesh Salgaonkar MCE_ECLASS_HARDWARE,
193cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
194c7e790c5SNicholas Piggin { 0x00000000081c0000, 0x00000000001c0000, true,
19550dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
196cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
197c7e790c5SNicholas Piggin { 0x00000000081c0000, 0x0000000008000000, true,
19850dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_IFETCH_TIMEOUT, MCE_ECLASS_HARDWARE,
199cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
200c7e790c5SNicholas Piggin { 0x00000000081c0000, 0x0000000008040000, true,
201c7e790c5SNicholas Piggin MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
20250dbabe0SMahesh Salgaonkar MCE_ECLASS_HARDWARE,
203cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
204cda6618dSMahesh Salgaonkar { 0, 0, 0, 0, 0, 0, 0 } };
205631bc46cSNicholas Piggin
206631bc46cSNicholas Piggin static const struct mce_ierror_table mce_p9_ierror_table[] = {
207631bc46cSNicholas Piggin { 0x00000000081c0000, 0x0000000000040000, true,
20850dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
209cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
210631bc46cSNicholas Piggin { 0x00000000081c0000, 0x0000000000080000, true,
21150dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
212cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
213631bc46cSNicholas Piggin { 0x00000000081c0000, 0x00000000000c0000, true,
21450dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
215cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
216631bc46cSNicholas Piggin { 0x00000000081c0000, 0x0000000000100000, true,
21750dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
218cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
219631bc46cSNicholas Piggin { 0x00000000081c0000, 0x0000000000140000, true,
22050dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
221cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
222631bc46cSNicholas Piggin { 0x00000000081c0000, 0x0000000000180000, true,
22350dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
224cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
22590df4bfbSNicholas Piggin { 0x00000000081c0000, 0x00000000001c0000, true,
22650dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH_FOREIGN, MCE_ECLASS_SOFTWARE,
227cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
228631bc46cSNicholas Piggin { 0x00000000081c0000, 0x0000000008000000, true,
22950dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_IFETCH_TIMEOUT, MCE_ECLASS_HARDWARE,
230cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
231631bc46cSNicholas Piggin { 0x00000000081c0000, 0x0000000008040000, true,
232631bc46cSNicholas Piggin MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
23350dbabe0SMahesh Salgaonkar MCE_ECLASS_HARDWARE,
234cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
235631bc46cSNicholas Piggin { 0x00000000081c0000, 0x00000000080c0000, true,
23650dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH, MCE_ECLASS_SOFTWARE,
237cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
238631bc46cSNicholas Piggin { 0x00000000081c0000, 0x0000000008100000, true,
23950dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_SOFTWARE,
240cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
241631bc46cSNicholas Piggin { 0x00000000081c0000, 0x0000000008140000, false,
24250dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_RA, MCE_RA_ERROR_STORE, MCE_ECLASS_HARDWARE,
243cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_FATAL, false }, /* ASYNC is fatal */
244631bc46cSNicholas Piggin { 0x00000000081c0000, 0x0000000008180000, false,
245631bc46cSNicholas Piggin MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_STORE_TIMEOUT,
246cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_FATAL, false }, /* ASYNC is fatal */
24750dbabe0SMahesh Salgaonkar { 0x00000000081c0000, 0x00000000081c0000, true, MCE_ECLASS_HARDWARE,
248631bc46cSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
249cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
250cda6618dSMahesh Salgaonkar { 0, 0, 0, 0, 0, 0, 0 } };
251631bc46cSNicholas Piggin
252201220bbSNicholas Piggin static const struct mce_ierror_table mce_p10_ierror_table[] = {
253201220bbSNicholas Piggin { 0x00000000081c0000, 0x0000000000040000, true,
254201220bbSNicholas Piggin MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
255201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
256201220bbSNicholas Piggin { 0x00000000081c0000, 0x0000000000080000, true,
257201220bbSNicholas Piggin MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
258201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
259201220bbSNicholas Piggin { 0x00000000081c0000, 0x00000000000c0000, true,
260201220bbSNicholas Piggin MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
261201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
262201220bbSNicholas Piggin { 0x00000000081c0000, 0x0000000000100000, true,
263201220bbSNicholas Piggin MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
264201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
265201220bbSNicholas Piggin { 0x00000000081c0000, 0x0000000000140000, true,
266201220bbSNicholas Piggin MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
267201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
268201220bbSNicholas Piggin { 0x00000000081c0000, 0x0000000000180000, true,
269201220bbSNicholas Piggin MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
270201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
271201220bbSNicholas Piggin { 0x00000000081c0000, 0x00000000001c0000, true,
272201220bbSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH_FOREIGN, MCE_ECLASS_SOFTWARE,
273201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
274201220bbSNicholas Piggin { 0x00000000081c0000, 0x0000000008080000, true,
275201220bbSNicholas Piggin MCE_ERROR_TYPE_USER,MCE_USER_ERROR_SCV, MCE_ECLASS_SOFTWARE,
276201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
277201220bbSNicholas Piggin { 0x00000000081c0000, 0x00000000080c0000, true,
278201220bbSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH, MCE_ECLASS_SOFTWARE,
279201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
280201220bbSNicholas Piggin { 0x00000000081c0000, 0x0000000008100000, true,
281201220bbSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_SOFTWARE,
282201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
283201220bbSNicholas Piggin { 0x00000000081c0000, 0x0000000008140000, false,
284201220bbSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_STORE, MCE_ECLASS_HARDWARE,
285201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_FATAL, false }, /* ASYNC is fatal */
286201220bbSNicholas Piggin { 0x00000000081c0000, 0x00000000081c0000, true, MCE_ECLASS_HARDWARE,
287201220bbSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
288201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
289201220bbSNicholas Piggin { 0, 0, 0, 0, 0, 0, 0 } };
290201220bbSNicholas Piggin
291631bc46cSNicholas Piggin struct mce_derror_table {
292631bc46cSNicholas Piggin unsigned long dsisr_value;
293631bc46cSNicholas Piggin bool dar_valid; /* dar is a valid indicator of faulting address */
294631bc46cSNicholas Piggin unsigned int error_type;
295631bc46cSNicholas Piggin unsigned int error_subtype;
29650dbabe0SMahesh Salgaonkar unsigned int error_class;
297631bc46cSNicholas Piggin unsigned int initiator;
298631bc46cSNicholas Piggin unsigned int severity;
299cda6618dSMahesh Salgaonkar bool sync_error;
300631bc46cSNicholas Piggin };
301631bc46cSNicholas Piggin
302631bc46cSNicholas Piggin static const struct mce_derror_table mce_p7_derror_table[] = {
303631bc46cSNicholas Piggin { 0x00008000, false,
30450dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
305cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
306631bc46cSNicholas Piggin { 0x00004000, true,
307631bc46cSNicholas Piggin MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
30850dbabe0SMahesh Salgaonkar MCE_ECLASS_HARDWARE,
309cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
310631bc46cSNicholas Piggin { 0x00000800, true,
31150dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
312cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
313631bc46cSNicholas Piggin { 0x00000400, true,
31450dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
315cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
31654dbcfc2SMichael Ellerman { 0x00000080, true,
31750dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
318cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
319631bc46cSNicholas Piggin { 0x00000100, true,
32050dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
321cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
322631bc46cSNicholas Piggin { 0x00000040, true,
323631bc46cSNicholas Piggin MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE, /* BOTH */
32450dbabe0SMahesh Salgaonkar MCE_ECLASS_HARD_INDETERMINATE,
325cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
326cda6618dSMahesh Salgaonkar { 0, false, 0, 0, 0, 0, 0 } };
327631bc46cSNicholas Piggin
328631bc46cSNicholas Piggin static const struct mce_derror_table mce_p8_derror_table[] = {
329631bc46cSNicholas Piggin { 0x00008000, false,
33050dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
331cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
332631bc46cSNicholas Piggin { 0x00004000, true,
333631bc46cSNicholas Piggin MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
33450dbabe0SMahesh Salgaonkar MCE_ECLASS_HARDWARE,
335cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
336c7e790c5SNicholas Piggin { 0x00002000, true,
33750dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT, MCE_ECLASS_HARDWARE,
338cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
339c7e790c5SNicholas Piggin { 0x00001000, true,
340c7e790c5SNicholas Piggin MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
34150dbabe0SMahesh Salgaonkar MCE_ECLASS_HARDWARE,
342cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
343631bc46cSNicholas Piggin { 0x00000800, true,
34450dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
345cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
346631bc46cSNicholas Piggin { 0x00000400, true,
34750dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
348cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
349631bc46cSNicholas Piggin { 0x00000200, true,
350631bc46cSNicholas Piggin MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, /* SECONDARY ERAT */
35150dbabe0SMahesh Salgaonkar MCE_ECLASS_SOFT_INDETERMINATE,
352cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
35354dbcfc2SMichael Ellerman { 0x00000080, true,
35454dbcfc2SMichael Ellerman MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, /* Before PARITY */
35550dbabe0SMahesh Salgaonkar MCE_ECLASS_SOFT_INDETERMINATE,
356cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
357631bc46cSNicholas Piggin { 0x00000100, true,
35850dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
359cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
360cda6618dSMahesh Salgaonkar { 0, false, 0, 0, 0, 0, 0 } };
361631bc46cSNicholas Piggin
362631bc46cSNicholas Piggin static const struct mce_derror_table mce_p9_derror_table[] = {
363631bc46cSNicholas Piggin { 0x00008000, false,
36450dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
365cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
366631bc46cSNicholas Piggin { 0x00004000, true,
367631bc46cSNicholas Piggin MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
36850dbabe0SMahesh Salgaonkar MCE_ECLASS_HARDWARE,
369cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
370631bc46cSNicholas Piggin { 0x00002000, true,
37150dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT, MCE_ECLASS_HARDWARE,
372cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
373631bc46cSNicholas Piggin { 0x00001000, true,
374631bc46cSNicholas Piggin MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
37550dbabe0SMahesh Salgaonkar MCE_ECLASS_HARDWARE,
376cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
377631bc46cSNicholas Piggin { 0x00000800, true,
37850dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
379cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
380631bc46cSNicholas Piggin { 0x00000400, true,
38150dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
382cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
383631bc46cSNicholas Piggin { 0x00000200, false,
38450dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE, MCE_ECLASS_SOFTWARE,
385cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
38654dbcfc2SMichael Ellerman { 0x00000080, true,
38754dbcfc2SMichael Ellerman MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, /* Before PARITY */
38850dbabe0SMahesh Salgaonkar MCE_ECLASS_SOFT_INDETERMINATE,
389cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
390631bc46cSNicholas Piggin { 0x00000100, true,
39150dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
392cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
393631bc46cSNicholas Piggin { 0x00000040, true,
39450dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD, MCE_ECLASS_HARDWARE,
395cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
396631bc46cSNicholas Piggin { 0x00000020, false,
397631bc46cSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
39850dbabe0SMahesh Salgaonkar MCE_ECLASS_HARDWARE,
399cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
400631bc46cSNicholas Piggin { 0x00000010, false,
401631bc46cSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
40250dbabe0SMahesh Salgaonkar MCE_ECLASS_HARDWARE,
403cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
404631bc46cSNicholas Piggin { 0x00000008, false,
40550dbabe0SMahesh Salgaonkar MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN, MCE_ECLASS_HARDWARE,
406cda6618dSMahesh Salgaonkar MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
407cda6618dSMahesh Salgaonkar { 0, false, 0, 0, 0, 0, 0 } };
408631bc46cSNicholas Piggin
409201220bbSNicholas Piggin static const struct mce_derror_table mce_p10_derror_table[] = {
410201220bbSNicholas Piggin { 0x00008000, false,
411201220bbSNicholas Piggin MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
412201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
413201220bbSNicholas Piggin { 0x00004000, true,
414201220bbSNicholas Piggin MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
415201220bbSNicholas Piggin MCE_ECLASS_HARDWARE,
416201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
417201220bbSNicholas Piggin { 0x00000800, true,
418201220bbSNicholas Piggin MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
419201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
420201220bbSNicholas Piggin { 0x00000400, true,
421201220bbSNicholas Piggin MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
422201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
423201220bbSNicholas Piggin { 0x00000200, false,
424201220bbSNicholas Piggin MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE, MCE_ECLASS_SOFTWARE,
425201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
426201220bbSNicholas Piggin { 0x00000080, true,
427201220bbSNicholas Piggin MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, /* Before PARITY */
428201220bbSNicholas Piggin MCE_ECLASS_SOFT_INDETERMINATE,
429201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
430201220bbSNicholas Piggin { 0x00000100, true,
431201220bbSNicholas Piggin MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
432201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
433201220bbSNicholas Piggin { 0x00000040, true,
434201220bbSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD, MCE_ECLASS_HARDWARE,
435201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
436201220bbSNicholas Piggin { 0x00000020, false,
437201220bbSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
438201220bbSNicholas Piggin MCE_ECLASS_HARDWARE,
439201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
440201220bbSNicholas Piggin { 0x00000010, false,
441201220bbSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
442201220bbSNicholas Piggin MCE_ECLASS_HARDWARE,
443201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
444201220bbSNicholas Piggin { 0x00000008, false,
445201220bbSNicholas Piggin MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN, MCE_ECLASS_HARDWARE,
446201220bbSNicholas Piggin MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
447201220bbSNicholas Piggin { 0, false, 0, 0, 0, 0, 0 } };
448201220bbSNicholas Piggin
mce_find_instr_ea_and_phys(struct pt_regs * regs,uint64_t * addr,uint64_t * phys_addr)44999ead78aSBalbir Singh static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr,
450ba41e1e1SBalbir Singh uint64_t *phys_addr)
451ba41e1e1SBalbir Singh {
452ba41e1e1SBalbir Singh /*
453ba41e1e1SBalbir Singh * Carefully look at the NIP to determine
454ba41e1e1SBalbir Singh * the instruction to analyse. Reading the NIP
455ba41e1e1SBalbir Singh * in real-mode is tricky and can lead to recursive
456ba41e1e1SBalbir Singh * faults
457ba41e1e1SBalbir Singh */
458*c545b9f0SChristophe Leroy ppc_inst_t instr;
459ba41e1e1SBalbir Singh unsigned long pfn, instr_addr;
460ba41e1e1SBalbir Singh struct instruction_op op;
461ba41e1e1SBalbir Singh struct pt_regs tmp = *regs;
462ba41e1e1SBalbir Singh
463ba41e1e1SBalbir Singh pfn = addr_to_pfn(regs, regs->nip);
464ba41e1e1SBalbir Singh if (pfn != ULONG_MAX) {
465ba41e1e1SBalbir Singh instr_addr = (pfn << PAGE_SHIFT) + (regs->nip & ~PAGE_MASK);
46669d4d6e5SChristophe Leroy instr = ppc_inst_read((u32 *)instr_addr);
467ba41e1e1SBalbir Singh if (!analyse_instr(&op, &tmp, instr)) {
468ba41e1e1SBalbir Singh pfn = addr_to_pfn(regs, op.ea);
469ba41e1e1SBalbir Singh *addr = op.ea;
470ba41e1e1SBalbir Singh *phys_addr = (pfn << PAGE_SHIFT);
471ba41e1e1SBalbir Singh return 0;
472ba41e1e1SBalbir Singh }
473ba41e1e1SBalbir Singh /*
474ba41e1e1SBalbir Singh * analyse_instr() might fail if the instruction
475ba41e1e1SBalbir Singh * is not a load/store, although this is unexpected
476ba41e1e1SBalbir Singh * for load/store errors or if we got the NIP
477ba41e1e1SBalbir Singh * wrong
478ba41e1e1SBalbir Singh */
479ba41e1e1SBalbir Singh }
480ba41e1e1SBalbir Singh *addr = 0;
481ba41e1e1SBalbir Singh return -1;
482ba41e1e1SBalbir Singh }
483ba41e1e1SBalbir Singh
mce_handle_ierror(struct pt_regs * regs,unsigned long srr1,const struct mce_ierror_table table[],struct mce_error_info * mce_err,uint64_t * addr,uint64_t * phys_addr)4843729e0ecSNicholas Piggin static int mce_handle_ierror(struct pt_regs *regs, unsigned long srr1,
485631bc46cSNicholas Piggin const struct mce_ierror_table table[],
48601eaac2bSBalbir Singh struct mce_error_info *mce_err, uint64_t *addr,
48701eaac2bSBalbir Singh uint64_t *phys_addr)
488631bc46cSNicholas Piggin {
489755309beSNicholas Piggin int handled = 0;
490631bc46cSNicholas Piggin int i;
491631bc46cSNicholas Piggin
492631bc46cSNicholas Piggin *addr = 0;
493631bc46cSNicholas Piggin
494631bc46cSNicholas Piggin for (i = 0; table[i].srr1_mask; i++) {
495631bc46cSNicholas Piggin if ((srr1 & table[i].srr1_mask) != table[i].srr1_value)
496631bc46cSNicholas Piggin continue;
497631bc46cSNicholas Piggin
4980ce23826SNicholas Piggin if (!mce_in_guest()) {
499755309beSNicholas Piggin /* attempt to correct the error */
500755309beSNicholas Piggin switch (table[i].error_type) {
501755309beSNicholas Piggin case MCE_ERROR_TYPE_SLB:
502387e220aSNicholas Piggin #ifdef CONFIG_PPC_64S_HASH_MMU
5037290f3b3SNicholas Piggin if (local_paca->in_mce == 1)
5047290f3b3SNicholas Piggin slb_save_contents(local_paca->mce_faulty_slbs);
505387e220aSNicholas Piggin #endif
506755309beSNicholas Piggin handled = mce_flush(MCE_FLUSH_SLB);
507755309beSNicholas Piggin break;
508755309beSNicholas Piggin case MCE_ERROR_TYPE_ERAT:
509755309beSNicholas Piggin handled = mce_flush(MCE_FLUSH_ERAT);
510755309beSNicholas Piggin break;
511755309beSNicholas Piggin case MCE_ERROR_TYPE_TLB:
512755309beSNicholas Piggin handled = mce_flush(MCE_FLUSH_TLB);
513755309beSNicholas Piggin break;
514755309beSNicholas Piggin }
5150ce23826SNicholas Piggin }
516755309beSNicholas Piggin
517755309beSNicholas Piggin /* now fill in mce_error_info */
518631bc46cSNicholas Piggin mce_err->error_type = table[i].error_type;
51950dbabe0SMahesh Salgaonkar mce_err->error_class = table[i].error_class;
520631bc46cSNicholas Piggin switch (table[i].error_type) {
521631bc46cSNicholas Piggin case MCE_ERROR_TYPE_UE:
522631bc46cSNicholas Piggin mce_err->u.ue_error_type = table[i].error_subtype;
523631bc46cSNicholas Piggin break;
524631bc46cSNicholas Piggin case MCE_ERROR_TYPE_SLB:
525631bc46cSNicholas Piggin mce_err->u.slb_error_type = table[i].error_subtype;
526631bc46cSNicholas Piggin break;
527631bc46cSNicholas Piggin case MCE_ERROR_TYPE_ERAT:
528631bc46cSNicholas Piggin mce_err->u.erat_error_type = table[i].error_subtype;
529631bc46cSNicholas Piggin break;
530631bc46cSNicholas Piggin case MCE_ERROR_TYPE_TLB:
531631bc46cSNicholas Piggin mce_err->u.tlb_error_type = table[i].error_subtype;
532631bc46cSNicholas Piggin break;
533631bc46cSNicholas Piggin case MCE_ERROR_TYPE_USER:
534631bc46cSNicholas Piggin mce_err->u.user_error_type = table[i].error_subtype;
535631bc46cSNicholas Piggin break;
536631bc46cSNicholas Piggin case MCE_ERROR_TYPE_RA:
537631bc46cSNicholas Piggin mce_err->u.ra_error_type = table[i].error_subtype;
538631bc46cSNicholas Piggin break;
539631bc46cSNicholas Piggin case MCE_ERROR_TYPE_LINK:
540631bc46cSNicholas Piggin mce_err->u.link_error_type = table[i].error_subtype;
541631bc46cSNicholas Piggin break;
542631bc46cSNicholas Piggin }
543cda6618dSMahesh Salgaonkar mce_err->sync_error = table[i].sync_error;
544631bc46cSNicholas Piggin mce_err->severity = table[i].severity;
545631bc46cSNicholas Piggin mce_err->initiator = table[i].initiator;
5460ce23826SNicholas Piggin if (table[i].nip_valid && !mce_in_guest()) {
547631bc46cSNicholas Piggin *addr = regs->nip;
548cda6618dSMahesh Salgaonkar if (mce_err->sync_error &&
54901eaac2bSBalbir Singh table[i].error_type == MCE_ERROR_TYPE_UE) {
55001eaac2bSBalbir Singh unsigned long pfn;
55101eaac2bSBalbir Singh
55201eaac2bSBalbir Singh if (get_paca()->in_mce < MAX_MCE_DEPTH) {
55301eaac2bSBalbir Singh pfn = addr_to_pfn(regs, regs->nip);
55401eaac2bSBalbir Singh if (pfn != ULONG_MAX) {
55501eaac2bSBalbir Singh *phys_addr =
55601eaac2bSBalbir Singh (pfn << PAGE_SHIFT);
55701eaac2bSBalbir Singh }
55801eaac2bSBalbir Singh }
55901eaac2bSBalbir Singh }
56001eaac2bSBalbir Singh }
561755309beSNicholas Piggin return handled;
562631bc46cSNicholas Piggin }
563631bc46cSNicholas Piggin
564631bc46cSNicholas Piggin mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
56550dbabe0SMahesh Salgaonkar mce_err->error_class = MCE_ECLASS_UNKNOWN;
566cda6618dSMahesh Salgaonkar mce_err->severity = MCE_SEV_SEVERE;
567631bc46cSNicholas Piggin mce_err->initiator = MCE_INITIATOR_CPU;
568cda6618dSMahesh Salgaonkar mce_err->sync_error = true;
569755309beSNicholas Piggin
570755309beSNicholas Piggin return 0;
571631bc46cSNicholas Piggin }
572631bc46cSNicholas Piggin
mce_handle_derror(struct pt_regs * regs,const struct mce_derror_table table[],struct mce_error_info * mce_err,uint64_t * addr,uint64_t * phys_addr)573755309beSNicholas Piggin static int mce_handle_derror(struct pt_regs *regs,
574631bc46cSNicholas Piggin const struct mce_derror_table table[],
575ba41e1e1SBalbir Singh struct mce_error_info *mce_err, uint64_t *addr,
576ba41e1e1SBalbir Singh uint64_t *phys_addr)
577631bc46cSNicholas Piggin {
578631bc46cSNicholas Piggin uint64_t dsisr = regs->dsisr;
579755309beSNicholas Piggin int handled = 0;
580755309beSNicholas Piggin int found = 0;
581631bc46cSNicholas Piggin int i;
582631bc46cSNicholas Piggin
583631bc46cSNicholas Piggin *addr = 0;
584631bc46cSNicholas Piggin
585631bc46cSNicholas Piggin for (i = 0; table[i].dsisr_value; i++) {
586631bc46cSNicholas Piggin if (!(dsisr & table[i].dsisr_value))
587631bc46cSNicholas Piggin continue;
588631bc46cSNicholas Piggin
5890ce23826SNicholas Piggin if (!mce_in_guest()) {
590755309beSNicholas Piggin /* attempt to correct the error */
591755309beSNicholas Piggin switch (table[i].error_type) {
592755309beSNicholas Piggin case MCE_ERROR_TYPE_SLB:
593387e220aSNicholas Piggin #ifdef CONFIG_PPC_64S_HASH_MMU
5947290f3b3SNicholas Piggin if (local_paca->in_mce == 1)
5957290f3b3SNicholas Piggin slb_save_contents(local_paca->mce_faulty_slbs);
596387e220aSNicholas Piggin #endif
597755309beSNicholas Piggin if (mce_flush(MCE_FLUSH_SLB))
598755309beSNicholas Piggin handled = 1;
599755309beSNicholas Piggin break;
600755309beSNicholas Piggin case MCE_ERROR_TYPE_ERAT:
601755309beSNicholas Piggin if (mce_flush(MCE_FLUSH_ERAT))
602755309beSNicholas Piggin handled = 1;
603755309beSNicholas Piggin break;
604755309beSNicholas Piggin case MCE_ERROR_TYPE_TLB:
605755309beSNicholas Piggin if (mce_flush(MCE_FLUSH_TLB))
606755309beSNicholas Piggin handled = 1;
607755309beSNicholas Piggin break;
608755309beSNicholas Piggin }
6090ce23826SNicholas Piggin }
610755309beSNicholas Piggin
611755309beSNicholas Piggin /*
612755309beSNicholas Piggin * Attempt to handle multiple conditions, but only return
613755309beSNicholas Piggin * one. Ensure uncorrectable errors are first in the table
614755309beSNicholas Piggin * to match.
615755309beSNicholas Piggin */
616755309beSNicholas Piggin if (found)
617755309beSNicholas Piggin continue;
618755309beSNicholas Piggin
619755309beSNicholas Piggin /* now fill in mce_error_info */
620631bc46cSNicholas Piggin mce_err->error_type = table[i].error_type;
62150dbabe0SMahesh Salgaonkar mce_err->error_class = table[i].error_class;
622631bc46cSNicholas Piggin switch (table[i].error_type) {
623631bc46cSNicholas Piggin case MCE_ERROR_TYPE_UE:
624631bc46cSNicholas Piggin mce_err->u.ue_error_type = table[i].error_subtype;
625631bc46cSNicholas Piggin break;
626631bc46cSNicholas Piggin case MCE_ERROR_TYPE_SLB:
627631bc46cSNicholas Piggin mce_err->u.slb_error_type = table[i].error_subtype;
628631bc46cSNicholas Piggin break;
629631bc46cSNicholas Piggin case MCE_ERROR_TYPE_ERAT:
630631bc46cSNicholas Piggin mce_err->u.erat_error_type = table[i].error_subtype;
631631bc46cSNicholas Piggin break;
632631bc46cSNicholas Piggin case MCE_ERROR_TYPE_TLB:
633631bc46cSNicholas Piggin mce_err->u.tlb_error_type = table[i].error_subtype;
634631bc46cSNicholas Piggin break;
635631bc46cSNicholas Piggin case MCE_ERROR_TYPE_USER:
636631bc46cSNicholas Piggin mce_err->u.user_error_type = table[i].error_subtype;
637631bc46cSNicholas Piggin break;
638631bc46cSNicholas Piggin case MCE_ERROR_TYPE_RA:
639631bc46cSNicholas Piggin mce_err->u.ra_error_type = table[i].error_subtype;
640631bc46cSNicholas Piggin break;
641631bc46cSNicholas Piggin case MCE_ERROR_TYPE_LINK:
642631bc46cSNicholas Piggin mce_err->u.link_error_type = table[i].error_subtype;
643631bc46cSNicholas Piggin break;
644631bc46cSNicholas Piggin }
645cda6618dSMahesh Salgaonkar mce_err->sync_error = table[i].sync_error;
646631bc46cSNicholas Piggin mce_err->severity = table[i].severity;
647631bc46cSNicholas Piggin mce_err->initiator = table[i].initiator;
648631bc46cSNicholas Piggin if (table[i].dar_valid)
649631bc46cSNicholas Piggin *addr = regs->dar;
6500ce23826SNicholas Piggin else if (mce_err->sync_error && !mce_in_guest() &&
651ba41e1e1SBalbir Singh table[i].error_type == MCE_ERROR_TYPE_UE) {
652ba41e1e1SBalbir Singh /*
653ba41e1e1SBalbir Singh * We do a maximum of 4 nested MCE calls, see
654ba41e1e1SBalbir Singh * kernel/exception-64s.h
655ba41e1e1SBalbir Singh */
656ba41e1e1SBalbir Singh if (get_paca()->in_mce < MAX_MCE_DEPTH)
65799ead78aSBalbir Singh mce_find_instr_ea_and_phys(regs, addr,
65899ead78aSBalbir Singh phys_addr);
659ba41e1e1SBalbir Singh }
660755309beSNicholas Piggin found = 1;
661631bc46cSNicholas Piggin }
662631bc46cSNicholas Piggin
663755309beSNicholas Piggin if (found)
664755309beSNicholas Piggin return handled;
665755309beSNicholas Piggin
666631bc46cSNicholas Piggin mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
66750dbabe0SMahesh Salgaonkar mce_err->error_class = MCE_ECLASS_UNKNOWN;
668cda6618dSMahesh Salgaonkar mce_err->severity = MCE_SEV_SEVERE;
669631bc46cSNicholas Piggin mce_err->initiator = MCE_INITIATOR_CPU;
670cda6618dSMahesh Salgaonkar mce_err->sync_error = true;
671755309beSNicholas Piggin
672755309beSNicholas Piggin return 0;
673631bc46cSNicholas Piggin }
674631bc46cSNicholas Piggin
mce_handle_ue_error(struct pt_regs * regs,struct mce_error_info * mce_err)675895e3dceSBalbir Singh static long mce_handle_ue_error(struct pt_regs *regs,
676895e3dceSBalbir Singh struct mce_error_info *mce_err)
677631bc46cSNicholas Piggin {
6780ce23826SNicholas Piggin if (mce_in_guest())
6790ce23826SNicholas Piggin return 0;
680895e3dceSBalbir Singh
681efbc4303SGanesh Goudar mce_common_process_ue(regs, mce_err);
682efbc4303SGanesh Goudar if (mce_err->ignore_event)
683895e3dceSBalbir Singh return 1;
684631bc46cSNicholas Piggin
685631bc46cSNicholas Piggin /*
686631bc46cSNicholas Piggin * On specific SCOM read via MMIO we may get a machine check
687631bc46cSNicholas Piggin * exception with SRR0 pointing inside opal. If that is the
688631bc46cSNicholas Piggin * case OPAL may have recovery address to re-read SCOM data in
689631bc46cSNicholas Piggin * different way and hence we can recover from this MC.
690631bc46cSNicholas Piggin */
691631bc46cSNicholas Piggin
692631bc46cSNicholas Piggin if (ppc_md.mce_check_early_recovery) {
693631bc46cSNicholas Piggin if (ppc_md.mce_check_early_recovery(regs))
6940ce23826SNicholas Piggin return 1;
695631bc46cSNicholas Piggin }
6960ce23826SNicholas Piggin
6970ce23826SNicholas Piggin return 0;
698631bc46cSNicholas Piggin }
699631bc46cSNicholas Piggin
mce_handle_error(struct pt_regs * regs,unsigned long srr1,const struct mce_derror_table dtable[],const struct mce_ierror_table itable[])700755309beSNicholas Piggin static long mce_handle_error(struct pt_regs *regs,
7013729e0ecSNicholas Piggin unsigned long srr1,
702755309beSNicholas Piggin const struct mce_derror_table dtable[],
703755309beSNicholas Piggin const struct mce_ierror_table itable[])
704e22a2274SMahesh Salgaonkar {
705755309beSNicholas Piggin struct mce_error_info mce_err = { 0 };
70675ecfb49SMahesh Salgaonkar uint64_t addr, phys_addr = ULONG_MAX;
707755309beSNicholas Piggin long handled;
708e22a2274SMahesh Salgaonkar
709755309beSNicholas Piggin if (SRR1_MC_LOADSTORE(srr1))
710ba41e1e1SBalbir Singh handled = mce_handle_derror(regs, dtable, &mce_err, &addr,
711ba41e1e1SBalbir Singh &phys_addr);
712755309beSNicholas Piggin else
7133729e0ecSNicholas Piggin handled = mce_handle_ierror(regs, srr1, itable, &mce_err, &addr,
71401eaac2bSBalbir Singh &phys_addr);
715e22a2274SMahesh Salgaonkar
716755309beSNicholas Piggin if (!handled && mce_err.error_type == MCE_ERROR_TYPE_UE)
717895e3dceSBalbir Singh handled = mce_handle_ue_error(regs, &mce_err);
718755309beSNicholas Piggin
719ba41e1e1SBalbir Singh save_mce_event(regs, handled, &mce_err, regs->nip, addr, phys_addr);
720755309beSNicholas Piggin
721755309beSNicholas Piggin return handled;
722e22a2274SMahesh Salgaonkar }
723e22a2274SMahesh Salgaonkar
__machine_check_early_realmode_p7(struct pt_regs * regs)724e22a2274SMahesh Salgaonkar long __machine_check_early_realmode_p7(struct pt_regs *regs)
725e22a2274SMahesh Salgaonkar {
726631bc46cSNicholas Piggin /* P7 DD1 leaves top bits of DSISR undefined */
727631bc46cSNicholas Piggin regs->dsisr &= 0x0000ffff;
728631bc46cSNicholas Piggin
7293729e0ecSNicholas Piggin return mce_handle_error(regs, regs->msr,
7303729e0ecSNicholas Piggin mce_p7_derror_table, mce_p7_ierror_table);
731ae744f34SMahesh Salgaonkar }
732ae744f34SMahesh Salgaonkar
__machine_check_early_realmode_p8(struct pt_regs * regs)733ae744f34SMahesh Salgaonkar long __machine_check_early_realmode_p8(struct pt_regs *regs)
734ae744f34SMahesh Salgaonkar {
7353729e0ecSNicholas Piggin return mce_handle_error(regs, regs->msr,
7363729e0ecSNicholas Piggin mce_p8_derror_table, mce_p8_ierror_table);
7377b9f71f9SNicholas Piggin }
7387b9f71f9SNicholas Piggin
__machine_check_early_realmode_p9(struct pt_regs * regs)7397b9f71f9SNicholas Piggin long __machine_check_early_realmode_p9(struct pt_regs *regs)
7407b9f71f9SNicholas Piggin {
7413729e0ecSNicholas Piggin unsigned long srr1 = regs->msr;
7423729e0ecSNicholas Piggin
743d8bd9f3fSMichael Neuling /*
744d8bd9f3fSMichael Neuling * On POWER9 DD2.1 and below, it's possible to get a machine check
745bca73f59SMichael Neuling * caused by a paste instruction where only DSISR bit 25 is set. This
746d8bd9f3fSMichael Neuling * will result in the MCE handler seeing an unknown event and the kernel
747d8bd9f3fSMichael Neuling * crashing. An MCE that occurs like this is spurious, so we don't need
748d8bd9f3fSMichael Neuling * to do anything in terms of servicing it. If there is something that
749d8bd9f3fSMichael Neuling * needs to be serviced, the CPU will raise the MCE again with the
750d8bd9f3fSMichael Neuling * correct DSISR so that it can be serviced properly. So detect this
751d8bd9f3fSMichael Neuling * case and mark it as handled.
752d8bd9f3fSMichael Neuling */
753bca73f59SMichael Neuling if (SRR1_MC_LOADSTORE(regs->msr) && regs->dsisr == 0x02000000)
754d8bd9f3fSMichael Neuling return 1;
755d8bd9f3fSMichael Neuling
7563729e0ecSNicholas Piggin /*
7573729e0ecSNicholas Piggin * Async machine check due to bad real address from store or foreign
7583729e0ecSNicholas Piggin * link time out comes with the load/store bit (PPC bit 42) set in
7593729e0ecSNicholas Piggin * SRR1, but the cause comes in SRR1 not DSISR. Clear bit 42 so we're
7603729e0ecSNicholas Piggin * directed to the ierror table so it will find the cause (which
7613729e0ecSNicholas Piggin * describes it correctly as a store error).
7623729e0ecSNicholas Piggin */
7633729e0ecSNicholas Piggin if (SRR1_MC_LOADSTORE(srr1) &&
7643729e0ecSNicholas Piggin ((srr1 & 0x081c0000) == 0x08140000 ||
7653729e0ecSNicholas Piggin (srr1 & 0x081c0000) == 0x08180000)) {
7663729e0ecSNicholas Piggin srr1 &= ~PPC_BIT(42);
7673729e0ecSNicholas Piggin }
7683729e0ecSNicholas Piggin
7693729e0ecSNicholas Piggin return mce_handle_error(regs, srr1,
7703729e0ecSNicholas Piggin mce_p9_derror_table, mce_p9_ierror_table);
7717b9f71f9SNicholas Piggin }
772201220bbSNicholas Piggin
__machine_check_early_realmode_p10(struct pt_regs * regs)773201220bbSNicholas Piggin long __machine_check_early_realmode_p10(struct pt_regs *regs)
774201220bbSNicholas Piggin {
7753729e0ecSNicholas Piggin unsigned long srr1 = regs->msr;
7763729e0ecSNicholas Piggin
7773729e0ecSNicholas Piggin /*
7783729e0ecSNicholas Piggin * Async machine check due to bad real address from store comes with
7793729e0ecSNicholas Piggin * the load/store bit (PPC bit 42) set in SRR1, but the cause comes in
7803729e0ecSNicholas Piggin * SRR1 not DSISR. Clear bit 42 so we're directed to the ierror table
7813729e0ecSNicholas Piggin * so it will find the cause (which describes it correctly as a store
7823729e0ecSNicholas Piggin * error).
7833729e0ecSNicholas Piggin */
7843729e0ecSNicholas Piggin if (SRR1_MC_LOADSTORE(srr1) &&
7853729e0ecSNicholas Piggin (srr1 & 0x081c0000) == 0x08140000) {
7863729e0ecSNicholas Piggin srr1 &= ~PPC_BIT(42);
7873729e0ecSNicholas Piggin }
7883729e0ecSNicholas Piggin
7893729e0ecSNicholas Piggin return mce_handle_error(regs, srr1,
7903729e0ecSNicholas Piggin mce_p10_derror_table, mce_p10_ierror_table);
791201220bbSNicholas Piggin }
792