powerpc/64: Refactor interrupt exit irq disabling sequence
authorNicholas Piggin <npiggin@gmail.com>
Wed, 29 Apr 2020 06:24:21 +0000 (16:24 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 28 May 2020 13:24:34 +0000 (23:24 +1000)
The same complicated sequence for juggling EE, RI, soft mask, and
irq tracing is repeated 3 times, tidy these up into one function.

This differs qiute a bit between sub architectures, so this makes
the ppc32 port cleaner as well.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200429062421.1675400-1-npiggin@gmail.com
arch/powerpc/kernel/syscall_64.c

index 7b7c89cad901b8e2455dfc3f751931c8b8265dcb..613da0d0fa8cb6551dde3763e4f7f6b41e127715 100644 (file)
@@ -101,6 +101,31 @@ notrace long system_call_exception(long r3, long r4, long r5,
        return f(r3, r4, r5, r6, r7, r8);
 }
 
+/*
+ * local irqs must be disabled. Returns false if the caller must re-enable
+ * them, check for new work, and try again.
+ */
+static notrace inline bool prep_irq_for_enabled_exit(void)
+{
+       /* This must be done with RI=1 because tracing may touch vmaps */
+       trace_hardirqs_on();
+
+       /* This pattern matches prep_irq_for_idle */
+       __hard_EE_RI_disable();
+       if (unlikely(lazy_irq_pending_nocheck())) {
+               /* Took an interrupt, may have more exit work to do. */
+               __hard_RI_enable();
+               trace_hardirqs_off();
+               local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
+
+               return false;
+       }
+       local_paca->irq_happened = 0;
+       irq_soft_mask_set(IRQS_ENABLED);
+
+       return true;
+}
+
 /*
  * This should be called after a syscall returns, with r3 the return value
  * from the syscall. If this function returns non-zero, the system call
@@ -186,21 +211,10 @@ again:
                }
        }
 
-       /* This must be done with RI=1 because tracing may touch vmaps */
-       trace_hardirqs_on();
-
-       /* This pattern matches prep_irq_for_idle */
-       __hard_EE_RI_disable();
-       if (unlikely(lazy_irq_pending_nocheck())) {
-               __hard_RI_enable();
-               trace_hardirqs_off();
-               local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
+       if (unlikely(!prep_irq_for_enabled_exit())) {
                local_irq_enable();
-               /* Took an interrupt, may have more exit work to do. */
                goto again;
        }
-       local_paca->irq_happened = 0;
-       irq_soft_mask_set(IRQS_ENABLED);
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
        local_paca->tm_scratch = regs->msr;
@@ -264,19 +278,11 @@ again:
                }
        }
 
-       trace_hardirqs_on();
-       __hard_EE_RI_disable();
-       if (unlikely(lazy_irq_pending_nocheck())) {
-               __hard_RI_enable();
-               trace_hardirqs_off();
-               local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
+       if (unlikely(!prep_irq_for_enabled_exit())) {
                local_irq_enable();
                local_irq_disable();
-               /* Took an interrupt, may have more exit work to do. */
                goto again;
        }
-       local_paca->irq_happened = 0;
-       irq_soft_mask_set(IRQS_ENABLED);
 
 #ifdef CONFIG_PPC_BOOK3E
        if (unlikely(ts->debug.dbcr0 & DBCR0_IDM)) {
@@ -334,13 +340,7 @@ again:
                        }
                }
 
-               trace_hardirqs_on();
-               __hard_EE_RI_disable();
-               if (unlikely(lazy_irq_pending_nocheck())) {
-                       __hard_RI_enable();
-                       irq_soft_mask_set(IRQS_ALL_DISABLED);
-                       trace_hardirqs_off();
-                       local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
+               if (unlikely(!prep_irq_for_enabled_exit())) {
                        /*
                         * Can't local_irq_restore to replay if we were in
                         * interrupt context. Must replay directly.
@@ -354,8 +354,6 @@ again:
                        /* Took an interrupt, may have more exit work to do. */
                        goto again;
                }
-               local_paca->irq_happened = 0;
-               irq_soft_mask_set(IRQS_ENABLED);
        } else {
                /* Returning to a kernel context with local irqs disabled. */
                __hard_EE_RI_disable();