Skip to content

[SL7 Intel] s2idle hangs indefinitely in dw8250_suspend on the SAM UART - soft lockup, free_irq never completes #2263

Description

@walkingchimp

[SL7 Intel] s2idle hangs indefinitely in dw8250_suspend on the SAM UART — soft lockup, free_irq never completes

Surface Laptop 7 for Business (Intel, Lunar Lake). I think I've found the cause of the intermittent "closes lid, never wakes, battery flat" failures on this machine, and it isn't any of the usual suspects. Posting the evidence in case it's useful to others here and to see whether anyone recognises a fix.

Summary: suspend hangs in dw8250_suspend on ttyS4 — the DesignWare UART that carries the Surface Aggregator Module. free_irq() waits in __synchronize_hardirq() for the UART interrupt handler to go idle, and it never does, because IRQ 16 is storming. The result is a soft lockup with a CPU pinned for as long as the machine is left closed.

Environment

Hardware      Microsoft Corporation / Surface Laptop for Business 7th Edition with Intel
BIOS          17.101.143 (2025-11-19)
Kernel        6.19.8-surface-3 (linux-image-surface 6.19.8-surface-3)
SAM firmware  11.103.139
Distro        Ubuntu 26.04
cmdline       ... quiet splash acpi_mask_gpe=0xAB crashkernel=...
Sleep state   s2idle (no S3 on this platform)

The hang

watchdog: BUG: soft lockup - CPU#1 stuck for 33170s! [systemd-sleep:13024]

33,170 s — 9.2 hours, i.e. the entire time the lid was closed. Trace:

CPU: 1 UID: 0 PID: 13024 Comm: systemd-sleep  6.19.8-surface-3 #3 PREEMPT(voluntary)
RIP: 0010:_raw_spin_unlock_irqrestore+0x21/0x60
Call Trace:
 <TASK>
 __synchronize_hardirq+0x94/0xd0
 __synchronize_irq+0x2b/0xb0
 free_irq+0x11e/0x2f0
 univ8250_release_irq+0xd8/0xe0
 serial8250_do_shutdown+0x1eb/0x340
 serial8250_shutdown+0x26/0x30
 uart_suspend_port+0x291/0x480
 serial8250_suspend_port+0x4f/0xb0
 dw8250_suspend+0x14/0x20 [8250_dw]
 platform_pm_suspend+0x2b/0x70
 dpm_run_callback+0x93/0x200
 device_suspend+0x18a/0x650
 dpm_suspend+0x1c7/0x3a0
 dpm_suspend_start+0x6c/0x80
 suspend_devices_and_enter+0x177/0xa10
 pm_suspend+0x224/0x5b0
 state_store+0x85/0xf0
 ...
 entry_SYSCALL_64_after_hwframe+0x76/0x7e

The port is the SAM transport

Serial: 8250/16550 driver, 32 ports, IRQ sharing enabled
dw-apb-uart.4: ttyS4 at MMIO 0x202c004000 (irq = 16, base_baud = 6250000) is a 16550A
serial serial0: tty port ttyS4 registered
surface_serial_hub serial0-0: SAM firmware version: 11.103.139

So ttyS4 = dw-apb-uart.4 = serial0 = the MSHW0551 hub carrying keyboard and touchpad. This is why the hang is unrecoverable rather than merely annoying - the input transport is the thing that's wedged.

Why free_irq never returns: IRQ 16 is storming

 16:  0  0  0  0  1561055591  0  0  0  IR-IO-APIC  16-fasteoi  idma64.4, ttyS4

1,561,055,591 interrupts in 19.4 h of uptime — ~22,500/s average, and 17× more than the system timer (LOC = 91,043,998). All on a single CPU. IRQ 16 is shared between idma64.4 and ttyS4.

With the line permanently active, __synchronize_hardirq() can never observe the handler idle, so free_irq() spins forever and dw8250_suspend never returns.

The storm is episodic, not continuous — sampling /proc/interrupts while idle often shows 0/s. That matches the failure being intermittent: over ~3 months I have 33 suspends that never resumed, interleaved with many that worked fine. Anything
evaluated over a handful of suspend cycles can therefore look like a fix by luck; I wasted a fair amount of time on that.

Corroboration: the SAM RX parser sees garbage at the same instant

Sep 01 08:21:03 surface_serial_hub serial0-0: rx: parser: invalid start of frame, skipping
Sep 01 08:21:03 surface_serial_hub serial0-0: rx: parser: invalid payload CRC
Sep 01 08:21:03 surface_serial_hub serial0-0: rx: parser: invalid start of frame, skipping

Same timestamp as the lockup. The UART is delivering junk into the SAM frame parser, which is consistent with a bogus RX-timeout interrupt condition rather than real traffic.

Things I ruled out first, in case it saves anyone else the effort

  • Zombie EVDI devices (DisplayLink). Four phantom DRM cards were being created at boot via /etc/modules-load.d/evdi.conf + initial_device_count=4. Removing them was worth doing, but did not fix the hangs.
  • GPE 0xAB. acpi_mask_gpe=0xAB is applied and effective (ACPI: Masking GPE 0xab., counter reads 0 enabled masked), yet \_GPE._LAB still storms (Could not resolve symbol [\_GPE._LAB.SLAB], AE_NOT_FOUND). Necessary but not sufficient, and not this bug.
  • Bluetooth. A sleep hook here unloaded btintel_pcie on suspend; the crash-time module list reads [last unloaded: btintel]. That makes Bluetooth appear to crash (the post hook never runs, so it stays unloaded until reboot) but it is a consequence of the hang, not a cause. Removing the hook changed nothing about the hangs.
  • pm_trace. ⚠️ Warning to others: arming /sys/power/pm_trace on this machine makes suspend impossible. It writes its hash to the RTC and that itself generates an immediate wake, so every attempt bounces straight back out with PM: Some devices failed to suspend, or early wake event detected. It corrupted my RTC to 2036 and cost a flat battery. Use pm_debug_messages instead.
  • Hibernation. Worth masking hibernate.target / hybrid-sleep.target here:
    /sys/power/resume is 0:0 and swap is an 8 G file against 30 GiB RAM, so a failed s2idle escalating to hibernate produces a second, guaranteed hang.

How to check whether you're affected

grep -E '^\s*16:' /proc/interrupts          # or whichever IRQ lists ttyS4

A count in the hundreds of millions means the storm has been running. To get a live rate, sample twice a few seconds apart. If it's high, don't trust suspend.

Questions

  1. Does anyone recognise this as the known DesignWare bogus RX-timeout condition (cf. serial: 8250_dw: Avoid "too much work" from bogus rx timeout interrupt)?
    Is that mitigation present in 6.19, and if not would it apply here?
  2. idma64.4 shares IRQ 16 with ttyS4. Is the storm plausibly the DMA side rather than the UART? Is there a way to run the SAM UART without DMA to test that?
  3. Is there a reason uart_suspend_port() needs to free_irq() at all on a port whose device must stay alive across s2idle — or would IRQF_NO_SUSPEND / keeping the IRQ registered be viable for the SAM port specifically?

Happy to test patches. Full dmesg from the affected boot and the previous boot are attached.

Activity

  1. Majsvaffla commented on Sep 14, 2026

    @Majsvaffla

    I can confirm this bug too as I've been debugging the "hanging suspends" for the last couple of months.

    On my machine the SAM transport is ttyS0 on IRQ 16, shared with idma64.3. Same structure, same failure mode.

    Environment

    Hardware      Microsoft / Surface Laptop for Business 7th Edition with Intel
    BIOS          22.112.143 (2025-12-24)
    Kernel        6.19.8
    Distro        NixOS 26.05
    Sleep state   s2idle (no S3)
    

    The storm, caught mid-simmer. Three /proc/interrupts samples a few seconds apart while the machine sat idle:

    16: ... 494529 ... IR-IO-APIC 16-fasteoi idma64.3, ttyS0
    16: ... 496011 ...
    16: ... 496201 ...
    

    ~200–300/s at rest here — low, but nonzero and climbing. Matches your "episodic, often 0/s while idle" observation; I take this to be a quiet phase between spikes rather than the storm being absent.

    Same RX-parser garbage. My failed-wake incidents show the SAM parser choking at the moment of the hang, identical to yours:

    surface_serial_hub serial0-0: rx: parser: invalid start of frame, skipping
    surface_serial_hub serial0-0: rx: parser: invalid payload CRC
    surface_serial_hub serial0-0: rx: parser: invalid start of frame, skipping
    

    Symptom profile matches, including the intermittency and both failure faces: most suspends are fine and sip power; occasionally one hangs with the lid closed and drains the battery flat, unrecoverable except by a forced power-off. I'd previously misattributed this to a platform/SoC s2idle-exit problem and to Thunderbolt wake-source arming — chased the latter for a while and it looked fixed until it wasn't, exactly as you warn about evaluating over too few cycles.

    Also reproduces on firmware newer than the fix would need to be: your BIOS (17.101.143, 2025-11) and SAM firmware (11.103.139) are both newer than mine and you still hang, so a firmware update doesn't look like a fix. Noting this so others don't treat it as one.

    On your questions — I don't have the depth to answer 1–3 authoritatively, but the mainline "8250_dw: Avoid 'too much work' from bogus rx timeout interrupt" mitigation in question 1 looks like the most promising lead; if someone can confirm whether it's in 6.19 and applies to the SAM port, I'm glad to test. I'm happy to run patches or capture any additional logs 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions