[RFC,2/2] opal: Add support to handle machine check interrupt for Power9.

Submitted by Mahesh Salgaonkar on Feb. 21, 2017, 1:47 a.m.

Details

Message ID 148764161505.19040.17410002247968356116.stgit@jupiter.in.ibm.com
State New
Headers show

Commit Message

Mahesh Salgaonkar Feb. 21, 2017, 1:47 a.m.
From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>

Machine check handler in OPAL for Power9 and above. From power9 and above
linux will depend on OPAL handler to extract the MCE error reasons.

This is a RFC implementation that proposes an approach where linux would
still take an MCE interrupt but it would make opal call to handle all
chip specific processing to extract the error reason. OPAL would then
present a high level information about MCE error that will be enough
for linux to take corrective actions.

TODO:
- Add a check for P9 chip and return OPAL_UNSUPPORTED to non P9 chip.

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
 core/Makefile.inc  |    2 
 core/exceptions.c  |    1 
 core/mce.c         |  376 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/opal-api.h |  179 +++++++++++++++++++++++++
 4 files changed, 555 insertions(+), 3 deletions(-)
 create mode 100644 core/mce.c

Patch hide | download patch | download mbox

diff --git a/core/Makefile.inc b/core/Makefile.inc
index ae3c297..f7f464e 100644
--- a/core/Makefile.inc
+++ b/core/Makefile.inc
@@ -8,7 +8,7 @@  CORE_OBJS += pci-opal.o fast-reboot.o device.o exceptions.o trace.o affinity.o
 CORE_OBJS += vpd.o hostservices.o platform.o nvram.o nvram-format.o hmi.o
 CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o pool.o errorlog.o
 CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o ipmi-opal.o
-CORE_OBJS += flash-subpartition.o bitmap.o buddy.o
+CORE_OBJS += flash-subpartition.o bitmap.o buddy.o mce.o
 
 ifeq ($(SKIBOOT_GCOV),1)
 CORE_OBJS += gcov-profiling.o
diff --git a/core/exceptions.c b/core/exceptions.c
index c4acf85..5997d49 100644
--- a/core/exceptions.c
+++ b/core/exceptions.c
@@ -56,4 +56,3 @@  static int64_t opal_register_exc_handler(uint64_t opal_exception __unused,
 	return OPAL_UNSUPPORTED;
 }
 opal_call(OPAL_REGISTER_OPAL_EXCEPTION_HANDLER, opal_register_exc_handler, 3);
-
diff --git a/core/mce.c b/core/mce.c
new file mode 100644
index 0000000..8f7548a
--- /dev/null
+++ b/core/mce.c
@@ -0,0 +1,376 @@ 
+/* Copyright 2017-2018 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <skiboot.h>
+#include <stack.h>
+#include <opal-api.h>
+#include <processor.h>
+#include <cpu.h>
+
+/*
+ * Machine Check bits on power9
+ */
+#define P9_SRR1_MC_LOADSTORE(srr1)	((srr1) & PPC_BIT(42)) /* P9 */
+
+/*
+ * SRR1 bits for machine check (On Power9)
+ *
+ * I-Side errors are reported through SRR1 bits 36,43:45
+ */
+#define P9_SRR1_MC_IFETCH(srr1)		\
+		((srr1) & (PPC_BIT(36) | PPC_BITMASK(43, 45))) /* P9 */
+
+#define P9_SRR1_MC_IFETCH_UE		(0x1 << PPC_BITLSHIFT(45)) /* P9 */
+#define P9_SRR1_MC_IFETCH_SLB_PARITY	(0x2 << PPC_BITLSHIFT(45)) /* P9 */
+#define P9_SRR1_MC_IFETCH_SLB_MULTIHIT	(0x3 << PPC_BITLSHIFT(45)) /* P9 */
+#define P9_SRR1_MC_IFETCH_ERAT_MULTIHIT	(0x4 << PPC_BITLSHIFT(45)) /* P9 */
+#define P9_SRR1_MC_IFETCH_TLB_MULTIHIT	(0x5 << PPC_BITLSHIFT(45)) /* P9 */
+#define P9_SRR1_MC_IFETCH_UE_TLB_RELOAD	(0x6 << PPC_BITLSHIFT(45)) /* P9 */
+#define P9_SRR1_MC_IFETCH_FSPACE_ADDR	(0x7 << PPC_BITLSHIFT(45)) /* P9 */
+#define P9_SRR1_MC_IFETCH_NEST_ABRT	(PPC_BIT(36))              /* P9 */
+#define P9_SRR1_MC_IFETCH_NEST_ABRT_TABLEWALK		\
+			((PPC_BIT(36)) | (0x1 << PPC_BITLSHIFT(45))) /* P9 */
+#define P9_SRR1_MC_IFETCH_REAL_ADDR			\
+			((PPC_BIT(36)) | (0x3 << PPC_BITLSHIFT(45))) /* P9 */
+#define P9_SRR1_MC_IFETCH_REAL_ADDR_TABLEWALK		\
+			((PPC_BIT(36)) | (0x4 << PPC_BITLSHIFT(45))) /* P9 */
+#define P9_SRR1_MC_IFETCH_HOST_REAL_ADDR		\
+			((PPC_BIT(36)) | (0x7 << PPC_BITLSHIFT(45))) /* P9 */
+
+/* In the Power9 core, there are two asynchronous machine check interrupts.
+ * One is take when store instruction has an out of range real address
+ * associated with it. This is in general a programming error. The second
+ * asynchronous case is when a store is being performed and a foreign link
+ * times out.
+ * Both machine checks will set following bits in SRR1 to identify the
+ * cause:
+ *	SRR1 bit [42]=1, [36]=1 and [43]=1 and 44:45 = 01 0r 10
+ */
+#define P9_SRR1_ASYNC_MC	(PPC_BIT(36) | PPC_BITMASK(42, 43))
+#define P9_SRR1_ASYNC_MC_MASK	(PPC_BIT(36) | PPC_BITMASK(42, 43))
+
+#define P9_SRR1_ASYNC_REAL_ADDR_STORE			\
+			((PPC_BIT(36)) | (0x5 << PPC_BITLSHIFT(45))) /* P9 */
+#define P9_SRR1_ASYNC_NEST_ABRT_STORE			\
+			((PPC_BIT(36)) | (0x6 << PPC_BITLSHIFT(45))) /* P9 */
+
+/* DSISR bits for machine check On Power9. */
+#define P9_DSISR_MC_UE				(PPC_BIT(48))	/* P9 */
+#define P9_DSISR_MC_UE_TABLEWALK		(PPC_BIT(49))	/* P9 */
+#define P9_DSISR_MC_NEST_ABRT_LOAD		(PPC_BIT(50))	/* P9 */
+#define P9_DSISR_MC_NEST_ABRT_TABLEWALK		(PPC_BIT(51))	/* P9 */
+#define P9_DSISR_MC_ERAT_MULTIHIT		(PPC_BIT(52))	/* P9 */
+#define P9_DSISR_MC_TLB_MULTIHIT_MFTLB		(PPC_BIT(53))	/* P9 */
+#define P9_DSISR_MC_TLBIEL_PROG_ERROR		(PPC_BIT(54))	/* P9 */
+#define P9_DSISR_MC_SLB_PARITY_MFSLB		(PPC_BIT(55))	/* P9 */
+#define P9_DSISR_MC_SLB_MULTIHIT		(PPC_BIT(56))	/* P9 */
+#define P9_DSISR_MC_BAD_REAL_ADDR_LOAD		(PPC_BIT(57))	/* P9 */
+#define P9_DSISR_MC_BAD_REAL_ADDR_TABLEWALK	(PPC_BIT(58))	/* P9 */
+#define P9_DSISR_MC_HOST_TO_FSPACE_TRANS	(PPC_BIT(59))	/* P9 */
+#define P9_DSISR_MC_HOST_TO_FSPACE_LOAD_STORE	(PPC_BIT(60))	/* P9 */
+
+/* P9 SLB error bits */
+#define P9_DSISR_MC_SLB_ERRORS		(P9_DSISR_MC_ERAT_MULTIHIT |	\
+					 P9_DSISR_MC_SLB_PARITY_MFSLB | \
+					 P9_DSISR_MC_SLB_MULTIHIT)
+
+/* P9 TLB error bits */
+#define P9_DSISR_MC_TLB_ERRORS		(P9_DSISR_MC_TLB_MULTIHIT_MFTLB | \
+					 P9_DSISR_MC_TLBIEL_PROG_ERROR)
+
+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;
+		enum MCE_NestErrorType nest_error_type:8;
+		enum MCE_CrespErrorType cresp_error_type:8;
+		enum MCE_FspaceErrorType fspace_error_type:8;
+		enum MCE_FspaceErrorType async_error_type:8;
+	} u;
+	uint8_t		reserved[2];
+};
+
+struct mce_reason_regs {
+	uint64_t	srr0;
+	uint64_t	srr1;
+	uint64_t	dar;
+	uint64_t	dsisr;
+};
+
+static void mce_get_ierror_p9(struct mce_error_info *mce_err, uint64_t srr1)
+{
+	switch (P9_SRR1_MC_IFETCH(srr1)) {
+	case P9_SRR1_MC_IFETCH_SLB_PARITY:
+		mce_err->error_type = MCE_ERROR_TYPE_SLB;
+		mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY;
+		break;
+	case P9_SRR1_MC_IFETCH_SLB_MULTIHIT:
+		mce_err->error_type = MCE_ERROR_TYPE_SLB;
+		mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT;
+		break;
+	case P9_SRR1_MC_IFETCH_ERAT_MULTIHIT:
+		mce_err->error_type = MCE_ERROR_TYPE_ERAT;
+		mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
+		break;
+	case P9_SRR1_MC_IFETCH_TLB_MULTIHIT:
+		mce_err->error_type = MCE_ERROR_TYPE_TLB;
+		mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT;
+		break;
+	case P9_SRR1_MC_IFETCH_UE:
+		mce_err->error_type = MCE_ERROR_TYPE_UE;
+		mce_err->u.ue_error_type = MCE_UE_ERROR_IFETCH;
+		break;
+	case P9_SRR1_MC_IFETCH_UE_TLB_RELOAD:
+		mce_err->error_type = MCE_ERROR_TYPE_UE;
+		mce_err->u.ue_error_type =
+				MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH;
+		break;
+	case P9_SRR1_MC_IFETCH_FSPACE_ADDR:
+		mce_err->error_type = MCE_ERROR_TYPE_FSPACE;
+		mce_err->u.fspace_error_type = MCE_FSPACE_ERROR_IFETCH;
+		break;
+	case P9_SRR1_MC_IFETCH_NEST_ABRT:
+		mce_err->error_type = MCE_ERROR_TYPE_NEST;
+		mce_err->u.nest_error_type = MCE_NEST_ERROR_ABRT_IFETCH;
+		break;
+	case P9_SRR1_MC_IFETCH_NEST_ABRT_TABLEWALK:
+		mce_err->error_type = MCE_ERROR_TYPE_NEST;
+		mce_err->u.nest_error_type =
+				MCE_NEST_ERROR_ABRT_IFETCH_TABLEWALK;
+		break;
+	case P9_SRR1_MC_IFETCH_REAL_ADDR:
+		mce_err->error_type = MCE_ERROR_TYPE_CRESP;
+		mce_err->u.cresp_error_type =
+				MCE_CRESP_ERROR_BAD_RADDR_IFETCH;
+		break;
+	case P9_SRR1_MC_IFETCH_REAL_ADDR_TABLEWALK:
+		mce_err->error_type = MCE_ERROR_TYPE_CRESP;
+		mce_err->u.cresp_error_type =
+				MCE_CRESP_ERROR_BAD_RADDR_IFETCH_TABLEWALK;
+		break;
+	case P9_SRR1_MC_IFETCH_HOST_REAL_ADDR:
+		mce_err->error_type = MCE_ERROR_TYPE_FSPACE;
+		mce_err->u.fspace_error_type =
+					MCE_FSPACE_ERROR_IFETCH_TABLEWALK;
+		break;
+	}
+}
+
+static void mce_get_derror_p9(struct mce_error_info *mce_err, uint64_t dsisr)
+{
+	if (dsisr & P9_DSISR_MC_UE) {
+		mce_err->error_type = MCE_ERROR_TYPE_UE;
+		mce_err->u.ue_error_type = MCE_UE_ERROR_LOAD_STORE;
+	} else if (dsisr & P9_DSISR_MC_UE_TABLEWALK) {
+		mce_err->error_type = MCE_ERROR_TYPE_UE;
+		mce_err->u.ue_error_type =
+				MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE;
+	} else if (dsisr & P9_DSISR_MC_NEST_ABRT_LOAD) {
+		mce_err->error_type = MCE_ERROR_TYPE_NEST;
+		mce_err->u.nest_error_type = MCE_NEST_ERROR_ABRT_LOAD;
+	} else if (dsisr & P9_DSISR_MC_NEST_ABRT_TABLEWALK) {
+		mce_err->error_type = MCE_ERROR_TYPE_NEST;
+		mce_err->u.nest_error_type =
+				MCE_NEST_ERROR_ABRT_LOAD_TABLEWALK;
+	} else if (dsisr & P9_DSISR_MC_ERAT_MULTIHIT) {
+		mce_err->error_type = MCE_ERROR_TYPE_ERAT;
+		mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
+	} else if (dsisr & P9_DSISR_MC_TLB_MULTIHIT_MFTLB) {
+		mce_err->error_type = MCE_ERROR_TYPE_TLB;
+		mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT;
+	} else if (dsisr & P9_DSISR_MC_TLBIEL_PROG_ERROR) {
+		mce_err->error_type = MCE_ERROR_TYPE_TLB;
+		mce_err->u.tlb_error_type = MCE_TLB_ERROR_TLBIEL_PROG_ERROR;
+	} else if (dsisr & P9_DSISR_MC_SLB_PARITY_MFSLB) {
+		mce_err->error_type = MCE_ERROR_TYPE_SLB;
+		mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY;
+	} else if (dsisr & P9_DSISR_MC_SLB_MULTIHIT) {
+		mce_err->error_type = MCE_ERROR_TYPE_SLB;
+		mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT;
+	} else if (dsisr & P9_DSISR_MC_BAD_REAL_ADDR_LOAD) {
+		mce_err->error_type = MCE_ERROR_TYPE_CRESP;
+		mce_err->u.cresp_error_type = MCE_CRESP_ERROR_BAD_RADDR_LOAD;
+	} else if (dsisr & P9_DSISR_MC_BAD_REAL_ADDR_TABLEWALK) {
+		mce_err->error_type = MCE_ERROR_TYPE_CRESP;
+		mce_err->u.cresp_error_type =
+				MCE_CRESP_ERROR_BAD_RADDR_LOAD_TABLEWALK;
+	} else if (dsisr & P9_DSISR_MC_HOST_TO_FSPACE_TRANS) {
+		mce_err->error_type = MCE_ERROR_TYPE_FSPACE;
+		mce_err->u.fspace_error_type =
+				MCE_FSPACE_ERROR_RADDR_TRANSLATION;
+	} else if (dsisr & P9_DSISR_MC_HOST_TO_FSPACE_LOAD_STORE) {
+		mce_err->error_type = MCE_ERROR_TYPE_FSPACE;
+		mce_err->u.fspace_error_type =
+				MCE_FSPACE_ERROR_RADDR_LOAD;
+	}
+}
+
+static void mce_get_async_err_p9(struct mce_error_info *mce_err, uint64_t srr1)
+{
+	switch (P9_SRR1_MC_IFETCH(srr1)) {
+	case P9_SRR1_ASYNC_REAL_ADDR_STORE:
+		mce_err->error_type = MCE_ERROR_TYPE_ASYNC;
+		mce_err->u.async_error_type = MCE_ASYNC_ERROR_REAL_ADDR_STORE;
+		break;
+	case P9_SRR1_ASYNC_NEST_ABRT_STORE:
+		mce_err->error_type = MCE_ERROR_TYPE_ASYNC;
+		mce_err->u.async_error_type = MCE_ASYNC_ERROR_NEST_ABRT_STORE;
+		break;
+	}
+}
+
+
+static void mce_set_error_info(struct OpalMachineCheckEvent *mce,
+			       struct mce_error_info *mce_err)
+{
+	mce->error_type = mce_err->error_type;
+	switch (mce_err->error_type) {
+	case MCE_ERROR_TYPE_UE:
+		mce->u.ue_error.ue_error_type = mce_err->u.ue_error_type;
+		break;
+	case MCE_ERROR_TYPE_SLB:
+		mce->u.slb_error.slb_error_type = mce_err->u.slb_error_type;
+		break;
+	case MCE_ERROR_TYPE_ERAT:
+		mce->u.erat_error.erat_error_type = mce_err->u.erat_error_type;
+		break;
+	case MCE_ERROR_TYPE_TLB:
+		mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type;
+		break;
+	case MCE_ERROR_TYPE_NEST:
+		mce->u.nest_error.nest_error_type = mce_err->u.nest_error_type;
+		break;
+	case MCE_ERROR_TYPE_CRESP:
+		mce->u.cresp_error.cresp_error_type =
+						mce_err->u.cresp_error_type;
+		break;
+	case MCE_ERROR_TYPE_FSPACE:
+		mce->u.fspace_error.fspace_error_type =
+						mce_err->u.fspace_error_type;
+		break;
+	case MCE_ERROR_TYPE_ASYNC:
+		mce->u.async_error.async_error_type =
+						mce_err->u.async_error_type;
+		break;
+	case MCE_ERROR_TYPE_UNKNOWN:
+	default:
+		break;
+	}
+}
+
+static void save_mce_event(struct mce_error_info *mce_err,
+		    uint64_t addr, struct OpalMachineCheckEvent *mce)
+{
+	mce->severity = MCE_SEV_ERROR_SYNC;
+
+	/*
+	 * Populate the mce error_type and type-specific error_type.
+	 */
+	mce_set_error_info(mce, mce_err);
+
+	if (!addr)
+		return;
+
+	if (mce->error_type == MCE_ERROR_TYPE_TLB) {
+		mce->u.tlb_error.effective_address_provided = true;
+		mce->u.tlb_error.effective_address = addr;
+	} else if (mce->error_type == MCE_ERROR_TYPE_SLB) {
+		mce->u.slb_error.effective_address_provided = true;
+		mce->u.slb_error.effective_address = addr;
+	} else if (mce->error_type == MCE_ERROR_TYPE_ERAT) {
+		mce->u.erat_error.effective_address_provided = true;
+		mce->u.erat_error.effective_address = addr;
+	} else if (mce->error_type == MCE_ERROR_TYPE_UE) {
+		mce->u.ue_error.effective_address_provided = true;
+		mce->u.ue_error.effective_address = addr;
+	} else if (mce->error_type == MCE_ERROR_TYPE_NEST) {
+		mce->u.nest_error.effective_address_provided = true;
+		mce->u.nest_error.effective_address = addr;
+	} else if (mce->error_type == MCE_ERROR_TYPE_CRESP) {
+		mce->u.cresp_error.effective_address_provided = true;
+		mce->u.cresp_error.effective_address = addr;
+	} else if (mce->error_type == MCE_ERROR_TYPE_FSPACE) {
+		mce->u.fspace_error.effective_address_provided = true;
+		mce->u.fspace_error.effective_address = addr;
+	}
+	return;
+}
+
+static void __machine_check_p9(struct mce_reason_regs *regs,
+				struct OpalMachineCheckEvent *mce)
+{
+	uint64_t srr1, addr = 0;
+	struct mce_error_info mce_error_info = { 0 };
+
+	srr1 = regs->srr1;
+
+	if ((srr1 & P9_SRR1_ASYNC_MC_MASK) == P9_SRR1_ASYNC_MC) {
+		/* Asynch machine check. */
+		mce_get_async_err_p9(&mce_error_info, srr1);
+		mce->severity = MCE_SEV_WARNING;
+	} else if (P9_SRR1_MC_LOADSTORE(srr1)) {
+		mce_get_derror_p9(&mce_error_info, regs->dsisr);
+		addr = regs->dar;
+	} else {
+		mce_get_ierror_p9(&mce_error_info, srr1);
+		addr = regs->srr0;
+	}
+
+	save_mce_event(&mce_error_info, addr, mce);
+}
+
+static int64_t opal_handle_machine_check(uint64_t srr0, uint64_t srr1,
+				uint64_t dar, uint64_t dsisr,
+				struct OpalMachineCheckEvent *mce)
+{
+	struct mce_reason_regs mce_regs = { 0 };
+
+	if (!mce)
+		return OPAL_PARAMETER;
+
+	/*
+	 * TODO: Add check for P9 chip.
+	 * Handle only for P9 chip.
+	 * For non-p9 chip return OPAL_UNSUPPORTED so that linux
+	 * will fallback to in-kernel MCE handling for older chips.
+	 */
+
+	/* Populate generic machine check event info */
+	mce->version = MCE_V1;
+	mce->srr0 = srr0;
+	mce->srr1 = srr1;
+	mce->in_use = 1;
+
+	mce->initiator = MCE_INITIATOR_CPU;
+	mce->disposition = MCE_DISPOSITION_NOT_RECOVERED;
+	mce->severity = MCE_SEV_ERROR_SYNC;
+
+	mce_regs.srr0 = srr0;
+	mce_regs.srr1 = srr1;
+	mce_regs.dar = dar;
+	mce_regs.dsisr = dsisr;
+	/*
+	 * Populate the mce error_type and type-specific error_type.
+	 */
+	__machine_check_p9(&mce_regs, mce);
+
+	return OPAL_SUCCESS;
+}
+
+opal_call(OPAL_HANDLE_MACHINE_CHECK, opal_handle_machine_check, 5);
diff --git a/include/opal-api.h b/include/opal-api.h
index c891db9..00968f7 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -200,7 +200,8 @@ 
 #define OPAL_XIVE_RESERVED2			142
 #define OPAL_XIVE_RESERVED3			143
 #define OPAL_XIVE_RESERVED4			144
-#define OPAL_LAST				144
+#define OPAL_HANDLE_MACHINE_CHECK		145
+#define OPAL_LAST				145
 
 /* Device tree flags */
 
@@ -740,6 +741,182 @@  struct OpalHMIEvent {
 	} u;
 };
 
+/* Machine Check event */
+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,
+	MCE_SEV_ERROR_ASYNC = 4,
+};
+
+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,
+	MCE_ERROR_TYPE_NEST = 5,
+	MCE_ERROR_TYPE_CRESP = 6,
+	MCE_ERROR_TYPE_FSPACE = 7,
+	MCE_ERROR_TYPE_ASYNC = 8,
+};
+
+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,
+	MCE_TLB_ERROR_TLBIEL_PROG_ERROR = 3,
+};
+
+enum MCE_NestErrorType {
+	MCE_NEST_ERROR_ABRT_IFETCH = 0,
+	MCE_NEST_ERROR_ABRT_IFETCH_TABLEWALK = 1,
+	MCE_NEST_ERROR_ABRT_LOAD = 2,
+	MCE_NEST_ERROR_ABRT_LOAD_TABLEWALK = 3,
+};
+
+enum MCE_CrespErrorType {
+	MCE_CRESP_ERROR_BAD_RADDR_IFETCH = 0,
+	MCE_CRESP_ERROR_BAD_RADDR_IFETCH_TABLEWALK = 1,
+	MCE_CRESP_ERROR_BAD_RADDR_LOAD = 2,
+	MCE_CRESP_ERROR_BAD_RADDR_LOAD_TABLEWALK = 3,
+};
+
+enum MCE_FspaceErrorType {
+	MCE_FSPACE_ERROR_IFETCH = 0,
+	MCE_FSPACE_ERROR_IFETCH_TABLEWALK = 1,
+	MCE_FSPACE_ERROR_RADDR_TRANSLATION = 2,
+	MCE_FSPACE_ERROR_RADDR_LOAD = 3,
+};
+
+enum MCE_AsyncErrorType {
+	MCE_ASYNC_ERROR_REAL_ADDR_STORE = 0,
+	MCE_ASYNC_ERROR_NEST_ABRT_STORE = 1,
+};
+
+struct OpalMachineCheckEvent {
+	uint8_t			version;	/* 0x00 */
+	uint8_t			in_use;		/* 0x01 */
+	uint8_t			severity;	/* 0x02 */
+	uint8_t			initiator;	/* 0x03 */
+	uint8_t			error_type;	/* 0x04 */
+	uint8_t			disposition;	/* 0x05 */
+	uint8_t			reserved_1[2];	/* 0x06 */
+	uint64_t		gpr3;		/* 0x08 */
+	uint64_t		srr0;		/* 0x10 */
+	uint64_t		srr1;		/* 0x18 */
+
+	union {					/* 0x20 */
+		/* Next 32 bytes contains specific information of MCE error. */
+		struct {
+			/* enum MCE_UeErrorType */
+			uint8_t		ue_error_type;
+			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 */
+			uint8_t		slb_error_type;
+			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 */
+			uint8_t		erat_error_type;
+			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  */
+			uint8_t		tlb_error_type;
+			uint8_t		effective_address_provided;
+			uint8_t		reserved_1[6];
+			uint64_t	effective_address;
+			uint8_t		reserved_2[16];
+		} tlb_error;
+
+		struct {
+			/* enum MCE_NestErrorType */
+			uint8_t		nest_error_type;
+			uint8_t		effective_address_provided;
+			uint8_t		reserved_1[6];
+			uint64_t	effective_address;
+			uint8_t		reserved_2[16];
+		} nest_error;
+
+		struct {
+			/* enum MCE_CrespErrorType */
+			uint8_t		cresp_error_type;
+			uint8_t		effective_address_provided;
+			uint8_t		reserved_1[6];
+			uint64_t	effective_address;
+			uint8_t		reserved_2[16];
+		} cresp_error;
+
+		struct {
+			/* enum MCE_FspaceErrorType */
+			uint8_t		fspace_error_type;
+			uint8_t		effective_address_provided;
+			uint8_t		reserved_1[6];
+			uint64_t	effective_address;
+			uint8_t		reserved_2[16];
+		} fspace_error;
+
+		struct {
+			/* enum MCE_AsyncErrorType */
+			uint8_t		async_error_type;
+			uint8_t		reserved_1[7];
+			uint8_t		reserved_2[24];
+		} async_error;
+	} u;
+};
+
 enum {
 	OPAL_P7IOC_DIAG_TYPE_NONE	= 0,
 	OPAL_P7IOC_DIAG_TYPE_RGC	= 1,