All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes
@ 2022-09-26  5:42 Nicholas Piggin
  2022-09-26  5:42 ` [PATCH v3 1/7] powerpc/64/interrupt: Fix false warning in context tracking due to idle state Nicholas Piggin
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Nicholas Piggin @ 2022-09-26  5:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Nicholas Piggin

No real changes since last posting, I just pulled fixes from several
series together and rearranged them and updated changelogs slightly.

Thanks,
Nick

Nicholas Piggin (7):
  powerpc/64/interrupt: Fix false warning in context tracking due to
    idle state
  powerpc/64: mark irqs hard disabled in boot paca
  powerpc/64/interrupt: Fix return to masked context after hard-mask irq
    becomes pending
  powerpc/64s: Fix irq state management in runlatch functions
  powerpc/64s/interrupt: masked handler debug check for previous hard
    disable
  powerpc/64/interrupt: avoid BUG/WARN recursion in interrupt entry
  powerpc/64/irq: tidy soft-masked irq replay and improve documentation

 arch/powerpc/include/asm/interrupt.h | 36 ++++++-----
 arch/powerpc/include/asm/runlatch.h  |  6 +-
 arch/powerpc/kernel/exceptions-64s.S | 10 +++
 arch/powerpc/kernel/interrupt.c      | 10 ---
 arch/powerpc/kernel/interrupt_64.S   | 34 +++++++++-
 arch/powerpc/kernel/irq_64.c         | 93 ++++++++++++++++++----------
 arch/powerpc/kernel/setup_64.c       |  4 +-
 7 files changed, 129 insertions(+), 64 deletions(-)

-- 
2.37.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/7] powerpc/64/interrupt: Fix false warning in context tracking due to idle state
  2022-09-26  5:42 [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Nicholas Piggin
@ 2022-09-26  5:42 ` Nicholas Piggin
  2022-09-26  5:43 ` [PATCH v3 2/7] powerpc/64: mark irqs hard disabled in boot paca Nicholas Piggin
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Nicholas Piggin @ 2022-09-26  5:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Nicholas Piggin

Commit 171476775d32 ("context_tracking: Convert state to atomic_t")
added a CONTEXT_IDLE state which can be encountered by interrupts from
kernel mode in the idle thread, causing a false positive warning.

Fixes: 171476775d32 ("context_tracking: Convert state to atomic_t")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/include/asm/interrupt.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h
index 8069dbc4b8d1..b61555e30c7c 100644
--- a/arch/powerpc/include/asm/interrupt.h
+++ b/arch/powerpc/include/asm/interrupt.h
@@ -195,7 +195,8 @@ static inline void interrupt_enter_prepare(struct pt_regs *regs)
 		 * so avoid recursion.
 		 */
 		if (TRAP(regs) != INTERRUPT_PROGRAM) {
-			CT_WARN_ON(ct_state() != CONTEXT_KERNEL);
+			CT_WARN_ON(ct_state() != CONTEXT_KERNEL &&
+				   ct_state() != CONTEXT_IDLE);
 			if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
 				BUG_ON(is_implicit_soft_masked(regs));
 		}
-- 
2.37.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 2/7] powerpc/64: mark irqs hard disabled in boot paca
  2022-09-26  5:42 [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Nicholas Piggin
  2022-09-26  5:42 ` [PATCH v3 1/7] powerpc/64/interrupt: Fix false warning in context tracking due to idle state Nicholas Piggin
@ 2022-09-26  5:43 ` Nicholas Piggin
  2022-09-26  5:43 ` [PATCH v3 3/7] powerpc/64/interrupt: Fix return to masked context after hard-mask irq becomes pending Nicholas Piggin
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Nicholas Piggin @ 2022-09-26  5:43 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Nicholas Piggin

This prevents interrupts in early boot (e.g., program check) from
enabling MSR[EE], potentially causing endian mismatch or other
crashes when reporting early boot traps.

Fixes: 4423eb5ae32ec ("powerpc/64/interrupt: make normal synchronous interrupts enable MSR[EE] if possible")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/kernel/setup_64.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 2b2d0b0fbb30..ce8fc6575eaa 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -182,8 +182,10 @@ static void __init fixup_boot_paca(void)
 	get_paca()->cpu_start = 1;
 	/* Allow percpu accesses to work until we setup percpu data */
 	get_paca()->data_offset = 0;
-	/* Mark interrupts disabled in PACA */
+	/* Mark interrupts soft and hard disabled in PACA */
 	irq_soft_mask_set(IRQS_DISABLED);
+	get_paca()->irq_happened = PACA_IRQ_HARD_DIS;
+	WARN_ON(mfmsr() & MSR_EE);
 }
 
 static void __init configure_exceptions(void)
-- 
2.37.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 3/7] powerpc/64/interrupt: Fix return to masked context after hard-mask irq becomes pending
  2022-09-26  5:42 [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Nicholas Piggin
  2022-09-26  5:42 ` [PATCH v3 1/7] powerpc/64/interrupt: Fix false warning in context tracking due to idle state Nicholas Piggin
  2022-09-26  5:43 ` [PATCH v3 2/7] powerpc/64: mark irqs hard disabled in boot paca Nicholas Piggin
@ 2022-09-26  5:43 ` Nicholas Piggin
  2022-09-26  5:43 ` [PATCH v3 4/7] powerpc/64s: Fix irq state management in runlatch functions Nicholas Piggin
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Nicholas Piggin @ 2022-09-26  5:43 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Nicholas Piggin

If a synchronous interrupt (e.g., hash fault) is taken inside an
irqs-disabled region which has MSR[EE]=1, then an asynchronous interrupt
that is PACA_IRQ_MUST_HARD_MASK (e.g., PMI) is taken inside the
synchronous interrupt handler, then the synchronous interrupt will
return with MSR[EE]=1 and the asynchronous interrupt fires again.

If the asynchronous interrupt is a PMI and the original context does not
have PMIs disabled (only Linux IRQs), the asynchronous interrupt will
fire despite having the PMI marked soft pending. This can confuse the
perf code and cause warnings.

This patch changes the interrupt return so that irqs-disabled MSR[EE]=1
contexts will be returned to with MSR[EE]=0 if a PACA_IRQ_MUST_HARD_MASK
interrupt has become pending in the meantime.

The longer explanation for what happens:
1. local_irq_disable()
2. Hash fault interrupt fires, do_hash_fault handler runs
3. interrupt_enter_prepare() sets IRQS_ALL_DISABLED
4. interrupt_enter_prepare() sets MSR[EE]=1
5. PMU interrupt fires, masked handler runs
6. Masked handler marks PMI pending
7. Masked handler returns with PACA_IRQ_HARD_DIS set, MSR[EE]=0
8. do_hash_fault interrupt return handler runs
9. interrupt_exit_kernel_prepare() clears PACA_IRQ_HARD_DIS
10. interrupt returns with MSR[EE]=1
11. PMU interrupt fires, perf handler runs

Fixes: 4423eb5ae32e ("powerpc/64/interrupt: make normal synchronous interrupts enable MSR[EE] if possible")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/kernel/interrupt.c    | 10 ---------
 arch/powerpc/kernel/interrupt_64.S | 34 +++++++++++++++++++++++++++---
 2 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c
index 0e75cb03244a..f9db0a172401 100644
--- a/arch/powerpc/kernel/interrupt.c
+++ b/arch/powerpc/kernel/interrupt.c
@@ -431,16 +431,6 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs)
 
 		if (unlikely(stack_store))
 			__hard_EE_RI_disable();
-		/*
-		 * Returning to a kernel context with local irqs disabled.
-		 * Here, if EE was enabled in the interrupted context, enable
-		 * it on return as well. A problem exists here where a soft
-		 * masked interrupt may have cleared MSR[EE] and set HARD_DIS
-		 * here, and it will still exist on return to the caller. This
-		 * will be resolved by the masked interrupt firing again.
-		 */
-		if (regs->msr & MSR_EE)
-			local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
 #endif /* CONFIG_PPC64 */
 	}
 
diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S
index ce25b28cf418..d76376ce7291 100644
--- a/arch/powerpc/kernel/interrupt_64.S
+++ b/arch/powerpc/kernel/interrupt_64.S
@@ -559,15 +559,43 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_kernel)
 	ld	r11,SOFTE(r1)
 	cmpwi	r11,IRQS_ENABLED
 	stb	r11,PACAIRQSOFTMASK(r13)
-	bne	1f
+	beq	.Linterrupt_return_\srr\()_soft_enabled
+
+	/*
+	 * Returning to soft-disabled context.
+	 * Check if a MUST_HARD_MASK interrupt has become pending, in which
+	 * case we need to disable MSR[EE] in the return context.
+	 */
+	ld	r12,_MSR(r1)
+	andi.	r10,r12,MSR_EE
+	beq	.Lfast_kernel_interrupt_return_\srr\() // EE already disabled
+	lbz	r11,PACAIRQHAPPENED(r13)
+	andi.	r10,r11,PACA_IRQ_MUST_HARD_MASK
+	beq	1f // No HARD_MASK pending
+
+	/* Must clear MSR_EE from _MSR */
+#ifdef CONFIG_PPC_BOOK3S
+	li	r10,0
+	/* Clear valid before changing _MSR */
+	.ifc \srr,srr
+	stb	r10,PACASRR_VALID(r13)
+	.else
+	stb	r10,PACAHSRR_VALID(r13)
+	.endif
+#endif
+	xori	r12,r12,MSR_EE
+	std	r12,_MSR(r1)
+	b	.Lfast_kernel_interrupt_return_\srr\()
+
+.Linterrupt_return_\srr\()_soft_enabled:
 #ifdef CONFIG_PPC_BOOK3S
 	lbz	r11,PACAIRQHAPPENED(r13)
 	andi.	r11,r11,(~PACA_IRQ_HARD_DIS)@l
 	bne-	interrupt_return_\srr\()_kernel_restart
 #endif
-	li	r11,0
-	stb	r11,PACAIRQHAPPENED(r13) # clear out possible HARD_DIS
 1:
+	li	r11,0
+	stb	r11,PACAIRQHAPPENED(r13) // clear the possible HARD_DIS
 
 .Lfast_kernel_interrupt_return_\srr\():
 	cmpdi	cr1,r3,0
-- 
2.37.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 4/7] powerpc/64s: Fix irq state management in runlatch functions
  2022-09-26  5:42 [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Nicholas Piggin
                   ` (2 preceding siblings ...)
  2022-09-26  5:43 ` [PATCH v3 3/7] powerpc/64/interrupt: Fix return to masked context after hard-mask irq becomes pending Nicholas Piggin
@ 2022-09-26  5:43 ` Nicholas Piggin
  2022-09-26  5:43 ` [PATCH v3 5/7] powerpc/64s/interrupt: masked handler debug check for previous hard disable Nicholas Piggin
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Nicholas Piggin @ 2022-09-26  5:43 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Nicholas Piggin

When irqs are soft-disabled, MSR[EE] is volatile and can change from
1 to 0 asynchronously (if a PACA_IRQ_MUST_HARD_MASK interrupt hits).
So it can not be used to check hard IRQ enabled status, except to
confirm it is disabled.

ppc64_runlatch_on/off functions use MSR this way to decide whether to
re-enable MSR[EE] after disabling it, which leads to MSR[EE] being
enabled when it shouldn't be (when a PACA_IRQ_MUST_HARD_MASK had
disabled it between reading the MSR and clearing EE).

This has been tolerated in the kernel previously, and it doesn't seem
to cause a problem, but it is unexpected and may trip warnings or cause
other problems as we tighten up this state management. Fix this by only
re-enabling if PACA_IRQ_HARD_DIS is clear.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/include/asm/runlatch.h | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/runlatch.h b/arch/powerpc/include/asm/runlatch.h
index cfb390edf7d0..ceb66d761fe1 100644
--- a/arch/powerpc/include/asm/runlatch.h
+++ b/arch/powerpc/include/asm/runlatch.h
@@ -19,10 +19,9 @@ extern void __ppc64_runlatch_off(void);
 	do {							\
 		if (cpu_has_feature(CPU_FTR_CTRL) &&		\
 		    test_thread_local_flags(_TLF_RUNLATCH)) {	\
-			unsigned long msr = mfmsr();		\
 			__hard_irq_disable();			\
 			__ppc64_runlatch_off();			\
-			if (msr & MSR_EE)			\
+			if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS)) \
 				__hard_irq_enable();		\
 		}      						\
 	} while (0)
@@ -31,10 +30,9 @@ extern void __ppc64_runlatch_off(void);
 	do {							\
 		if (cpu_has_feature(CPU_FTR_CTRL) &&		\
 		    !test_thread_local_flags(_TLF_RUNLATCH)) {	\
-			unsigned long msr = mfmsr();		\
 			__hard_irq_disable();			\
 			__ppc64_runlatch_on();			\
-			if (msr & MSR_EE)			\
+			if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS)) \
 				__hard_irq_enable();		\
 		}      						\
 	} while (0)
-- 
2.37.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 5/7] powerpc/64s/interrupt: masked handler debug check for previous hard disable
  2022-09-26  5:42 [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Nicholas Piggin
                   ` (3 preceding siblings ...)
  2022-09-26  5:43 ` [PATCH v3 4/7] powerpc/64s: Fix irq state management in runlatch functions Nicholas Piggin
@ 2022-09-26  5:43 ` Nicholas Piggin
  2022-09-26  5:43 ` [PATCH v3 6/7] powerpc/64/interrupt: avoid BUG/WARN recursion in interrupt entry Nicholas Piggin
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Nicholas Piggin @ 2022-09-26  5:43 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Nicholas Piggin

Prior changes eliminated cases of masked PACA_IRQ_MUST_HARD_MASK
interrupts that re-fire due to MSR[EE] being enabled while they are
pending. Add a debug check in the masked interrupt handler to catch
if this occurs.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/kernel/exceptions-64s.S | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 3d0dc133a9ae..dafa275f18bc 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -2794,6 +2794,16 @@ masked_Hinterrupt:
 masked_interrupt:
 	.endif
 	stw	r9,PACA_EXGEN+EX_CCR(r13)
+#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG
+	/*
+	 * Ensure there was no previous MUST_HARD_MASK interrupt or
+	 * HARD_DIS setting.
+	 */
+	lbz	r9,PACAIRQHAPPENED(r13)
+	andi.	r9,r9,(PACA_IRQ_MUST_HARD_MASK|PACA_IRQ_HARD_DIS)
+0:	tdnei	r9,0
+	EMIT_BUG_ENTRY 0b,__FILE__,__LINE__,0
+#endif
 	lbz	r9,PACAIRQHAPPENED(r13)
 	or	r9,r9,r10
 	stb	r9,PACAIRQHAPPENED(r13)
-- 
2.37.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 6/7] powerpc/64/interrupt: avoid BUG/WARN recursion in interrupt entry
  2022-09-26  5:42 [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Nicholas Piggin
                   ` (4 preceding siblings ...)
  2022-09-26  5:43 ` [PATCH v3 5/7] powerpc/64s/interrupt: masked handler debug check for previous hard disable Nicholas Piggin
@ 2022-09-26  5:43 ` Nicholas Piggin
  2022-09-26  5:43 ` [PATCH v3 7/7] powerpc/64/irq: tidy soft-masked irq replay and improve documentation Nicholas Piggin
  2022-10-04 13:25 ` [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Michael Ellerman
  7 siblings, 0 replies; 9+ messages in thread
From: Nicholas Piggin @ 2022-09-26  5:43 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Nicholas Piggin

BUG/WARN are handled with a program interrupt which can turn into an
infinite recursion when there are bugs in interrupt handler entry
(which can be irritated by bugs in other parts of the code).

There is one feeble attempt to avoid this recursion, but it misses
several cases. Make a tidier macro for this and switch most bugs in
the interrupt entry wrapper over to use it.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/include/asm/interrupt.h | 33 +++++++++++++++++-----------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h
index b61555e30c7c..7f3180047115 100644
--- a/arch/powerpc/include/asm/interrupt.h
+++ b/arch/powerpc/include/asm/interrupt.h
@@ -74,6 +74,19 @@
 #include <asm/kprobes.h>
 #include <asm/runlatch.h>
 
+#ifdef CONFIG_PPC64
+/*
+ * WARN/BUG is handled with a program interrupt so minimise checks here to
+ * avoid recursion and maximise the chance of getting the first oops handled.
+ */
+#define INT_SOFT_MASK_BUG_ON(regs, cond)				\
+do {									\
+	if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG) &&		\
+	    (user_mode(regs) || (TRAP(regs) != INTERRUPT_PROGRAM)))	\
+		BUG_ON(cond);						\
+} while (0)
+#endif
+
 #ifdef CONFIG_PPC_BOOK3S_64
 extern char __end_soft_masked[];
 bool search_kernel_soft_mask_table(unsigned long addr);
@@ -170,8 +183,7 @@ static inline void interrupt_enter_prepare(struct pt_regs *regs)
 	 * context.
 	 */
 	if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS)) {
-		if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
-			BUG_ON(!(regs->msr & MSR_EE));
+		INT_SOFT_MASK_BUG_ON(regs, !(regs->msr & MSR_EE));
 		__hard_irq_enable();
 	} else {
 		__hard_RI_enable();
@@ -194,20 +206,15 @@ static inline void interrupt_enter_prepare(struct pt_regs *regs)
 		 * CT_WARN_ON comes here via program_check_exception,
 		 * so avoid recursion.
 		 */
-		if (TRAP(regs) != INTERRUPT_PROGRAM) {
+		if (TRAP(regs) != INTERRUPT_PROGRAM)
 			CT_WARN_ON(ct_state() != CONTEXT_KERNEL &&
 				   ct_state() != CONTEXT_IDLE);
-			if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
-				BUG_ON(is_implicit_soft_masked(regs));
-		}
-
-		/* Move this under a debugging check */
-		if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG) &&
-				arch_irq_disabled_regs(regs))
-			BUG_ON(search_kernel_restart_table(regs->nip));
+		INT_SOFT_MASK_BUG_ON(regs, is_implicit_soft_masked(regs));
+		INT_SOFT_MASK_BUG_ON(regs, arch_irq_disabled_regs(regs) &&
+					   search_kernel_restart_table(regs->nip));
 	}
-	if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
-		BUG_ON(!arch_irq_disabled_regs(regs) && !(regs->msr & MSR_EE));
+	INT_SOFT_MASK_BUG_ON(regs, !arch_irq_disabled_regs(regs) &&
+				   !(regs->msr & MSR_EE));
 #endif
 
 	booke_restore_dbcr0();
-- 
2.37.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 7/7] powerpc/64/irq: tidy soft-masked irq replay and improve documentation
  2022-09-26  5:42 [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Nicholas Piggin
                   ` (5 preceding siblings ...)
  2022-09-26  5:43 ` [PATCH v3 6/7] powerpc/64/interrupt: avoid BUG/WARN recursion in interrupt entry Nicholas Piggin
@ 2022-09-26  5:43 ` Nicholas Piggin
  2022-10-04 13:25 ` [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Michael Ellerman
  7 siblings, 0 replies; 9+ messages in thread
From: Nicholas Piggin @ 2022-09-26  5:43 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Nicholas Piggin

irq replay is quite complicated because of softirq processing which
itself enables and disables irqs. Several considerations need to be
accounted for due to this, and they are not clearly documented.

Refactor the irq replay code a bit to tidy and deduplicate some common
functions. Add comments, debug checks.

This has a minor functional change that irq tracing enable/disable is
done after each interrupt replayed, rather than after a batch. It also
re-sets state to IRQS_ALL_DISABLED after an interrupt, which doesn't
matter much because interrupts are hard disabled at this point, but it
is more consistent with how interrupt handlers are called.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/kernel/irq_64.c | 93 +++++++++++++++++++++++-------------
 1 file changed, 61 insertions(+), 32 deletions(-)

diff --git a/arch/powerpc/kernel/irq_64.c b/arch/powerpc/kernel/irq_64.c
index 01645e03e9f0..eb2b380e52a0 100644
--- a/arch/powerpc/kernel/irq_64.c
+++ b/arch/powerpc/kernel/irq_64.c
@@ -68,6 +68,35 @@
 
 int distribute_irqs = 1;
 
+static inline void next_interrupt(struct pt_regs *regs)
+{
+	/*
+	 * Softirq processing can enable/disable irqs, which will leave
+	 * MSR[EE] enabled and the soft mask set to IRQS_DISABLED. Fix
+	 * this up.
+	 */
+	if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
+		hard_irq_disable();
+	else
+		irq_soft_mask_set(IRQS_ALL_DISABLED);
+
+	/*
+	 * We are responding to the next interrupt, so interrupt-off
+	 * latencies should be reset here.
+	 */
+	trace_hardirqs_on();
+	trace_hardirqs_off();
+}
+
+static inline bool irq_happened_test_and_clear(u8 irq)
+{
+	if (local_paca->irq_happened & irq) {
+		local_paca->irq_happened &= ~irq;
+		return true;
+	}
+	return false;
+}
+
 void replay_soft_interrupts(void)
 {
 	struct pt_regs regs;
@@ -79,18 +108,25 @@ void replay_soft_interrupts(void)
 	 * recurse into this function. Don't keep any state across
 	 * interrupt handler calls which may change underneath us.
 	 *
+	 * Softirqs can not be disabled over replay to stop this recursion
+	 * because interrupts taken in idle code may require RCU softirq
+	 * to run in the irq RCU tracking context. This is a hard problem
+	 * to fix without changes to the softirq or idle layer.
+	 *
 	 * We use local_paca rather than get_paca() to avoid all the
 	 * debug_smp_processor_id() business in this low level function.
 	 */
 
+	if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
+		WARN_ON_ONCE(mfmsr() & MSR_EE);
+		WARN_ON(!(local_paca->irq_happened & PACA_IRQ_HARD_DIS));
+	}
+
 	ppc_save_regs(&regs);
 	regs.softe = IRQS_ENABLED;
 	regs.msr |= MSR_EE;
 
 again:
-	if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
-		WARN_ON_ONCE(mfmsr() & MSR_EE);
-
 	/*
 	 * Force the delivery of pending soft-disabled interrupts on PS3.
 	 * Any HV call will have this side effect.
@@ -105,56 +141,47 @@ void replay_soft_interrupts(void)
 	 * This is a higher priority interrupt than the others, so
 	 * replay it first.
 	 */
-	if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_HMI)) {
-		local_paca->irq_happened &= ~PACA_IRQ_HMI;
+	if (IS_ENABLED(CONFIG_PPC_BOOK3S) &&
+	    irq_happened_test_and_clear(PACA_IRQ_HMI)) {
 		regs.trap = INTERRUPT_HMI;
 		handle_hmi_exception(&regs);
-		if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
-			hard_irq_disable();
+		next_interrupt(&regs);
 	}
 
-	if (local_paca->irq_happened & PACA_IRQ_DEC) {
-		local_paca->irq_happened &= ~PACA_IRQ_DEC;
+	if (irq_happened_test_and_clear(PACA_IRQ_DEC)) {
 		regs.trap = INTERRUPT_DECREMENTER;
 		timer_interrupt(&regs);
-		if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
-			hard_irq_disable();
+		next_interrupt(&regs);
 	}
 
-	if (local_paca->irq_happened & PACA_IRQ_EE) {
-		local_paca->irq_happened &= ~PACA_IRQ_EE;
+	if (irq_happened_test_and_clear(PACA_IRQ_EE)) {
 		regs.trap = INTERRUPT_EXTERNAL;
 		do_IRQ(&regs);
-		if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
-			hard_irq_disable();
+		next_interrupt(&regs);
 	}
 
-	if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (local_paca->irq_happened & PACA_IRQ_DBELL)) {
-		local_paca->irq_happened &= ~PACA_IRQ_DBELL;
+	if (IS_ENABLED(CONFIG_PPC_DOORBELL) &&
+	    irq_happened_test_and_clear(PACA_IRQ_DBELL)) {
 		regs.trap = INTERRUPT_DOORBELL;
 		doorbell_exception(&regs);
-		if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
-			hard_irq_disable();
+		next_interrupt(&regs);
 	}
 
 	/* Book3E does not support soft-masking PMI interrupts */
-	if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_PMI)) {
-		local_paca->irq_happened &= ~PACA_IRQ_PMI;
+	if (IS_ENABLED(CONFIG_PPC_BOOK3S) &&
+	    irq_happened_test_and_clear(PACA_IRQ_PMI)) {
 		regs.trap = INTERRUPT_PERFMON;
 		performance_monitor_exception(&regs);
-		if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
-			hard_irq_disable();
+		next_interrupt(&regs);
 	}
 
-	if (local_paca->irq_happened & ~PACA_IRQ_HARD_DIS) {
-		/*
-		 * We are responding to the next interrupt, so interrupt-off
-		 * latencies should be reset here.
-		 */
-		trace_hardirqs_on();
-		trace_hardirqs_off();
+	/*
+	 * Softirq processing can enable and disable interrupts, which can
+	 * result in new irqs becoming pending. Must keep looping until we
+	 * have cleared out all pending interrupts.
+	 */
+	if (local_paca->irq_happened & ~PACA_IRQ_HARD_DIS)
 		goto again;
-	}
 }
 
 #if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_KUAP)
@@ -270,10 +297,12 @@ notrace void arch_local_irq_restore(unsigned long mask)
 	trace_hardirqs_off();
 
 	replay_soft_interrupts_irqrestore();
-	local_paca->irq_happened = 0;
 
 	trace_hardirqs_on();
 	irq_soft_mask_set(IRQS_ENABLED);
+	if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
+		WARN_ON(local_paca->irq_happened != PACA_IRQ_HARD_DIS);
+	local_paca->irq_happened = 0;
 	__hard_irq_enable();
 	preempt_enable();
 }
-- 
2.37.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes
  2022-09-26  5:42 [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Nicholas Piggin
                   ` (6 preceding siblings ...)
  2022-09-26  5:43 ` [PATCH v3 7/7] powerpc/64/irq: tidy soft-masked irq replay and improve documentation Nicholas Piggin
@ 2022-10-04 13:25 ` Michael Ellerman
  7 siblings, 0 replies; 9+ messages in thread
From: Michael Ellerman @ 2022-10-04 13:25 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev

On Mon, 26 Sep 2022 15:42:58 +1000, Nicholas Piggin wrote:
> No real changes since last posting, I just pulled fixes from several
> series together and rearranged them and updated changelogs slightly.
> 
> Thanks,
> Nick
> 
> Nicholas Piggin (7):
>   powerpc/64/interrupt: Fix false warning in context tracking due to
>     idle state
>   powerpc/64: mark irqs hard disabled in boot paca
>   powerpc/64/interrupt: Fix return to masked context after hard-mask irq
>     becomes pending
>   powerpc/64s: Fix irq state management in runlatch functions
>   powerpc/64s/interrupt: masked handler debug check for previous hard
>     disable
>   powerpc/64/interrupt: avoid BUG/WARN recursion in interrupt entry
>   powerpc/64/irq: tidy soft-masked irq replay and improve documentation
> 
> [...]

Applied to powerpc/next.

[1/7] powerpc/64/interrupt: Fix false warning in context tracking due to idle state
      https://git.kernel.org/powerpc/c/56adbb7a8b6cc7fc9b940829c38494e53c9e57d1
[2/7] powerpc/64: mark irqs hard disabled in boot paca
      https://git.kernel.org/powerpc/c/799f7063c7645f9a751d17f5dfd73b952f962cd2
[3/7] powerpc/64/interrupt: Fix return to masked context after hard-mask irq becomes pending
      https://git.kernel.org/powerpc/c/e485f6c751e0a969327336c635ca602feea117f0
[4/7] powerpc/64s: Fix irq state management in runlatch functions
      https://git.kernel.org/powerpc/c/9524f2278f2e6925f147d9140c83f658e7a7c84f
[5/7] powerpc/64s/interrupt: masked handler debug check for previous hard disable
      https://git.kernel.org/powerpc/c/c39fb71a54f09977eba7584ef0eebb25047097c6
[6/7] powerpc/64/interrupt: avoid BUG/WARN recursion in interrupt entry
      https://git.kernel.org/powerpc/c/f7bff6e7759b1abb59334f6448f9ef3172c4c04a
[7/7] powerpc/64/irq: tidy soft-masked irq replay and improve documentation
      https://git.kernel.org/powerpc/c/1da5351f9eb9b72a7d25316b4d38bf10b6e671b1

cheers

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-10-04 14:02 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-26  5:42 [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Nicholas Piggin
2022-09-26  5:42 ` [PATCH v3 1/7] powerpc/64/interrupt: Fix false warning in context tracking due to idle state Nicholas Piggin
2022-09-26  5:43 ` [PATCH v3 2/7] powerpc/64: mark irqs hard disabled in boot paca Nicholas Piggin
2022-09-26  5:43 ` [PATCH v3 3/7] powerpc/64/interrupt: Fix return to masked context after hard-mask irq becomes pending Nicholas Piggin
2022-09-26  5:43 ` [PATCH v3 4/7] powerpc/64s: Fix irq state management in runlatch functions Nicholas Piggin
2022-09-26  5:43 ` [PATCH v3 5/7] powerpc/64s/interrupt: masked handler debug check for previous hard disable Nicholas Piggin
2022-09-26  5:43 ` [PATCH v3 6/7] powerpc/64/interrupt: avoid BUG/WARN recursion in interrupt entry Nicholas Piggin
2022-09-26  5:43 ` [PATCH v3 7/7] powerpc/64/irq: tidy soft-masked irq replay and improve documentation Nicholas Piggin
2022-10-04 13:25 ` [PATCH v3 0/7] powerpc/64: interrupt soft-mask and context fixes Michael Ellerman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.