Skip to content

drm/apple: use the 14.7 swap_start layout in the classic template - #327

Merged
chriskearney merged 1 commit into
omacom:integration/aurorafrom
scottjones:pr/t8122-dcpext-swap-start-layout
Nov 2, 2026
Merged

chriskearney merged 1 commit into
omacom:integration/aurorafrom
scottjones:pr/t8122-dcpext-swap-start-layout

Conversation

@scottjones

@scottjones scottjones commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

An M3 Air with the external display opt-in on gets no picture, even with #316 fixing its DMA windows. The mode set succeeds, then every swap is dropped with swap_start was rejected.

On the J613's external processor, swap_start's reply is eight bytes, the swap ID and a status. The classic template still expected 24, with the status at the end. Since framebuffer retention (c6cec21), replies are filled with 0xff first and the status is checked, so the template read 0xffffffff from bytes the firmware never wrote. The tree where external display first worked on a J613 (a372a72) didn't have that check.

-#if DCP_FW_VER >= DCP_FW_VERSION(26, 0, 0)
+#if DCP_FW_VER >= DCP_FW_VERSION(26, 0, 0) || DCP_FW_LAYOUT_14_7(DCP_FW_VER)
 struct dcp_swap_start_req { u32 swap_id; u64 client; u8 client_null; u8 padding[3]; };
 struct dcp_swap_start_resp { u32 swap_id; u32 ret; };

This also shrinks the request to 16 bytes, matching the native 14.7 path. On an M3 Air it only matters with chosen.asahi,t8122-dcpext=1, which stays off by default. Depends on #316 for a picture: without it the internal display faults with the opt-in on.

Evidence

J613, encrypted, firmware 14.7, m1n1 aurora22, opt-in on, #316 underneath, LG 4K on USB-C.

  • Before: swap_start was rejected on every swap, 1,169 times in one boot (lab job j1102-001943-748d). No faults, no picture at 3840x2160 or 1920x1080.
  • The reply, with the fill changed to 0xa5: 00000001 00000000 a5a5a5a5 a5a5a5a5 a5a5a5a5 a5a5a5a5: swap ID, status 0, unwritten.
  • After, unattended:
    • 10 minutes of load on the external display at about 29 swaps a second: 18,276 submits, 18,276 completions, none unpaired, no aborts, no faults.
    • DPMS on the external display and on both together, 3 cycles each: no clear swap timed out, no scanout stop was not confirmed.
    • Hyprland monitor disable and enable, 3 cycles: swaps resumed each time.
    • The lab's device suspend test passed.
  • After, by hand, 20 minutes:
    • A picture on both screens at boot, with the monitor on the front left port.
    • Replugged back and forth between both left ports, with a picture each time.
    • A YouTube video on the monitor, framebuffers steady at 14.
    • s2idle from the menu, with both screens back on wake. It woke by itself after about 4 seconds, probably from USB-C, so a longer sleep isn't tested.
    • No rejected DMA windows, DART faults or crashes in the whole boot.

Our test kernel also carried a framebuffer-leak fix for the panel, the same as #325. It doesn't touch this path. It also carried a TEST ONLY line adding apple,dma-range to the gate; not part of this PR.

Please check: dcp.c also sends generic M1/M2 DCPs to this template when m1n1 reports firmware 14.7.0. Standard M1/M2 installs use 13.5, so this only reaches non-standard M1/M2 installs on 14.x system firmware. On those, it's inferred and untested: they've likely been refusing every swap since retention, and this would fix them, but if their firmware still uses the old 24-byte layout, this breaks them instead.

Not tested: J615 (we don't have one).

Merge Danger

Door: two-way.

Blast Radius: small. DCPs on the classic template with firmware 14.7.0, which m1n1 also reports on 14.8.3 installs. That's the M3 Air's external display (opt-in only), and M1/M2 only on non-standard 14.x installs.

🤖 Generated with Claude Code

On a J613's external processor, swap_start's reply is eight bytes, the
swap ID and a status, as the native 14.7 path and the 26.x template read
it. The classic template's 14.7 instance still expected 24, with the status
at the end.

That didn't matter until "drm: apple: retain displaced framebuffers until
confirmed completion" began checking the status and filling replies with
0xff first. The firmware doesn't write that far, so the template read
0xffffffff and refused every swap: the mode set succeeds, and the display
stays dark. A dump of the reply, with the fill changed, shows the swap ID,
a status of 0, then the bytes it left alone.

Use the 0x10-byte request and 8-byte reply for this template instance, as
those paths do. Any other DCP on 14.7.0 firmware also uses this instance:
we have no way to test one.

Fixes: 98d767e ("drm/apple, media: apple: avd: T6030 internal panel, external display and AVD fixes")
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Scott Jones <scottajones@gmail.com>

@chriskearney chriskearney left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed caaef21. No source blockers; merge with or after #316.

The change consistently moves classic 14.7 swap_start to a 16-byte request and eight-byte response, with status at +4. Both normal-present and clear-swap callbacks use that layout. The builders zero-initialize their requests, and the contract matches native 14.7's four-u32 request/two-u32 response. Separating set_power_state preserves its existing layout for every firmware instance.

Our host-only size/offset control on the extracted header confirmed that only classic 14.7 changes: 12.3/13.5 and H17P are unchanged, including their power-state requests. CI 41461774567 passed compilation, KUnit, packaging and boot checks. No KUnit case directly verifies this firmware exchange, and we did not perform a local kernel build or hardware boot.

I also inspected the retained J613 test logs: the earlier stack records 1,169 rejected swaps; la325 records 18,293 submits/18,292 completions, no unpaired swaps or aborts, and successful DPMS/monitor cycling. These are instrumented superset kernels containing #316, the gate-property shim and a framebuffer-retention fix, not an exact-head boot of this PR. Retained screenshots were absent; picture/replug/video and real s2idle remain the author's observations. The automated suspend check was pm_test=devices. The overall jobs remained tests_failed because of the custom kernel's repository-update check; I am not calling them full-suite passes.

The M1/M2 caveat in the body is appropriate: standard installs use 13.5; generic DCPs on non-standard stubs reporting 14.7.0 also reach this template, and their ABI remains inferred rather than hardware-qualified. m1n1's shared iBoot identifier also makes 14.8.3 report 14.7.0. Our native-path M3 Pro coverage does not qualify this classic path. J615 remains untested.

@chriskearney
chriskearney added this pull request to the merge queue Nov 2, 2026
Merged via the queue into omacom:integration/aurora with commit 2a76ae3 Nov 2, 2026
14 checks passed
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.

2 participants