Skip to content

T1 phydm-runtime residuals: DIG floor + TX BB-swing thermal-meter pwrtrk#65

Merged
josephnef merged 2 commits into
masterfrom
t1-phydm-runtime-residuals
Jun 2, 2026
Merged

T1 phydm-runtime residuals: DIG floor + TX BB-swing thermal-meter pwrtrk#65
josephnef merged 2 commits into
masterfrom
t1-phydm-runtime-residuals

Conversation

@josephnef
Copy link
Copy Markdown
Collaborator

Summary

Closes the last two T1 canary divergences from PR #64 by porting the relevant phydm runtime loops directly into devourer:

  • 0xc50 / 0xe50 (RX Initial Gain) — kernel converges to 0x1c via DIG (phydm_dig.c:dm_dig_min = 0x1c for ODM_RTL8812 | RTL8814A | RTL8821 | RTL8822B). Devourer had no watchdog, was stuck at the BB-init seed 0x20 (~4 dB less sensitive). Pre-converged to the documented floor at init.
  • 0xc1c / 0xe1c bits 31:21 (TX BB-swing) — kernel walks this up/down through tx_scaling_table_jaguar from odm_txpowertracking_callback_thermal_meter based on RF[A][0x42] thermal-meter reads. Full port of the loop + the 12 g_delta_swing_table_idx_mp_*_txpowertrack_usb_8812a lookup tables. odm_clear_txpowertracking_state hooked into phy_SetBBSwingByBand_8812A so the next tick re-applies after channel-set rewrites the BB-swing base.

Helpers omitted because they're not reachable from devourer's monitor-mode RX/TX path: by-rate pwr_tracking_limit table (devourer always sees tx_rate==0xFF), tx-AGC remnant compensation (final_idx is clamped to pwr_tracking_limit), IQK/LCK retrigger on thermal delta, CCK / xtal-offset / DPK paths, 8814A path-C/D.

Canary diff vs kernel reference (aircrack-ng/88XXau on ch6)

Register Kernel Pre-port Post-port
BB 0xc50 (rA_IGI) 0x0000001C 0x00000020 0x0000001C
BB 0xe50 (rB_IGI) 0x0000001C 0x00000020 0x0000001C
BB 0xc1c (rA_TxScale[31:21]) 0x47C00003 0x40000003 0x47C00003
BB 0xe1c (rB_TxScale[31:21]) 0x47C00003 0x40000003 0x47C00003

Remaining canary divergences against /tmp/kernel-canary.txt are runtime ephemeral state only — MAC TBTT/queue counters, RF[A][0x42] thermal sample timing, MAC 0x550/0x560 beacon-window state. Not init bugs.

Test plan

Full regression matrix vs PR #64 baseline (5b7fc12) — VM mode, three channels, all three adapters (8812AU / 8821AU / 8814AU):

  • ch6 (2.4 GHz): 22/24 cells pass. Only fails = pre-existing 8814AU TX-gate (issue RTL8814AU: devourer TX degrades to LIBUSB_ERROR_IO after USB passthrough cycles #36). No regression.
  • ch36 (UNII-1): same pass set as master. Dev-dev pair fails verified pre-existing via targeted single-cell test on 5b7fc12 (8812-dev → 8821-dev at ch36 = 0/7000 on both pre- and post-port — symptom is the known UNII-1 dev-dev gap, not introduced here).
  • ch100 (UNII-2): same pass set as master — matches the documented UNII-2/3 receiver-asymmetry state in the README.
  • RX smoke test on 8812AU at ch6: frames received within seconds of init, no crash.
  • DEVOURER_DUMP_CANARY=1 confirms all four target registers now match kernel byte-for-byte.

🤖 Generated with Claude Code

josephnef and others added 2 commits June 1, 2026 23:26
T1 canary diff residual #1 of 2 from PR #64. Upstream phydm runs DIG
(Dynamic Initial Gain) from a watchdog timer and walks 0xc50/0xe50
down to 0x1c on all Jaguar chips (phydm_dig.c sets dm_dig_min = 0x1c
for ODM_RTL8812 | RTL8814A | RTL8821 | RTL8822B). Devourer has no
phydm watchdog so its IGI was stuck at the BB-init seed 0x20 — about
4 dB less RX sensitivity than the kernel driver in clean conditions.

Cross-checked against /tmp/kernel-canary.txt (aircrack-ng/88XXau on
ch6, same dongle): kernel reads BB 0xc50/0xe50 = 0x0000001C
post-init; devourer now matches byte-for-byte (previously 0x20).

Also documents the second canary residual (0xc1c bits 31:21, phydm
TX BB-swing thermal compensation, kernel value 0x23E) inline on both
sides of the canary tooling. Closing that one would require porting
~2800 LOC of phydm power-tracking + a watchdog timer; the divergence
itself is benign (0 dB devourer vs +1 dB warmed-kernel) and is now
explicitly flagged in the diff oracle so the next reader doesn't
chase it as a real init bug.

Verified RX path still works after the change: WiFiDriverDemo at ch6
captures frames within seconds, no init failures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes T1 canary residual #2 of 2 — BB 0xc1c bits 31:21 (and the
path-B equivalent 0xe1c). The previous commit annotated this as
out-of-scope; that was wrong. T1's goal is byte-for-byte parity with
the kernel reference, and 0xc1c is part of it.

Port covers:
  - The 12 USB delta_swing tables from upstream's
    `halhwimg8812a_rf.c:txpowertrack_usb` (per-band, per-RF-path,
    per-temperature-direction lookups, [3][30] for 5G sub-bands).
  - `tx_scaling_table_jaguar` (37-entry BB-swing table covering
    -12 dB to +6 dB in 0.5 dB steps).
  - `odm_txpowertracking_thermal_meter_init` — seeds
    default_ofdm_index from the current 0xc1c[31:21] value (24 for a
    0 dB BB-init seed).
  - `odm_txpowertracking_callback_thermal_meter` + `odm_pwrtrk_method`
    + `odm_tx_pwr_track_set_pwr8812a` MIX_MODE branch — read RF[A]
    [0x42][15:10], fold into a 4-sample rolling average, compute
    delta vs the EFUSE thermal baseline, walk the channel/band-
    specific delta_swing table, clamp to the pwr_tracking_limit of
    26 (+1 dB; same default upstream uses when tx_rate is unknown),
    and write `tx_scaling_table_jaguar[final_idx]` to 0xc1c[31:21]
    and 0xe1c[31:21].
  - `odm_clear_txpowertracking_state` — called from
    `phy_SetBBSwingByBand_8812A` after the BB-swing base is
    rewritten, mirroring upstream. Without this hook the next
    pwrtrk tick sees delta_abs==0 (thermal unchanged since last
    tick) and short-circuits the re-apply, leaving 0xc1c stuck at
    the BB-init base after every channel-set.

Helpers intentionally omitted because they're not reachable from
devourer's monitor-mode RX/TX path: by-rate `pwr_tracking_limit`
table (we always see tx_rate==0xFF), tx-AGC remnant compensation
(final_idx is clamped to pwr_tracking_limit), IQK/LCK retrigger on
thermal delta (IQK is done at init only), CCK / xtal-offset / DPK
paths, 8814A path-C/D (separate port).

Verification (8812AU dongle 0bda:8812, ch6, post-init):
  Pre-port:    BB 0xc1c = 0x40000003 (0x200 / 0 dB)
  Post-port:   BB 0xc1c = 0x47C00003 (0x23E / +1 dB)
  Kernel ref:  BB 0xc1c = 0x47C00003 — byte-for-byte match.
  Path-B 0xe1c likewise. Remaining canary divergences against
  /tmp/kernel-canary.txt are all runtime ephemeral state (MAC TBTT
  counters, RF[A][0x42] thermal sample timing, etc.) — not init
  bugs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@josephnef josephnef merged commit aec62e1 into master Jun 2, 2026
5 checks passed
@josephnef josephnef deleted the t1-phydm-runtime-residuals branch June 2, 2026 09:20
josephnef added a commit that referenced this pull request Jun 2, 2026
## Summary

Port of upstream phydm's IQK (`phy_iq_calibrate_8812a` →
`_iqk_tx_8812a`) for RTL8812AU. Closes the IQK side of T1 canary
divergence vs `aircrack-ng/88XXau`:

- **BB 0x8b0**: `0x00000642` matches kernel byte-for-byte (was
`0x00000618` pre-port — IQK side effect we'd been mis-attributing as
static init drift).
- IQK output regs (`0xc10`, `0xccc`, `0xcd4`, `0xe10`, `0xecc`, `0xed4`)
now get calibrated values; previously held BB-init seeds.
- Convergence: TX A_done=1 B_done=1, RX A_done=1 B_done=1 with 0-1
retries per path.

## Wiring

- `HalModule::rtl8812au_hal_init` arms `_needIQK = true` post-RF-config
via new `RadioManagementModule::ArmIQKOnNextChannelSet`.
- `phy_SwBand8812` arms `_needIQK = true` on band transitions (2.4G ↔
5G).
- `phy_SwChnlAndSetBwMode8812` calls `_iqk.Calibrate()` when `_needIQK`
is set.
- Env knobs:
- `DEVOURER_FORCE_IQK=1` — run IQK on every channel-set (canary-diff
workflow).
  - `DEVOURER_DISABLE_IQK=1` — emergency escape hatch.

## Scope

**In:** `_phy_iq_calibrate_8812a` end-to-end (backup → run → restore),
`_iqk_tx_8812a` TX-tone + RX-tone calibration loops with ±4 averaging
convergence over up to 10 cal iterations per path, `_iqk_backup_*` /
`_iqk_restore_*` for MAC/BB/RF/AFE state, `_iqk_configure_mac_8812a`,
`_iqk_tx_fill_iqc_8812a` / `_iqk_rx_fill_iqc_8812a`.

**Out (not reachable from devourer's monitor-mode init):** FW-offload
IQK (no H2C mailbox), per-channel `iqk_matrix_reg_setting[]` cache,
VDF/VHT-160, LC calibration, DPK (`_phy_dp_calibrate_8812a`, separate
~700 LOC; that's where BB 0xc90 and residual RF[A/B] 0x00 divergence
come from).

## Bug found during validation: 5GHz TX regression

First matrix run with IQK enabled surfaced a regression — 8812AU TX at
ch36 dropped from `6500/6500 ✓` to `0/6500 ✗`. Root cause was a subtle
porting bug in commit `b4b1038`:

Upstream uses `odm_get_bb_reg(dm, 0xd00, 0x07ff0000) << 21` to read the
11-bit IQK output. `odm_get_bb_reg` **right-shifts by the mask offset
(16) before returning** — devourer's `phy_query_bb_reg` matches this
contract, but my naive port used `(rtw_read32(0xd00) & 0x07ff0000) <<
21` which leaves the value at bits 16:26, then shifts to positions 37:47
— UB in 32-bit int, in practice yields 0. All 8 TX/RX read sites had the
bug → every IQK sample was 0 → convergence "succeeded" with both samples
== 0 → FillIQC wrote X=0 instead of either calibrated or default X=0x200
→ 5GHz TX broken.

Fix: insert the missing `>> 16` to match `odm_get_bb_reg`'s shift-down
semantics. The lesson is now captured in kaeru (`Realtek phydm porting
trap — odm_get_bb_reg returns shifted-down value`).

## Test plan

Full matrix in VM mode across 3 channels with IQK default-on:

- [x] **ch6**: 22/24 ✓ — identical to PR #65 baseline. Only fails are
pre-existing 8814 TX-gate (issue #36).
- [x] **ch36**: 8812-dev TX cells restored — `8812-dev → 8821-ker =
6440/6500 ✓`, `8812-dev → 8814-ker = 5870/6500 ✓` (vs `0/6500` pre-fix).
All other cells match master baseline. Pre-existing failures unchanged
(8814 TX-gate, 5G dev-dev gap, 5G UNII-1 8814 RX).
- [x] **ch100**: matches master baseline pattern. Pre-existing UNII-2/3
receiver asymmetries unchanged.
- [x] `DEVOURER_DUMP_CANARY=1` at ch6: `BB 0x8b0 = 0x642` matches kernel
byte-for-byte.
- [x] RX smoke test: frames received within seconds, no init failures.

## Commits

1. `6027fe9` Initial IQK port (env-gated due to regression).
2. `b4b1038` Fix mask-extract bug — root cause of 5GHz TX regression.
3. `af97973` Flip IQK trigger back to default-on after fix verified.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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