Repository navigation
PCI: apple: adopt the T6050 root ports the boot loader trained - #937
Conversation
c1eb476 to
a873be0
Compare
…oader Add apple,t6050-pcie, a T6050 (M5 Ultra) PCIe host whose root ports the boot loader powered, trained and left running. Each such port is marked apple,link-trained-by-bootloader and named by its port<n>, phy<n> and intr2axi<n> register ranges and its port<n> interrupt; the host's local MSI map starts at apple,msi-vector-base. The OS adopts the trained state and never resets, retrains or changes the port's power: reset-gpios, pwren-gpios and power-domains are not allowed on it. Also name nonposted-mmio, which these hosts take. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com> Developed with Claude Code. Signed-off-by: Erik Bourget <erik@ebourget.net>
On the M5 Ultra (T6050, J775D) running Linux on the hardware, the boot loader brings up the internal PCIe host's ports itself: it powers the shared PHY, trains each port's link and leaves it up, with the endpoint idle. Port 2 carries the onboard RTL8127 Ethernet controller and port 3 the ASM3142 xHCI behind the rear USB-A ports. Repeating the reset and training sequence from Linux is not needed and not known to be safe on this SoC. Add apple,t6050-pcie, a host whose root ports marked apple,link-trained-by-bootloader are adopted as they are: no reset, no tunable replay, no clock or power change and no retraining. Every resource comes from the DT by the port's index (port<n>, phy<n>, intr2axi<n>, interrupt port<n>, the iommu-map entry for the endpoint's RID). Before the first PCIe register write the driver checks that the link is up and not retraining at Gen3 x1, that the boot loader numbered the root port's buses (primary 0, one secondary), that the endpoint on it is device 0 function 0 with DMA and MSI off and a well-formed capability list, and that the port's RID table holds no valid entry. A port that fails a check is left alone and the others are still adopted. Then the endpoint's RID is routed to its SID, the host's MSI map is set up from apple,msi-vector-base, and only the adopted root ports and the endpoint behind each are enumerated. The links cannot be recovered by a user reset or removal, since the boot loader owns them. No other SoC sets adopt_link. Testing: on J775D, every boot adopts port 2 (RTL8127, DHCP and SSH over it on every boot) and port 3 (ASM3142, a USB keyboard and mouse driving the desktop session). Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com> Developed with Claude Code. Signed-off-by: Erik Bourget <erik@ebourget.net>
A driver's work item that rescans or resets part of a bus takes the rescan/remove lock. When the device is being removed, the remover holds that lock while it cancels the work, so a worker that blocks on the lock deadlocks against its own cancellation. Add pci_trylock_rescan_remove(), which takes the rescan/remove lock only if it is free. A worker that cannot get it returns and retries later, and the remover's cancellation completes. Signed-off-by: Dj <hey@djdev.me> Developed with Claude Code. Signed-off-by: Erik Bourget <erik@ebourget.net>
…uences An adopted T6050 port is left as the boot loader trained it, but an endpoint that has to come back on a retrained link (the N1 on port 0, after its ROM boot) needs the host to take the port down and bring it up again. Add the sequences for that, on the port's own register blocks (port<n>, phy<n> and intr2axi<n>) and the root port's config space: - Disable: wait for the link to leave L1 and go idle, assert the port's PERST# through its handshake, then stop the lane clocks and the port's application clock. - Enable: the port reset table, which also clears the RID2SID and MSI map tables, the port's tunables, then the application clock and the PERST# release handshake, until the port is ready and its link idle. - Configure: with the root complex's read-only registers opened, its tunables and the per-rate shadow tunables, then a Gen3 x1 link (target speed, link width and capability) and a directed speed change; Intr2AXI enabled. - Train: the lane's reference clocks, the endpoint's PERST# released through its pad, the LTSSM started, then the 100 ms wait after link up. The tunables are the lists the boot loader copies onto the root port node, groups of (offset, 4, mask, value); a list it did not copy is skipped. The root-port reset that runs the sequences follows; until then they are marked __maybe_unused. Co-developed-by: Dj <hey@djdev.me> Signed-off-by: Dj <hey@djdev.me> Developed with Claude Code. Signed-off-by: Erik Bourget <erik@ebourget.net>
… port The N1 Wi-Fi/Bluetooth sits on apcie0 port 0, which the bootloader now trains like ports 2 and 3. Two things the adoption assumed do not hold for it: - It is multi-function. In its ROM personality only function 0 answers; after its firmware starts, Control, Alpha and Beta (0-2) do. Each function's RID is routed to its own DART stream from the iommu-map (slot == SID) when it is enabled, instead of the one route set at adoption; config accesses on the adopted bus reach every function of device 0; teardown clears every slot it routed. Port 0 is accepted. - Its ROM links at Gen1. Adoption takes an x1 link at Gen1 to Gen3 (the bootloader's target), not only Gen3; the endpoint picks the speed. - After the ROM boot it must come back on a retrained link. The host provides reset_root_port for an adopted port that names its PERST# pad (perst<n>): PME_Turn_Off to L2, PERST#, then the T6050 port disable, reset, enable, configure and train sequences, with the routes and the MSI map rewritten in between. Tunables the boot loader copied onto the root port node are applied; absent ones are skipped. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com> Developed with Claude Code. Signed-off-by: Erik Bourget <erik@ebourget.net>
The adopted port 0 named its PERST# pad as a 4-byte reg of the host (perst0, one word inside the pin controller's block) and wrote it raw. With the pin controller in the device tree the two nodes claim the same MMIO word, and whichever probes second fails: when pinctrl wins, the host's port setup stops with -EBUSY and no port is adopted, so the Ethernet and USB behind ports 2 and 3 are gone with it. One owner for the pad: the pin controller. The port node carries reset-gpios, as every other Apple host's port nodes do, and the host takes the line as the bootloader left it (GPIOD_ASIS: probe never touches a trained link's reset) and drives it only in the root-port reset, as a GPIO output at the logical level the reset asks for. The raw pad write set the same things (function bits cleared, mode output, the data bit) plus the pad's input enable, which the pin controller leaves as the bootloader set it. Probe asks for the line before any port is set up, so a host whose pin controller is not up yet defers instead of adopting nothing; an adopted port without reset-gpios has no reset, as before (reset_root_port answers -EOPNOTSUPP). The perst<n> reg, its binding entry and the raw pad write go; the binding allows reset-gpios on an adopted port again. Probe names the port whose line it cannot have, as the probe of the other hosts' ports does: a line the pin controller reserves (gpio-reserved-ranges) is refused with -EINVAL, which the host's probe otherwise returned with no word of which port or property. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com> Developed with Claude Code. Signed-off-by: Erik Bourget <erik@ebourget.net>
a873be0 to
2b76075
Compare
The PCIe-C policy test extracts driver macro definitions to compile its production-code fixture. Taking only the first physical line truncates T6050_ROUTE and joins the following directive to its trailing backslash, so the fixture fails to compile after the T6050 host support is added. Copy continuation lines along with their define. The production fixture and both negative controls now pass. Developed with Claude Code. Signed-off-by: Erik Bourget <erik@ebourget.net>
DjDeveloperr
left a comment
There was a problem hiding this comment.
Works on the M5 Pro (MacBook Pro 14", J714sAP, T6050), bare metal, once the boot loader trains the link.
Our M5 aura had no T6050 PCIe bring-up, so I put erikwb's on it from ewb/j716c-daily: e7d6b647, e7f2008d, d28dedf2, 33af8bff, 859595d6, 67b111e6, 59c2d169, and 37c0da7d's SMC function reset. That is a local test image; the only change is a size flag. On J714s it finds port 0's bridge only (ports 2 and 3: "no bridge on this board") and releases the N1's gP13 reset. It then trains port 0 at Gen1 x1 to endpoint 106b:1900, and storage is unchanged after every stage.
This head (911da8c), with #938 and #1199 in the same kernel on PR1012's base:
- adopts the link:
port 0: RID 0100 -> SID 1, slot 1,adopted port 0, endpoint 01:00. The root port (106b:100c) and the N1 enumerate with no PCIe or DART errors. - does the N1's post-ROM root-port reset:
port 0: link retrained after a root-port reset. Functions 01:00.1 (1902) and 01:00.2 (1903) then appear and get their streams (e.g.RID 0102 -> SID 3). - carries the N1's traffic for #938: 64 MiB in and 32 MiB out over Wi-Fi, byte-exact.
Same result on three boots.
Note: the port's reset-gpios needs pinctrl-apple-gpio, so the host defers until that module loads. That's expected, but a system that doesn't load it stays without PCIe. This head merges cleanly into current integration/aurora.
#937 was merged into integration/aurora on its own. This series carries the same seven commits rebased, so every file #937 touches resolves to this branch's version; the only conflict was this series' PCIe-C definitions and MSI-slice check next to #937's lines in pcie-apple.c. Signed-off-by: Diljit Singh <hey@djdev.me>
On T6050 the boot loader powers the internal PCIe host, trains each port and leaves the links up. Re-running reset and training from Linux isn't needed and isn't known to be safe, so without an adopting host there's no Ethernet, rear USB-A or Wi-Fi.
apple,t6050-pcie: adopt ports markedapple,link-trained-by-bootloaderas they are (no reset, tunable replay, power change or retraining), with every resource taken from the DT by port index.pci_trylock_rescan_remove()(Dj's), so a worker cancelled by removal doesn't wait on the remover's lock.pcie-apple.con the port's own register blocks and the root port's config space. They are Dj's sequences (co-developed), now native to the driver.Commits by Jeff Queisser, Dj and Erik Bourget. On J716c (MacBook Pro 16-inch, M5 Max) this runs as part of the full T6050 stack (
j716c/t6050-platform): the machine boots to userspace from NVMe with all 18 CPUs, N1 Wi-Fi up and CPU frequency scaling active. The N1 drivers that sit on port 0 are the next PR, stacked on this one.Rebased onto current
integration/aurora. The T6050 adoption/reset paths are preserved alongside the newer PCIe host definitions. Validation of the rebased series: arm64 LLVM driver builds withW=1, binding schema/example checks, and PCIe binding validation of J716c, J775D, T8152 J873g and T6040 J616s device trees. The exact rebased kernel has not been installed or booted.The PCIe-C policy test now preserves multiline driver macros in its compiled fixture. The previously failing production case and both negative controls pass locally.
Reviewed with sol-loop: 2 rounds with GPT-6.1 Sol. Sol verdict: approved (rebase and subsequent test fix).
Created with Claude Opus 5.5 in Claude Code.