Skip to content
This repository was archived by the owner on Nov 8, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions mseries/OS9-HANDOFF.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## Dock monitor dark on wip3: dcpext1 DPTX stall, wip4 draft patch — 2026-10-22 (Claude Code)

Owner plugged the WD22TB4 on the running wip3 trial kernel; no picture. Dock USB/Thunderbolt fine; `28cc00000` (dcpext1) never
answered `validate DPTX target` (six attempts), its release then timed out too, and replugging the same port failed again
(`DP tunnel setup failed: -110`). Moving the dock to another USB-C port routed it to `289c00000` and gave 1080p/60 at once.
Full timeline, what is and is not shown: `mseries/aurora/hardware-tests/2026-10-22-j314s-wip3-dcpext1-dptx-wedge.md`.

- **Cause (partly shown).** The pinned source keeps a Thunderbolt route owned when its release is refused; a timeout is
treated as a refusal, so the port stays on the dead pipeline. Why `28cc00000` was picked first and why it went silent: not shown.
- **Draft.** wip4 candidate (`unified72/series.json` revision 5, `patches/0002-...`). Build-only: patch applies on the pinned
files, routing logic exercised in userspace; kernel build, KUnit and every boot are open. wip3 untouched, nothing staged.
- **Workaround on wip3.** Use a different USB-C port; reboot clears a pinned port.
- **Side note.** Audio blips on dock plug/unplug coincide with `mseries-power` re-applying the CPU profile on each AC flip; one logged
ALSA underrun at the first plug. Not investigated further.
- **Next.** CI native build of the PR, then owner decides on unarmed staging; design the same-plug re-request on the Thunderbolt side.

## Bounded Aurora CI dependency downloads — 2026-10-22

The unified72 check spent 47m17s fetching 144 MB from the Azure Ubuntu
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# J314S wip3: first dock plug lands on a silent dcpext1 — 2026-10-22

Diagnosis by Claude Code on the owner's J314S (MacBook Pro 14-inch, M1 Pro), running the trial kernel
`7.2.11-elementary-aurora72-wip3` (up since 2026-10-21 16:42 EDT; `apple_sep.xart_guard=0`), with the Dell WD22TB4.
Owner report: the dock's monitor did not come on. The diagnosis changed nothing on the host. Times are EDT on 2026-10-22.

## Result

The dock's Thunderbolt link, USB hubs, Ethernet and HID all came up. The DisplayPort side did not, and could not be
recovered by replugging into the same port. It worked at once on a different port. The fix drafted for it
(`unified72/patches/0002-...`) is **build-only and unproven**: nothing here was compiled into a kernel or booted.

## Timeline

| Time | Event |
| --- | --- |
| 07:04:23 | `mseries-power` runs (AC arrived); `38bc` (panel) power-cycles; `289c00000` logs `dcp_dptx_disconnect(port=0)` and `connected:0`. |
| 07:04:27.95 | Dock `thunderbolt 0-1` authorised. `28cc00000` (dcpext1): `allocated Type-C DPTX PHY 0`, `display routed to Thunderbolt DP tunnel dpin0`. |
| 07:04:29–07:04:39 | Six attempts (the first plus five retries), two seconds apart (1 s timeout, 1 s delay): `AppleDCPDPTXRemotePort (chan:1) command type 0xc0 ... timed out after 1000 ms`, `service call group 0 cmd 12 failed ... -110`, `dcp_dptx_connect: failed to validate DPTX target 0:0: -110`. Then `Type-C DPTX reconnect failed after 5 retries: -110`. |
| 07:04:40–41 | `dcp_hotplug() connected:0`; teardown: `group 8 cmd 8 failed ... -110`, `dpin0: display teardown failed: -110`. |
| 07:10:40–50 | Owner unplugs and replugs the **same** port. Dock re-enumerates on Thunderbolt. |
| 07:10:51–52 | `28cc00000` again; a `group 8 cmd 8` call times out; `dpin0: DP tunnel setup failed: -110`. 07:11:03 `0:5 <-> 1:14 (DP): not active, tearing down`. |
| 07:12:21–27 | Owner moves the dock to **another** port. `289c00000` (dcpext0): `allocated Type-C DPTX PHY 1`, `DCPDP13Service` appears in 26 ms, `connected:1`, 1920x1080@60, `card2-DP-2 connected`. |

## What the evidence supports

1. **dcpext1's DPTX RemotePort service stopped answering.** `validate` (cmd 12) timed out on all six attempts; the later
release (cmd 8, group 8) timed out too, in the same state and on the next plug. Nothing on `289c00000` timed out.
2. **The failed port stays pinned.** In `dcp_tb_release_locked()` (drivers/gpu/drm/apple/dcp-fabric.c at the pinned
source), a failing `dcp_dptx_disconnect_oob()` returns before the route is freed; the comment there says the
route "stays owned for the next request to release". A timeout is not a refusal, and the next request
(07:10:51) hit the same timeout in that same release. That matches `DP tunnel setup failed: -110` appearing
one second after `group 8 cmd 8 failed`. The port that was moved to was a different `apple_dcp_typec_port`, so
it did not inherit the stuck ownership.
3. **The kernel does not look at the other display controller.** After the failed validates nothing tried
`289c00000` for that plug.
4. **The same failure is not new in wip3's source.** `dcp.c`, `dptxep.c`, `dcp-fabric.c` and `dcp-fabric-core.c` are
unchanged between the wip2 pin (`644133b7`) and the wip3 pin (`bd526b3c`) (the first three fetched at both
refs and compared by size and by the GitHub compare file list; `dcp.c` by the compare list only); only `apple_drv.c`,
`iomfb_plane.h`, `iomfb_template.c`, `plane.c` and `plane.h` differ in `drivers/gpu/drm/apple/` (GitHub compare).
So this is not a wip3 regression in the code that decides routing or talks to the DPTX service. (It remains
possible that something outside those files changed the firmware's behaviour; not shown.)
5. **Earlier boots never hit it.** In boots −4 to −7 (wip2 and `.20-enh1`) every dock plug logged either an answer
within ~80 ms from `28cc00000` (a cold-boot plug, after which `289c00000` took over the picture) or went straight
to `289c00000`. No `failed to validate DPTX target` line exists in the kernel journal of boots −1 to −7. This boot
(wip3) had no earlier dock plug; the three wip3 boots before it ran for under an hour each and none logged a dock.

## Related

`dcpext1` is `28cc00000` (the tunnel connector, no Type-C mux in the device tree); `dcpext0` is `289c00000`
(the built-in HDMI). An earlier, different failure of the same DCP is recorded in
[`fairydust/usb4/evidence/2026-10-16-dbgboot-dcp-silent-never-configures-link.md`](../../fairydust/usb4/evidence/2026-10-16-dbgboot-dcp-silent-never-configures-link.md)
(older kernel: firmware silent after ACTIVATE, never answering `set_hpd`). Not shown to be the same cause.

## What is not shown

- **Why `28cc00000` was chosen at 07:04:27.** The candidate scorer prefers the lowest CRTC index among available
pipelines (`dcp_fabric_tunnel_candidate()`), which would be `289c00000`. Both `dcp_fabric_available()` (owned,
fixed output busy, HDMI presence not settled) and the planner (`keep_order`, another port wanting that pipeline) can
exclude it. `289c00000` logged a disconnect at 07:04:23, four seconds earlier. No verbose logging was on, so the
reason is not in the journal.
- **Why the service went silent.** Candidates: long idle since boot (14 h) of an external DCP; the 07:04:23 power
event; a firmware state left by the previous trial boots. None is tested. A reboot is expected to clear it, since
a fresh `28cc00000` answered on every earlier boot — not verified on this boot.
- **Whether this repeats.** One occurrence.

## Workaround for the running kernel

Move the dock to another USB-C port. If the port stays dark on the same port after replug, that port is pinned until
reboot (finding 2). Reboot also clears it.

## The draft patch

`unified72/patches/0002-drm-apple-free-dp-tunnel-route-from-silent-dcpext.patch`, series revision 5, candidate
`7.2.11-elementary-aurora72-wip4`:

- A DPTX call that times out marks that DCP's pipeline unresponsive for 300 s (cleared on the next connect that
gets an answer). New `dptx_holdoff` fields on `struct apple_dcp`; `unresponsive` on `struct dcp_fabric_pipeline`.
- `dcp_fabric_available()` is false for an unresponsive pipeline and `dcp_fabric_plan()` does not plan onto one,
unless a tunnel already holds it. With no other pipeline free the request returns `-EBUSY`; the Thunderbolt side
already treats that as "no display pipeline free; waiting for one" and retries every 2 s
(`apple_dpin_m1`, `capacity_retry`), so a retry lands on `289c00000` when it is free.
- `dcp_tb_release_locked()` completes a release whose firmware call timed out: it drops the DCP's connected view
(`dcp_dptx_abandon()`) and goes on to free the crossbar route, instead of keeping the route owned.

### What it fixes and what it does not

- Fixes: a port pinned to a dead pipeline until reboot (finding 2), and the next plug choosing the dead pipeline
again while it is held off.
- Does **not** move the dock to `289c00000` within the plug that already attached to the silent pipeline (the
07:04 case): the tunnel is attached before the validate runs, and the Thunderbolt driver only re-requests
on a new tunnel event. The expected result there is a dark monitor, then a working one after one replug,
instead of a port dark until reboot. Closing that gap needs the DCP to ask the Thunderbolt side for a new request
(not designed here).
- Does not explain or prevent the silence itself.

### Checked here

- The patch applies (`git apply --check`) on the exact pinned files with 0001 applied. The six file blobs were read
from GitHub at `bd526b3c`; no archive was downloaded and no full tree was built.
- The pure routing change (`dcp_fabric_available()`, `dcp_fabric_tunnel_candidate()`, `dcp_fabric_plan()`) was
compiled from the real `dcp-fabric-core.c` against stub headers and run in userspace. The scenario passes, and
four checks fail when the availability change is removed. The same scenario is added as the KUnit case
`fabric_unresponsive_pipeline_test`; KUnit itself was not run.
- `dcp.c` and `dcp-fabric.c` edits were not compiled. The `aurora-enhancements` workflow builds `unified72` on this PR.

### Acceptance before anyone arms it

Native build and KUnit pass in CI; stage unarmed beside wip3 (owner decision); then on the J314S: dock plug on each port
from a fresh boot, a plug after hours idle, and a deliberate replug on the port that failed. Look for
`DPTX service not answering`, `no display pipeline free; waiting for one` and `a display pipeline came free`. Keep
`.20` as the default and the wip3 rollback in `unified72/BOOT-TRIAL.md`.

## Side observation: audio blips on plug and unplug

Each dock plug or unplug flips AC/battery; `mseries-power` then reapplies the CPU profile (07:12:20–23: power-saver
2208 MHz caps, then balanced 3036 MHz, three runs in 3 s) and the panel DCP power-cycles. The only logged glitch is one
`snd_pcm_avail after recover: Broken pipe` on `hw:AppleJ314,1p` at 07:04:23. The dock exposes no audio device to
PipeWire. Cause not established.
19 changes: 13 additions & 6 deletions mseries/aurora/test_qualification.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,27 +224,34 @@ def test_unified72_snapshot_has_separate_identity_and_no_moving_branch_url(self)
self.assertRegex(data["source"]["sha256"], r"^[a-f0-9]{64}$")
self.assertTrue(data["kernel_release"]["unified72"].startswith("7.2.11-"))
lane = candidate.HERE / "unified72"
# wip3 carries exactly the reviewed #157 display patch on the #158 source.
# wip4 carries the reviewed #157 display patch, then one local DPTX-stall patch.
self.assertEqual([patch["file"] for patch in data["patches"]],
["0001-drm-apple-srgb-external-display-colour.patch"])
["0001-drm-apple-srgb-external-display-colour.patch",
"0002-drm-apple-free-dp-tunnel-route-from-silent-dcpext.patch"])
for entry in data["patches"]:
self.assertEqual(entry["profile"], "candidate")
self.assertEqual(candidate.sha256(lane / "patches" / entry["file"]), entry["sha256"])
patch = data["patches"][0]
self.assertEqual(patch["profile"], "candidate")
self.assertEqual(candidate.sha256(lane / "patches" / patch["file"]), patch["sha256"])
self.assertIsNone(data["patches"][1]["upstream"])
self.assertEqual(data["superseded_patches"][0]["head"],
"4c56f9cd3033e5f65ef9c61bc7b396d50bce23f7")
retired = data["superseded_patches"][0]
self.assertEqual(candidate.sha256(lane / "patches" / retired["file"]),
retired["sha256"])
self.assertEqual(data["kernel_release"]["unified72"],
"7.2.11-elementary-aurora72-wip3")
self.assertEqual(data["debian_package"], "linux-image-elementary-aurora72-wip3")
"7.2.11-elementary-aurora72-wip4")
self.assertEqual(data["debian_package"], "linux-image-elementary-aurora72-wip4")
# The installed wip3 and wip2 packages must stay distinct from this one.
self.assertNotEqual(data["debian_package"], "linux-image-elementary-aurora72-wip3")
self.assertNotEqual(data["debian_package"], "linux-image-elementary-aurora72-wip2")
receipt = json.loads((lane / data["review_receipt"]).read_text())
self.assertEqual(receipt["source"], data["source"]["commit"])
self.assertEqual(receipt["archive_verification"]["sha256"], data["source"]["sha256"])
self.assertEqual(receipt["archive_verification"]["archive_root"],
data["source"]["archive_root"])
self.assertEqual(receipt["patches"][0]["head"], patch["head"])
self.assertEqual([entry["file"] for entry in receipt["patches"]],
[entry["file"] for entry in data["patches"]])
self.assertIn("not_rerun", receipt)
self.assertEqual(candidate.settings(data, "unified72")["DRM_AMDGPU"], "n")

Expand Down
13 changes: 13 additions & 0 deletions mseries/aurora/unified72/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Unified Aurora 7.2.10 build candidate

## wip4 candidate — October 22, 2026 (build-only, not booted)

**Revision 5 pins `7.2.11-elementary-aurora72-wip4`:** the same #158 source and #157 patch as wip3, plus one local
patch, `patches/0002-drm-apple-free-dp-tunnel-route-from-silent-dcpext.patch`. It answers the first wip3 dock plug of
a boot (2026-10-22), where `dcpext1` (`28cc00000`) never answered the DisplayPort validate call and its port stayed
pinned to it until reboot. A DCP whose DPTX call times out is passed over for 300 s, and a timed-out release is
completed instead of kept owned. Evidence, the reasoning, and what it does **not** fix (a tunnel already attached to
the silent pipeline is not moved within that plug):
[2026-10-22-j314s-wip3-dcpext1-dptx-wedge.md](../hardware-tests/2026-10-22-j314s-wip3-dcpext1-dptx-wedge.md).
Receipt: [review-wip4-2026-10-22.json](review-wip4-2026-10-22.json). Checked: patch applies on the exact pinned
files; the routing change ran in userspace against the real `dcp-fabric-core.c`. **Not done:** kernel build, KUnit,
any boot. wip3 stays installed and is the running trial kernel; nothing is staged or armed for wip4.

## wip3 candidate — October 21, 2026 (build-only, not booted)

**Revision 4 pins `7.2.11-elementary-aurora72-wip3`:** unmerged upstream
Expand Down
Loading
Loading