Nothing lives outside the repo: the bench ixgbe driver source moves in tracked at kernel/ixgbe-sff/ (build artifacts gitignored, load-ixgbe repointed, module build verified from the new home — the reg_ops/ts_bench bench extras are finally versioned), the ice sff_i2c patch is vendored at docs/nics/e810/ice-sff-i2c.patch with its out-of-tree build recipe (TRACE_INCLUDE_PATH fixup, version-matched Makefile), the e810 NVM flash logistics land in the e810 README (exact package name, rollback -m B49691D578EC into the inactive bank, post-flash inventory failing until power cycle is the expected tell), and every ~/work/phydiag-work pointer becomes an inline statement; phydiag-work, ice-sff, e810nvm and the wiitekphy CLI (a duplicate of documented transport+protocol) are deleted
This commit is contained in:
@@ -77,7 +77,7 @@ Protocol and full verified catalog: [bcm84891l-mdio-commands.md](bcm84891l-mdio-
|
||||
|
||||
**The internal poll's clock, measured on hardware.** One poll every 3.49–4.22 s, regime-dependent but rock-stable within a regime (±15 ms): ≈3.50 s warm and idle, ≈3.70 s, ≈4.01 s cool and idle, ≈4.21 s under continuous host mailbox load — host traffic *defers* the poll, never advances it, and nothing observed brings two polls closer than 3.49 s. The poll is link-independent: it runs straight through an AN restart and the whole retrain without missing a beat. Around each poll's service the bridge serves stale data for ~50 ms: every read returns the last value successfully fetched before the µC went busy (stuck-at-last-fetch, not one-behind), which is exactly how 3.33 inherits 1.147's 0x0011. The window closes *before* the poll is detectable — a CMD read returning the fresh resident 0x0031 is itself proof the µC serviced the fetch, so flip detection doubles as the all-clear.
|
||||
|
||||
**The windowed protocol (`phy.go`) — contention resolved by time-division.** Since the poll cannot be silenced, the host schedules around it. One goroutine per module owns every transport touch (requests execute one at a time on the loop — nothing else can reach the wire, by construction), and each request is admitted only inside a fixed 3.4 s window following an observed poll (CMD flipping to resident 0x0031, polled at 10 ms); at the cutoff the host goes quiet until the next flip. 3.4 s sits below every observed cadence, so a regime switch mid-run lands harmlessly in vacated time — no prediction, no period tracking, just the last observed flip plus two constants. **Re-lock — no window at assumed phase**: edge detection needs CMD ≠ 0x0031, and handler commands leave it armed (every one rewrites CMD); whenever CMD sits at the resident 0x0031 at expiry the phase is unknown and admission arms first, then anchors on the true edge that follows. Steady-state polling issues no handler commands of its own (the SNR GET is dropped), so each taken edge immediately re-arms with a bare GET_PAIR_SWAP: the single CMD write per window lands at the start of the quiet period, maximally far from the next poll — the wedge risk is writes near the poll — and every later expiry reads the phase without writing. One command per ~4 s window replaces a handler GET per second. Admission then arms first (a bare GET_PAIR_SWAP, resident 0x0000) and anchors only on the true edge that follows, so every window is edge-locked from first contact at boot; bringup pays one phase acquisition per module (~2–4 s). A missing heartbeat free-runs one window rather than stall (never observed — the heartbeat survives retrains). Before re-lock the post-diag window anchored blind on the stale resident, and every ghost observed under windowing sat in exactly that window; with re-lock, ghost-free across all bench diags to date. A poisoned batch is self-consistent and forensically visible: the stuck value clears the link bit (SNR skipped, panel shows "-", the ghost-SNR panic sidestepped) while 3.33 charges the same value as errored blocks (0x0011 → the "+17"); every corrected charge and link-down reading prints its raw 1.1/3.33/1.147 on the console, so events self-attribute — a ghost names its neighbor register, real correction decodes as nothing but itself. Validated on hardware in `~/work/phydiag-work/bcm_phaselock_bench.py`: aiming read bursts at the poll reproduces the poisoning on 100% of polls (the "+17" manufactured on demand); windowed operation ran 2,881 back-to-back batches — 16× the production rate, riding the cutoff — with zero stale values, and the production 1 Hz stream is unperturbed (blackout hides inside natural gaps, worst sample gap ~1.6 s).
|
||||
**The windowed protocol (`phy.go`) — contention resolved by time-division.** Since the poll cannot be silenced, the host schedules around it. One goroutine per module owns every transport touch (requests execute one at a time on the loop — nothing else can reach the wire, by construction), and each request is admitted only inside a fixed 3.4 s window following an observed poll (CMD flipping to resident 0x0031, polled at 10 ms); at the cutoff the host goes quiet until the next flip. 3.4 s sits below every observed cadence, so a regime switch mid-run lands harmlessly in vacated time — no prediction, no period tracking, just the last observed flip plus two constants. **Re-lock — no window at assumed phase**: edge detection needs CMD ≠ 0x0031, and handler commands leave it armed (every one rewrites CMD); whenever CMD sits at the resident 0x0031 at expiry the phase is unknown and admission arms first, then anchors on the true edge that follows. Steady-state polling issues no handler commands of its own (the SNR GET is dropped), so each taken edge immediately re-arms with a bare GET_PAIR_SWAP: the single CMD write per window lands at the start of the quiet period, maximally far from the next poll — the wedge risk is writes near the poll — and every later expiry reads the phase without writing. One command per ~4 s window replaces a handler GET per second. Admission then arms first (a bare GET_PAIR_SWAP, resident 0x0000) and anchors only on the true edge that follows, so every window is edge-locked from first contact at boot; bringup pays one phase acquisition per module (~2–4 s). A missing heartbeat free-runs one window rather than stall (never observed — the heartbeat survives retrains). Before re-lock the post-diag window anchored blind on the stale resident, and every ghost observed under windowing sat in exactly that window; with re-lock, ghost-free across all bench diags to date. A poisoned batch is self-consistent and forensically visible: the stuck value clears the link bit (SNR skipped, panel shows "-", the ghost-SNR panic sidestepped) while 3.33 charges the same value as errored blocks (0x0011 → the "+17"); every corrected charge and link-down reading prints its raw 1.1/3.33/1.147 on the console, so events self-attribute — a ghost names its neighbor register, real correction decodes as nothing but itself. Validated on hardware: aiming read bursts at the poll reproduces the poisoning on 100% of polls (the "+17" manufactured on demand); windowed operation ran 2,881 back-to-back batches — 16× the production rate, riding the cutoff — with zero stale values, and the production 1 Hz stream is unperturbed (blackout hides inside natural gaps, worst sample gap ~1.6 s).
|
||||
|
||||
## ECD — recovered from the OpenBCM SDK, proven on hardware
|
||||
|
||||
@@ -96,7 +96,6 @@ Observed on a plugged, linked, healthy cable: verdicts OK×4 and per-pair length
|
||||
- **An interrupted run can wedge the µC's SMI service** (observed after a process died mid-diag): the bridge ACKs I2C but serves 0x0000 for every register at any delay and silently drops MDIO writes — no in-band recovery, not even PMA reset — while the EEPROM path and the trained link keep working. Recovery: a driver unbind/rebind of the port (the SFP re-initialization resets the µC); a reseat would do the same.
|
||||
- Fault verdicts (open/short/inter-pair) are unexercised — deliberately: the product is a closed-loop tester, both ends always plugged.
|
||||
- Family constraints from the SDK: port must be enabled; unsupported at forced 100M.
|
||||
- `bcm_ecd_probe.py` in phydiag-work implements the recipe.
|
||||
|
||||
## Missing datasheet chapters
|
||||
|
||||
|
||||
Reference in New Issue
Block a user