Skip to content

RTL8814AU: TX FIFO bring-up fixes + cross-adapter validation tooling#24

Merged
josephnef merged 4 commits into
masterfrom
feat/8814-tx-fixes
May 22, 2026
Merged

RTL8814AU: TX FIFO bring-up fixes + cross-adapter validation tooling#24
josephnef merged 4 commits into
masterfrom
feat/8814-tx-fixes

Conversation

@josephnef
Copy link
Copy Markdown
Collaborator

Summary

Three logically separate improvements that fell out of investigating the
RTL8814AU TX path. TX is still not validated end-to-end, but each change
in this PR is independently correct and verified on hardware to not regress
the existing RX path on either 8812 or 8814.

Commits

  1. demo: cross-adapter TX-validation tooling for the Jaguar family

    • txdemo learns a Linux VID/PID open path (Termux argv[1]=fd still works
      when present and parses to a positive int).
    • Fork-RX child gated behind DEVOURER_TX_WITH_RX=1 — on plain Linux
      libusb the post-fork parent/child race on the shared handle and both
      crash with rtw_read: iostream error before TX begins. Cross-adapter
      (TX on one adapter, RX on another) is the only configuration that
      actually works on regular Linux.
    • DEVOURER_PID / DEVOURER_CHANNEL / DEVOURER_SKIP_RESET env vars
      for parity with the RX demo.
    • Both demos detect the txdemo's hardcoded injected-beacon SA
      (57:42:75:05:d6:00) and log <devourer-tx-hit> on match. A clean
      signal for cross-adapter TX validation.
  2. 8814AU: TX FIFO bring-up — page allocation, auto-LLT, REG_CR preserve
    Three real chip-init bugs the 8812-path init silently no-ops on the 8814:

    • Page allocation. The 8812 writes 8-bit REG_RQPN / REG_BCNQ_BDNY
      / REG_TRXFF_BNDY (256-page TX FIFO model). The 8814 has a 2048-page
      TX FIFO and uses 32-bit REG_FIFOPAGE_INFO_{1..5}_8814A + 16-bit
      boundary registers. Port _InitQueueReservedPage_8814AUsb and
      _InitPageBoundary_8814AUsb from upstream
      hal/rtl8814a/usb/usb_halinit.c. Verified: HPQ=32, PUB=1912,
      bndy=0x07F8 after the fix.
    • Auto-LLT trigger. Without auto-LLT firing post-fwdl the per-queue
      free-page linked-list never gets built (page counts advertised but no
      actual pages linked). Upstream's InitLLTTable8814A writes BIT0 of an
      8-bit access at 0x208 — that's the wrong bit; the actual trigger
      per hal_com_reg.h:1424 is BIT_AUTO_INIT_LLT = BIT(16) of the 32-bit
      register. Use the correct BIT(16) trigger as a 32-bit RMW. Verified:
      BIT16 self-clears within 2ms, confirming the chip processed it.
    • REG_CR preserve. Final-state force-write to REG_CR now reads
      observed value first and OR's in our minimum-required bits, instead of
      clobbering the whole word. Defensive — on this hardware fw doesn't
      set high bits but the read-OR-write shape is the safer pattern.
  3. 8814AU: TX-state diagnostic dump + send_packet pre-TX probe + DEVOURER_TX_EP

    • Post-init dump of REG_CR / TXPAUSE / FWHW_TXQ_CTRL / FIFOPAGE_*
      / MCUFWDL / TXDMA_STATUS / TXDMA_OFFSET_CHK / HWSEQ_CTRL / TCR / RCR.
      One log per register (Logger format helper truncates multi-placeholder
      lines).
    • send_packet: on first call only, log CR / TXPAUSE / TXDMA_OFFSET_CHK
      / FWHW_TXQ_CTRL / MCUFWDL / HCIPWR. Surfaces any clobber between
      init-end and the actual first TX.
    • DEVOURER_TX_EP=0xNN overrides the hardcoded bulk OUT endpoint 0x02
      for EP-bisection diagnostics without a rebuild.

All diagnostic output is gated behind CHIP_8814A or env vars; 8812 path
is untouched at runtime.

Known limitation

8814 TX end-to-end still doesn't work. All three OUT EPs (0x02 / 0x03 / 0x04)
silently time out (LIBUSB_TRANSFER_TIMED_OUT, actual_length=0). Chip
state at TX time looks correct on every register we've examined — CR=0x00FF,
TXPAUSE=0x00, FW running (MCUFWDL[0]=0x78), queues have pages, auto-LLT
fires, TX descriptor checksum matches upstream byte-for-byte. The remaining
gate is somewhere we haven't dumped yet. Diagnostic infrastructure in
commit 3 is ready for the next investigation.

Test plan

  • Build clean on Linux (trainer-arch, kernel 6.18-lts, gcc 15.2.1).
  • 8812 RX regression: WiFiDriverDemo on 0bda:8812, channel 36 — 8000+
    frames received in 18s.
  • 8814 RX regression: WiFiDriverDemo on 0bda:8813, channel 36 — should
    still receive (page allocation + auto-LLT + REG_CR-preserve only
    enhance bring-up, none remove or rewrite registers the RX path
    requires).
  • 8814 TX: deferred. Tooling in commit 1 + diagnostics in commit 3
    make this a future PR; chip-init fixes in commit 2 are landed
    regardless.

🤖 Generated with Claude Code

josephnef and others added 4 commits May 22, 2026 08:43
WiFiDriverTxDemo previously only supported the Termux/Android pattern
of taking a USB fd as argv[1] and wrapping it via libusb_wrap_sys_
device. On a regular Linux libusb context that path doesn't apply,
and the demo also forked an RX child to run alongside TX on the same
USB handle — which races on a libusb context that isn't fork-safe
and crashes both processes with "rtw_read: iostream error" before
TX even begins.

Changes:

- txdemo: when argv[1] is absent or non-numeric, fall through to a
  VID/PID open against the same Realtek PID list as the RX demo
  (0x8812 / 0x0811 / 0xa811 / 0xb811 / 0x8813). The Termux fd path
  is preserved when argv[1] is a positive int. Adds DEVOURER_PID,
  DEVOURER_CHANNEL, DEVOURER_SKIP_RESET env vars (parity with RX
  demo).
- txdemo: gate the fork-RX child behind DEVOURER_TX_WITH_RX=1.
  Default is TX-only on a single handle. Cross-adapter validation
  (TX on one adapter, RX on another) is the only configuration that
  actually works on plain Linux.
- txdemo: throttle the TX loop with usleep(2000) and log every Nth
  TX so it doesn't peg a core or spam stdout.
- demo (RX) + txdemo (RX-when-DEVOURER_TX_WITH_RX): detect the
  txdemo's hardcoded injected-beacon SA (57:42:75:05:d6:00) and log
  <devourer-tx-hit> on match. Provides a clean signal for cross-
  adapter TX validation — each hit is one frame round-tripped over
  the air.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 8812-path HalModule init steps that program the TX FIFO silently no-op
on the 8814AU. Three separate chip-init bugs that have to be fixed before
any TX path can work on this chip:

1) **Page allocation.** _InitQueueReservedPage_8812AUsb and
   _InitTxBufferBoundary_8812AUsb write 8-bit fields in REG_RQPN /
   REG_RQPN_NPQ (0x200-0x202) and REG_BCNQ_BDNY / REG_MGQ_BDNY /
   REG_TRXFF_BNDY (0x424-... 8-bit). That register set is the 8812's
   ~256-page TX FIFO model. The 8814 has a 2048-page TX FIFO and uses
   completely different registers: 32-bit REG_FIFOPAGE_INFO_{1..5}_8814A
   (0x230-0x240) for per-queue page counts, 16-bit REG_TXPKTBUF_BCNQ_BDNY
   /BCNQ1_BDNY/MGQ_PGBNDY for queue boundaries, plus REG_FIFOPAGE_CTRL_2
   for BCNQ head pages.
   Port _InitQueueReservedPage_8814AUsb + _InitPageBoundary_8814AUsb from
   upstream hal/rtl8814a/usb/usb_halinit.c. Dispatch on CHIP_8814A so the
   8812 path stays untouched. Register addresses + page constants
   extracted into a local `namespace rtl8814a` because the upstream
   rtl8814a_spec.h / rtl8814a_hal.h pull in kernel-only deps
   (drv_conf.h, hal_data.h) we can't satisfy in userspace.

2) **Auto-LLT trigger.** Without HW auto-LLT firing post-fwdl, the chip's
   per-queue free-page linked-list never gets built — the page counts we
   just wrote are advertised but no actual pages are linked into the
   per-queue free lists. TX would have nowhere to land buffer headers
   even if the rest of bring-up were correct.
   Upstream's hal/rtl8814a/rtl8814a_hal_init.c::InitLLTTable8814A writes
   BIT0 of an 8-bit read at 0x208 and polls BIT0 to clear. That is the
   wrong bit — verified empirically: the trigger never fires and the
   poll exits in 0 iterations because BIT0 was never set in the chip's
   response. The generic BIT_AUTO_INIT_LLT in hal_com_reg.h:1424 says
   BIT(16) of the 32-bit register at 0x208 (aliased REG_TDECTRL). Use a
   32-bit RMW with the correct BIT(16) trigger.
   Verified the fix lands: REG_AUTO_LLT readback shows BIT16 self-cleared
   within 2ms after our trigger, confirming the chip processed it.

3) **REG_CR preserve.** Some 8812-path init helpers reset REG_CR back to
   only MACTXEN|MACRXEN (0xC0). Our existing final-state force-write of
   0x00FF restored the DMA + protocol + scheduler bits but clobbered any
   high bits firmware may have set. Read REG_CR observed-value first,
   then OR-in our minimum-required low byte. Defensive — verified that
   on this hardware fw doesn't set any high bits, but it's the safer
   shape.

Each of the three is necessary but not by itself sufficient for TX. TX
end-to-end validation is still WIP (tracked separately). RX path is
unaffected by all three changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…R_TX_EP

Add three diagnostic hooks that make future 8814 TX investigations
tractable without rebuilding. All gated behind CHIP_8814A or an opt-in
env var; the 8812 path is untouched at runtime.

- HalModule::rtl8812au_hal_init: dump the registers that gate USB→TX
  dataflow at the end of init (REG_CR, TXPAUSE, FWHW_TXQ_CTRL,
  FIFOPAGE_CTRL_2, MGQ_PGBNDY, FIFOPAGE_INFO_1/5, MCUFWDL,
  TXDMA_STATUS, TXDMA_OFFSET_CHK, HWSEQ_CTRL via both 8-bit and
  32-bit byte-3 access, TCR, RCR). One log line per register —
  the Logger's homegrown format helper truncates lines with too
  many placeholders.
- RtlUsbAdapter::send_packet: on the first call only, dump CR /
  TXPAUSE / TXDMA_OFFSET_CHK / FWHW_TXQ_CTRL / MCUFWDL / HCIPWR.
  Surfaces any clobber between init-end and the actual first TX
  (e.g. SetMonitorChannel writing registers).
- RtlUsbAdapter::send_packet: DEVOURER_TX_EP=0xNN overrides the
  hardcoded bulk OUT endpoint 0x02. Lets bisecting EP routing
  without a rebuild (0x03 = NQ, 0x04 = LQ on the 8814's 3-OUT-EP
  layout).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MSVC doesn't ship <unistd.h>/usleep so the Windows CI build fails with
"identifier not found". Use std::this_thread::sleep_for which is portable
and already pulled in by the existing <thread> include in this file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@josephnef josephnef merged commit 8bd4ed2 into master May 22, 2026
5 checks passed
@josephnef josephnef deleted the feat/8814-tx-fixes branch May 22, 2026 05:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant