s390: add stack switch helper
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 7 Sep 2017 15:03:19 +0000 (17:03 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 9 Oct 2018 09:20:56 +0000 (11:20 +0200)
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/processor.h
arch/s390/kernel/irq.c

index 7f2953c..43494a0 100644 (file)
@@ -250,6 +250,55 @@ static inline unsigned short stap(void)
        return cpu_address;
 }
 
+#define CALL_ARGS_0()                                                  \
+       register unsigned long r2 asm("2")
+#define CALL_ARGS_1(arg1)                                              \
+       register unsigned long r2 asm("2") = (unsigned long)(arg1)
+#define CALL_ARGS_2(arg1, arg2)                                                \
+       CALL_ARGS_1(arg1);                                              \
+       register unsigned long r3 asm("3") = (unsigned long)(arg2)
+#define CALL_ARGS_3(arg1, arg2, arg3)                                  \
+       CALL_ARGS_2(arg1, arg2);                                        \
+       register unsigned long r4 asm("4") = (unsigned long)(arg3)
+#define CALL_ARGS_4(arg1, arg2, arg3, arg4)                            \
+       CALL_ARGS_3(arg1, arg2, arg3);                                  \
+       register unsigned long r4 asm("5") = (unsigned long)(arg4)
+#define CALL_ARGS_5(arg1, arg2, arg3, arg4, arg5)                      \
+       CALL_ARGS_4(arg1, arg2, arg3, arg4);                            \
+       register unsigned long r4 asm("6") = (unsigned long)(arg5)
+
+#define CALL_FMT_0
+#define CALL_FMT_1 CALL_FMT_0, "0" (r2)
+#define CALL_FMT_2 CALL_FMT_1, "d" (r3)
+#define CALL_FMT_3 CALL_FMT_2, "d" (r4)
+#define CALL_FMT_4 CALL_FMT_3, "d" (r5)
+#define CALL_FMT_5 CALL_FMT_4, "d" (r6)
+
+#define CALL_CLOBBER_5 "0", "1", "14", "cc", "memory"
+#define CALL_CLOBBER_4 CALL_CLOBBER_5
+#define CALL_CLOBBER_3 CALL_CLOBBER_4, "5"
+#define CALL_CLOBBER_2 CALL_CLOBBER_3, "4"
+#define CALL_CLOBBER_1 CALL_CLOBBER_2, "3"
+#define CALL_CLOBBER_0 CALL_CLOBBER_1
+
+#define CALL_ON_STACK(fn, stack, nr, args...)                          \
+({                                                                     \
+       CALL_ARGS_##nr(args);                                           \
+       unsigned long prev;                                             \
+                                                                       \
+       asm volatile(                                                   \
+               "       la      %[_prev],0(15)\n"                       \
+               "       la      15,0(%[_stack])\n"                      \
+               "       stg     %[_prev],%[_bc](15)\n"                  \
+               "       brasl   14,%[_fn]\n"                            \
+               "       la      15,0(%[_prev])\n"                       \
+               : "+&d" (r2), [_prev] "=&a" (prev)                      \
+               : [_stack] "a" (stack),                                 \
+                 [_bc] "i" (offsetof(struct stack_frame, back_chain)), \
+                 [_fn] "X" (fn) CALL_FMT_##nr : CALL_CLOBBER_##nr);    \
+       r2;                                                             \
+})
+
 /*
  * Give up the time slice of the virtual PU.
  */
index 3d17c41..0e8d68b 100644 (file)
@@ -172,15 +172,7 @@ void do_softirq_own_stack(void)
        /* Check against async. stack address range. */
        new = S390_lowcore.async_stack;
        if (((new - old) >> (PAGE_SHIFT + THREAD_SIZE_ORDER)) != 0) {
-               /* Need to switch to the async. stack. */
-               new -= STACK_FRAME_OVERHEAD;
-               ((struct stack_frame *) new)->back_chain = old;
-               asm volatile("   la    15,0(%0)\n"
-                            "   brasl 14,__do_softirq\n"
-                            "   la    15,0(%1)\n"
-                            : : "a" (new), "a" (old)
-                            : "0", "1", "2", "3", "4", "5", "14",
-                              "cc", "memory" );
+               CALL_ON_STACK(__do_softirq, new, 0);
        } else {
                /* We are already on the async stack. */
                __do_softirq();