8814 port-audit: fix 8812-on-8814 mis-ports + CCK/FW-boot bugs (no regressions)#96
Merged
Conversation
send_packet defaults fixed_rate to MGN_1M (1M CCK) and only overrides it from the radiotap RATE/VHT fields (or HT-MCS when DEVOURER_TX_HT_MCS is set). CCK rates (1/2/5.5/11M) do not exist at 5GHz: the RTL8814AU silently drops a CCK-rated frame on a 5GHz channel -- the bulk-OUT completes (rc ok, 100% URB completion) but nothing goes on-air. 2.4GHz CCK transmits fine. On a 5GHz channel (Channel > 14), clamp a CCK fixed_rate to the lowest OFDM rate (MGN_6M). The 8812 chip happens to auto-fall-back CCK->OFDM at 5G; the 8814 does not, so devourer must do it in software. Verified on hardware (RTL8814AU 0bda:8813, 8821 kernel-monitor witness): 8814 TX at ch100 with the default rate goes 0 -> ~13770 on-air frames (6M OFDM, 11a); ch6 (2.4G CCK) unaffected. Addresses the 5GHz half of the 8814 devourer-TX on-air gate (#50). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ORE_INIT) The 8814 init path skips BOTH rtl8812au_hw_reset() (the DEINIT_BEFORE_INIT double-init guard) and InitPowerOn(), relying on the 242-op rtw88-mimic in FirmwareDownload_8814A. So a warm/dirty 8814 (a re-run without a cold USB Vbus power-cycle, or after rtw88_8814au auto-bound it) is never reset: the RX bulk-IN wedges (~10 frames then LIBUSB_ERROR_TIMEOUT) and TX goes 0 on-air, recoverable only by dropping Vbus. The kernel avoids this by card_disable-on-unbind (CardDisableRTL8814AU runs Rtl8814A_NIC_DISABLE_FLOW); devourer never powers the chip off. Add a deinit-before-init that runs rtl8814A_card_disable_flow for a warm 8814, mirroring the kernel's teardown deinit. Gated behind DEVOURER_8814_DEINIT_BEFORE_INIT (default OFF) because the 8814 PWR_SEQ has a known cut-mask-filter interaction with fwdl and this needs clean-rig validation (run twice with no power-cycle: 2nd run must not wedge; cold init must be unaffected) before becoming the default. NOT YET HARDWARE-VALIDATED — rig RF is degraded; staged for validation.
…14A bInit) devourer's phy_SetRFEReg8814A programs only the per-band RFE pinmux *functions* (0xCB0/0xEB0/0x18B4/0x1AB4) but never runs the kernel's one-time bInit branch (rtl8814a_phycfg.c:1026-1039, called from usb_halinit.c:1279) that selects the GPIO pins which physically drive the external RFE (PA + T/R antenna switch): 0x1994[3:0]=0xf and REG_GPIO_IO_SEL_8814A(0x42)[23:20]=0xf (rfe_type 1/2) or 0xc0 (type 0). Add it as InitRFEGpio8814A(), called once after the initial band-set. This is a genuine kernel divergence (verified: devourer had zero writes to 0x1994 / 0x42). NECESSARY but NOT SUFFICIENT on its own: with this applied, 8814 TX still emits 0 on-air at ch6 (submits err:0). Remaining divergence is in the BB/RF TX-chain config at channel-set time — to be found via a usbmon register diff against the proven-working kernel IBSS reference (kernel TXes 228 beacons @ -34dBm on this same chip, so the PA is healthy; this is purely a devourer software bug). Not yet on-air-validated as a fix.
…(kernel usb_halinit.c:_InitBurstPktLen)
The 8812 _InitBurstPktLen body ran unconditionally on 8814A. Its
0x456=0x70 write (REG_AMPDU_MAX_TIME_8812, "suggested by Zhilin") lands
on REG_TXPKTBUF_BCNQ1_BDNY_8814A, corrupting the beacon-queue TX-buffer
boundary that _InitQueueReservedPage_8814AUsb programmed to 0x7F6 moments
earlier — the same register class (TX FIFO page layout) whose mis-set is
already known to make 8814 bulk-OUT frames land nowhere.
Also wrong for 8814 in the 8812 body: USTIME_TSF/EDCA forced to 0x50
(8812's 80MHz-clock tick; the 8814 MAC table value is 0x64 and the
kernel's _InitEDCA_8814AUsb keeps the 0x50 writes commented out), PIFS
zeroed (kernel table value 0x1C stands), MAX_AGGR_NUM 16-bit 0x1f1f
(kernel: per-byte 0x36/0x36 — restored in a follow-up commit), plus
RSV_CTRL/0xf050/0x288/0x289/ARFR0-3/RX_PKT_LIMIT/HT_SINGLE_AMPDU pokes
that have no counterpart in the kernel's 8814 init.
The new _InitBurstPktLen_8814A ports the kernel body: FAST_EDCA
VOVI/BEBK = 0x08070807, RXDMA burst mode by USB speed (0x1e/0x2e/0x0e),
RXDMA_AGG_PG_TH = 0x2005 (USB2) / 0x0a05 (USB3), and on USB3 the
0xf008[3:4] U1/U2 disable, 0xf002=0 ("to avoid usb 3.0 H2C fail") and
LDPC pre-TX off (0x4BC &= ~BIT6). Kernel's trailing AMPDUBurstMode=0x5F
write never runs there (flag is never assigned) so it is not ported.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…halinit.c:_InitEDCA_8814AUsb)
_InitEDCA_8812AUsb forced USTIME_TSF(0x55C)/USTIME_EDCA(0x638) to 0x50 on
every chip. 0x50 is 8812's 80MHz-clock microsecond tick; the 8814 MAC
table programs 0x64 (100MHz) and the kernel's _InitEDCA_8814AUsb keeps
the 0x50 writes commented out ("0x50 for 80MHz clock"). Running the MAC
~25% fast skews every microsecond-derived TX timing (SIFS/slot/timeout).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…b_AggSettingTxUpdate_8814A) The kernel always runs usb_AggSettingTxUpdate_8814A with UsbTxAggMode=1, UsbTxAggDescNum=3: REG_TDECTRL[7:4]=3 plus REG_TDECTRL+3 (0x20B)=0x06. Devourer's _usbTxAggMode=false meant neither write happened (and the 8812 path omits the 0x20B write even when enabled), leaving the TXDMA block-descriptor state different from every working kernel chip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…b_halinit.c:_InitMacConfigure_8814A) The kernel folded the old _InitWMACSetting_8812A + _InitAdaptiveCtrl into _InitMacConfigure_8814A, whose tail writes REG_MAX_AGGR_NUM_8814A(0x4CA) and REG_RTS_MAX_AGGR_NUM_8814A(0x4CB) to 0x36 each. Devourer ported the old 8812 pair, whose only aggregation-limit write was the 8812-body 16-bit 0x4CA=0x1f1f in _InitBurstPktLen (removed for 8814 in c5bb4ad). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…linit.c HW_VAR_NAV_UPPER)
Both drivers zero 0x652 mid-init ("Nav limit, suggest by scott"), but the
kernel restores it at the end of hal init: rtw_hal_set_hwreg(
HW_VAR_NAV_UPPER, 30000us) -> ceil(30000/128) = 0xEB
(rtl8814a_hal_init.c:3794-3807). Devourer left it at 0, i.e. the MAC
honours arbitrarily long NAV reservations - on a busy channel that can
defer TX indefinitely.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… commented out) The kernel 8814 init never writes REG_USB_HRPWM (0xFE58); its only live writes are on the LPS enter/leave path, unreachable in monitor mode. Keep the write for 8812/8821 whose kernels do it at init. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The TX-power loop default flipped when the 8814 packed-0x1998 TXAGC path landed: it now runs on every chip and DEVOURER_SKIP_TXPWR is the only knob (RadioManagementModule.cpp). DEVOURER_FORCE_TXPWR no longer exists in code. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e (kernel usb_halinit.c:hal_carddisable_8814)
Three deltas vs the kernel teardown the scaffold mirrors:
- Quiesce MAC first: hal_carddisable_8814 writes REG_CR=0 ("stop rx")
before running NIC_DISABLE_FLOW (usb_halinit.c:1394-1398); the scaffold
went straight to the power-seq while RX/TX DMA enables were live.
(Mid-lifecycle REG_CR=0 is a known #36 foot-gun, but here the full init
that follows rebuilds CR — same position as the kernel's write.)
- Gate on the warm-boot detect: the kernel only card-disables when HW
init completed (usb_halinit.c:1453); feeding ACT_TO_CARDEMU to a cold
chip is a path the kernel never exercises. Reuse the REG_SYS_CLKR/REG_CR
warm detect computed just above instead of discarding it.
- Cut mask: the kernel passes the chip-independent CONSTANT
(u8)~PWR_CUT_TESTCHIP_MSK for both 8814 flows (usb_halinit.c:217,:1398).
Devourer's relaxed PWR_CUT_ALL_MSK additionally executed the
test-chip-only entries (0x0002[0]=0 + 2us delay in the disable flow).
Match the constant for 8814; 8821 logic unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Cmd.c:134) HalPwrSeqCmdParsing retried failing PWR_CMD_POLLING reads every 10ms; the kernel uses rtw_udelay_os(10). With maxPollingCnt=5000 the worst-case failing-poll budget is ~50ms upstream - devourer's was ~50s, which is what a wedged chip would cost each regress cell. Success path (first read matches) is unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…a_hal_init.c:649-656) The 8814 branch of _FWFreeToGo8812 accepted byte0==0x78 of REG_MCUFWDL as "fw booted" — but devourer itself writes 0x6078 there in the kick immediately before polling, so the check self-satisfied on the first read. A never-booted 3081 was indistinguishable from success, which is exactly the blind spot the silent-TX investigation has been circling: every "fw is fine" assumption downstream was unvalidated. The kernel's terminal success condition is CPU_DL_READY (BIT15), set by the chip when the 3081 boots, polled at 50ms x 100 — only sound because the bit is stable once set (the old "transient BIT15" rationale here contradicted the kernel's own polling structure). Poll BIT15 only, keep the fast cadence, and log loudly on timeout: a failure here on a virgin chip is the smoking gun. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…l GET_FIRMWARE_HDR_VERSION_3081) GET_FIRMWARE_HDR_VERSION_8812 reads LE16 at __FwHdr+4; passing fw+4 double-offset it to header bytes 8-9 (= 0) so every boot logged fw_ver=0. The blob actually carries v33 (byte-identical to the kernel's array_mp_8814a_fw_nic, md5 42b8d181d0aaa7946ebec6d0bd5f068d). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Several post-download writes carried wrong register names (8812-era or guessed): 0x010d is REG_TRXDMA_CTRL+1 (not REG_RD_CTRL+1), 0x0230 is REG_FIFOPAGE_INFO_1_8814A i.e. the HPQ page count - zeroed here and only restored later by _InitQueueReservedPage_8814AUsb (not REG_PCIE_CTRL), 0x022c is REG_RQPN_CTRL_2 / LD_RQPN (not REG_BIST_CTRL), 0x0210 is REG_TXDMA_STATUS W1C (not REG_RXFLTMAP), 0x001d is REG_RSV_CTRL+1, and 0x0003 is REG_SYS_FUNC_EN+1. Comment-only change, but these labels were actively misleading while debugging the TX gate (e.g. "fixing" RXFLTMAP via 0x0210 would poke TXDMA error-status). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… keys off maintained cur_channel) send_packet's CCK->OFDM clamp (126fb4e, the 5GHz TX fix) gated on _channel.Channel, but _channel was never assigned anywhere: not in the constructor init-list, and SetMonitorChannel/InitWrite passed the channel through to RadioManagementModule without storing it. The only band-aware TX-rate decision therefore read indeterminate memory - if the garbage byte was <=14 the clamp never fired on 5GHz (CCK beacon, 0 frames on air); if >14 it silently clamped on 2.4GHz too. The kernel keys the same decision off pmlmeext->cur_channel, which every channel-set maintains (core/rtw_mlme_ext.c:1058). Store the channel in SetMonitorChannel (both Init and InitWrite route through it) and value-initialise the member so the clamp is off until the first channel set. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… vs CHANNEL_WIDTH enums) The VHT info-field parse stored 40/80 (MHz) into bwidth, but the DATA_BW switch compares against CHANNEL_WIDTH_40(1)/CHANNEL_WIDTH_80(2) - 40!=1, 80!=2 - so every VHT frame transmitted at 20MHz regardless of the requested bandwidth (kernel reference: BWMapping_8814, rtl8814a_xmit.c:443). The HT path already used the enums; align the VHT path. Affects DEVOURER_TX_VHT=1 + DEVOURER_TX_BW=40/80 and the encoding-matrix VHT-BW cells. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…l phydm_cfotracking.c, rtl8814a_rf6052.c:143) Two RF/BB trim fixes from the init-order audit: 1. hal_set_crystal_cap applied the 8812A mask 0x7FF80000 (0x2C[30:25]=[24:19]) to every chip. Upstream phydm places the XTAL-trim field per chip: 8814A at 0x2C[26:21]=[20:15] (0x07FF8000), 8821A at 0x2C[23:18]=[17:12] (0x00FFF000). On 8814 the EFUSE cap landed 4 bits high - real trim field untouched, bits [30:27] clobbered - i.e. an uncorrected carrier-frequency offset on TX and RX on every init. (8821's 5GHz gates are still open; wrong XTAL trim is a plausible contributor there too.) 2. PHY_RFConfig8814A's tail copies path A's RC-calibration word (RF 0x1C, RF_RCK1_Jaguar) to paths B/C/D after the radio tables load (rtl8814a_rf6052.c:143-146); devourer never did, leaving B/C/D at table-default RC trim - RC filter bandwidth skew across chains. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
….c:1250) REG_SECONDARY_CCA_CTRL_8814A was one of the few unported MAC writes left in the TX-relevant 0x5xx block; the kernel writes it unconditionally right after the BAR-mode disable. Gates TX deferral behaviour on the secondary channel. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…erLevel8814 has none) PHY_SetTxPowerLevel8814 (rtl8814a_phycfg.c:636-673) only loops phy_set_tx_power_level_by_path; no TxPowerTraining exists anywhere in the 8814 kernel tree and the BB table initialises 0xC54/0xE54 to 0. Devourer ran the 8812 trainee for all 4 paths on every channel set: paths B, C and D collapsed onto 0xE54 (the 8812 function only knows two write offsets, last-writer-wins) and 0xC54 got a non-zero training word the kernel never writes - an uncontrolled write into page-C/E AGC space. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t.c:hal_ReadRFEType_8814A) The 8812 RFE parser ran for 8814: unprogrammed/BIT7 EFUSE 0xCA resolved to rfe_type=0 (kernel 8814AU: 1), the programmed-value mask was 0x3F + the rfe==4 customer workaround (kernel 8814: plain 0x7F), and amplifier state came from the 8812 0xBC-0xC0 byte parse (kernel 8814 derives it from the resolved rfe_type; the byte-parsing hal_ReadPAType_8814A is dead code upstream). On unburnt boards the wrong fallback selected the rfe-0 pinmux/GPIO branches (5G pinmux 0x54775477 vs 0x33173317, GPIO 0x42|=0xc0 vs 0xf0) - the register class that drives the external PA/T-R switch. The CF-938AC burns 0xCA=0x01, so both parsers agreed there (rfe=1); ground truth from the 2026-05-29 EFUSE readout. With the kernel tree in place the GetPhyContext rfe 0->1 patch-up is redundant (and would mis-map a legitimately-burnt rfe=0 board), so it is removed; the constructor's autoload-fail parse now also lands on 1 per the kernel's autoload-fail branch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…load_pg_txpwr_info_path_5g) The 5G section was parsed with the 2.4G shape (two bytes per Ntx). The kernel's 5G layout after the 14 base bytes + tx0 byte is: one byte per tx 1..3 (MSB=BW40,LSB=BW20), one OFDM-2T~3T byte (MSB|LSB), one OFDM-4T byte (LSB), then four BW80|BW160 bytes for tx 0..3. Total stride is 24 both ways, so path alignment and all 2.4G fields survived - but every 5G field from relative byte 16 onward was wrong-sourced: BW20/40 diffs for 3S/4S read OFDM bytes, OFDM 2T-4T read BW40/BW80 bytes, and the BW80 diffs read BW160 nibbles. Affects 5G TX-power index for >=2SS rates and all 80MHz rates on PG-programmed boards. Found independently by two audit passes with matching byte maps. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…hal_com_phycfg.c:2490-2601) The kernel adds the per-Ntx diff for every rate range that *includes* the rate: MCS8-31 gets [0]+[1], MCS16-31 gets [0]+[1]+[2], VHT2SS+ adds [1], VHT3SS+ adds [2]. Devourer used exclusive windows (MCS16-23 -> [2] only) on 2.4G, and the 5G branch had no VHT clauses beyond [0] at all - so 5G VHT2SS missed [1] and VHT3SS missed [1]+[2]. Wrong TXAGC indexes for every >=2SS rate on PG-programmed boards (0.5dB per diff step). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The 0x670=0xc0000000 end-of-init write was commented "NAV-related"; it is REG_CAMCMD BIT31|BIT30 = security-CAM clear-all, i.e. the kernel's invalidate_cam_all (usb_halinit.c:1236) relocated to end-of-init. Remove the uncalled BIT0-style InitLLTTable8814A(): the init-order audit adjudicated the auto-LLT trigger as BIT16 (the only structured in-tree field definition, hal_com_reg.h "2 AUTO_LLT", hardware-verified self-clear) and the vendor BIT0 function's poll tests a stale pre-write variable - keeping a dead "corrected port" of it around only invites someone to wire it back up. A comment now records the adjudication and the pages-before-trigger invariant. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…F_SZ=32768)
The 8814 init programs REG_RXDMA_AGG_PG_TH=0x05 ("dmc agg th 20K") - as
of c5bb4ad via the kernel-parity burst-len port - but infinite_read()
posted a 16 KB host buffer. Realtek sized the contract together: 20 KB
threshold + in-flight frame <= 32 KB URB (rtl8814a_recv.h:25, 8 async
URBs). A 16 KB read is an exact wMaxPacketSize multiple, so an oversize
aggregate is split with no short packet: its tail lands at the head of
the next transfer where it gets parsed as an RX descriptor and the
remainder is discarded. 8812/8821 final thresholds (<=12-16 KB) fit the
old buffer, consistent with only 8814 RX misbehaving under load.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nel usb_AggSettingRxUpdate_8814A) The kernel RMW-clears USB_AGG_EN_8814A in REG_RXDMA_AGG_PG_TH+3 during RX-aggregation setup (usb_halinit.c:705-727); devourer's executed path never wrote that byte, relying on the reset value. If the bit powers up (or a previous driver leaves it) set, the chip produces mixed DMA+USB aggregation framing that the RND8 parse walk does not expect. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…caveat Three RX-parse robustness items vs the kernel walk: - gate the PHY-status memcpy on drvinfo_sz >= report size + buffer bound (kernel gates on pattrib->physt, usb_ops_linux.c:179); frames without a PHY status had payload bytes decoded as RSSI/EVM/SNR, and frames ending near the buffer tail over-read the transfer buffer. - never parse a descriptor out of a tail fragment < RXDESC_SIZE (kernel rejects short transfers before parsing). - document that SGI/LDPC/STBC/BW descriptor fields are 8812/8821-only: 8814 DWORD4 holds PATTERN_IDX/RX_EOF/RX_SCRAMBLER and the kernel's 8814 rx-desc query never reads them (no current consumer, but a trap). - demote the "Unprocessed packets" log: DMA_AGG_NUM is informational and never decremented, so it fired on every aggregated transfer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…dback (kernel rtl8814a_phycfg.c:phy_RFRead_8814A) The kernel reads 8814 RF registers through per-path direct BB addresses (0x2800/0x2C00/0x3800/0x3C00 + reg*4); devourer used the 8812 HSSI/LSSI serial mechanism for every chip. On paths C/D the serial readback returns garbage, so every masked (read-modify-write) RF write corrupted all bits outside its mask there - the channel write (RF 0x18, BIT18|17|16|9|8|byte0) and the bandwidth write (RF 0x18, BIT11|10) destroyed path C/D tuning state on every channel set. This also overturns the standing "paths C/D are write-only by HW design" note: they are readable, just not via the 3-wire SI path. Route phy_RFSerialRead through the direct block on 8814; the RMW in phy_set_rf_reg, phy_query_rf_reg, the RCK1 sync and IQK backup/restore all inherit the fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…8814A) The 5G case-2 branch wrote 0x33173717 to the A/B/C RFE pinmux regs - nibble [27:24] carried rfe-1's value, a copy slip between adjacent cases. Kernel writes 0x37173717 on all three. Latent on the CF-938AC (rfe_type 1) but wrong antenna-switch function codes on rfe-2 boards. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… ODM_IC_AC_4SS) phydm_SetIgiFloor_Jaguar floored only 0xC50/0xE50 to 0x1c; on the 4-path 8814 that left C/D (0x1850/0x1A50) at the BB-table seed 0x20 - a 4 dB per-path initial-gain imbalance the kernel never has (its DIG writes all four paths the same value), skewing MRC combining and per-path RSSI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ion plan Full source-level audit of the 8814 code paths against aircrack-ng/rtl8814au: 27 fix commits ranked by TX-relevance, the settled negative results (zero H2C in monitor mode, IQK-off parity, table/walker/pwr-seq parity, BIT16 LLT verdict), residual unported- feature risks, the C4 experiment list, and the pending hardware validation checklist. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 11, 2026
josephnef
added a commit
that referenced
this pull request
Jun 11, 2026
## Summary The RTL8814AU's 3081 MCU firmware never booted under devourer — `CPU_DL_READY` (REG_MCUFWDL bit15) never asserted — which was the root cause of dead host-pushed TX (#50, #95) while RX worked. (The port-audit groundwork merged separately as #96; this PR is the firmware-boot fix on top.) ### Firmware-boot fix The fwdl bracket is now a verbatim port of the vendor kernel's `FirmwareDownload8814A` + `HalROMDownloadFWRSVDPage8814A`, wired through helpers that already existed in-tree but were never called: `_FWDownloadEnable_8814A` → `_3081Disable` → DDMA BIT16 toggle → RSVD-page download (kernel chunking, beacon-queue state set once, per-section checksum-driven `DL_RDY|CHKSUM_OK` RMW) → conditional `FW_DW_RDY` → `_3081Enable` → poll `CPU_DL_READY`. The rtw88-mimic power-on prefix is retained (devourer's only 8814 power-on path). The legacy fwdl sequence is preserved bit-for-bit behind `DEVOURER_8814_FWDL=rtw88` and still reproduces the failure — clean causal A/B. `DEVOURER_8814_FWDL_CHUNK` overrides chunk size; `_DumpFwdlState8814A` traces each bracket step. Boot trajectory on a virgin chip: `REG_MCUFWDL 0x...2079 → 0x...6079 → 0x...E078` (`CPU_DL_READY` asserts instantly on `_3081Enable`). ### Also in this PR - Logger: byte-sized integers stream as numbers, not raw chars (register values like `0xF0` were landing in logs as invalid UTF-8 and crashing `tests/regress.py` parsing); regress parsers made byte-tolerant - Docs: hardware table flips 8814 to TX + RX on every band; stale gotchas removed ## Validation (real hardware) Regress matrix, TX=RTL8814AU / RX=RTL8812AU, VM-mode kernel cells: | channel | devourer→kernel | devourer→devourer | |---|---|---| | 6 | ✓ 4281/4500 | ✓ 4500/4500 | | 36 | ✓ 2315/4500 | ✓ 2200/4500 | | 100 | ✓ 1378/4500 | ✓ 1400/4500 | (kernel-TX cells read 0 at every channel — `88XXau` host-push beacon injection doesn't emit on that driver; its probe-request injection does. Pre-existing, documented in CLAUDE.md.) - 8814 RX unaffected; 8812 TX/RX unaffected (8463 frames on-air) - #36 passthrough-cycle wedge no longer reproduces: 9 virsh attach/detach cycles, then 14,500 submits with 0 `LIBUSB_ERROR_IO`, 10,688 frames on-air, FW boots from the dirty post-passthrough state Fixes #95. Fixes #50. Fixes #36. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.
What
A full audit of devourer's RTL8814AU code path against the kernel reference (aircrack-ng/rtl8814au), fixing structural mis-ports plus two pure C++ bugs. 31 commits, all build-verified; ranked findings + coverage map in
docs/8814-port-audit.md.Root pattern: most findings are 8812-suffixed code running unconditionally on the 8814, where the 8814 needs a different value/register/sequence — e.g. the burst-len body (clobbered the BCNQ1 TX-buffer boundary via a moved register), USTIME clock constants, crystal-cap trim bit positions, RF serial readback (paths C/D are readable via direct shadow blocks, not 8812 serial readback), the RFE-type parser, TX-power-training, the 5G EFUSE PG-block layout, and the IGI floor (must cover paths C/D). Plus two C++ bugs no wire-diff would catch: the 5 GHz CCK clamp read an uninitialized channel member, and the FW-boot poll was satisfied by devourer's own register write.
Regression validation (on hardware, this branch vs working baseline)
Tested the full devourer TX/RX matrix on the rig — no functional regressions:
The shared-code changes (
FrameParserRX parse hardening,RtlUsbAdapter20 K bulk-IN buffer, the VHT-TX bandwidth fix) do not regress the working chips. The VHT 80 MHz frame is now genuinely 80 MHz wide (the bandwidth field finally reaches the descriptor) — that's the9c38f80fix working, not a break.Important: this does NOT fix 8814 TX
8814 TX remains 0 on-air — root-caused (and validated this branch) to the firmware never booting (
CPU_DL_READY/bit15 never asserts; the 3081 MCU stays halted). That is the now-real FW-boot check (2931ad6) exposing what the old self-satisfied poll hid. Tracked separately in #95 (root cause of #50). This PR lands the correctness fixes + the diagnostics that pinpointed it; the FW-download/boot port is follow-up work.Side effect to note: the real FW-boot poll adds ~5 s to every 8814 init (it waits for a
CPU_DL_READYthat never comes today). RX still works; init is just slower until #95 is fixed.Refs
docs/8814-port-audit.md🤖 Generated with Claude Code