aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2019-02-26 18:51:08 +1000
committerMichael Ellerman <mpe@ellerman.id.au>2019-02-26 23:28:25 +1100
commitcbf2ba952a70399c972f2a2126a4ac6f79437f37 (patch)
tree9eeb7c98b7915885032123073fc6bf5f4046b766 /arch/powerpc
parentpowerpc/64s: Fix HV NMI vs HV interrupt recoverability test (diff)
downloadlinux-dev-cbf2ba952a70399c972f2a2126a4ac6f79437f37.tar.xz
linux-dev-cbf2ba952a70399c972f2a2126a4ac6f79437f37.zip
powerpc/64s: system reset interrupt preserve HSRRs
Code that uses HSRR registers is not required to clear MSR[RI] by convention, however the system reset NMI itself may use HSRR registers (e.g., to call OPAL) and clobber them. Rather than introduce the requirement to clear RI in order to use HSRRs, have system reset interrupt save and restore HSRRs. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/traps.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index eee8f843f3d6..a5757bef03cd 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -435,14 +435,32 @@ nonrecoverable:
void system_reset_exception(struct pt_regs *regs)
{
+ unsigned long hsrr0, hsrr1;
+ bool nested = in_nmi();
+ bool saved_hsrrs = false;
+
/*
* Avoid crashes in case of nested NMI exceptions. Recoverability
* is determined by RI and in_nmi
*/
- bool nested = in_nmi();
if (!nested)
nmi_enter();
+ /*
+ * System reset can interrupt code where HSRRs are live and MSR[RI]=1.
+ * The system reset interrupt itself may clobber HSRRs (e.g., to call
+ * OPAL), so save them here and restore them before returning.
+ *
+ * Machine checks don't need to save HSRRs, as the real mode handler
+ * is careful to avoid them, and the regular handler is not delivered
+ * as an NMI.
+ */
+ if (cpu_has_feature(CPU_FTR_HVMODE)) {
+ hsrr0 = mfspr(SPRN_HSRR0);
+ hsrr1 = mfspr(SPRN_HSRR1);
+ saved_hsrrs = true;
+ }
+
hv_nmi_check_nonrecoverable(regs);
__this_cpu_inc(irq_stat.sreset_irqs);
@@ -492,6 +510,11 @@ out:
if (!(regs->msr & MSR_RI))
nmi_panic(regs, "Unrecoverable System Reset");
+ if (saved_hsrrs) {
+ mtspr(SPRN_HSRR0, hsrr0);
+ mtspr(SPRN_HSRR1, hsrr1);
+ }
+
if (!nested)
nmi_exit();