summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/pseries
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2021-02-07 22:54:12 +1000
committerMichael Ellerman <mpe@ellerman.id.au>2021-02-09 00:10:50 +1100
commit74c3354bc1d89d53e8da2dcc6f9f6bfc28b2900f (patch)
treeb425ea9c93f11676b45ef202772ee713250adb51 /arch/powerpc/platforms/pseries
parent56acfdd8bf9f75e83a1b2957bd415368f39b67b6 (diff)
powerpc/pseries/mce: restore msr before returning from handler
The pseries real-mode machine check handler can enable the MMU, and return from the handler with the MMU still enabled. This works, but real-mode handler wrapper exit handlers want to rely on the MMU being in real-mode. So change the pseries handler to restore the MSR after it has finished virtual mode tasks. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/1612702361.lm7fqo56re.astroid@bobo.none
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r--arch/powerpc/platforms/pseries/ras.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index 92c08fe893cf..f8b390a9d9fb 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -717,6 +717,7 @@ static int mce_handle_error(struct pt_regs *regs, struct rtas_error_log *errp)
struct pseries_errorlog *pseries_log;
struct pseries_mc_errorlog *mce_log = NULL;
int disposition = rtas_error_disposition(errp);
+ unsigned long msr;
u8 error_type;
if (!rtas_error_extended(errp))
@@ -742,9 +743,21 @@ static int mce_handle_error(struct pt_regs *regs, struct rtas_error_log *errp)
* SLB multihit is done by now.
*/
out:
- mtmsr(mfmsr() | MSR_IR | MSR_DR);
+ msr = mfmsr();
+ mtmsr(msr | MSR_IR | MSR_DR);
+
disposition = mce_handle_err_virtmode(regs, errp, mce_log,
disposition);
+
+ /*
+ * Queue irq work to log this rtas event later.
+ * irq_work_queue uses per-cpu variables, so do this in virt
+ * mode as well.
+ */
+ irq_work_queue(&mce_errlog_process_work);
+
+ mtmsr(msr);
+
return disposition;
}
@@ -860,10 +873,8 @@ long pseries_machine_check_realmode(struct pt_regs *regs)
* virtual mode.
*/
disposition = mce_handle_error(regs, errp);
- fwnmi_release_errinfo();
- /* Queue irq work to log this rtas event later. */
- irq_work_queue(&mce_errlog_process_work);
+ fwnmi_release_errinfo();
if (disposition == RTAS_DISP_FULLY_RECOVERED)
return 1;