Skip to content

Jaguar1: power the chip down at teardown (mechanism open; thermal explanation retracted) - #350

Closed
josephnef wants to merge 2 commits into
masterfrom
jaguar1-teardown-power-down
Closed

Jaguar1: power the chip down at teardown (mechanism open; thermal explanation retracted)#350
josephnef wants to merge 2 commits into
masterfrom
jaguar1-teardown-power-down

Conversation

@josephnef

@josephnef josephnef commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Addresses the reproducible half of #348. Note the title is now inaccurate
see "Mechanism: open" below; the fix stands, the explanation did not.

What is fixed

A Jaguar1 session left the chip in the ACT power state with the RF front end
live, indefinitely
, long after the owning process exited. Nothing else in the
tree does this: Jaguar2 resets at init, Jaguar3 has run a full card-disable at
teardown for a long time.

Stop() and the destructor now run HalModule::rtw_hal_deinit() — halt the MAC
engines (REG_CR, REG_RCR), then the die's card-disable power sequence,
through the same HalPwrSeqCmdParsing and the same three-way chip dispatch
InitPowerOn already uses. The tables (rtl8812_card_disable_flow and the
8814A/8821A equivalents) had been sitting in hal/Hal88*PwrSeq.c since the port
began with nothing calling them.

Measured effect — same repro, before and after:

stage before after
60 s idle, no power cycle thermal 48, MCS7 73.0% thermal 40, MCS7 85.8%

~13 points, about 7 sd against the measured noise floor. Before the fix, no
amount of idling recovered anything and only pulling VBUS helped.

The change is also justified independently of any performance argument: leaving
a radio powered and transmitting-capable after its owning process has exited is
wrong, it is what every other generation already avoids, and it is what makes an
autonomously-airing beacon stop at session end.

Mechanism: open (a correction)

An earlier revision of this PR claimed the cause was chip temperature. That
was correlation across sessions presented as causation, and it is retracted.

Every recovery that works removes power, and removing power resets chip state
and lets the die cool — no power-cycle experiment separates them. Two
harnesses added here try to, and both argue against cooling:

  • thermal_offtime_sweep.sh — degrade, then power down for 5/15/30/60/120 s
    before an otherwise identical probe. Reset bit-identical in every arm; only
    cooling time varies. Temperature fell cleanly with off-time (47 → 40) but
    delivery scattered 63–83% with no relation to off-time or temperature
    best result from the shortest off-time and the hottest chip.
  • thermal_causation_probe.sh — delivery inside a single uninterrupted
    session (one bring-up, no re-init, no state change). Thermal stayed pinned
    through 240 s of max-duty TX while MCS7 drifted ~10% and the control held flat.

Heat remains a real correlate within one probe sequence (thermal 39 → 45 costing
~5 points, control flat, RSSI unchanged) and is demonstrably not the driver
above. The docs now say the mechanism is open rather than asserting it.

Know the noise floor

probe_repeatability.sh is the measurement that should have come first: ten
identical back-to-back probes, nothing changed between them.

mean sd range
MCS7/20 67.3% 1.8 65.0 – 70.7
MCS1/20 control 98.0% 0.2 97.5 – 98.3

A single probe is worth ±3 points, so effects under ~4 points are not
findings
— and several plausible-looking decay curves in this investigation sat
inside that band. This is now documented in CLAUDE.md as a bench rule.

Behaviour change

A beacon in the MAC's reserved page now stops when the session ends instead of
airing until re-enumeration. Matches Jaguar3 and the vendor driver; CLAUDE.md
updated.

Testing

  • 8812AU, 8814AU, 8821AU each re-init cleanly across three consecutive sessions
    after the power-down.
  • teardown_gen_sanity.sh 10/10 across every plugged generation.
  • tx_teardown_asan.sh 6/6 including max-duty kills — the case that matters now
    that teardown writes registers while URBs may be in flight.
  • ctest 48/48.

Not included, deliberately

  • No in-flight recovery API. Until the mechanism is understood there is
    nothing principled to implement.
  • No init-side power-off. It runs immediately before power-on, so it buys
    nothing while adding risk to a working bring-up path.
  • Jaguar2 unchanged. Audited and inconclusive — thermal did not move and the
    available link was too marginal at MCS7 to resolve a small effect. No
    measurement, no speculative change.

Still open in #348

The severe form (MCS5/6/7 at 0% while MCS0–4 held ~88%) is unreproduced, the
mechanism is unresolved, and SIGKILL still leaves the chip powered.

🤖 Generated with Claude Code

A Jaguar1 session left the chip in the ACT power state with its RF front end
live, indefinitely, long after the process that brought it up had exited.
Nothing else in the tree does that: Jaguar2 resets at init, Jaguar3 has run a
full card-disable at teardown for a long time.

The cost was a transmitter that quietly lost its dense constellations. Across
back-to-back sessions on an 8812AU at ch6/20 MHz, constant TX config, the chip
thermal meter climbed 43 -> 53 and MCS7 (64-QAM 5/6) delivery fell 83% -> 71%
while the MCS1 control held at 98% and RSSI never moved — no power is lost,
only signal quality. Nothing logs an error, and the signature is
indistinguishable from a link too weak to carry the rate.

Idling did not help, because a chip held in ACT keeps dissipating whether or
not it is transmitting: 120 s of idle bought 4 thermal units where a 12 s VBUS
cycle bought 9. That is why only pulling power appeared to recover it.

Stop() and the destructor now run HalModule::rtw_hal_deinit(): halt the MAC
engines (REG_CR, REG_RCR) then the die's card-disable power sequence, through
the same HalPwrSeqCmdParsing and the same three-way chip dispatch InitPowerOn
already uses. The sequence tables have been sitting in hal/Hal88*PwrSeq.c since
the port began with nothing calling them. Both call sites are best-effort; a
chip already off the bus makes the writes fail, which is fine at teardown.

Measured effect, same repro: 60 s of idle with no power cycle went from
thermal 48 / MCS7 73.0% to thermal 40 / MCS7 85.8%. An ordinary gap between
sessions now restores the part completely without touching the hardware.

Deliberately not included. There is no in-flight recovery API: the mechanism is
heat, recovery needs the radio to stop transmitting for around a minute, and a
call that restores the rate by killing the link for a minute is not a recovery
for an airborne link. An init-side power-off was also rejected — it would run
immediately before power-on and buys no cooling time, while adding risk to a
bring-up path that works. Jaguar2 keeps its current teardown: its thermal meter
did not move across the same run and the link available was too marginal at
MCS7 to resolve a small effect, so there is no measurement to justify changing
it.

Validated on hardware: 8812AU, 8814AU and 8821AU all re-init cleanly across
three consecutive sessions after the power-down; teardown_gen_sanity 10/10;
tx_teardown_asan 6/6 including max-duty kills, which is the case that matters
now that teardown writes registers while URBs may be in flight. The 8814AU
barely heats at this duty (34 -> 37) and shows no degradation to fix.

Also flips a documented wart: a beacon loaded into the MAC reserved page now
stops when the session ends instead of airing until re-enumeration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… refuted it

The previous commit asserted that warm-session TX degradation is caused by chip
temperature. That was correlation across sessions presented as causation, and
two experiments added here argue against it:

thermal_offtime_sweep.sh degrades the part, then powers it down for 5/15/30/60/
120 s before an otherwise identical probe. The reset is bit-identical in every
arm; only cooling time varies — which is the one way to separate "the die
cooled" from "the state was reset", since every recovery observed does both at
once. Temperature fell cleanly with off-time (47 -> 40) while delivery scattered
63-83% with no relation to off-time or temperature: the best result came from
the shortest off-time and the hottest chip.

thermal_causation_probe.sh measures delivery inside a single uninterrupted
session — one bring-up, no re-init, no state change, so only temperature can
move. The thermal meter stayed pinned for 240 s of max-duty TX while MCS7
delivery still drifted ~10% and the control held flat.

probe_repeatability.sh is the measurement that should have come first: ten
identical back-to-back probes, nothing changed between them, give MCS7/20
sd 1.8 and a 5.7-point spread (MCS1 control 98.0 +/- 0.2). A single probe is
worth about +/-3 points, so effects under ~4 points are not findings — and
several plausible-looking decay curves in this investigation sat inside that
band. Run it before believing a delivery difference.

What survives: the fix itself. A 60 s idle recovers MCS7 from 73.0% to 85.8%
only once the teardown power-down exists — ~13 points, about 7 sd, comfortably
real — where before it idling recovered nothing. And the change is right on its
own terms regardless of mechanism: leaving a radio powered and
transmitting-capable after its owning process has exited is wrong, and is what
every other generation already avoids.

What does not: any claim about why. Heat is a real correlate of delivery within
one probe sequence (thermal 39 -> 45 costing ~5 points, control flat, RSSI
unchanged) and demonstrably not the driver in the two experiments above. The
mechanism is open, and the docs now say so instead of asserting it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@josephnef josephnef changed the title Jaguar1: power the chip down at teardown so it can cool Jaguar1: power the chip down at teardown (mechanism open; thermal explanation retracted) Jul 28, 2026
@josephnef

Copy link
Copy Markdown
Collaborator Author

Closing while the investigation continues, per review.

The teardown power-down here has a measured effect but does not fix #348, and I got its justification wrong twice (latched state, then thermal — both asserted from correlation, both retracted). Shipping it now would mean shipping a change whose reason I cannot state.

The branch stays so the harnesses and measurements are not lost:

  • probe_repeatability.sh — the noise floor (MCS7/20 sd 1.8, 5.7-point spread; effects under ~4 points are not findings)
  • thermal_offtime_sweep.sh — identical reset, only cooling time varies; refuted the thermal story
  • thermal_causation_probe.sh — delivery inside one uninterrupted session
  • warm_tx_degradation_repro.sh — the mild-form repro

Investigation continues on the actual lead: TX IQ correction (0xcc4/0xcc8/0xccc/0xcd4, 0xec4/…) and RF 0x58 LOK are written per session, are not reset by the BB/RF init tables, and are not in any dump we have — so they are both invisible and potentially persistent, and they govern exactly the EVM/phase-noise damage that kills dense constellations while leaving robust rates intact.

Everything will come back as a single PR once the state is demonstrated and the fix is validated.

@josephnef josephnef closed this Jul 28, 2026
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