T1: fix 5G TX-AGC over-power + expand canary set (path-B mirror, IQK/DPK outputs)#67
Merged
Conversation
…trk fix Two related fixes to bring devourer's 5GHz TX-AGC output byte-for-byte in line with the upstream aircrack-ng/88XXau USB build. Surfaced by expanding the T1 canary set to cover ch36 + ch100 and the path-B AGC table mirror — at ch36 devourer was writing `BB 0xc24 = 0x1E1E1E1E` while kernel wrote `0x18181818`; the divergence ran across 0xc24-0xc40 + 0xe24-0xe40, ~6 power-index steps higher than upstream. ## Root causes (1) **Per-rate TX-power offset enabled by default in devourer, but upstream's USB driver builds with `CONFIG_TXPWR_BY_RATE_EN = n`** (`Makefile:48`). This sets `RegEnableTxPowerByRate = 0` → `phy_is_tx_power_by_rate_needed()` returns FALSE → `PHY_GetTxPowerByRate()` short-circuits to return 0. Upstream's USB build NEVER applies the PG-table per-rate offsets; all TX power = `base + boost (=2)`. At 2.4G devourer's headroom-cap formula happened to zero out by_rate (since `base + boost > limit` for FCC's 2.4G OFDM caps) → canary matched. At 5G headroom is positive, by_rate gets applied as +6 → devourer overshoots kernel by 6 indices uniformly across 0xc24-0xc40. Default-off the by-rate layer to match upstream's USB build. The EFUSE PG-table parse + headroom-cap formula are preserved behind `DEVOURER_ENABLE_TXPWR_BY_RATE=1` for deployments that mirror upstream's `CONFIG_TXPWR_BY_RATE_EN=y` (Windows, some Android variants). (2) **PowerTracking8812a init-ordering bug**: `PowerTracking8812a::Init()` captured `default_ofdm_index` BEFORE `phy_SetBBSwingByBand_8812A` ran the per-band BB-swing write. For 5G dongles with EFUSE-driven swing-down (e.g. our 8812AU at `0x16A = -3 dB` per `EEPROM_TX_BBSWING_5G_8812`), this left `default_ofdm_index = 24` (matching the post-BB-init `0x200`) while the actual base after band switch was index 18 (`0x16A`). The first pwrtrk tick then computed `final = 24 + abs_swing_idx` instead of `18 + abs_swing_idx` — six steps too high. Refresh `default_ofdm_index = LookupSwingIndexFromBb()` from inside `ClearState()` (which `phy_SetBBSwingByBand_8812A` already calls post-write). The Init()-time snapshot stays as the cold-init seed; every band switch + tx_agc change reseeds correctly. ## Canary expansion Added path-B TX-AGC mirror (0xe20-0xe40), IQK output regs (0xc10, 0xc14, 0xe10, 0xe14), and DPK output regs (0xc94, 0xe94, 0xc90 was already in the set) to `DEVOURER_DUMP_CANARY` + the kernel-side companion script. The path-B mirror covers a class of 2T2R-specific init drifts the previous canary couldn't surface. Also added `DEVOURER_LOG_TXPWR=1` diagnostic — traces base/by_rate/limit/headroom/final per (channel, path, rate, ntx, bw) for canary-divergence chasing on the per-rate calc. ## Verification Canary diff (8812AU, kernel = aircrack-ng/88XXau v5.6.4.2 in VM): | Reg | Pre-fix ch36 | Post-fix ch36 | Kernel ch36 | |---|---|---|---| | BB 0xc24 | `0x1E1E1E1E` | `0x16161616` ✓ | `0x16161616` | | BB 0xc28 | `0x181A1E1E` | `0x16161616` ✓ | `0x16161616` | | BB 0xc3c | `0x2E303232` | `0x16161616` ✓ | `0x16161616` | | BB 0xc40 | `0x161E2024` | `0x16161616` ✓ | `0x16161616` | | BB 0xe20-0xe40 | non-homogeneous | matches path-A | matches | Single-cell + partial matrix (8821AU dongle was temporarily detached mid-run, full matrix re-runs deferred until rig stabilises): - `8812-dev → 8821-ker @ ch36 = 6528/6500 ✓` (was `0/6500 ✗` pre-fix) - `8812-dev → 8814-ker @ ch36 = 6182/6500 ✓` (was `0/6500 ✗` pre-fix) - `8821-dev → 8814-ker @ ch36 = 6464/7000 ✓` (unchanged) - Full matrix at ch6: `22/24 ✓` identical to PR #66 baseline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
josephnef
added a commit
that referenced
this pull request
Jun 2, 2026
…14) (#69) ## Summary The 8821AU canary diff (T1 follow-on) caught this bug: `PowerTracking8812a::TickThermalMeter` was firing on every Jaguar chip (8812 / 8821 / 8814), but its delta-swing tables + math are 8812-specific. Upstream maintains a parallel `halrf_8821a_ce.c` for 8821 with different per-band tables and 1T1R-specific logic — the 8812 code produces wrong values on 8821. ## Findings **8821 ch6 canary divergences (pre-gate):** | Register | Kernel | Devourer | Notes | |---|---|---|---| | BB 0xc1c[31:21] | 0x200 (0 dB) | 0x1C8 (-1 dB) | devourer's wrong pwrtrk write | | BB 0x8b0 | 0x18 | 0x42 | AGC-state side effect | **Post-gate:** both divergences disappear — pwrtrk no longer fires on 8821, BB stays at band-init values matching kernel's not-yet-converged state. ## Fix Gate the trigger at both call sites with `_eepromManager->version_id.ICType == CHIP_8812`: - `RadioManagementModule::phy_SwChnlAndSetBwMode8812` (per channel-set tick) - `HalModule::rtl8812au_hal_init` (cold-init seed) Matches the same chip-gating pattern already used for IQK (`Iqk8812a`). 8814AU also benefits — pwrtrk was firing on it with the same 8812 tables. No matrix run for 8814 because 8814 TX is gated by issue #36, but canary correctness improves. ## Future work 8821AU pwrtrk port — separate change. Needs `halrf_8821a_ce.c` translation + 1T1R-specific table simplification. ## Test plan - [x] 8821 ch6 canary: BB 0xc1c + BB 0x8b0 divergences gone (verified post-build). - [x] Build clean. - [ ] Full matrix at ch6/ch36/ch100 with all 3 adapters — 8812 dongle was off USB during this work; verification pending re-plug. Expected: 8821 + 8814 unchanged from PR #67 baseline (which is currently stacked under this); 8812 unchanged (still runs pwrtrk). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <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.
Summary
Two related fixes uncovered by expanding the T1 canary set to 5G channels and the path-B TX-AGC mirror. Brings devourer's 5GHz TX power output byte-for-byte in line with the upstream aircrack-ng/88XXau USB build.
Findings
Pre-fix, at ch36 + ch100, devourer wrote ~6 power-index steps higher than kernel across the full TX-AGC table:
BB 0xc24(OFDM 6/9/12/18)0x1E1E1E1E0x16161616BB 0xc28(OFDM 24/36/48/54)0x181A1E1E0x16161616BB 0xc3c(VHT1SS 0..3)0x2E3032320x16161616Two root causes:
1.
CONFIG_TXPWR_BY_RATE_EN=non upstream USB buildUpstream aircrack-ng/88XXau ships with
CONFIG_TXPWR_BY_RATE_EN = n(Makefile line 48). This setsRegEnableTxPowerByRate = 0→phy_is_tx_power_by_rate_needed()returns FALSE →PHY_GetTxPowerByRate()short-circuits to always return 0. Upstream's USB driver never applies the PG-table per-rate offsets; all TX power =base + boost (=2).PR #64's
LoadTxPowerByRate+ headroom-cap formula was effectively a no-op at 2.4G (because the cap zeroed by_rate whenbase + boost > limitfor FCC's 2.4G OFDM caps), so the canary matched — masking the bug. At 5G the headroom is positive, by_rate gets applied as +6 → devourer overshoots uniformly.Fix: default-off the by-rate layer to match upstream's USB build. The EFUSE PG-table parse + headroom-cap formula are preserved behind
DEVOURER_ENABLE_TXPWR_BY_RATE=1for deployments that mirror upstream'sCONFIG_TXPWR_BY_RATE_EN=y(Windows / some Android variants).2.
PowerTracking8812ainit-ordering bugPowerTracking8812a::Init()capturesdefault_ofdm_indexBEFOREphy_SetBBSwingByBand_8812Aruns the per-band BB-swing write. For 5G dongles with EFUSE-driven swing-down (our 8812AU writes0x16A = -3 dBperEEPROM_TX_BBSWING_5G_8812), this leavesdefault_ofdm_index = 24(matching the post-BB-init0x200) while the actual base after band switch is index 18. The first pwrtrk tick then computesfinal = 24 + abs_swing_idxinstead of18 + abs_swing_idx— six steps too high.Fix: refresh
default_ofdm_index = LookupSwingIndexFromBb()from insideClearState(), whichphy_SetBBSwingByBand_8812Aalready calls post-write. Init()-time snapshot remains as the cold-init seed; every band switch reseeds.Canary expansion
Added to
DEVOURER_DUMP_CANARY+tools/canary_kernel_dump.sh:0xe20-0xe40(catches 2T2R-specific drifts the previous canary couldn't surface).0xc10,0xc14,0xe10,0xe14.0xc94,0xe94(0xc90was already there).Plus a new env-gated diagnostic
DEVOURER_LOG_TXPWR=1— tracesbase/by_rate/limit/headroom/finalper (channel, path, rate, ntx, bw) for future canary-divergence investigations on the per-rate calc.Test plan
8812-dev → 8821-ker = 6528/6500 ✓(was0/6500 ✗pre-fix).8812-dev → 8814-ker = 6182/6500 ✓(was0/6500 ✗pre-fix).22/24 ✓identical to PR T1: port 8812AU phydm I/Q calibration #66 baseline.🤖 Generated with Claude Code