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} |
|