Skip to content

drm/apple: don't latch ->crashed when the poweroff clear swap times out - #2

Open
Chromatischer wants to merge 1 commit into
aurora-wipfrom
fix/dcp-clear-swap-timeout
Open

Chromatischer wants to merge 1 commit into
aurora-wipfrom
fix/dcp-clear-swap-timeout

Conversation

@Chromatischer

@Chromatischer Chromatischer commented Sep 17, 2026

Copy link
Copy Markdown
Owner

One unplug of a Type-C display kills that output until reboot. This is the -EINVAL-after-replug from aurora-silicon#2 on J416c. It is not possible_crtcs.

iomfb_poweroff() waits 50 ms for a clear swap. On unplug the display is already gone and the firmware swallows it:

IOMFB: swap_submit_dcp: swallowed swap ID 1348 as fControllerPowerState is 0 for External Display

so the completion misses its window and iomfb_template.c:939 sets dcp->crashed = true, silently. dcp_crtc_atomic_check() then rejects every later commit on that CRTC. The replug still trains the link and reads a 256-byte EDID and 31 modes, so the connector reads connected while the screen stays dark and the compositor gives up after 141 rejected commits. Nothing is logged — the other assignment, dcp_rtk_crashed(), prints "DCP has crashed"; this one prints nothing.

Warn instead. A real firmware crash still arrives through dcp_rtk_crashed().

The early return is load-bearing. Continuing into iomfb_abort_swaps_dcp() and setPowerState(0) was built and tested first — for a display that is already gone the dptx HPD deassert then fails with -110, the next plug never asserts HPD, and the display does not come back at all.

Tested on J313 (M1 MacBook Air, t8103), USB-C to HDMI adapter, LG 4K at 3840x2160@30: plug, unplug, replug and suspend/resume all bring the display back. Rejected atomic commits 141 → 0.

iomfb_poweroff() submits a clear swap and waits 50 ms for it. When the
display is a Type-C output that has already been unplugged, the firmware
has nothing left to swap to and swallows the request:

  IOMFB: swap_submit_dcp: swallowed swap ID 1348 as
  fControllerPowerState is 0 for External Display

The completion misses its window, the wait times out, and ->crashed is
set with nothing logged. dcp_crtc_atomic_check() then returns -EINVAL
for every commit on that CRTC, so the next plug trains the link, reads a
256-byte EDID and a full mode list, and reports the connector as
connected -- while the screen stays dark. The compositor walks every
mode down to 640x480, has each one rejected, and gives up. Only a reboot
clears it.

One unplug is enough to reach that state. The DCP has not crashed: a
real firmware crash arrives through dcp_rtk_crashed(), which sets the
same flag and says so. A swallowed clear swap on the way down is the
ordinary unplug.

Warn instead, and keep the early return. Carrying on into
iomfb_abort_swaps_dcp() and setPowerState(0) leaves less state behind
and matches what the setPowerState(0) wait further down already does on
its own timeout, so it was tried first -- but for a display that is
already gone it is worse. The dptx HPD deassert then fails:

  apple-dcp 271c00000.dcp: failed to deassert Type-C DPTX HPD: -110

and the next plug borrows the route and reports connected=0 without ever
asserting HPD, so the display does not come back at all. The early
return is load-bearing.

Tested on J313 (M1 MacBook Air, t8103) with a Type-C to HDMI adapter.
Plug, unplug, replug and suspend/resume all bring the display back;
before, one unplug left it enumerated but unusable for the rest of the
boot.

Signed-off-by: Chromatischer <dominik@hildania.de>
Assisted-by: Claude:claude-opus-5
@Chromatischer
Chromatischer force-pushed the fix/dcp-clear-swap-timeout branch from 6060a10 to c1e902d Compare September 17, 2026 13:47
@greptile-apps

greptile-apps Bot commented Sep 17, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

The PR is not yet safe to merge because an undifferentiated poweroff timeout can now leave a silently wedged DCP marked healthy.

Findings

  1. P1 Silent wedges remain healthy
  2. P2 Normal unplug emits warnings
Summary

This PR stops permanently marking an Apple DCP as crashed when its poweroff clear swap times out, allowing an unplugged Type-C display to work after replug.

  • Preserves the existing early return that avoids a failing HPD teardown.
  • Adds a warning for an unacknowledged clear swap.
  • Also removes the timeout-based crash latch for indistinguishable silent firmware wedges, which requires further handling.

Reviews (1) · Last reviewed commit: "drm: apple: don't latch ->crashed when t..."

Comment on lines +939 to +947
/*
* An unplugged display leaves this swap unacknowledged. That
* is not a crash, and ->crashed rejects every later commit on
* this CRTC until reboot. Return rather than continuing the
* teardown: that path fails the dptx HPD deassert and the
* display never comes back.
*/
dev_warn(dcp->dev,
"poweroff: clear swap did not complete in 50 ms\n");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Silent wedges remain healthy

A clear-swap timeout can also occur when the DCP silently stops responding. RTKit only calls dcp_rtk_crashed() after an explicit crashlog message, so a silent wedge does not set dcp->crashed. This change treats every timeout as benign, allowing later atomic checks and readiness waits to keep sending work to unresponsive firmware instead of failing fast, which can cause repeated command timeouts. Only suppress the crash latch when the timeout can be attributed to a disconnected output.

Comment on lines +946 to +947
dev_warn(dcp->dev,
"poweroff: clear swap did not complete in 50 ms\n");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Normal unplug emits warnings

This branch is described as an expected result of routinely unplugging an external display, but it emits an unconditional warning each time. That makes normal hot-unplug activity look like a driver fault and adds avoidable kernel-log noise. Use an informational or debug-level message, or rate-limit the diagnostic.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant