Jaguar1 hardware beacon + TBTT steering — StartBeacon on every generation#243
Merged
Conversation
…tion
Unlock StartBeacon / AdjustBeaconTiming / AdjustBeaconTimingFine on
Jaguar1 (8812AU/8811AU/8821AU/8814AU), closing the last generation gap
in the hardware-beacon time-distribution feature. The old refusal ("no
reserved-page path, bench-confirmed negative") only ruled out a plain
QSEL-beacon send; golden usbmon dumps of the in-tree rtw88_8821au and
rtw88_8814au (captured on the same adapters) recovered the real store
bracket:
clear BCN_VALID (W1C) -> CR+1 |= BIT0 (SW beacon DMA) -> beacon
function off -> bulk [MINIMAL descriptor][MPDU] -> poll BCN_VALID ->
function on -> CR+1 &= ~BIT0 (0x422[6] stays set throughout)
The store descriptor is the crack: LAST_SEG + OFFSET + PKT_SIZE +
QSEL_BEACON only — OWN/FIRST_SEG/BMC/HWSEQ/USE_RATE mark a live TX and
the store silently no-ops (BCN_VALID still latches, deceptively). The
enable is the vendor port-0 AP recipe (MSR=AP, DUAL_TSF_RST BIT0,
BCN_CTRL 0x18, ResumeTxBeacon — init leaves the StopTxBeacon state) plus
the 8821A "BCN on port 0" 0x454[5] clear.
8814A specifics (own golden dump + register diff against the live
beacons-airing kernel state): valid latch at 0x204[15] with the head
HELD AT THE BCNQ BOUNDARY during the store (page 0 — the fw-download
bracket's shape — stores where the TBTT engine never reads), enable
bits 0x420[12] + 0x454[2:0]=0x05, and its stored beacon airs with the
802.11 seq pinned at 0 (kernel rtw88 parity — verified). Steering: the
8814 TBTT counter free-runs across the EN_BCN toggle, so the fine steer
pulses DUAL_TSF_RST — the grid re-derives absolutely from the shifted
TSF (TSF-locked TBTT; each steer also cancels accumulated drift).
Steering rides the J2 steer-then-re-download pattern (the J1 engines
also drop the bcn-valid latch on a re-latch). The coarse interval tweak
is inert on the J1 engine (bench: beacon survives, phase never moves),
so AdjustBeaconTiming delegates TU-quantized to the fine mechanism.
Bench (observer = 8811CU): 8821AU fine 11/11 + coarse 3/3 PASS,
-3392..-3472 us for a -5000 us request (±40 us consistency, ~1.6 ms USB
systematic a closed loop absorbs), 0-1 beacon lost per steer; 8814AU
fine 5/5 + coarse 3/3 PASS, 0-3 lost (RF-weak unit). Beacon body
timestamp verified live on both (hw_beacon_txtsf now true on J1).
Docs/comments swept for stale "Jaguar2/3-only" claims on this feature;
tests/beacon_steer_survival.sh gates its frozen-seq check on seq!=0 for
the 8814A and grows a MASTER_CMD hook for remote masters.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
josephnef
added a commit
that referenced
this pull request
Jul 11, 2026
…k-PTP bridge (#244) Doc-only pass on `docs/time-distribution.md`, folding in two bench results that were living only in session notes: - **Transport floors for the software downlink**: the ~94 µs per-slave absolute lock is the transport's submit-to-air floor, not a protocol property — USB ~93 µs RMS vs **PCIe ~12 µs RMS** (robust outlier-rejecting fit; `tests/pcie_txegress_tx.cpp` + `tests/txegress_witness.cpp`). A PCIe master lifts the absolute software-path lock ~8×; the inter-slave difference and the hardware-beacon path are unaffected (already transport-free). - **New "Bridging to network PTP (IEEE 1588)" section**: the 8821CE TSF exposed as a Linux PHC (`tests/pcie_phc/`) and disciplined by `phc2sys` to the Radxa X4's Intel I226 holds **~290 ns RMS** (the TSF's own 1 µs-quantization floor: uniform ±0.5 µs → 289 ns) with the ~+42 ppm raw crystal offset servoed out. Combined with the TBTT steering actuator (#242/#243), that's the complete wired-PTP → Wi-Fi-beacon time bridge: network PTP disciplines the master's TSF, the TSF-locked hardware beacon distributes it, slaves inherit the wired timebase at the sub-µs beacon floor. Numbers cross-checked against `docs/timing-accuracy.md`; all referenced tools exist in-tree. (The "Beacon-TBTT steering is Jaguar3-only" wording was already removed by #242 — repo-wide grep is clean.) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
josephnef
added a commit
that referenced
this pull request
Jul 11, 2026
…'t corrupt the discipline loop's clock (#245) Follow-up to #242/#243, driven by bench feedback from the 8821CE AP↔PTP discipline loop. ## The problem (bench-observed) `AdjustBeaconTimingFine` necessarily jumps the reported TSF — that's the steering mechanism (the TBTT re-derives from a shifted TSF). But the discipline loop's phase estimate is a fit against that same TSF (`ref = a·tsf + b`), so **every steer corrupts the controller's own sensor**: - high-authority controllers (PI, ±200 µs clamped steps) chase the corrupted estimate into a limit cycle - the working ~60 µs proportional loop is a **sweet spot, not a floor** — its ~0.5·e steers are just small enough not to wreck the fit; more authority = more fit corruption = worse - `SetXtalCap` can't buy a lower steer cadence: the AFE trim moves only ~10 of the ~42 ppm crystal offset ## The fix `IRtlDevice::PinBeaconTbtt(offset_us)` inverts the oldest finding in this feature — *a bare TSF write does not move the TBTT* (why `WriteTsf` failed as an actuator). Do the shift + re-latch, then **immediately write the TSF back onto its original timeline**: the steered TBTT phase survives, the clock the loop reads stays continuous. Semantics are **absolute**: the TBTT fires at `TSF % interval == offset`. The controller commands the target offset directly (no step integration), and a PTP-disciplined TSF drags the pinned TBTT with it between corrections. ## Bench (8821CE PCIe, `TSF_WATCH=1` probe) | actuator | TSF discontinuity / steer | on-air phase | beacons lost | |---|---|---|---| | `AdjustBeaconTimingFine` | **+4996 µs** (the full steer) | steers | 0–1 | | `PinBeaconTbtt` | **−9…−11 µs** | pins within ±150 µs of the commanded offset, both directions | **0** | ~500× less fit disturbance — full control authority is safe again. ## Scope & caveats - Jaguar2 implementation (the loop hardware); base virtual is a no-op. The same pattern ports to J3/J1 when hardware is on the bench to validate. - USB caveat documented: the restore write costs ~0.5–1 ms there (worse than a small steer) — `docs/time-distribution.md` documents the controller-side **steering ledger** as the everywhere-fallback (add cumulative commanded shifts back onto the raw TSF before fitting). - `tests/beacon_steer_check.cpp` grows `STEER_MODE=pin` and `TSF_WATCH=1` (µs-resolution steady_clock-vs-ReadTsf discontinuity probe). - Docs record the sweet-spot and XtalCap findings so they aren't re-discovered. `ctest` 17/17. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
josephnef
added a commit
that referenced
this pull request
Jul 11, 2026
…bution doc consistency (#246) Follow-up to #245: port the TSF-preserving TBTT pin to J3 and J1, with per-die bench characterization that reshaped the contract — plus a latent #243 bug the port flushed out, and a consistency pass on `docs/time-distribution.md`. ## Pin per generation (all bench-proven this session) | generation | pin contract | bench | |---|---|---| | **Jaguar2** (#245) | full | ~10 µs TSF disturbance (PCIe); loop holds ~±1 µs | | **Jaguar3** (new, 8822CU) | full | offsets toggle on air as commanded, SURVIVAL PASS; TSF disturbance −0.5…−1.5 ms (USB restore write) vs the fine steer's full +4.5 ms jump | | **Jaguar1** (new, all three dies) | **offset 0 only** | a nonzero pin *never holds* — the J1 TBTT is **hardware-locked to the TSF grid** (steps identical for pin(0) and pin(−5000): pure bracket downtime). Refused honestly; flip side: a J1 master needs no actuator — discipline the TSF, the TBTT tracks in hardware | 8814A extra: `DUAL_TSF_RST` (its TBTT re-arm) **zeroes the reported TSF** — the fine steer was silently rewinding its clock by seconds per call; the 8814 pin path reconstructs the timeline from the host clock (~1 ms class). ## Latent #243 bug: J1 StartBeacon never ignited standalone Every prior J1 bench had steers — the first steer was the accidental igniter. Bench-swept the trigger: not a bare TSF write, not an EN toggle, not a write-inside-EN-bracket, not ordering — only the complete steer sequence with a real TSF **value edge** (same-value rewrites ignite nothing; the same-value-rewrite trap's third appearance). `StartBeacon` now runs enable → store → internal `PinBeaconTbtt(0)` igniter (full-extra-period shift: grid unchanged, edge guaranteed). First beacon ~200 ms after `StartBeacon` on all three dies, standalone. ## Doc consistency pass (`docs/time-distribution.md`) - stale claims removed: "which J2 does not survive" (false since #242), "both HalMAC generations" (wire-check is 3-generation now, 8814A seq-0 exception noted) - generation-scoped: "TBTT deaf to `REG_TSFTR`" and "bare TSF write does not move the TBTT" → latched J2/J3 engines only (J1 is the opposite architecture) - internal contradiction fixed: per-frame `tsfl` is universal (verified `FrameParser.cpp` fills it on J1); the *slave role* is what's J2/3-bench-validated - `SetCcaMode` noted as J2/J3-only (a J1 HW-beacon master still defers to CSMA) - per-generation pin table + the held **~±1 µs** AP↔PTP loop result folded in; all referenced files/symbols verified in-tree `ctest` 17/17; J1 fine-steer regressions PASS post-change. 🤖 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.
Extends #242's beacon-TBTT steering to Jaguar1 —
StartBeacon/AdjustBeaconTiming/AdjustBeaconTimingFinenow work on all three generations (8812AU / 8811AU / 8821AU / 8814AU included), so the hardware-beacon downlink and the uplink-TA / PTP-discipline actuator are no longer generation-gated.AdapterCaps.hw_beacon_txtsfis now true on J1 (body-timestamp verified live on air).How the old "impossible" became possible
The previous refusal ("no reserved-page path on Jaguar1, bench-confirmed negative") only ruled out a plain QSEL-beacon send. Golden usbmon dumps of the in-tree
rtw88_8821au/rtw88_8814au— captured on the same adapters — recovered the real store bracket:The descriptor is the crack:
LAST_SEG + OFFSET + PKT_SIZE + QSEL_BEACONonly.OWN/FIRST_SEG/BMC/HWSEQ/USE_RATEmark a live TX and make the store silently no-op — while BCN_VALID still latches, deceptively. Enable = the vendor port-0 AP recipe (MSR=AP,DUAL_TSF_RSTBIT0, BCN_CTRL 0x18, ResumeTxBeacon) + the 8821A-only "BCN on port 0"0x454[5]clear.8814A specifics (own golden dump + live register diff)
0x204[15], with the head held at the BCNQ boundary during the store — pointing it at page 0 (the fw-download bracket's shape) stores the beacon where the TBTT engine never reads0x420[12](gen1EN_BCNQ_DLanalog) +0x454[2:0]=0x05DUAL_TSF_RST: the grid re-derives absolutely from the shifted TSF — the TBTT ends up TSF-locked and each steer cancels accumulated driftSteering
Rides #242's steer-then-re-download pattern (the J1 engines also lose the bcn-valid latch on a re-latch). The coarse one-shot interval tweak is inert on the J1 engine (bench: beacon survives, phase never moves), so
AdjustBeaconTimingdelegates TU-quantized to the fine mechanism (documented: it then also shifts the reported TSF).Bench (observer = 8811CU,
tests/beacon_steer_survival.sh)Beacon body timestamps verified live on both.
ctest17/17.Docs/comments sweep
All stale "Jaguar2/3-only" / "both HalMAC generations" / "no reserved-page path on Jaguar1" claims for this feature removed across
IRtlDevice.h,AdapterCaps.h,docs/time-distribution.md,docs/ap-mode.md, and the beacon test headers.tests/beacon_steer_survival.shgates its frozen-seq check onseq != 0(8814A kernel parity) and gains aMASTER_CMD='ssh …'hook for remote masters.🤖 Generated with Claude Code