summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries/ras.c
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2020-05-08 06:34:00 +0200
committerMichael Ellerman <mpe@ellerman.id.au>2020-05-18 16:10:05 +0200
commitd7b14c5c042865070a1411078ab49ea17bad0b41 (patch)
tree35bb0b32fea8fb00ffe4b2bd904534a37aa8ef97 /arch/powerpc/platforms/pseries/ras.c
parentpowerpc/pseries/ras: fwnmi avoid modifying r3 in error case (diff)
downloadlinux-d7b14c5c042865070a1411078ab49ea17bad0b41.tar.xz
linux-d7b14c5c042865070a1411078ab49ea17bad0b41.zip
powerpc/pseries/ras: fwnmi sreset should not interlock
PAPR does not specify that fwnmi sreset should be interlocked, and PowerVM (and therefore now QEMU) do not require it. These "ibm,nmi-interlock" calls are ignored by firmware, but there is a possibility that the sreset could have interrupted a machine check and release the machine check's interlock too early, corrupting it if another machine check came in. This is an extremely rare case, but it should be fixed for clarity and reducing the code executed in the sreset path. Firmware also does not provide error information for the sreset case to look at, so remove that comment. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> [mpe: Use __be64 to silence some sparse warnings] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20200508043408.886394-9-npiggin@gmail.com
Diffstat (limited to '')
-rw-r--r--arch/powerpc/platforms/pseries/ras.c48
1 files changed, 33 insertions, 15 deletions
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index fe14186a8cef..d20aecc52ece 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -406,6 +406,20 @@ static inline struct rtas_error_log *fwnmi_get_errlog(void)
return (struct rtas_error_log *)local_paca->mce_data_buf;
}
+static __be64 *fwnmi_get_savep(struct pt_regs *regs)
+{
+ unsigned long savep_ra;
+
+ /* Mask top two bits */
+ savep_ra = regs->gpr[3] & ~(0x3UL << 62);
+ if (!VALID_FWNMI_BUFFER(savep_ra)) {
+ printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]);
+ return NULL;
+ }
+
+ return __va(savep_ra);
+}
+
/*
* Get the error information for errors coming through the
* FWNMI vectors. The pt_regs' r3 will be updated to reflect
@@ -423,20 +437,14 @@ static inline struct rtas_error_log *fwnmi_get_errlog(void)
*/
static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
{
- unsigned long savep_ra;
- unsigned long *savep;
struct rtas_error_log *h;
+ __be64 *savep;
- /* Mask top two bits */
- savep_ra = regs->gpr[3] & ~(0x3UL << 62);
-
- if (!VALID_FWNMI_BUFFER(savep_ra)) {
- printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]);
+ savep = fwnmi_get_savep(regs);
+ if (!savep)
return NULL;
- }
- savep = __va(savep_ra);
- regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
+ regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
h = (struct rtas_error_log *)&savep[1];
/* Use the per cpu buffer from paca to store rtas error log */
@@ -483,11 +491,21 @@ int pSeries_system_reset_exception(struct pt_regs *regs)
#endif
if (fwnmi_active) {
- struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs);
- if (errhdr) {
- /* XXX Should look at FWNMI information */
- }
- fwnmi_release_errinfo();
+ __be64 *savep;
+
+ /*
+ * Firmware (PowerVM and KVM) saves r3 to a save area like
+ * machine check, which is not exactly what PAPR (2.9)
+ * suggests but there is no way to detect otherwise, so this
+ * is the interface now.
+ *
+ * System resets do not save any error log or require an
+ * "ibm,nmi-interlock" rtas call to release.
+ */
+
+ savep = fwnmi_get_savep(regs);
+ if (savep)
+ regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
}
if (smp_handle_nmi_ipi(regs))