Skip to content

HID: dockchannel-hid: write each frame to the FIFO under one lock - #1010

Merged
DjDeveloperr merged 7 commits into
integration/aurorafrom
satchlj/mtp-tx-lock-20261105
Nov 11, 2026
Merged

DjDeveloperr merged 7 commits into
integration/aurorafrom
satchlj/mtp-tx-lock-20261105

Conversation

@satchlj

@satchlj satchlj commented Nov 6, 2026

Copy link
Copy Markdown
Member

Stacked on #971 (J613 MTP live handoff); review that first.

On J613 (M3 MacBook Air, 26.6.2 firmware) the built-in keyboard and trackpad sometimes die right after boot: the adopted MTP firmware crashes about 1 s after the kernel takes over, and input stays dead until reboot.

Cause: dchid_send() writes one frame as up to four dockchannel_send() calls (header, body, tail, checksum), serialized only by the per-interface out_mutex. Two interfaces can therefore interleave frames in the shared TX FIFO. The firmware's crash log shows it:

RTKit: Message (id=1): [dock ch tl]: xsum err [comp=0xfff2ec9d; rcvd=0xc1108]

rcvd is 08 11 0c 00, the header of a 12-byte interface-enable command sitting where another frame's checksum belonged. In all three crashed boots the actuator enable (0xb4 on comm) and magicmouse's dimension query (0xd9 on multi-touch, sent as multi-touch reports ready) were in flight together.

Fix: a transport-wide lock held across all dockchannel_send() calls of one frame. dchid_send() is the only TX path.

Testing:

  • tools/asahi/mtp-tx-frame-tests.py (registered in run-host-tests.py) reproduces the interleave on the old code and passes with the fix.
  • On rubra (J613), as modules on the C13 7.2.11 kernel: 10/10 boots clean, 5 of them inside the race window (2 with the two sends fully overlapping). Before: 3 crashes, including 2 of 4 boots that hit the window.
  • Not yet run on a 7.3 J613 boot; that's next, with the rest of the stack.

@DjDeveloperr @RyanTheTide

Keep the boot loader DMA context for a running J613 MTP session. Admit
only the T8122 MTP DART at 0x2fa808000, exactly stream 1, and verify
that its control register still selects bypass before skipping reset.

Select an identity domain and reject paging, blocked-domain attachment
and runtime suspend while the inherited session runs. Retain the clock
and bypass state at removal. This permits the existing mtp-live-v1 RTKit
adoption path to keep serving input without another INIT.

The C-diag11 implementation passed owner input testing on J613 with
firmware 26.6.2. The rebased series requires a separate owner boot test.

Signed-off-by: Satya Benson <satya@benson.earth>
The J613 and J615 25G83 device trees list the MTP as "apple,t8122-mtp",
"apple,t8122-rtk-helper-asc4", "apple,mtp" without the generic
"apple,rtk-helper-asc4" fallback, and say that Linux binds the
SoC-specific compatible. The helper only matches the generic one, so on
those boards it never probes, DockChannel HID defers forever and the
built-in keyboard and trackpad stay absent.

Match "apple,t8122-rtk-helper-asc4" as well.

Signed-off-by: Satya Benson <satya@benson.earth>
Conflict in drivers/iommu/apple-dart.c, apple_dart_probe(): integration
added the v2.2 reg size check (d6b6f2e, #924) right after the
stream count check, where this branch adds the J613 live MTP bypass
check. Keep both. The size check comes first: it only needs num_streams
and validates the MMIO region before the J613 check reads a stream
control register. Both checks fail the probe, so the order only decides
which error a bad node reports.

The J613 MTP DART node has a 0x4000 reg. T8122 DARTs report a version
below 2.2: the other T8122 DARTs have the same reg size and are reset on
J613 by kernels whose reset path reads the v2.2 exception records at
0x8000, without faulting. The size check therefore does not refuse the
J613 MTP DART.
dchid_send() writes a frame as up to four dockchannel_send() calls:
header, body, tail word and checksum. Only the interface's out_mutex
serializes it, so frames for two interfaces can interleave in the shared
TX FIFO.

On J613 (M3 MacBook Air, T8122, 26.6.2 firmware) this crashes the MTP
firmware, and the internal keyboard and trackpad stay dead until reboot.
The firmware's crash log reads

  RTKit: Message (id=1): [dock ch tl]: xsum err [comp=0xfff2ec9d; rcvd=0xc1108]

rcvd holds the bytes 08 11 0c 00: the header of a 12-byte command frame,
an interface enable, where another frame's checksum belonged. In the
three crashed boots, the actuator enable (0xb4 on comm) and magicmouse's
dimension query (0xd9 on multi-touch, sent when multi-touch reports
ready) both timed out at the same moment.

Hold a transport-wide mutex across the writes of one frame. dchid_send()
is the only path that writes to the FIFO. The lock order is the
interface's out_mutex, then tx_mutex.

The host test sends frames from two interfaces in two threads through the
production dchid_send() and parses the FIFO with dchid_verify_checksum();
the driver before this change fails it.

Signed-off-by: Satya Benson <satya@benson.earth>
@satchlj

satchlj commented Nov 6, 2026

Copy link
Copy Markdown
Member Author

J613 boot result on 7.3 (rubra, M3 MacBook Air 13", macOS 26.6.2 / 25G83 firmware), 2026-11-05.

Keep only the transport-wide MTP TX frame lock and registered tests over the merged J613 handoff fix. Preserve zero-stream/J700 admission and newer DART PM handling.

Signed-off-by: DjDeveloperr <43033058+DjDeveloperr@users.noreply.github.com>
@DjDeveloperr
DjDeveloperr changed the base branch from satchlj/port-328-20261104 to integration/aurora November 11, 2026 14:46

@DjDeveloperr DjDeveloperr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codex (GPT-6.1 Sol), reviewing on @DjDeveloperr’s behalf.

No blocking findings in the rebased lock-only change. Latest #971 is now merged; this head targets integration/aurora and its net delta is only dockchannel-HID, the existing concurrent-frame regression harness and its runner entry. The stale DART handoff implementation was not reintroduced. A transport-wide mutex covers the complete frame helper and releases on error via its wrapper; initialization precedes interface setup. Existing production-code positive and real old-code negative controls passed locally, including 40+40 concurrent frames. Fresh broad host CI is required before merge: retargeting emits edited and did not trigger host-tests, so I dispatched the workflow once on this exact branch. Source/Rust/KUnit CI also runs. Repeated startup/physical input and cross-board regression remain rollout follow-ups, not fresh hardware claims from this review.

@satchlj

satchlj commented Nov 11, 2026

Copy link
Copy Markdown
Member Author

GPT-6.1 Sol on @satchlj's behalf

Exact PR head tested: 9cd563665164658e149c26502979501887c4a306.

Unattended J613/T8122, firmware 26.6.2. Kernel 7.3.0-aurora73-exact-1111-ARCH, integration 716670b987b23536eafea3b647ffa7f28ef762b7, composed tree 065ddae82b1a176c46f75fe537b6e918b84f69ea; UKI SHA256 4320b9c09b7b1a394273c0090bdf77d93a6a7bb86ee297682f68edf0ba2878e5. Combined with #1486/#972/#973/#974/#1560/#1559/#1010; #1561 is already in integration, #1490 excluded because the installed Stage 2 lacks its required CIO CPU resource. This is combined-tree evidence, not an isolated-PR kernel. Installed Stage 2 was unchanged.

The listed production-source fixture ran on J613 both on the initial 30.12 baseline and again on the exact combined trial: 40 + 40 concurrent-interface frames, all whole and checksum-valid. Both fixture inputs are byte-identical to this PR head:

  • tools/asahi/mtp-tx-frame-tests.py SHA256 aaa0d7ad1d49c37262ddc6e13413151745aac4dee13fb738867601c7a01a9f45
  • drivers/hid/dockchannel-hid/dockchannel-hid.c SHA256 e3b5e27f9f3e9c9d9359b388378a60acdf21dad99c5adcbcbbdc10e9f171329f

This compiles/exercises production functions against the fixture FIFO; it is not a hardware FIFO trace. Trial boot and three RTC s2idle cycles had keyboard/multi-touch evdev nodes and no MTP/checksum crash diagnostics. The RTC loop's SSH stdout transport was lost, but all three completed sleeps were recovered from the durable kernel journal; the post-cycle device inventory is saved.

Not run: the old-transport negative control, repeated cold-boot race-window campaign/instrumentation, or physical typing/trackpad interaction. Left on default 30.12, trial cleaned and lease released.

@DjDeveloperr
DjDeveloperr merged commit 727f6fc into integration/aurora Nov 11, 2026
6 of 11 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