Skip to content

kestrel: park the EDCCA level on 5 GHz as on 6 GHz - #491

Merged
josephnef merged 2 commits into
masterfrom
kestrel-edcca-5g
Oct 15, 2026
Merged

josephnef merged 2 commits into
masterfrom
kestrel-edcca-5g

Conversation

@josephnef

Copy link
Copy Markdown
Collaborator

The problem

Host injection from an 8832CU goes silent on the upper 5 GHz channels. With the BB table's EDCCA level the MAC energy-detect TX gate latches busy on the receiver's own floor (-65..-69 dBm as the BB measures it, no DIG), the mechanism the 6 GHz path already parks (src/kestrel/CLAUDE.md). Measured on the bench (TX50UH injector, 20 ms gap, 8812CU witness, default configuration):

channel witnessed of ~435
6 / 36 / 44 205 / 192 / 211
52 / 60 / 64 226 / 92 / 12
100 / 149 / 157 / 161 0

SDR airtime on ch161 under a max-duty flood: 0.0% (ch44: +4% over idle); the injector stalls on bulk-OUT timeouts. The fixed TX-power knob (8 / 14 / 20 dBm) changes nothing. DEVOURER_CCA_GATES=0,1 (EDCCA gate alone cleared) restores ch64 / 100 / 161 to 220-226; 1,0 (primary alone) restores nothing. The tune log says it on every 5 GHz tune: EDCCA band1 pwdB fb=-67 ... busy=1.

The change

kestrel_halbb_edcca_6g becomes kestrel_halbb_edcca_park(band_type, bw) and the channel set calls it for 5 GHz as well as 6 GHz: the vendor's unlinked EDCCA_NORMAL_MODE level, its own level for an unassociated device, never busy. Preamble carrier sense stays on. 2.4 GHz is untouched (floor -82 dBm, busy=0). Comments and the Kestrel notes carry the measurements; the compliance consequence the 6 GHz note already states now covers 5 GHz.

Measured after the change

Default configuration, same setup: ch6 196/423, ch44 215/434, ch100 227/440, ch161 224/437. Deferral still holds on ch161: a max-duty 6M injector sent 19063 frames in 8 s on a quiet channel, 7327 (7086 witnessed) under a co-channel max-duty MCS1 flood with the gates on, 15676 (10639) with DEVOURER_DIS_CCA=1. Linux build + ctest 83/83.

One bench, one injecting unit (the second TX50UH on this bench does not host-inject at all, on any band, for an unrelated reason tracked in #490), near field.

Part of #490.

🤖 Generated with Claude Code

With the BB table's EDCCA level the MAC energy-detect gate latches busy on
the receiver's own floor (-65..-69 dBm as the BB measures it, no DIG) on
5 GHz too, and more the higher the channel: host injection from an 8832CU
at a 20 ms gap reached an 8812CU witness at ~50% on ch6/36/44, 52% on ch52,
21% on ch60, 3% on ch64 and 0 of ~435 frames on ch100/149/157/161, with
0.0% SDR airtime on ch161 and the injector stalling on bulk-OUT timeouts.
Clearing the EDCCA gate alone restored ch64-161 to the ch6 rate; clearing
the primary gate alone restored nothing.

Program the vendor's unlinked EDCCA_NORMAL_MODE level on 5 GHz as the
6 GHz path already does (the vendor's own level for an unassociated
device, never busy); preamble carrier sense stays on. After the change,
default configuration: ch6 / 44 / 100 / 161 all ~50% witnessed at the
same rate. Deferral still holds on ch161: a max-duty injector sent 19063
frames on a quiet channel, 7327 under a co-channel max-duty MCS1 flood
with the gates on, 15676 with DEVOURER_DIS_CCA=1. 2.4 GHz is untouched
(floor -82 dBm, busy=0).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Kestrel: park EDCCA on 5 GHz to restore host injection

🐞 Bug fix 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Park 5 GHz EDCCA at the existing unlinked level to prevent the receiver’s noise floor from
 blocking injection.
• Preserve preamble carrier sense and leave 2.4 GHz unchanged.
• Document bench results and the resulting 5 GHz regulatory energy-detect limitation.
Diagram

graph TD
  Tune["Channel tune"] --> BB["BB configuration"] --> Band{"Band selection"}
  Band -->|"5/6 GHz"| Park["EDCCA park"] --> Calc["Vendor threshold"] --> TX["Preamble deferral"]
  Band -->|"2.4 GHz"| Default["Table default"] --> TX
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Disable the EDCCA MAC gate on 5 GHz
  • ➕ Bench isolation indicates this would restore injection.
  • ➖ Bypasses the gate rather than using the existing vendor threshold path.
  • ➖ Would still forgo regulatory energy-detect behavior.
2. Calibrate and enforce band-specific EDCCA thresholds
  • ➕ Could retain energy-detect deferral where regulatory rules require it.
  • ➖ Requires a reliable noise-floor calibration and broader hardware and regulatory validation.

Recommendation: Use the existing 6 GHz parking mechanism for this unassociated injection path: it directly addresses the measured false-busy condition without disabling preamble carrier sense. Treat regulatory-compliant energy detection as a separate requirement; this approach does not enforce it on either 5 or 6 GHz.

Files changed (4) +50 / -28

Bug fix (3) +31 / -18
kestrel_halbb_glue.cGeneralize EDCCA parking across 5 and 6 GHz +7/-5

Generalize EDCCA parking across 5 and 6 GHz

• Renames the 6 GHz helper and accepts a band type so the vendor threshold calculation uses the current band. Its existing one-time initialization and unlinked normal-mode threshold behavior remain intact; the comment now states the expanded regulatory consequence.

hal/halbb/g6/kestrel_halbb_glue.c

kestrel_halbb_glue.hExpose the band-aware EDCCA parking helper +2/-1

Expose the band-aware EDCCA parking helper

• Updates the public declaration to accept the band type alongside bandwidth. The adjacent comment still describes the helper as 6 GHz-only.

hal/halbb/g6/kestrel_halbb_glue.h

HalKestrel.cppPark EDCCA after 5 GHz channel configuration +22/-12

Park EDCCA after 5 GHz channel configuration

• Calls the generalized helper after BB configuration on both 5 and 6 GHz, while leaving 2.4 GHz unchanged. Updates the tune log annotation and records bench evidence for restored injection and continued carrier-sense deferral.

src/kestrel/HalKestrel.cpp

Documentation (1) +19 / -10
CLAUDE.mdDocument 5 GHz EDCCA failure and trade-off +19/-10

Document 5 GHz EDCCA failure and trade-off

• Adds the 5 GHz channel measurements, explains why parking restores injection, and records that preamble carrier sense still defers transmission. Extends the stated regulatory energy-detect limitation to 5 GHz.

src/kestrel/CLAUDE.md

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. A 5 GHz visit leaves 2.4 GHz detection off ✓ Resolved
Description
vnd_bb_ctrl_bw_ch() parks the EDCCA threshold on 5 GHz but skips any threshold update when the
next tune has band_type == 0. After a 5-to-2.4 GHz channel switch, the parked, never-busy
threshold remains in hardware because the channel-control and reset paths do not restore the 2.4 GHz
table value.
Code

src/kestrel/HalKestrel.cpp[R2316-2317]

+  if (band_type == 2 || band_type == 1)
+    kestrel_halbb_edcca_park(_halbb_ctx, band_type, hbw);
Evidence
The channel setter maps 2.4 GHz to band type 0 and calls the common BB tune path. The new guard
excludes that band; parking writes the unlinked EDCCA_MAX threshold to hardware, while the
per-channel BB path and BB reset do not rewrite those threshold registers. Thus the newly parked 5
GHz value persists across the switch.

src/kestrel/HalKestrel.cpp[2609-2612]
src/kestrel/HalKestrel.cpp[2680-2685]
src/kestrel/HalKestrel.cpp[2316-2317]
hal/halbb/g6/kestrel_halbb_glue.c[192-198]
hal/halbb/g6/vendor/halbb_edcca.c[157-176]
hal/halbb/g6/vendor/halbb_edcca.c[212-227]
hal/halbb/g6/vendor/halbb_8852c/halbb_8852c_api.c[1446-1519]
hal/halbb/g6/vendor/halbb_8852c/halbb_8852c_api.c[392-405]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A 5 GHz tune programs a never-busy EDCCA threshold that survives a later 2.4 GHz tune, despite the intended 2.4 GHz table default.
## Fix Focus Areas
- src/kestrel/HalKestrel.cpp[2312-2317]
- hal/halbb/g6/kestrel_halbb_glue.c[175-198]
## Recommended Fix
On a 2.4 GHz tune following a parked-band tune, explicitly restore the 2.4 GHz table EDCCA register values and update the HALBB channel descriptor. Preserve the existing 5/6 GHz parking behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can hide the parts of a finding you never read, like the evidence or the agent prompt

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/kestrel/HalKestrel.cpp
Review point: the park rewrites the threshold CRs in place and a later
2.4 GHz tune left them parked. The glue now captures the table's five
threshold CRs (level_p, level, ppdu, dwn, obss) before the first park and
a 2.4 GHz tune after a parked band writes them back; the tune log carries
the programmed level. Measured: a fresh ch6 tune logs level=66; a
161->6->161->6 hop session logs 249 on each 5 GHz tune and 66 on each
return to ch6, with 440 of the ch6 dwell frames witnessed; ch161 and ch6
injection unchanged (222/435, 209/431).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@josephnef
josephnef merged commit 5b12c86 into master Oct 15, 2026
28 checks passed
@josephnef
josephnef deleted the kestrel-edcca-5g branch October 15, 2026 19:04
agustinglez added a commit to agustinglez/devourer that referenced this pull request Oct 15, 2026
Some 8852C bring-ups armed the ACK responder, read the entry back, and
answered no ACK for the whole session (OpenIPC#490). The chip built the ACK,
but the TX path selection the MAC attached to it was garbage in those
bring-ups: it enabled a path this 2T2R die does not have, or mapped path
A off the signal, so no antenna sent it. The selection comes from MAC
state nothing initialises, which is why it changed per bring-up.

The halbb glue now follows the T-MAC path routing at bring-up with
halbb_ctrl_tx_path_pmac_8852c(RF_PATH_AB): the BB takes the path enable
and the path A/B maps from its own P-MAC registers (0x09a4 [4:2]), paths
A+B with A on IFFT 0 and B on IFFT 1, plus the vendor's per-path TSSI
reset pulse. 8852C only; the switch applies to every PPDU.

- ack_responder_ok is true on the 8852C as well (still an explicit list
  of measured variants).
- docs/kestrel-ack-responder.md: the dead-bring-up section now gives the
  cause, how it was found (the TX-info debug port, decoded with the BB's
  INTF_TXINFO layout), what was ruled out, and the fix's numbers.

Measured (TX50UH responder, TX20U Nano soliciting, ch161, MCS1, 8 s per
session): before, 3 of 12, 6 of 15 and 4 of 30 sessions dead (the last
on master with OpenIPC#491); the map-A-1 selection died 10 of 10 times. After,
0 dead of 123 armed sessions across the register-level override and this
vendor call (30 of them on this exact code), 15 of them with the bad
selection, all 96.8-100%; solicitor across a live disarm 3791/3845 then
0/1602 and 3829/3843 then 0/1639; never armed 0/1591. Second bench: 0 of
20 on ch6 and ch161, both units. One-stream injection unchanged (MCS1 and
6M ~1900/2000 to the 8852B, ch6 and ch161 with carrier sense on). Two-
stream injection from the 8852C does not decode with or without this,
so its effect there is not measured.
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