Re: [PATCH 1/6] irq_work: Re-raise pending irq_work after system resume
From: Adrian Hunter
Date: Tue Nov 03 2026 - 12:35:18 EST
On 02/11/2026 18:39, Sebastian Andrzej Siewior wrote:
> On 2026-11-02 12:54:22 [+0200], Adrian Hunter wrote:
>>
>> Yes CPUs remain online for suspend2idle, but currently the choice between
>> suspend2idle and "deep" (S3) suspend is a user space choice,
>> refer /sys/power/mem_sleep. Many modern systems do not support S3
>> anymore, but it has not gone away.
>>
>>>
>>> Anyway, I'm torn; I would much rather make this trigger a WARN and have
>>
>> AI now also identifies ftrace, BPF, GHES NMI, and #MC as possible causes,
>> not just perf. I haven't tried to confirm any of those.
>>
>> And, belatedly, AI is now saying an irq_work raised before lapic_resume()
>> might result in #GP if the APIC is left in xAPIC mode at resume. Also
>> not confirmed.
>
> Could we flush this before similarly to what happens during CPU-hotplug.
> The question is if this event can stay enqueued during suspend (and
> handled on resume) or should be taken care before entering suspend.
WRT "might result in #GP if the APIC is left in xAPIC mode at resume",
the systems I have checked restore the APIC in x2APIC mode, so the
issue is theoretical at this point, although I can get "unchecked MSR
access error: WRMSR to 0x83f" if I deliberately add code to change
x2APIC to xAPIC early in S3 wake (in x86_acpi_suspend_lowlevel()),
and then do:
perf record -e power:suspend_resume --filter 'action == "machine_suspend" && start == 0' --no-buffering -C 0 -o /tmp/x.data &
rtcwake -m mem -s 10
The error can be avoided with:
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 08c9aa176c33..41f93586f22c 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -63,6 +63,7 @@ extern int apic_verbosity;
extern int local_apic_timer_c2_ok;
extern bool apic_is_disabled;
+extern bool lapic_suspended;
extern unsigned int lapic_timer_period;
extern enum apic_intr_mode_id apic_intr_mode;
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 40fa7bc7fb97..187cbfad0d76 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -2385,6 +2385,8 @@ void __init up_late_init(void)
}
#endif
+bool lapic_suspended;
+
/*
* Power management
*/
@@ -2454,6 +2456,8 @@ static int lapic_suspend(void *data)
*/
mask_ioapic_entries();
+ WRITE_ONCE(lapic_suspended, true);
+
disable_local_APIC();
irq_remapping_disable();
@@ -2534,6 +2538,8 @@ static void lapic_resume(void *data)
irq_remapping_reenable(x2apic_mode);
+ WRITE_ONCE(lapic_suspended, false);
+
local_irq_restore(flags);
}
diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c
index 308c62411ff4..32386b7cf84e 100644
--- a/arch/x86/kernel/irq_work.c
+++ b/arch/x86/kernel/irq_work.c
@@ -25,7 +25,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_irq_work)
void arch_irq_work_raise(void)
{
- if (!arch_irq_work_has_interrupt())
+ if (!arch_irq_work_has_interrupt() || READ_ONCE(lapic_suspended))
return;
__apic_send_IPI_self(IRQ_WORK_VECTOR);