diff --git a/docs/modules/fs/README.md b/docs/modules/fs/README.md index 1c7cc03..2db26f9 100644 --- a/docs/modules/fs/README.md +++ b/docs/modules/fs/README.md @@ -33,7 +33,7 @@ Protocol and full verified catalog: [bcm84891l-mdio-commands.md](bcm84891l-mdio- | Capability | How | Observed | |---|---|---| -| Per-pair SNR | `CMD_GET_SNR` 0x8030, **invoked bare** (writing the documented DATA1 display flag returns zeros; IEEE 1.133–1.140 never populate — constant 0x8080) | DATA2–5 = SNR A–D ×0.1 dB; ≈ 27–32 dB absolute on bench, 0.1–0.4 dB jitter. 10GBASE-T operating point ≈ 26.5 dB, so margin ≈ value − 26.5. cabletest shows the margin classified green ≥ 3 dB / amber ≥ 1 dB / red below — provisional thresholds until the graded-noise correlation run | +| Per-pair SNR | `CMD_GET_SNR` 0x8030, **invoked bare** (writing the documented DATA1 display flag returns zeros; IEEE 1.133–1.140 never populate — constant 0x8080) | DATA2–5 = SNR A–D ×0.1 dB; ≈ 27–32 dB absolute on bench, 0.1–0.4 dB jitter. 10GBASE-T operating point ≈ 26.5 dB, so margin ≈ value − 26.5. cabletest shows the margin classified green ≥ 3 dB / amber ≥ 1 dB / red below — provisional thresholds until the graded-noise correlation run. **Each training re-converges differently**: back-to-back retrains with identical roles, temperature and noise moved one pair by 3.6 dB (roles pinned, launch power pinned — the convergence itself is the variable, and the two bench modules differ in stability: ≤1.5 dB spread on one, 3.6 dB on the other). A single training's absolute SNR is a weak qualification number; qualification wants median-of-N trainings, live SNR is honest as a within-session tracker | | Die temperature | `CMD_GET_CURRENT_TEMP` 0x8031 | ~68–70 °C on bench | | Supply rails | `GET_CURRENT_VOLTAGE` 0x802F | 0.8 V and 1.88 V rails, tenths of mV | | Error counters | IEEE PCS 3.32/3.33 — block lock, latched errored-block/BER, clear-on-read | The noise-stress error proxy | @@ -52,6 +52,8 @@ Protocol and full verified catalog: [bcm84891l-mdio-commands.md](bcm84891l-mdio- | Jumbo | 0x801C/0x801D | GET 0x801D answers in DATA1 — scratch-prone, unusable — and bringup cannot assume a cable to probe through, so cabletest forces enable every boot (SET 0x801C + AN restart); the running mix's 9018-byte frames are the standing wire truth (`phy.go`). The FS at its 9K option passes them at line rate with zero loss/corrupt | | 1588 | 0x8004 | Disabled (engine registers undocumented — see asks below) | | Limited reach | 0x8006 | Disabled — its DATA3 "linked in LR mode" bit, the only handler-visible trace of the DSP length estimate, is unavailable without a config change | +| Master/slave role | IEEE 7.32 bits 15/14 | Left to AN the resolution is a per-training lottery; manual config writes stick exactly and the resolution follows deterministically (7.33.14, no config fault with complementary ends). cabletest forces A master / B slave every boot (`phy.go`) so sessions are measured under identical conditions | +| Launch power | IEEE 1.130, 1.0.11 | 1.130 reads 0x0003 and is firmware-pinned: host writes to the short-reach bit revert instantly and the value never changes across retrains, so launch power is constant and not host-influenceable. PMA low-power bit clear. The handler catalog has no TX-power command | ## Firmware-reliability notes diff --git a/docs/state.md b/docs/state.md index 026540d..b7738d5 100644 --- a/docs/state.md +++ b/docs/state.md @@ -2,7 +2,7 @@ ## Committed tree -AF_PACKET raw sockets everywhere (`sock.go`); flow-director steering; per-packet-MAC-rx-stamped rate buckets (`SO_TIMESTAMPING` cmsg, `rx_filter=ALL` as a hard host check — nics/README.md for what that demands of the NIC; **temporarily bypassed** in `ts.go` so BCM work can run on the X520, which cannot stamp — the check reports yellow and the panel rates read zero there; restore to fatal for the product NIC); read-time-stamped NIC-counter rates; test interfaces pinned to MTU 9000 with a 9018-byte jumbo in the size mix (the modules' jumbo path is exercised, not assumed); BCM module diagnostics (`phy.go`, over the patched-ixgbe `sff_i2c` debugfs, compound-op framing; one per-module lock around every whole operation, and steady-state work time-division-multiplexed with the firmware's own mailbox client — every operation admitted only inside a 3.4 s window after each observed internal temp poll, which ends the stale-read poisoning of the corrected channel — modules/fs/ for the full trap list and validation): bringup identifies both modules and forces EEE off and jumbo on every boot — no trustworthy readback exists and no cable is guaranteed to probe through; the ECD — per-pair verdicts, lengths and pair maps are the length/wiring path — runs through one async path at startup and on every reset, never blocking the UI, with counters re-baselining only after the diag's own link blip so it is never charged to the run; a 1 Hz poller feeds per-pair SNR margin (vs the ≈26.5 dB operating point; green ≥ 3 dB, amber ≥ 1 dB — provisional until the graded-noise run) and the corrected-error set (PCS 3.33 errored blocks/BER, PMA 1.147 fast-retrain count) to the panel and console; framebuffer UI; harness. +AF_PACKET raw sockets everywhere (`sock.go`); flow-director steering; per-packet-MAC-rx-stamped rate buckets (`SO_TIMESTAMPING` cmsg, `rx_filter=ALL` as a hard host check — nics/README.md for what that demands of the NIC; **temporarily bypassed** in `ts.go` so BCM work can run on the X520, which cannot stamp — the check reports yellow and the panel rates read zero there; restore to fatal for the product NIC); read-time-stamped NIC-counter rates; test interfaces pinned to MTU 9000 with a 9018-byte jumbo in the size mix (the modules' jumbo path is exercised, not assumed); BCM module diagnostics (`phy.go`, over the patched-ixgbe `sff_i2c` debugfs, compound-op framing; one per-module lock around every whole operation, and steady-state work time-division-multiplexed with the firmware's own mailbox client — every operation admitted only inside a 3.4 s window after each observed internal temp poll, which ends the stale-read poisoning of the corrected channel — modules/fs/ for the full trap list and validation): bringup identifies both modules and forces EEE off, jumbo on and the master/slave roles (A master / B slave — left to AN the role is a per-training lottery) every boot — no trustworthy readback exists and no cable is guaranteed to probe through; the ECD — per-pair verdicts, lengths and pair maps are the length/wiring path — runs through one async path at startup and on every reset, never blocking the UI, with counters re-baselining only after the diag's own link blip so it is never charged to the run; a 1 Hz poller feeds per-pair SNR margin (vs the ≈26.5 dB operating point; green ≥ 3 dB, amber ≥ 1 dB — provisional until the graded-noise run) and the corrected-error set (PCS 3.33 errored blocks/BER, PMA 1.147 fast-retrain count) to the panel and console; framebuffer UI; harness. ## Stashes diff --git a/phy.go b/phy.go index 086879d..1f1481b 100644 --- a/phy.go +++ b/phy.go @@ -313,6 +313,24 @@ func (b *bcm) forceJumbo() error { return err } +// Left to AN, master/slave is a per-training lottery and each training's DSP +// convergence moves per-pair SNR by up to ~3.6 dB; pinned roles at least keep +// every session measured under identical conditions. +func (b *bcm) forceRole(master bool) error { + defer b.acquire()() + v, err := b.mdioRead(7, 32) + if err != nil { + return err + } + v |= 0x8000 + if master { + v |= 0x4000 + } else { + v &^= 0x4000 + } + return b.mdioWrite(7, 32, v) +} + func (b *bcm) restartAN() error { defer b.acquire()() v, err := b.mdioRead(7, 0) @@ -822,6 +840,15 @@ func moduleChecks(mods []*phyModule, names [2]string) []checkResult { } out = append(out, res) + res = checkResult{item: names[i] + " role", state: "forced master"} + if i > 0 { + res.state = "forced slave" + } + if err := m.bcm.forceRole(i == 0); err != nil { + return fail(res.item, err) + } + out = append(out, res) + if err := m.bcm.restartAN(); err != nil { return fail(names[i]+" retrain", err) }