s390/nmi: implement and use local_mcck_save() / local_mcck_restore()
authorHeiko Carstens <hca@linux.ibm.com>
Fri, 1 Dec 2023 13:09:31 +0000 (14:09 +0100)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Mon, 11 Dec 2023 13:33:05 +0000 (14:33 +0100)
Instead of using local_mcck_disable() / local_mcck_enable() implement and
use local_mcck_save() / local_mcck_restore() to disable machine checks, and
restoring the previous state.

The problem with using local_mcck_disable() / local_mcck_enable() is that
there is an assumption that machine checks are always enabled. While this
is currently the case the code still looks quite odd, readers need to
double check if the code is correct.

In order to increase readability save and then restore the old machine
check mask bit, instead of assuming that it must have been enabled.

Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
arch/s390/include/asm/processor.h
arch/s390/kernel/nmi.c
arch/s390/lib/test_unwind.c

index dc17896a001a9235d8cf21374f323917e46d1e97..0b625373a255e28a8be715e39b146b86507f5723 100644 (file)
@@ -332,14 +332,36 @@ static inline unsigned long __extract_psw(void)
        return (((unsigned long) reg1) << 32) | ((unsigned long) reg2);
 }
 
-static inline void local_mcck_enable(void)
+static inline unsigned long __local_mcck_save(void)
 {
-       __load_psw_mask(__extract_psw() | PSW_MASK_MCHECK);
+       unsigned long mask = __extract_psw();
+
+       __load_psw_mask(mask & ~PSW_MASK_MCHECK);
+       return mask & PSW_MASK_MCHECK;
+}
+
+#define local_mcck_save(mflags)                        \
+do {                                           \
+       typecheck(unsigned long, mflags);       \
+       mflags = __local_mcck_save();           \
+} while (0)
+
+static inline void local_mcck_restore(unsigned long mflags)
+{
+       unsigned long mask = __extract_psw();
+
+       mask &= ~PSW_MASK_MCHECK;
+       __load_psw_mask(mask | mflags);
 }
 
 static inline void local_mcck_disable(void)
 {
-       __load_psw_mask(__extract_psw() & ~PSW_MASK_MCHECK);
+       __local_mcck_save();
+}
+
+static inline void local_mcck_enable(void)
+{
+       __load_psw_mask(__extract_psw() | PSW_MASK_MCHECK);
 }
 
 /*
index 0daf0f1cdfc9360cad3cca894e5eeef65e55717f..60bcb451a4ebd5c43cf86ad1dc986e13fa6f3e59 100644 (file)
@@ -159,16 +159,17 @@ NOKPROBE_SYMBOL(s390_handle_damage);
 void s390_handle_mcck(void)
 {
        struct mcck_struct mcck;
+       unsigned long mflags;
 
        /*
         * Disable machine checks and get the current state of accumulated
         * machine checks. Afterwards delete the old state and enable machine
         * checks again.
         */
-       local_mcck_disable();
+       local_mcck_save(mflags);
        mcck = *this_cpu_ptr(&cpu_mcck);
        memset(this_cpu_ptr(&cpu_mcck), 0, sizeof(mcck));
-       local_mcck_enable();
+       local_mcck_restore(mflags);
 
        if (mcck.channel_report)
                crw_handle_channel_report();
index 7231bf97b93adbba06e949b8b8bf5d32111c5cde..2848e3fb2ff5e11e4d0ac437ec58ba6312bc61d1 100644 (file)
@@ -350,15 +350,15 @@ static noinline int unwindme_func3(struct unwindme *u)
 /* This function must appear in the backtrace. */
 static noinline int unwindme_func2(struct unwindme *u)
 {
-       unsigned long flags;
+       unsigned long flags, mflags;
        int rc;
 
        if (u->flags & UWM_SWITCH_STACK) {
                local_irq_save(flags);
-               local_mcck_disable();
+               local_mcck_save(mflags);
                rc = call_on_stack(1, S390_lowcore.nodat_stack,
                                   int, unwindme_func3, struct unwindme *, u);
-               local_mcck_enable();
+               local_mcck_restore(mflags);
                local_irq_restore(flags);
                return rc;
        } else {