Skip to content

PCIe: RTL8822BE (Jaguar2) + RTL8822CE (Jaguar3) support — bring-up recipe for when lab hardware arrives #214

Description

@josephnef

The PCIe transport (#213) is chip-agnostic for HalMAC-generation parts: both the RTL8822BE and RTL8822CE use the exact same 88xx buffer-descriptor rings and descriptor geometry as the validated RTL8821CE (tx_pkt_desc_sz=48, tx_buf_desc_sz=16, rx_pkt_desc_sz=24, rx_buf_desc_sz=8, per rtw88 v6.12 rtw8822b.c/rtw8822c.c). src/PcieTransport.{h,cpp} needs zero changes — each chip needs only its HAL-side gates, exactly the set the 8821CE port added to Jaguar2. This issue is the full recipe so the port can be executed as soon as either card is in the lab.

Shared work items (both chips)

  1. CMake: relax the DEVOURER_PCIE constraint in CMakeLists.txt — currently FATAL_ERRORs without DEVOURER_JAGUAR2_8821C; change to "requires at least one chip with a PCIe bring-up" and update the option comment + error text (they already describe this exact extension).
  2. Factory (WiFiDriver::CreateRtlDevicePcie, src/WiFiDriver.cpp): accept the new chip-id read from MMIO 0xFC and construct the right device — 0x0aRtlJaguar2Device/C8822B, 0x13RtlJaguar3Device/C8822C. Guard with the matching DEVOURER_HAVE_*.
  3. Power-on order: the device orchestrator must call _device.hci_setup() per bring-up attempt, before power_on() (rtw88: rtw_hci_setuprtw_mac_power_on; the DLFW rsvd-page path needs the BCN ring live, and the power seq clears 0x300/0x301 so it must re-run per attempt). Jaguar2 already does this (RtlJaguar2Device::bring_up); Jaguar3 does not yet — mirror it in RtlJaguar3Device.
  4. PCIe power-seq tables: transcribe the RTW_PWR_INTF_PCI_MSK | ALL_MSK rows from rtw88 v6.12 (trans_carddis_to_cardemu_* + trans_cardemu_to_act_* for on; trans_act_to_cardemu_* + trans_cardemu_to_carddis_* for off), selected by (variant, is_usb()). rtw88 has 7 PCI-only rows for 8822B, 9 for 8822C. The PFM_WOWL (0x04[3]) toggle-retry on POLL timeout is already in the Jaguar2 engine (run_pwr_seq) — port it to Jaguar3's engine too.
  5. MAC init PCIe values: rqpn = rqpn_table_*[1] (both chips: vo/vi→NORMAL, be/bk→LOW, mg→EXTRA, hi→HIGH ⇒ REG_TXDMA_PQ_MAP = (3<<14)|(0<<12)|(1<<10)|(1<<8)|(2<<6)|(2<<4)); FIFO pages = page_table_*[1] (both chips: hq/nq/lq/exq/gap = 64/64/64/64/1 — note exq=64, unlike the 8821CE's 14). Gate the USB-only steps on is_usb(): init_usb_cfg (RXDMA mode + USB RX-agg), any 0xFExx USB-page register touches (undefined over MMIO — the transport guards and warns).
  6. DLFW: gate the USB 512-byte-multiple add_pkt_offset pad on is_usb() (done in HalmacJaguar2Fw::send_fw_page; check HalmacJaguar3Fw for the same pad). The BCN-ring routing is automatic — send_fw_page's QSEL_BEACON descriptor is dispatched to the BCN ring by the transport.
  7. RCR/MAR traps (hardware-bisected on the 8821CE, then found latent on USB): monitor RCR must NOT set bits 11–13 (BIT_TA_BCN/BIT_RPFM_CAM_ENABLE on this MAC generation — bit 11 drops every ambient beacon) and REG_MAR (0x620/0x624) must be written all-ones. Jaguar2 is fixed; audit Jaguar3's enable_rx-equivalent for both before blaming RF for missing beacons.
  8. PCIe interface-PHY config (per-chip, run once before first power-on — the pcie_phy_cfg() slot):
    • 8822BE: non-trivial, cut-gated MDIO gen1 + gen2 tables (pcie_gen1_param_8822b / pcie_gen2_param_8822b in rtw8822b.c — e.g. {0x0001,0xA841,CUT_C}, {0x0002,0x60C6,CUT_D}, ...). Extend the existing MDIO helper (HalmacJaguar2MacInit::pcie_phy_cfg) to walk a cut-masked table instead of the 8821C's single write.
    • 8822CE: gen1/gen2 tables are empty, but two quirks replace them: DBI write RTK_PCIE_CLKDLY_CTRL (0x725) = 0 (REFCLK auto-cal, rtw_pci_link_cfg) and, for cut ≥ D, REG_HCI_MIX_CFG |= BIT_PCIE_EMAC_PDN_AUX_TO_FAST_CLK (rtw_pci_interface_cfg). DBI access = REG_DBI_WDATA_V1 0x3E8 / REG_DBI_FLAG_V1 0x3F0 — plain MAC registers, works through rtw_write.

Per-chip facts

RTL8822BE RTL8822CE
PCI id 10ec:b822 10ec:c822
chip-id @0xFC 0x0a 0x13
HAL Jaguar2 C8822B (2T2R) Jaguar3 C8822C
EFUSE MAC (logical) 0xD0 (rtw8822be_efuse) 0x120 (rtw8822ce_efuse)
rtw88 reference rtw8822b.c/.h v6.12 rtw8822c.c/.h v6.12
expected extra work smallest port — Jaguar2 already has every seam Jaguar3 needs hci_setup() wiring + PCIe pwr-seq engine retry + is_usb() gates (its HAL was USB-only so far)

Effort estimate: 8822BE is a day-scale port (every seam exists; fill in tables). 8822CE adds the Jaguar3-side seam work — budget 2–3× that. Do 8822BE first if both arrive together.

Acceptance criteria (all on hardware, in order)

  1. cmake -DDEVOURER_PCIE=ON + the chip's option builds; DEVOURER_PCIE=OFF build byte-identical; ctest 12/12 in both configs; CI matrix green (mind the Windows include-order rules documented in src/RtlAdapter.{h,cpp}).
  2. tests/pcie_vfio_bind.sh <bdf> binds (unbind from rtw88_8822be/rtw88_8822ce — same in-tree auto-probe trap as the 8821CE).
  3. pcieprobe <bdf> id → correct chip-id; power → power-on + chip version decode + EFUSE MAC matches what the kernel driver reported (offsets above); fwREG_MCUFW_CTRL == 0xC078 over the BCN DMA ring. (The probe is 8821C-hardcoded today — parameterize it per chip as part of this work.)
  4. sudo python3 tests/pcie_rx_smoke.py --bdf <bdf> → PASS on ch 6 and ch 36 (≥5 ambient beacons each, 0 beacon CRC fails). If mgmt frames are missing while ctrl/data flow: it's the RCR bit-11 / MAR trap (item 7), not RF — cross-check the environment with a Jaguar1 reference receiver before concluding anything.
  5. TX on-air: DEVOURER_PCIE_BDF=<bdf> txdemo, 10k canonical-SA beacons, 0 submit failures, ≥90% received by a second devourer monitor (rx.txhit).
  6. FastRetune hop (DEVOURER_HOP_CHANNELS=36,40,44) → hits received on all three channels.
  7. USB regression unchanged: tests/regress.py 4/4 with the corresponding USB sibling (8822BU / 8822CU) as RX DUT.
  8. No DMAR faults in host dmesg across all of the above (a fault means a bad IOVA/DESA — VT-d logs are the debugging gift here).

Environment / traps for the executing agent

  • Validation host needs VT-d/IOMMU with the NIC in its own group, CONFIG_VFIO_PCI (the radxa-x4 pattern; ssh radxa-x4 hosts the 8821CE reference setup).
  • vfio open FLRs the device → always full power-seq; MMIO reading 0xFFFFFFFF = link down, re-check config-space vendor-id first.
  • All descriptor dma fields and DESA registers are 32-bit — the transport already maps its slab below 4 GiB; don't change that.
  • The BF self-sounding cell (tests/bf_selfsound_jaguar2.sh cell C) is intermittently zero by pre-existing flakiness — run ≥3× before believing a failure.
  • MSI-via-eventfd RX is the transport default with automatic polling fallback (DEVOURER_PCIE_NO_MSI=1 for A/B) — nothing chip-specific.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions