Re: [PATCH] powerpc/64: refactor interrupt exit irq disabling sequence

2020-06-08 Thread Michael Ellerman
On Wed, 29 Apr 2020 16:24:21 +1000, Nicholas Piggin wrote:
> 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.

Applied to powerpc/next.

[1/1] powerpc/64: Refactor interrupt exit irq disabling sequence
  https://git.kernel.org/powerpc/c/0bdad33d6bd7b80722e2f9e588d3d7c6d6e34978

cheers


[PATCH] powerpc/64: refactor interrupt exit irq disabling sequence

2020-04-28 Thread Nicholas Piggin
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 
---
 arch/powerpc/kernel/syscall_64.c | 58 +++-
 1 file changed, 28 insertions(+), 30 deletions(-)

diff --git a/arch/powerpc/kernel/syscall_64.c b/arch/powerpc/kernel/syscall_64.c
index c74295a7765b..8f7e268f3294 100644
--- a/arch/powerpc/kernel/syscall_64.c
+++ b/arch/powerpc/kernel/syscall_64.c
@@ -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())) {
+   /* 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
@@ -184,21 +209,10 @@ notrace unsigned long syscall_exit_prepare(unsigned long 
r3,
}
}
 
-   /* 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())) {
-   __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;
@@ -262,19 +276,11 @@ notrace unsigned long interrupt_exit_user_prepare(struct 
pt_regs *regs, unsigned
}
}
 
-   trace_hardirqs_on();
-   __hard_EE_RI_disable();
-   if (unlikely(lazy_irq_pending())) {
-   __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)) {
@@ -332,13 +338,7 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct 
pt_regs *regs, unsign
}
}
 
-   trace_hardirqs_on();
-   __hard_EE_RI_disable();
-   if (unlikely(lazy_irq_pending())) {
-   __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.
@@ -352,8 +352,6 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct 
pt_regs *regs, unsign
/* 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();
-- 
2.23.0