mirror of
https://github.com/torvalds/linux.git
synced 2024-12-18 17:12:55 +00:00
55672ecfa2
Detect and recover from machine check when inside opal on a special scom load instructions. On specific SCOM read via MMIO we may get a machine check exception with SRR0 pointing inside opal. To recover from MC in this scenario, get a recovery instruction address and return to it from MC. OPAL will export the machine check recoverable ranges through device tree node mcheck-recoverable-ranges under ibm,opal: # hexdump /proc/device-tree/ibm,opal/mcheck-recoverable-ranges 0000000 0000 0000 3000 2804 0000 000c 0000 0000 0000010 3000 2814 0000 0000 3000 27f0 0000 000c 0000020 0000 0000 3000 2814 xxxx xxxx xxxx xxxx 0000030 llll llll yyyy yyyy yyyy yyyy ... ... # where: xxxx xxxx xxxx xxxx = Starting instruction address llll llll = Length of the address range. yyyy yyyy yyyy yyyy = recovery address Each recoverable address range entry is (start address, len, recovery address), 2 cells each for start and recovery address, 1 cell for len, totalling 5 cells per entry. During kernel boot time, build up the recovery table with the list of recovery ranges from device-tree node which will be used during machine check exception to recover from MMIO SCOM UE. Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
199 lines
5.8 KiB
C
199 lines
5.8 KiB
C
/*
|
|
* Machine check exception header file.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* Copyright 2013 IBM Corporation
|
|
* Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
|
|
*/
|
|
|
|
#ifndef __ASM_PPC64_MCE_H__
|
|
#define __ASM_PPC64_MCE_H__
|
|
|
|
#include <linux/bitops.h>
|
|
|
|
/*
|
|
* Machine Check bits on power7 and power8
|
|
*/
|
|
#define P7_SRR1_MC_LOADSTORE(srr1) ((srr1) & PPC_BIT(42)) /* P8 too */
|
|
|
|
/* SRR1 bits for machine check (On Power7 and Power8) */
|
|
#define P7_SRR1_MC_IFETCH(srr1) ((srr1) & PPC_BITMASK(43, 45)) /* P8 too */
|
|
|
|
#define P7_SRR1_MC_IFETCH_UE (0x1 << PPC_BITLSHIFT(45)) /* P8 too */
|
|
#define P7_SRR1_MC_IFETCH_SLB_PARITY (0x2 << PPC_BITLSHIFT(45)) /* P8 too */
|
|
#define P7_SRR1_MC_IFETCH_SLB_MULTIHIT (0x3 << PPC_BITLSHIFT(45)) /* P8 too */
|
|
#define P7_SRR1_MC_IFETCH_SLB_BOTH (0x4 << PPC_BITLSHIFT(45))
|
|
#define P7_SRR1_MC_IFETCH_TLB_MULTIHIT (0x5 << PPC_BITLSHIFT(45)) /* P8 too */
|
|
#define P7_SRR1_MC_IFETCH_UE_TLB_RELOAD (0x6 << PPC_BITLSHIFT(45)) /* P8 too */
|
|
#define P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL (0x7 << PPC_BITLSHIFT(45))
|
|
|
|
/* SRR1 bits for machine check (On Power8) */
|
|
#define P8_SRR1_MC_IFETCH_ERAT_MULTIHIT (0x4 << PPC_BITLSHIFT(45))
|
|
|
|
/* DSISR bits for machine check (On Power7 and Power8) */
|
|
#define P7_DSISR_MC_UE (PPC_BIT(48)) /* P8 too */
|
|
#define P7_DSISR_MC_UE_TABLEWALK (PPC_BIT(49)) /* P8 too */
|
|
#define P7_DSISR_MC_ERAT_MULTIHIT (PPC_BIT(52)) /* P8 too */
|
|
#define P7_DSISR_MC_TLB_MULTIHIT_MFTLB (PPC_BIT(53)) /* P8 too */
|
|
#define P7_DSISR_MC_SLB_PARITY_MFSLB (PPC_BIT(55)) /* P8 too */
|
|
#define P7_DSISR_MC_SLB_MULTIHIT (PPC_BIT(56)) /* P8 too */
|
|
#define P7_DSISR_MC_SLB_MULTIHIT_PARITY (PPC_BIT(57)) /* P8 too */
|
|
|
|
/*
|
|
* DSISR bits for machine check (Power8) in addition to above.
|
|
* Secondary DERAT Multihit
|
|
*/
|
|
#define P8_DSISR_MC_ERAT_MULTIHIT_SEC (PPC_BIT(54))
|
|
|
|
/* SLB error bits */
|
|
#define P7_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_ERAT_MULTIHIT | \
|
|
P7_DSISR_MC_SLB_PARITY_MFSLB | \
|
|
P7_DSISR_MC_SLB_MULTIHIT | \
|
|
P7_DSISR_MC_SLB_MULTIHIT_PARITY)
|
|
|
|
#define P8_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_SLB_ERRORS | \
|
|
P8_DSISR_MC_ERAT_MULTIHIT_SEC)
|
|
enum MCE_Version {
|
|
MCE_V1 = 1,
|
|
};
|
|
|
|
enum MCE_Severity {
|
|
MCE_SEV_NO_ERROR = 0,
|
|
MCE_SEV_WARNING = 1,
|
|
MCE_SEV_ERROR_SYNC = 2,
|
|
MCE_SEV_FATAL = 3,
|
|
};
|
|
|
|
enum MCE_Disposition {
|
|
MCE_DISPOSITION_RECOVERED = 0,
|
|
MCE_DISPOSITION_NOT_RECOVERED = 1,
|
|
};
|
|
|
|
enum MCE_Initiator {
|
|
MCE_INITIATOR_UNKNOWN = 0,
|
|
MCE_INITIATOR_CPU = 1,
|
|
};
|
|
|
|
enum MCE_ErrorType {
|
|
MCE_ERROR_TYPE_UNKNOWN = 0,
|
|
MCE_ERROR_TYPE_UE = 1,
|
|
MCE_ERROR_TYPE_SLB = 2,
|
|
MCE_ERROR_TYPE_ERAT = 3,
|
|
MCE_ERROR_TYPE_TLB = 4,
|
|
};
|
|
|
|
enum MCE_UeErrorType {
|
|
MCE_UE_ERROR_INDETERMINATE = 0,
|
|
MCE_UE_ERROR_IFETCH = 1,
|
|
MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH = 2,
|
|
MCE_UE_ERROR_LOAD_STORE = 3,
|
|
MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE = 4,
|
|
};
|
|
|
|
enum MCE_SlbErrorType {
|
|
MCE_SLB_ERROR_INDETERMINATE = 0,
|
|
MCE_SLB_ERROR_PARITY = 1,
|
|
MCE_SLB_ERROR_MULTIHIT = 2,
|
|
};
|
|
|
|
enum MCE_EratErrorType {
|
|
MCE_ERAT_ERROR_INDETERMINATE = 0,
|
|
MCE_ERAT_ERROR_PARITY = 1,
|
|
MCE_ERAT_ERROR_MULTIHIT = 2,
|
|
};
|
|
|
|
enum MCE_TlbErrorType {
|
|
MCE_TLB_ERROR_INDETERMINATE = 0,
|
|
MCE_TLB_ERROR_PARITY = 1,
|
|
MCE_TLB_ERROR_MULTIHIT = 2,
|
|
};
|
|
|
|
struct machine_check_event {
|
|
enum MCE_Version version:8; /* 0x00 */
|
|
uint8_t in_use; /* 0x01 */
|
|
enum MCE_Severity severity:8; /* 0x02 */
|
|
enum MCE_Initiator initiator:8; /* 0x03 */
|
|
enum MCE_ErrorType error_type:8; /* 0x04 */
|
|
enum MCE_Disposition disposition:8; /* 0x05 */
|
|
uint8_t reserved_1[2]; /* 0x06 */
|
|
uint64_t gpr3; /* 0x08 */
|
|
uint64_t srr0; /* 0x10 */
|
|
uint64_t srr1; /* 0x18 */
|
|
union { /* 0x20 */
|
|
struct {
|
|
enum MCE_UeErrorType ue_error_type:8;
|
|
uint8_t effective_address_provided;
|
|
uint8_t physical_address_provided;
|
|
uint8_t reserved_1[5];
|
|
uint64_t effective_address;
|
|
uint64_t physical_address;
|
|
uint8_t reserved_2[8];
|
|
} ue_error;
|
|
|
|
struct {
|
|
enum MCE_SlbErrorType slb_error_type:8;
|
|
uint8_t effective_address_provided;
|
|
uint8_t reserved_1[6];
|
|
uint64_t effective_address;
|
|
uint8_t reserved_2[16];
|
|
} slb_error;
|
|
|
|
struct {
|
|
enum MCE_EratErrorType erat_error_type:8;
|
|
uint8_t effective_address_provided;
|
|
uint8_t reserved_1[6];
|
|
uint64_t effective_address;
|
|
uint8_t reserved_2[16];
|
|
} erat_error;
|
|
|
|
struct {
|
|
enum MCE_TlbErrorType tlb_error_type:8;
|
|
uint8_t effective_address_provided;
|
|
uint8_t reserved_1[6];
|
|
uint64_t effective_address;
|
|
uint8_t reserved_2[16];
|
|
} tlb_error;
|
|
} u;
|
|
};
|
|
|
|
struct mce_error_info {
|
|
enum MCE_ErrorType error_type:8;
|
|
union {
|
|
enum MCE_UeErrorType ue_error_type:8;
|
|
enum MCE_SlbErrorType slb_error_type:8;
|
|
enum MCE_EratErrorType erat_error_type:8;
|
|
enum MCE_TlbErrorType tlb_error_type:8;
|
|
} u;
|
|
uint8_t reserved[2];
|
|
};
|
|
|
|
#define MAX_MC_EVT 100
|
|
|
|
/* Release flags for get_mce_event() */
|
|
#define MCE_EVENT_RELEASE true
|
|
#define MCE_EVENT_DONTRELEASE false
|
|
|
|
extern void save_mce_event(struct pt_regs *regs, long handled,
|
|
struct mce_error_info *mce_err, uint64_t nip,
|
|
uint64_t addr);
|
|
extern int get_mce_event(struct machine_check_event *mce, bool release);
|
|
extern void release_mce_event(void);
|
|
extern void machine_check_queue_event(void);
|
|
extern void machine_check_print_event_info(struct machine_check_event *evt);
|
|
extern uint64_t get_mce_fault_addr(struct machine_check_event *evt);
|
|
|
|
#endif /* __ASM_PPC64_MCE_H__ */
|