From: "Mukesh Kumar Chaurasiya (IBM)" <mkchauras@gmail.com>
To: maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com,
chleroy@kernel.org, sshegde@linux.ibm.com,
mchauras@linux.ibm.com, mkchauras@gmail.com,
linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org
Cc: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Subject: [PATCH V2] powerpc/entry: Fix irq_soft_mask corruption on replayed interrupt exit
Date: Thu, 20 Aug 2026 19:17:18 +0530 [thread overview]
Message-ID: <20260820134718.2176411-1-mkchauras@gmail.com> (raw)
When __replay_soft_interrupts() replays a pending interrupt (e.g.
PACA_IRQ_DEC → timer_interrupt), it calls the handler directly with a
synthetic pt_regs. The DEFINE_INTERRUPT_HANDLER_ASYNC wrapper around
each handler calls arch_interrupt_async_exit_prepare() on the way out,
which calls arch_interrupt_exit_prepare() → local_irq_disable() →
arch_local_irq_disable(), which does:
irq_soft_mask_set(IRQS_DISABLED) /* 0x1 */
This unconditionally overwrites irq_soft_mask with IRQS_DISABLED (0x1),
stripping the IRQS_PMI_DISABLED (0x2) bit. The result is that
irq_soft_mask is 0x1 instead of IRQS_ALL_DISABLED (0x3) when the
handler returns to __replay_soft_interrupts().
For a normally-taken interrupt this is harmless: the next interrupt
always enters through arch_interrupt_enter_prepare() which
unconditionally sets irq_soft_mask to IRQS_ALL_DISABLED.
But during replay, next_interrupt() is called
directly between replayed handlers without going back through
arch_interrupt_enter_prepare(), so the stripped bit is never restored.
next_interrupt() then fires a WARNING:
WARNING: arch/powerpc/kernel/irq_64.c:75
WARN_ON(irq_soft_mask_return() != IRQS_ALL_DISABLED)
This was introduced by commit bee25f97ad24 ("powerpc: Enable
GENERIC_ENTRY feature"). Before that commit, the old
interrupt_async_exit_prepare() called irq_exit() followed by an empty
interrupt_exit_prepare() stub and never touched irq_soft_mask at all,
so the soft mask was left at IRQS_ALL_DISABLED throughout replay.
The root cause: arch_interrupt_exit_prepare() uses local_irq_disable()
whose only job is to set the IRQS_DISABLED bit; it has no knowledge of
IRQS_PMI_DISABLED. It is there to satisfy irqentry_exit()'s
requirement that interrupts be disabled, but using the plain
irq_soft_mask_set(IRQS_ALL_DISABLED) is the right primitive:
- irq_soft_mask_set(IRQS_ALL_DISABLED): sets soft mask to 0x3
(both IRQS_DISABLED and IRQS_PMI_DISABLED). Touches only the soft
mask. MSR[EE] and PACA_IRQ_HARD_DIS are already correct because
hard interrupts were never re-enabled during replay
(PACA_IRQ_REPLAYING is in PACA_IRQ_MUST_HARD_MASK, which blocks
should_hard_irq_enable()).
- local_irq_disable() / arch_local_irq_disable(): sets soft mask to
IRQS_DISABLED (0x1) only, silently dropping IRQS_PMI_DISABLED.
- hard_irq_disable(): also issues __mtmsrd to clear MSR[EE] in
hardware and sets PACA_IRQ_HARD_DIS — redundant and wrong here
since both are already set.
Fix by replacing local_irq_disable() with irq_soft_mask_set(IRQS_ALL_DISABLED)
in arch_interrupt_exit_prepare(), making the exit symmetric with the
entry path in arch_interrupt_enter_prepare() which always sets
IRQS_ALL_DISABLED.
The warning was observed early in boot on a POWER10 pseries guest
during kmem_cache_init_late(), where a spinlock release triggers
interrupt replay that processes a pending timer interrupt.
Debugger state confirming the bug:
Before timer_interrupt(®s):
irq_soft_mask = 0x3 (IRQS_ALL_DISABLED) correct
irq_happened = 0x41 (HARD_DIS|REPLAYING) correct
After timer_interrupt(®s) returns:
irq_soft_mask = 0x1 (IRQS_DISABLED) WRONG — PMI bit stripped
irq_happened = 0x41 unchanged
Fixes: 334f3f6d7a16 ("powerpc/entry: Disable interrupts before irqentry_exit")
Reported-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Closes: https://lore.kernel.org/all/6f9bfb0f-b14c-468e-bb9f-c157d120d0dc@linux.ibm.com/
Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
---
Change log:
V1 -> V2:
- Instead of using hard_irq_disable use irq_soft_mask_set
V1: https://lore.kernel.org/all/20260812152035.1661781-1-mkchauras@gmail.com
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..2a153dca962c 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();
+ irq_soft_mask_set(IRQS_ALL_DISABLED);
}
static inline void arch_interrupt_async_enter_prepare(struct pt_regs *regs)
--
2.55.0
next reply other threads:[~2026-08-20 13:47 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-20 13:47 Mukesh Kumar Chaurasiya (IBM) [this message]
2026-08-20 14:47 ` [PATCH V2] powerpc/entry: Fix irq_soft_mask corruption on replayed interrupt exit Shrikanth Hegde
2026-08-20 16:06 ` Venkat Rao Bagalkote
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260820134718.2176411-1-mkchauras@gmail.com \
--to=mkchauras@gmail.com \
--cc=chleroy@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=maddy@linux.ibm.com \
--cc=mchauras@linux.ibm.com \
--cc=mpe@ellerman.id.au \
--cc=npiggin@gmail.com \
--cc=sshegde@linux.ibm.com \
--cc=venkat88@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.