@@ -108,6 +108,8 @@ struct machdep_calls {
/* Early exception handlers called in realmode */
int (*hmi_exception_early)(struct pt_regs *regs);
+ int (*machine_check_early)(struct pt_regs *regs,
+ long *handled);
/* Called during machine check exception to retrive fixup address. */
bool (*mce_check_early_recovery)(struct pt_regs *regs);
@@ -167,7 +167,8 @@
#define OPAL_INT_EOI 124
#define OPAL_INT_SET_MFRR 125
#define OPAL_PCI_TCE_KILL 126
-#define OPAL_LAST 126
+#define OPAL_HANDLE_MACHINE_CHECK 145
+#define OPAL_LAST 145
/* Device tree flags */
@@ -189,6 +189,8 @@ int64_t opal_set_param(uint64_t token, uint32_t param_id, uint64_t buffer,
uint64_t length);
int64_t opal_sensor_read(uint32_t sensor_hndl, int token, __be32 *sensor_data);
int64_t opal_handle_hmi(void);
+int64_t opal_rm_handle_machine_check(uint64_t srr0, uint64_t srr1, uint64_t dar,
+ uint64_t dsisr, uint64_t *mce);
int64_t opal_register_dump_region(uint32_t id, uint64_t start, uint64_t end);
int64_t opal_unregister_dump_region(uint32_t id);
int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val);
@@ -279,6 +281,7 @@ extern int opal_hmi_handler_init(void);
extern int opal_event_init(void);
extern int opal_machine_check(struct pt_regs *regs);
+extern int opal_machine_check_early(struct pt_regs *regs, long *handled);
extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
extern int opal_hmi_exception_early(struct pt_regs *regs);
extern int opal_handle_hmi_exception(struct pt_regs *regs);
@@ -302,12 +302,25 @@ void system_reset_exception(struct pt_regs *regs)
long machine_check_early(struct pt_regs *regs)
{
long handled = 0;
+ int rc = 0;
__this_cpu_inc(irq_stat.mce_exceptions);
add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
- if (cur_cpu_spec && cur_cpu_spec->machine_check_early)
+ /*
+ * See if platform is capable of handling machine check. (e.g. PowerNV
+ * platform may take help from OPAL firmware to handle machine check.)
+ * Otherwise fallthrough and allow CPU to handle this machine check.
+ *
+ * If rc == -1 then it means firmware does not provide support for
+ * machine check handling for this CPU chip. Fallback to in-kernel
+ * machine check handler.
+ */
+ if (ppc_md.machine_check_early)
+ rc = ppc_md.machine_check_early(regs, &handled);
+
+ if (!rc && cur_cpu_spec && cur_cpu_spec->machine_check_early)
handled = cur_cpu_spec->machine_check_early(regs);
return handled;
}
@@ -312,3 +312,4 @@ OPAL_CALL(opal_int_set_mfrr, OPAL_INT_SET_MFRR);
OPAL_CALL_REAL(opal_rm_int_set_mfrr, OPAL_INT_SET_MFRR);
OPAL_CALL(opal_pci_tce_kill, OPAL_PCI_TCE_KILL);
OPAL_CALL_REAL(opal_rm_pci_tce_kill, OPAL_PCI_TCE_KILL);
+OPAL_CALL_REAL(opal_rm_handle_machine_check, OPAL_HANDLE_MACHINE_CHECK);
@@ -488,6 +488,22 @@ int opal_machine_check(struct pt_regs *regs)
return 0;
}
+/* Early mce handler called in real mode. */
+int opal_machine_check_early(struct pt_regs *regs, long *handled)
+{
+ int rc;
+ struct OpalMachineCheckEvent evt = { 0 };
+
+ *handled = 0;
+
+ rc = opal_rm_handle_machine_check(regs->nip, regs->msr, regs->dar,
+ regs->dsisr, (uint64_t *)&evt);
+ if (rc != OPAL_SUCCESS)
+ return -1;
+
+ return 0;
+}
+
/* Early hmi handler called in real mode. */
int opal_hmi_exception_early(struct pt_regs *regs)
{
@@ -264,6 +264,10 @@ static void __init pnv_setup_machdep_opal(void)
ppc_md.mce_check_early_recovery = opal_mce_check_early_recovery;
ppc_md.hmi_exception_early = opal_hmi_exception_early;
ppc_md.handle_hmi_exception = opal_handle_hmi_exception;
+
+ /* Check if OPAL is capable of handling machine check. */
+ if (opal_check_token(OPAL_HANDLE_MACHINE_CHECK))
+ ppc_md.machine_check_early = opal_machine_check_early;
}
static int __init pnv_probe(void)