Repository navigation
J813: N1 Wi-Fi and Bluetooth on the MacBook Air M5, with real MSIs - #998
Merged
Merged
Conversation
[Thomas: the driver part of 9f4a5246489a on the J813 line of linux-aurora] Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
…g-up [Thomas: the driver part of c0f6eceacec7 on the J813 line of linux-aurora] Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The J813 constants of the port cycle and the ROM boot word were hard-coded. Move them into one table with a row per machine that has an N1 and add the J873 (the M6 Mac mini): firmware file name, the word written to BAR+0x807c, the root port device ID, and the port, PHY and PERST# addresses with the one differing config +0x130 value, all taken from the machine's ADT. Measured on an M6 Mac mini with the rest of this series: the ROM stage, the port cycle and the Control firmware reach their running stage. Needs the T8152 SoC and PCIe nodes (base layer). [Thomas: the driver part of 70d215465d13 on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The J813 port cycle zeroes 16 words at port+0x3000 and 256 words at port+0x3800. On the J873 those are the RID2SID and MSIMAP tables that pcie-apple programmed. The cycle then drops the stream entry of function 0 and its DMA arrives as SID 0 (DART "BPF reject"). A board with keep_port_tables set gets both tables written back after the cycle. Measured on an M6 Mac mini: with this change the Control firmware reaches its OS stage after the cycle. [Thomas: the driver part of fcbcd1529d03 on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
Each function of the N1 has its own IOMMU stream on the J873 (RID2SID entries 1, 2 and 3 and separate DART domains). A buffer that the firmware of a function reads or writes must be mapped through that function's own struct device. Function 0 is Control, function 1 Alpha (Wi-Fi) and function 2 Beta (Bluetooth). Measured on an M6 Mac mini: Control and Alpha complete their IPC handshakes with this change. [Thomas: the driver part of 12a5fd0d8fc0 on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
Function 0x1903 is the Beta (Bluetooth) function and btcentauri claims it. apple_centauri needs only the functions 0x1900, 0x1901 and 0x1902, so stop it from claiming 0x1903. Measured on an M6 Mac mini: btcentauri binds 0x1903 and registers its HCI transport. [Thomas: the driver part of 0f318aebe42f on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The N1 reports legacy scan responses in LE Extended Advertising Reports whose event type has the low byte 0x18 (legacy PDU and scan response, neither connectable nor scannable) and other bits in the high byte (seen: 0x2518, 0x2618, 0x2718; accepted legacy types arrive as 0x2613 and 0x2610). The core accepts only 0x1a and 0x1b for a legacy scan response and drops the others as "Unknown advertising packet type". Report the low byte 0x18 as 0x1a and keep the high byte. Measured on a Mac mini M6 (J873), 15 s LE discovery with btmgmt (LE on, power on, find), native startup and the LE and auxiliary rings armed: - without the change: 72 to 74 reports, 71 distinct addresses, 12 to 13 "Unknown advertising packet type: 0x18" kernel lines per run; - with the change: 89 reports, 83 distinct addresses, 0 such lines; btmon shows the scan responses as event types 0x251a, 0x261a and 0x271a. A first version of this patch compared the whole 16-bit type with 0x0018 and never matched; the high byte has to be ignored. Not measured: device names or scan response data content, connection, pairing, audio. [Thomas: the driver part of d3d8dab9dbf5 on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The macOS 27.0 WLAN adapter differs from the 26.6.1 one the J813 recipe came from. startInterface carries the three link addresses in TLV 386 (was 385). The scan request (command 0x1000f) carries a channel-list TLV 0x104 and an OCE TLV 0x165 after the fixed 14 bytes. Both are selected per board. Measured on an M6 Mac mini: start and scan commands are accepted. Whether the TLVs are required is untested. [Thomas: the driver part of 4061bf02639e on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The Alpha firmware of the J873 asserts in SCHED_Req_Add when the scan state machine selects a dwell of zero. The scan request carries the active minimum and maximum dwell at frame +0x20 and +0x22 and the passive dwell at +0x24 (in ms, as macOS fills them from the scan request). The driver sent 0 as passive dwell. The whole firmware then trapped at the first scan with PHY, UMAC crash handler and SCHED_Req_Add assertions. Send 110 ms active and 110 ms passive. Also correct the comment in centauri.h that blamed the missing TLVs. Measured on an M6 Mac mini with the original firmware table and no calibration data: the scan returns rc=0 with 24 channels and 51 BSS (31 to 51 BSS in three runs). [Thomas: the driver part of 6d4959cc6edb on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The macOS 27.0.1 adapter sends the MLD configuration TLV 0x178 of the join command (0x20000) with 14 bytes: the 12 default bytes and two zero bytes. With 12 bytes the Alpha firmware of the J873 rejects the join with firmware_status 347 and the 4-way handshake never starts. Measured on an M6 Mac mini: a WPA2-PSK join (CCMP, 5 GHz) completes the 4-way handshake. About 15 s after the join the Alpha firmware still traps (PHY5G irq_isr.c:105, PHY2G power_manager.c:394); that is not fixed by this change. [Thomas: the driver part of 57482a6f8eda on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
Without the host power state the Alpha firmware treats the host as asleep, powers the PHYs down and traps about 15 s after a join (PHY5G irq_isr.c:105, PHY2G power_manager.c:394, and in a log with a post-join frame also LMAC2G "PMGR - Assert while waiting"). Before the join, send the three commands that the host_wakeup and tx_config debugfs files already send: command 6 with a zero body (host power state awake), command 43 (packet lifetime) and command 52 (control profile). The debugfs files stay; the module skips what they applied. The new host_setup parameter (default on) turns this off. Measured on a Mac mini M6 (J873), WPA2-PSK, 5 GHz, with the data rings set up through the data_probe files as before: - the firmware stayed alive (stage 2) for the whole test, about 17 minutes connected in the run with the three commands sent through debugfs, and for the whole test in the run with this change; before, it trapped within 15 s in 14 of 14 variants; - DHCP lease over Wi-Fi; ping through wlan0; iperf3 to a host on the same network bound to the wlan0 address: 44.7 / 58.9 Mbit/s up / down with the debugfs commands, 43.7 / 40.2 Mbit/s with this change; - a 600 s iperf3 at 20 Mbit/s moved 1.40 GBytes without a stall. Not measured: more than 20 minutes, suspend, roaming, 2.4 GHz, WPA3. Some ping windows lost packets (0 to 50 percent in 10 to 20 packet samples). [Thomas: the driver part of 1242f12e876b on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
After the join the firmware runs its own roam and background scans. No host roam profile exists, and each scan takes the radio off channel for seconds. Send ACI command 0x20016 (no body) once the join succeeded, unless the new roam_scan parameter is set (default off, so the scan is off). Measured on a Mac mini M6 (J873), WPA2-PSK, 5 GHz, two boots with the host-awake commands from the previous patch, a ping every 0.5 s for 120 s to the Wi-Fi gateway, bound to wlan0: - without the command: 240 sent, 68 received (71.7 percent loss), received per 10 s: 13 0 13 0 10 3 3 10 0 13 0 3 0 of 20; - with the command in a separate boot: 240 of 240 received, rtt 9 to 73 ms, every 10 s bucket 20 of 20; - with this patch (default settings, third boot): 240 of 240 received, rtt 9.5 to 96 ms, 20 of 20 in every bucket. This is a choice for a stationary machine: with the scan off the firmware does not look for a better access point. A host roam profile (command 0x20014) would be the way to bring roaming back; it was accepted by the firmware but not tested as a replacement. [Thomas: the driver part of 00c55963147d on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
A connection needed three manual steps through debugfs: the passphrase file, the data_probe ids 76, 24, 15 and 12 before the join, and id 25 after it. Do the ring setup from the connect path (parameter auto_rings, default on): the four rings under the connect lock before the join, the normal TX ring once the connection result is reported, so the join stays inside the supplicant's timeout. The data_probe files keep working and are skipped for rings that are already open. The data_probe writer is split into a helper that the connect path calls with the lock held. The firmware accepts a join with the PMK from the supplicant alone, so the passphrase debugfs file and TLV 313 are gone. Measured on a Mac mini M6 (J873), WPA2-PSK, 5 GHz, wpa_supplicant started with a PSK configuration and nothing else (no passphrase file, no data_probe, no host_wakeup or tx_config write): the join completed, DHCP gave a lease, the log shows the four rings at join time, the host-awake and TX default commands, the roam scan switch-off and ring 25 after the result; 20 of 20 pings through wlan0 came back and iperf3 gave 56.3 Mbit/s up and 38.4 down over 10 s each. Measured on the same machine with the module installed and the standard services enabled (wpa_supplicant-nl80211@wlan0 and systemd-networkd, nothing started by hand): after one reboot wlan0 had its address 18 s after boot; the log shows the rings, the host-awake and TX default commands, the roam scan switch-off and ring 25 between 12.6 s and 17.0 s; 20 of 20 pings through wlan0 came back and iperf3 gave 54.8 Mbit/s up and 40.2 down over 10 s each. NetworkManager could not be used on that image: its iwd backend does not start on the test kernel, which lacks CONFIG_CRYPTO_USER_API_HASH, CONFIG_CRYPTO_USER_API_SKCIPHER and CONFIG_KEY_DH_OPERATIONS among others. [Thomas: the driver part of 8b8ec1a2ee3e on the J813 line of linux-aurora] Signed-off-by: Joshua Warren <816217+joshuaswarren@users.noreply.github.com> Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
wavemon and iw had nothing to show for the N1: the driver implemented no get_station or get_channel. Report the packet, byte, failure and drop counters the data path already keeps, the signal of the joined BSS as cfg80211 has it from the last scan (no firmware query for live link statistics is known yet), and the joined channel at the 20 MHz the driver associates with. Bitrates and transmit power stay unreported. [Thomas: the driver part of 767a663a63de on the J813 line of linux-aurora] Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The J873 device tree now uses the machine compatible from the binding, "apple,j873g" (after the ADT target-type J873g). Match that in the centauri board table and in btcentauri. [Thomas: the driver part of 9e911df6e4c0 on the J813 line of linux-aurora] Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
Without PM callbacks the PCI core's default suspend disables the function, which turns bus mastering off under the running N1 firmware. The firmware cannot be restarted without the bootloader's link training, and after resume every ring was dead (each scan failed with -EIO). Save the config space ourselves, so the core leaves the function enabled and in D0, and keep the PCIe host's power domains up through the noirq phase (device_set_awake_path()). Tested on J813: Wi-Fi associated and passing traffic after s2idle. [Thomas: the driver part of fd2382058a0a on the J813 line of linux-aurora] Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
As for the Wi-Fi functions: without PM callbacks the PCI core turned bus mastering off at suspend, and the next poll stopped the transport for good. Save the config space so the function stays enabled and in D0, keep the PCIe host powered, and pause the poll work across the sleep. Tested on J813: hci0 UP RUNNING after s2idle. [Thomas: the driver part of c1f436307d70 on the J813 line of linux-aurora] Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
On T8142 (J813) the bootloader trains apcie port 0 and Linux drives the
root port as a generic ECAM host, which has no MSI support: the N1's
functions could only be polled. The port still turns writes to the MSI
doorbell into AIC interrupts through its MSI map, as on T8140/T602X.
Add pcie-apple's MSI parent domain as a standalone driver
("apple,t8142-pcie-msi"): it programs the port's MSI address, MSI map
and MSI enable and parses msi-ranges like pcie-apple. It depends on
PCIE_APPLE=y for the doorbell address and the DART's reserved doorbell
IOVA.
Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The data rings were serviced by a 20 ms delayed work (24 ms at HZ=250) that drains at most 127 RX completions and reclaims the 128 TX slots per pass, which capped the J813 at ~65 Mbit/s with 0-24 ms of added latency. When the port has an MSI controller, give Control and Alpha up to 16 MSIs each (the port has 32) and kick the data worker from every MSI; Beta and ports without a controller keep the DMA mailbox. The poll stays as a fallback. The port cycle's reset clears MSICFG, MSIADDR and the MSI map, so save and restore them on every board (the RID2SID table still only with keep_port_tables). J813: iperf3 65 -> 579 Mbit/s to the host, 60 -> 451-505 Mbit/s from it, ping 15.7 -> 2.9 ms average. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The data rings tell the firmware to signal Alpha vectors 3 and 8. On the J873 the 10GbE NIC shares pcie-apple's 32 vectors with the N1; Control asked first and took the only free block of 16, Alpha got one vector, and the Alpha firmware faulted (stage 3) as soon as the first data ring was opened, so every later command failed with -EIO. Allocate Alpha before Control and only as a whole block of 16; a function that cannot get one keeps the DMA mailbox. On the J873 Control now stays on the mailbox and Alpha gets its 16 vectors. J873 (Mac mini M6, 5 GHz ch 44, -34 dBm): iperf3 60 -> 511 Mbit/s to the mini, 60 -> 530 Mbit/s from it, ping 17 -> 2.4 ms average. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The MSI map of one Apple PCIe root port that the bootloader trained and Linux drives as a generic ECAM host (the J813 N1 on T8142 apcie port 0). Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
This was referenced Nov 5, 2026
…nect The disconnect request sends TLV 328 with a zero timeout. The firmware uses zero to bypass its deauthentication/disassociation transmit path and immediately tears down the link. The old AP can retain the station while Linux associates with another BSSID, leaving cross-AP traffic without a working return path despite a completed WPA handshake. Use the firmware's 500 ms default disconnect budget so it can transmit the management frame and wait for completion before tearing down the link.
RyanTheTide
added a commit
that referenced
this pull request
Nov 6, 2026
Carries the work merged on aurora-wip since #1018 into the release branch: M5 T8142/J813 bring-up (#995 #996 #997 #998 #1001 #1002 #1003), T8152/J873 bring-up (#984 #1009 #1013 #1022), J813 AVD/ISP (#1026) and the selftest harness updates (#1014). The merge is clean; the 13 integration/aurora commits since #1018 are kept. Signed-off-by: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Assisted-by: LLM
This was referenced Nov 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The MacBook Air M5's N1 Wi-Fi and Bluetooth: Acelogic's native-PCIe N1 driver with Joshua Warren's fixes (authors kept; the driver part of each commit from the J813 line of linux-aurora), btcentauri, the s2idle fixes, and real MSIs: a small MSI controller for the bootloader-trained apcie port 0 (pcie-apple-msi, with its binding) and an interrupt-driven data path (65 -> 580 Mbit/s).
Integration's drivers/net/wireless/apple/centauri only has a Makefile and a header for the T6050 APIF driver, whose Kconfig depends on PCIE_APPLE_APIF, which integration does not have; this fills the directory with the native driver. The T6050 APIF variants are not part of this.
Acelogic's commits carry no Signed-off-by of their own; I have added mine as the one forwarding them. Acelogic, please add yours if you agree.
Tested on the MacBook Air 13-inch M5 (J813): the nine J813 branches (nvme, platform, dts, soc, wireless, media, sound, display, gpu-m5) merged onto integration/aurora 11eccbe, built with the J813 config (7.3.0) and booted through aura's aura-try trial boot. systemd reaches running: NVMe root, the N1 Wi-Fi (association; Bluetooth still needs the N1 firmware started first, as on the current kernel), the AVD and ISP drivers, PSCI cpuidle, the E/P states, CLPC/PMC and the PMP come up, the M5 GPU backend starts firmware 25G76, and drm/apple drives the panel.
Two sound findings from that boot, neither yet resolved: the installed aura predates the amp-level injection now in aura main, so macaudio disables the speakers (the card binds, but the DT this boot used carries no apple,speaker-config); and opening the microphone fails with
LEAP leaf 2 did not power up: Error(110), while the same T8152 driver on the J813's current 7.1 kernel records.Stability caveat: a second boot of the same image hung about 38 s in, just after the NTP step set off the daily fstrim/apt timers, with no panic record (no pstore). The first boot went through the same timer burst and stayed up for minutes. Until the hang is understood, the combined tree is not proven stable across reboots.
cc @Acelogic @DjDeveloperr @RyanTheTide @LiamRay10
AP-switching fix and combined hardware qualification
The disconnect command previously sent TLV 328 with a zero timeout. In the N1 firmware, zero bypasses the deauthentication/disassociation transmit path and immediately tears down the link. This can leave the old AP retaining the station while Linux associates with another BSSID, breaking the return path despite successful WPA and DHCP. The appended fix restores the firmware's 500 ms disconnect budget so the management frame can be sent before teardown. It does not add a userspace delay or disable power saving.
Validation of the combined public-base + #998 + #1013 source tree on physical J813 and J873, using fresh guarded RAM boots:
Earlier failed trials and packet captures are retained privately. Isolated packet loss also occurred without an AP change during control testing; this result qualifies the reproduced handoff stall, not loss-free RF operation. Bluetooth pairing/ACL/audio, suspend/resume and installed-rootfs stability remain outside this qualification. No firmware or internal-disk installation was performed.