mce_power.c (9b031c86506cef9acae45e61339fcf9deaabb793) mce_power.c (201220bb0e8cbc163ec7f550b3b7b3da46eb5877)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Machine check exception handling CPU-side for power7 and power8
4 *
5 * Copyright 2013 IBM Corporation
6 * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
7 */
8
9#undef DEBUG
10#define pr_fmt(fmt) "mce_power: " fmt
11
12#include <linux/types.h>
13#include <linux/ptrace.h>
14#include <linux/extable.h>
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Machine check exception handling CPU-side for power7 and power8
4 *
5 * Copyright 2013 IBM Corporation
6 * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
7 */
8
9#undef DEBUG
10#define pr_fmt(fmt) "mce_power: " fmt
11
12#include <linux/types.h>
13#include <linux/ptrace.h>
14#include <linux/extable.h>
15#include <linux/pgtable.h>
15#include <asm/mmu.h>
16#include <asm/mce.h>
17#include <asm/machdep.h>
16#include <asm/mmu.h>
17#include <asm/mce.h>
18#include <asm/machdep.h>
18#include <asm/pgtable.h>
19#include <asm/pte-walk.h>
20#include <asm/sstep.h>
21#include <asm/exception-64s.h>
22#include <asm/extable.h>
19#include <asm/pte-walk.h>
20#include <asm/sstep.h>
21#include <asm/exception-64s.h>
22#include <asm/extable.h>
23#include <asm/inst.h>
23
24/*
25 * Convert an address related to an mm to a PFN. NOTE: we are in real
26 * mode, we could potentially race with page table updates.
27 */
28unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
29{
24
25/*
26 * Convert an address related to an mm to a PFN. NOTE: we are in real
27 * mode, we could potentially race with page table updates.
28 */
29unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
30{
30 pte_t *ptep;
31 pte_t *ptep, pte;
31 unsigned int shift;
32 unsigned long pfn, flags;
33 struct mm_struct *mm;
34
35 if (user_mode(regs))
36 mm = current->mm;
37 else
38 mm = &init_mm;
39
40 local_irq_save(flags);
41 ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift);
32 unsigned int shift;
33 unsigned long pfn, flags;
34 struct mm_struct *mm;
35
36 if (user_mode(regs))
37 mm = current->mm;
38 else
39 mm = &init_mm;
40
41 local_irq_save(flags);
42 ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift);
43 if (!ptep) {
44 pfn = ULONG_MAX;
45 goto out;
46 }
47 pte = READ_ONCE(*ptep);
42
48
43 if (!ptep || pte_special(*ptep)) {
49 if (!pte_present(pte) || pte_special(pte)) {
44 pfn = ULONG_MAX;
45 goto out;
46 }
47
48 if (shift <= PAGE_SHIFT)
50 pfn = ULONG_MAX;
51 goto out;
52 }
53
54 if (shift <= PAGE_SHIFT)
49 pfn = pte_pfn(*ptep);
55 pfn = pte_pfn(pte);
50 else {
51 unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
56 else {
57 unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
52 pfn = pte_pfn(__pte(pte_val(*ptep) | (addr & rpnmask)));
58 pfn = pte_pfn(__pte(pte_val(pte) | (addr & rpnmask)));
53 }
59 }
54
55out:
56 local_irq_restore(flags);
57 return pfn;
58}
59
60/* flush SLBs and reload */
61#ifdef CONFIG_PPC_BOOK3S_64
62void flush_and_reload_slb(void)

--- 170 unchanged lines hidden (view full) ---

233{ 0x00000000081c0000, 0x0000000008180000, false,
234 MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_STORE_TIMEOUT,
235 MCE_INITIATOR_CPU, MCE_SEV_FATAL, false }, /* ASYNC is fatal */
236{ 0x00000000081c0000, 0x00000000081c0000, true, MCE_ECLASS_HARDWARE,
237 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
238 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
239{ 0, 0, 0, 0, 0, 0, 0 } };
240
60out:
61 local_irq_restore(flags);
62 return pfn;
63}
64
65/* flush SLBs and reload */
66#ifdef CONFIG_PPC_BOOK3S_64
67void flush_and_reload_slb(void)

--- 170 unchanged lines hidden (view full) ---

238{ 0x00000000081c0000, 0x0000000008180000, false,
239 MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_STORE_TIMEOUT,
240 MCE_INITIATOR_CPU, MCE_SEV_FATAL, false }, /* ASYNC is fatal */
241{ 0x00000000081c0000, 0x00000000081c0000, true, MCE_ECLASS_HARDWARE,
242 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
243 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
244{ 0, 0, 0, 0, 0, 0, 0 } };
245
246static const struct mce_ierror_table mce_p10_ierror_table[] = {
247{ 0x00000000081c0000, 0x0000000000040000, true,
248 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
249 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
250{ 0x00000000081c0000, 0x0000000000080000, true,
251 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
252 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
253{ 0x00000000081c0000, 0x00000000000c0000, true,
254 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
255 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
256{ 0x00000000081c0000, 0x0000000000100000, true,
257 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
258 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
259{ 0x00000000081c0000, 0x0000000000140000, true,
260 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
261 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
262{ 0x00000000081c0000, 0x0000000000180000, true,
263 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
264 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
265{ 0x00000000081c0000, 0x00000000001c0000, true,
266 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH_FOREIGN, MCE_ECLASS_SOFTWARE,
267 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
268{ 0x00000000081c0000, 0x0000000008080000, true,
269 MCE_ERROR_TYPE_USER,MCE_USER_ERROR_SCV, MCE_ECLASS_SOFTWARE,
270 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
271{ 0x00000000081c0000, 0x00000000080c0000, true,
272 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH, MCE_ECLASS_SOFTWARE,
273 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
274{ 0x00000000081c0000, 0x0000000008100000, true,
275 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_SOFTWARE,
276 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
277{ 0x00000000081c0000, 0x0000000008140000, false,
278 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_STORE, MCE_ECLASS_HARDWARE,
279 MCE_INITIATOR_CPU, MCE_SEV_FATAL, false }, /* ASYNC is fatal */
280{ 0x00000000081c0000, 0x00000000081c0000, true, MCE_ECLASS_HARDWARE,
281 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
282 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
283{ 0, 0, 0, 0, 0, 0, 0 } };
284
241struct mce_derror_table {
242 unsigned long dsisr_value;
243 bool dar_valid; /* dar is a valid indicator of faulting address */
244 unsigned int error_type;
245 unsigned int error_subtype;
246 unsigned int error_class;
247 unsigned int initiator;
248 unsigned int severity;

--- 102 unchanged lines hidden (view full) ---

351 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
352 MCE_ECLASS_HARDWARE,
353 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
354{ 0x00000008, false,
355 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN, MCE_ECLASS_HARDWARE,
356 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
357{ 0, false, 0, 0, 0, 0, 0 } };
358
285struct mce_derror_table {
286 unsigned long dsisr_value;
287 bool dar_valid; /* dar is a valid indicator of faulting address */
288 unsigned int error_type;
289 unsigned int error_subtype;
290 unsigned int error_class;
291 unsigned int initiator;
292 unsigned int severity;

--- 102 unchanged lines hidden (view full) ---

395 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
396 MCE_ECLASS_HARDWARE,
397 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
398{ 0x00000008, false,
399 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN, MCE_ECLASS_HARDWARE,
400 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
401{ 0, false, 0, 0, 0, 0, 0 } };
402
403static const struct mce_derror_table mce_p10_derror_table[] = {
404{ 0x00008000, false,
405 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
406 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
407{ 0x00004000, true,
408 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
409 MCE_ECLASS_HARDWARE,
410 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
411{ 0x00000800, true,
412 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
413 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
414{ 0x00000400, true,
415 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
416 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
417{ 0x00000200, false,
418 MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE, MCE_ECLASS_SOFTWARE,
419 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
420{ 0x00000080, true,
421 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, /* Before PARITY */
422 MCE_ECLASS_SOFT_INDETERMINATE,
423 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
424{ 0x00000100, true,
425 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
426 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
427{ 0x00000040, true,
428 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD, MCE_ECLASS_HARDWARE,
429 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
430{ 0x00000020, false,
431 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
432 MCE_ECLASS_HARDWARE,
433 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
434{ 0x00000010, false,
435 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
436 MCE_ECLASS_HARDWARE,
437 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
438{ 0x00000008, false,
439 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN, MCE_ECLASS_HARDWARE,
440 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
441{ 0, false, 0, 0, 0, 0, 0 } };
442
359static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr,
360 uint64_t *phys_addr)
361{
362 /*
363 * Carefully look at the NIP to determine
364 * the instruction to analyse. Reading the NIP
365 * in real-mode is tricky and can lead to recursive
366 * faults
367 */
443static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr,
444 uint64_t *phys_addr)
445{
446 /*
447 * Carefully look at the NIP to determine
448 * the instruction to analyse. Reading the NIP
449 * in real-mode is tricky and can lead to recursive
450 * faults
451 */
368 int instr;
452 struct ppc_inst instr;
369 unsigned long pfn, instr_addr;
370 struct instruction_op op;
371 struct pt_regs tmp = *regs;
372
373 pfn = addr_to_pfn(regs, regs->nip);
374 if (pfn != ULONG_MAX) {
375 instr_addr = (pfn << PAGE_SHIFT) + (regs->nip & ~PAGE_MASK);
453 unsigned long pfn, instr_addr;
454 struct instruction_op op;
455 struct pt_regs tmp = *regs;
456
457 pfn = addr_to_pfn(regs, regs->nip);
458 if (pfn != ULONG_MAX) {
459 instr_addr = (pfn << PAGE_SHIFT) + (regs->nip & ~PAGE_MASK);
376 instr = *(unsigned int *)(instr_addr);
460 instr = ppc_inst_read((struct ppc_inst *)instr_addr);
377 if (!analyse_instr(&op, &tmp, instr)) {
378 pfn = addr_to_pfn(regs, op.ea);
379 *addr = op.ea;
380 *phys_addr = (pfn << PAGE_SHIFT);
381 return 0;
382 }
383 /*
384 * analyse_instr() might fail if the instruction

--- 262 unchanged lines hidden (view full) ---

647 * correct DSISR so that it can be serviced properly. So detect this
648 * case and mark it as handled.
649 */
650 if (SRR1_MC_LOADSTORE(regs->msr) && regs->dsisr == 0x02000000)
651 return 1;
652
653 return mce_handle_error(regs, mce_p9_derror_table, mce_p9_ierror_table);
654}
461 if (!analyse_instr(&op, &tmp, instr)) {
462 pfn = addr_to_pfn(regs, op.ea);
463 *addr = op.ea;
464 *phys_addr = (pfn << PAGE_SHIFT);
465 return 0;
466 }
467 /*
468 * analyse_instr() might fail if the instruction

--- 262 unchanged lines hidden (view full) ---

731 * correct DSISR so that it can be serviced properly. So detect this
732 * case and mark it as handled.
733 */
734 if (SRR1_MC_LOADSTORE(regs->msr) && regs->dsisr == 0x02000000)
735 return 1;
736
737 return mce_handle_error(regs, mce_p9_derror_table, mce_p9_ierror_table);
738}
739
740long __machine_check_early_realmode_p10(struct pt_regs *regs)
741{
742 return mce_handle_error(regs, mce_p10_derror_table, mce_p10_ierror_table);
743}