Repository navigation
PCI: apple: bring up T600x/T602x PCIe-C tunnels without an m1n1 handoff - #10
Conversation
a5563cb to
b4a0f46
Compare
T600x and T602x PCIe-C (the Thunderbolt PCIe tunnel) is only brought up
after an m1n1 handoff ("apple,pciec-preinit-status" = 1), and no m1n1
performs one. The tunnel is always refused, so PCIe devices behind
Thunderbolt 3 docks and displays (their xHCI, audio, cameras, network)
never appear.
Add pcie_apple.tunnel_kernel_init (default off). When set, ports on
T6000/T6001/T6020/T6021 (M1 and M2 Pro/Max) without a handoff are
cold-initialized by the kernel through the existing t8103 paths:
apple_pcie_tunnel_prepare() clocks the port before its DART probes, and
apple_pcie_setup_port() cold-initializes a port that is not running. It
is a parameter rather than a DT property because m1n1 hands every
installed kernel the same DT. Ports whose DART has no "apple,tunable"
are refused: m1n1 does not provide them, and the DART cannot probe
without them.
apple_pcie_tunnel_cold_init() gains one ordering difference for these
ports: they must report RUN before the root complex config-space
tunables are written, which hard-resets a J416c otherwise. T600x/T602x
have no oe-fabric region and pulse Intr2AXI instead, and they keep the
0x208 reset table value. The t8103 power and resume paths, selected by
pcie->kernel_init, are not used.
Tested on a MacBook Pro 16" M2 Pro (j416s) with an Apple Studio Display
on each of its three USB-C ports, plugged in after boot and connected
at boot. T600x is untested.
Signed-off-by: Wes Grimes <wesgrimes@hey.com>
ACIO only populates the tunneled PCIe-C host after an m1n1 handoff or for "apple,pciec-kernel-init" (t8103) ports. Also accept ports that the PCIe driver will cold-initialize itself, which it does only when booted with pcie_apple.tunnel_kernel_init=1, and word the disabled-tunnel messages so that they no longer name the m1n1 handoff as the only way. Signed-off-by: Wes Grimes <wesgrimes@hey.com>
A function behind a cold-initialized T600x/T602x tunnel stays in D0 (NO_D3) when it runtime-suspends, but its wakeup never arrives. When a Studio Display is power-cycled, its Titan Ridge xHCI runtime-suspends before the display's hub reconnects and never sees the hub, so the display's USB devices do not come back. Hold a runtime PM reference on each function for as long as it exists, from a PCI bus notifier registered before the host is scanned, so that neither the driver nor userspace power policy (power/control = auto) can suspend it. A bus notifier rather than a PCI fixup, because fixups in a module are never run. Tested on j416s with an Apple Studio Display: after a display power cycle its hub, camera and audio come back by themselves. Signed-off-by: Wes Grimes <wesgrimes@hey.com>
…idle In suspend-to-idle ACIO and the router links stay powered, and t8103 already leaves a healthy tunnel running instead of stopping the port. Cold-initialized T600x/T602x ports took the stop path. On resume the router rebuilt its tunnels, the in-place restart brought the link up only for it to drop again, the xHCI behind it was lost, and that tunnel instance could not train a link again until reboot. Let these ports keep their link through suspend-to-idle too, so the NHI keeps its tunnels and nothing is retrained. If the link was lost while asleep anyway, fail the host like a surprise unplug rather than restarting it in place; ACIO then revalidates the connection and replaces it. Tested on j416s with an Apple Studio Display: after 20 s and 3 min suspends its hub, camera and audio keep working, and unplugging the display while asleep is handled as an unplug. Signed-off-by: Wes Grimes <wesgrimes@hey.com>
When ACIO deactivates the PCIe tunnel while the cable stays connected, apple_pcie_tunnel_quiesce() removes the hierarchy and stops the ports, leaving the host bus_stopped until apple_pcie_tunnel_restore() restarts them on reactivation. resume_noirq() nevertheless restarts every port after a system suspend. Without a tunnel that fails, sets resume_failed, and the host then refuses restore() until it is replaced. A quiesced host has nothing to resume, so leave its ports stopped. Signed-off-by: Wes Grimes <wesgrimes@hey.com>
The tunneled PCIe-C DART requires "apple,tunable". iBoot adds "dart-tunables-instance-0" to the ADT at boot, but m1n1 does not copy it for the dart-apciec* nodes. Without it the DART fails to probe and the xHCI behind the tunnel dies after its command ring times out. Add the values to the apciec0..2 DARTs of every T602x die. They were read from the ADTs of a J416c (T6021) and a J414s (T6020), and are identical on both machines and for all three ports; on j416s they bring up a Studio Display's xHCI. apciec3, present on the desktop machines, has no values yet, so pcie_apple.tunnel_kernel_init refuses that port. Signed-off-by: Wes Grimes <wesgrimes@hey.com>
As on T602x, the tunneled PCIe-C DART requires "apple,tunable", which iBoot adds to the ADT at boot as "dart-tunables-instance-0" and m1n1 does not copy for the dart-apciec* nodes. Add the values to the apciec0..2 DARTs of T6000/T6001. They were read from a J314s ADT and are identical for all three ports. They differ from the T602x values. apciec3 has no values yet, so pcie_apple.tunnel_kernel_init refuses that port. Signed-off-by: Wes Grimes <wesgrimes@hey.com>
A read-only script for testers of pcie_apple.tunnel_kernel_init on T600x/T602x: it checks the machine and parameter, lists the DART tunables per tunnel and the PCI and USB devices behind the tunnels, collects the relevant kernel log, and writes a markdown report. When a tunnel has no DART tunables, it prints the macOS ioreg command that reads them. Signed-off-by: Wes Grimes <wesgrimes@hey.com>
5f07612 to
c4726ef
Compare
|
Known compromises in this series, and the cleaner follow-ups for each:
The RUN-before-config-space order in the cold init is also empirical: writing the RC tunables first hard-resets a J416c. It isn't documented anywhere. None of these affect machines booted without |
iconidentify
left a comment
There was a problem hiding this comment.
Thanks @wesleygrimes, this is great work, and thanks for the "known compromises" note. We ran two independent reviews.
Already in good shape:
- It merges cleanly onto custom/sep and onto our Thunderbolt branch (aurora-silicon#8), and builds with W=1 clean.
- DTB changes are confined to the 11 T600x/T602x boards. t8103, t8112, Neo and the Ultras are byte-identical.
- No hunk touches the DP tunnel paths or the Type-C display routing.
- With the parameter off, T600x/T602x behave as today.
M1 Pro data check: the values in t600x-pciec-dart-tunables.dtsi match a second J314s (MacBookPro18,3, macOS 27.0.1) exactly. That covers all three tuples (0x20c/0x220/0x224 with the same masks and values) on apciec0–2, and apciec3 has none. We're installing Omarchy on that J314s now, to run the cold init with a Thunderbolt 3 dock. So please keep T600x in, pending that run.
Requested changes
-
PR text and the M1 change. "Don't restart a quiesced PCIe-C host on resume" changes t8103 even with the parameter off (
pcie-apple.cresume_noirq).- It's a correct fix: today a host quiesced by tunnel teardown gets
resume_failed, and the next restore returns -EIO until replug. - Please say so in the description.
- It's the same change as rryan's
18b9e789in aurora-silicon#50 (Sep 28). Please use his commit (see 6). - We'll test it on an M1 with a TB3 dock: tunnel deactivated, suspend, resume, reactivate.
- It's a correct fix: today a host quiesced by tunnel teardown gets
-
A lost link at resume on cold-initialised hosts (~3104 and ~3184).
- The stop/restart path is still reachable, with
s2idle_keep_link=0or a stale link-down bit at suspend. - Your commit says that path leaves the port unable to train until reboot, and T602x has no PCIe-C block reset.
- Please fail such a host (-ENOLINK, handled as a surprise unplug) instead of restarting it.
- The stop/restart path is still reachable, with
-
A failed cold init leaves the port clocked (~950–959). On the next plug,
prepareandsetup_portsee it running and skip cold init, so the root-complex tunables are never written. Please stop the port on failure. -
Runtime-PM reference (~2157–2176, ~2493).
- It pins every tunneled function, NICs and NVMe included, and overrides
power/control=autoand TLP. That costs battery whenever a dock is connected. - Could it be limited to the xHCI class that loses its PME, or use
pm_runtime_forbid()so a user can override it? - Your note 4, finding the root cause, is the real fix later.
- It pins every tunneled function, NICs and NVMe included, and overrides
-
Nits:
- The 250 ms busy-wait under
pcie_tunnel_lock(~951) should beread_poll_timeout. pr_warn_once(~110) hides the second and later refused ports.tb-pcie-reportreports M1 DART tunables as missing and sends M1 testers to macOS, but M1's PCIe-C DART has none by design. Please skip that check on t8103.- An unplug log, please.
apple_nhi_pci_tunnel_deactivate()holdstb->lockwhile waiting up to 1 s for the reset ack, which is where rryan logged -110. Could you share a log of an unplug or display power cycle with the parameter on, so we can see whether DP teardown or replug stalls?
- The 250 ms busy-wait under
-
Credit. aurora-silicon#50 (rryan, Sep 27) got to the same place first:
- the RUN-before-config-space order (the J416c hard reset comes from his reports);
- byte-identical T602x DART tunables;
- the same quiesced-host resume guard.
Your series is the better base: safer opt-in, built on #8's functions, plus s2idle handling. Please add
Co-developed-by: RJ Skerry-Ryan <rryan@alum.mit.edu>to the cold-init commit, use his resume commit in place of yours, and credit him for the T602x tunables. We'll close #50 as superseded, with credit, when this lands.
After the fixes:
- Default on: per our default-on policy, the plan is to turn this on by default for M2 Pro/Max once 2–4 are in, keeping the parameter as an off switch. T600x follows once the J314s run passes.
- Upstream follow-ups: your known compromises are the right ones (m1n1 copying
dart-tunables-instance-0, per-SoC compatibles instead of the compatible check). - On our side: we'll update our installer's test plan, which still calls the old "m1n1 handoff is not initialized" line normal.
Also, thanks for the Touch ID report on sepOS 27.0 (#8). It's the first M2-family keybag on 27.0.
Supervised test build: 11.25.1 plus #10 (PCIe-C cold init on T600x/T602x, opt-in with pcie_apple.tunnel_kernel_init=1), for an M1 Pro (J314s) dock test. Prerelease only. Signed-off-by: Chris Kearney <chris@kearneymail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwdG63dRaMrRbYrUBkSa1i
linux-aurora 7.1.12.aurora2-11.31, built from fd04a98: - PCIe over Thunderbolt on M1 Pro/Max and M2 Pro/Max by default (#10) with the T600x DART window and dock readiness fixes; - igb and igc for Thunderbolt 3 and 4 dock Ethernet; - the MacBook Neo radios in the shared kernel (#11); - Neural Engine runtime PM (aurora-silicon#155) and the ANE enabled on the M1, M1 Pro and M2 Pro. The installer checks a MacBook Neo for its own Wi-Fi firmware, calibration and country files and prints the Neo's sleep, Wi-Fi and Bluetooth limits. The test plan covers dock PCIe on the Pro/Max chips with exact log lines, the Neural Engine on the newly enabled chips, and a MacBook Neo step. libfprint, aurora-touchid and m1n1-aurora are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwdG63dRaMrRbYrUBkSa1i Signed-off-by: Chris Kearney <303316+iconidentify@users.noreply.github.com>
|
Merged and released in 11.31. Thank you, @wesleygrimes. Your cold init worked first time on an M1 Pro. Testing it there with docks that have several controllers inside found two bugs, now fixed in follow-up commits on
Also:
Tested on builds carrying exactly this Thunderbolt code (11.29–11.31):
Still untested:
A request: 11.31 also turns the Neural Engine on for the M2 Pro. It has the same die-0 ANE as the M2 Max and uses the same
A run with a multi-controller TB3 dock would be welcome too. The installer's 🤖 Generated with Claude Code |
ACIO returns -EAGAIN while its PCIe host is being populated or quiesced. CD321x treats this as a failed cable and forces a complete disconnect on the next status snapshot, resetting an otherwise unchanged USB4 session. Keep the bounded fresh-read retry budget, but only request a forced reconnect for non-deferred errors. Preserve any earlier genuine failure. Notify the Type-C consumer after asynchronous PCIe activation succeeds so an exhausted busy retry can read the current cable state again. Return -EAGAIN when an allegedly populated host is not yet available, rather than reporting false activation success. Propagate partner-registration errors and add regression tests for busy retries, completion after budget exhaustion and a busy retry following a real failure. [Chris Kearney: Ported onto custom/sep 1caa9fd (11.35) without code changes. The PR #10 cold-init acceptance and PR #15 follow-ups are retained. Review trial only: readiness and retry-budget concerns remain in the report.] Signed-off-by: Chris Kearney <303316+iconidentify@users.noreply.github.com> (cherry picked from commit cd2525c) (cherry picked from commit 39176aa921904549e1eeead5a2a36bc3bac6e67f)
Summary
Brings up the Thunderbolt PCIe tunnel (PCIe-C) on M2 Pro/Max (T602x) and M1 Pro/Max (T600x) without an m1n1 handoff, building on the existing M1 (t8103) path. Devices behind Thunderbolt 3 docks and displays now come up. For an Apple Studio Display, that's its USB hubs and USB-C ports, camera, speakers and microphone.
PCIe-C on these chips requires
apple,pciec-preinit-status = 1from m1n1, and no m1n1 sets it, so today the tunnel is always refused. This series is opt-in withpcie_apple.tunnel_kernel_init=1. With the parameter off, nothing changes on any machine.Commits
PCI: apple: Cold-init T600x/T602x PCIe-C ports without an m1n1 handoffapple_pcie_tunnel_needs_cold_init(), which also refuses ports whose DART has noapple,tunable. Reuses the t8103 cold-init, prepare and setup paths, with one difference: these ports must report RUN before the root-complex config space is written, because the t8103 order hard-resets a J416c. They use Intr2AXI instead of oe-fabric. The t8103 power and resume paths (pcie->kernel_init) are not used.thunderbolt: apple: Accept PCIe-C kernel cold init on T600x/T602xPCI: apple: Keep cold-initialized PCIe-C functions runtime-activepcie-appleis built as a module.PCI: apple: Keep cold-initialized PCIe-C links up through suspend-to-idlePCI: apple: Don't restart a quiesced PCIe-C host on resumeresume_noirq(), which fails without a tunnel and leaves the host markedresume_failed.apple_pcie_tunnel_restore()already restarts them on reactivation.arm64: dts: apple: t602x: Add PCIe-C DART tunablesdart-tunables-instance-0fordart-apciec*, and without it the DART fails to probe. Values were read from J416c and J414s ADTs and are identical on both machines and all ports.arm64: dts: apple: t600x: Add PCIe-C DART tunablestools: aurora-tb: Add a Thunderbolt PCIe test reporttools/aurora-tb/tb-pcie-report, a read-only report for testers, with a README.Why a parameter rather than a DT property: m1n1 bundles one DTB into
boot.binfor every installed kernel, so an older kernel would also see such a property. The DART tunables are harmless to older kernels, because without the handoff they never populate the tunnel.Testing
MacBook Pro 16" M2 Pro (
apple,j416s), Aurora 11.25 base and config, Apple Studio Display:8086:15f0) enumerates the display's USB2/USB3 hubs and05ac:1114: UVC camera, USB audio (speakers and mic) and its HID interfaces.power/control=onis set.Not tested
pcie-applebuilt as a module.Testers: boot with
pcie_apple.tunnel_kernel_init=1, plug in a Thunderbolt 3 dock or display, and runtools/aurora-tb/tb-pcie-report.Studio Display brightness isn't part of this series.