Re: [PATCH] powerpc/entry: Use hard_irq_disable() in arch_interrupt_exit_prepare()
Shrikanth Hegde <[email protected]>
| Newsgroups | org.ozlabs.lists.linuxppc-dev,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 8/12/26 8:50 PM, Mukesh Kumar Chaurasiya (IBM) wrote:
> commit 334f3f6d7a16 ("powerpc/entry: Disable interrupts before irqentry_exit")
> fixed a BUG in preempt_schedule_irq() by calling local_irq_disable()
> unconditionally in arch_interrupt_exit_prepare() before irqentry_exit().
> The fix is correct in intent but uses the wrong primitive for PPC64.
>
> On PPC64, local_irq_disable() only sets the soft-mask
> (irq_soft_mask = IRQS_DISABLED). It does not set PACA_IRQ_HARD_DIS in
> irq_happened and does not clear MSR[EE].
>
> This causes a continuous WARN_ON boot hang on Power11 pSeries LPARs
> using the dedicated-cede cpuidle path. When the CPU wakes from H_CEDE,
> interrupt_exit_kernel_prepare() calls replay_soft_interrupts(), which
> dispatches pending async handlers (timer_interrupt, do_IRQ) using the
> DEFINE_INTERRUPT_HANDLER_ASYNC macro. That macro calls
> arch_interrupt_async_exit_prepare() -> arch_interrupt_exit_prepare()
> before irqentry_exit(). With local_irq_disable(), PACA_IRQ_HARD_DIS
> is not set, but next_interrupt() unconditionally asserts it:
>
> WARN_ON(!(local_paca->irq_happened & PACA_IRQ_HARD_DIS));
>
> This fires on every replayed interrupt, looping indefinitely and
> preventing boot completion.
>
> Fix this by replacing local_irq_disable() with hard_irq_disable().
> On PPC64, hard_irq_disable() sets irq_soft_mask to IRQS_ALL_DISABLED,
> sets PACA_IRQ_HARD_DIS in irq_happened, and clears MSR[EE] — satisfying
> all of:
>
> - lockdep_assert_irqs_disabled() in irqentry_exit_to_kernel_mode()
> - next_interrupt()'s WARN_ON(!(irq_happened & PACA_IRQ_HARD_DIS))
> - preempt_schedule_irq()'s BUG_ON(!irqs_disabled())
>
> On PPC32/non-64, hard_irq_disable() is equivalent to local_irq_disable(),
> so there is no regression on those platforms.
>
This is good explanation, but what i not understanding is,
why pattern of setting PACA_IRQ_HARD_DIS changed?
Previous code at interrupt_exit_kernel_prepare which did local_irq_disable too.
Please check where was PACA_IRQ_HARD_DIS set without GENERIC_ENTRY which was preventing
this from happening?
> Fixes: 334f3f6d7a16 ("powerpc/entry: Disable interrupts before irqentry_exit")
> Reported-by: Venkat Rao Bagalkote <[email protected]>
> Closes: https://lore.kernel.org/all/[email protected]/
> Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <[email protected]>
> ---
> arch/powerpc/include/asm/entry-common.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/powerpc/include/asm/entry-common.h b/arch/powerpc/include/asm/entry-common.h
> index c5adb5006361..de64389b0815 100644
> --- a/arch/powerpc/include/asm/entry-common.h
> +++ b/arch/powerpc/include/asm/entry-common.h
> @@ -270,7 +270,7 @@ static inline void arch_interrupt_exit_prepare(struct pt_regs *regs)
> }
>
> /* irqentry_exit expects to be called with interrupts disabled */
> - local_irq_disable();
> + hard_irq_disable();
> }
>
> static inline void arch_interrupt_async_enter_prepare(struct pt_regs *regs)