| Rev | Date | Author | Change Description |
|---|---|---|---|
| 0.1 | 2026-05-12 | Natanel Gerbi | Initial draft. |
Tracking:
This HLD covers ASIC/SerDes precoding configuration on SPC-6 platforms while APSU is not yet supported by firmware.
In scope:
- Extending
media_settings.jsonwith per-lanetx_precoding/rx_precodingfields. - Extending orchagent (PortsOrch) to map the new fields to
SAI_PORT_SERDES_ATTR_{TX,RX}_PRECODING.
xcvrd requires no parser change — its data path is already field-agnostic (§7.2).
| Term | Definition |
|---|---|
| CMIS | Common Management Interface Specification |
| iLT | Initial Link Training — per-lane electrical handshake between switch SERDES and module host CDR |
| APSU | Autonomous Path Start-Up (IEEE 802.3dj Annex 178B) — end-to-end protocol that extends iLT with in-band precoding negotiation |
| Precoding | Gray-coding applied at Tx SERDES to prevent DFE error propagation on PAM4 links |
| SPC-6 | Spectrum-6 ASIC family |
| SAI | Switch Abstraction Interface |
iLT adapts equalization on the local electrical segment between switch SERDES and module CDR. APSU extends iLT so that the two link ends also negotiate precoding in-band, without manual intervention.
Until module FW supports APSU, there is no automatic precoding negotiation: switch SERDES and module each come up with their own defaults which may not match, preventing link training. SONiC must therefore configure precoding on the ASIC/SERDES side to match what the module expects.
| # | Requirement |
|---|---|
| R1 | Precoding shall be configured on the ASIC/SERDES side. |
| R2 | The standard SONiC/SAI flow (media_settings.json → APP_DB → SAI) shall be used. |
| R3 | The flow shall be a no-op on platforms / modules where media_settings.json does not declare precoding fields (back-compat). |
Assumption. SAI_PORT_SERDES_ATTR_TX_PRECODING and SAI_PORT_SERDES_ATTR_RX_PRECODING are already supported by NV SAI.
End-to-end flow — same path used today by every other SI parameter (pre1, main, idriver, …):
flowchart TD
JSON[["media_settings.json<br/>+ tx_precoding<br/>+ rx_precoding"]]
XCVRD["xcvrd<br/>(field-agnostic parser)"]
DB[("APP_DB:PORT_TABLE")]
ORCH["orchagent<br/>(PortsOrch)"]
SAI["SAI_PORT_SERDES_ATTR_<br/>TX/RX_PRECODING"]
JSON -->|"1. read"| XCVRD
XCVRD -->|"2. HSET fields"| DB
DB -->|"3. notify on change"| ORCH
ORCH -->|"4. create port_serdes"| SAI
style JSON fill:#e8f5e9,stroke:#2e7d32,color:#000
style DB fill:#e3f2fd,stroke:#1565c0,color:#000
style SAI fill:#fff8e1,stroke:#f9a825,color:#000
Steps:
- xcvrd reads
media_settings.json— on module insert (or boot), it locates the entry that matches the inserted module's<EEPROM_VENDOR_NAME>-<EEPROM_VENDOR_PN>and active<SPEED_KEY>. - xcvrd writes the matched SI fields to
APP_DB:PORT_TABLE|<lport>viaHSET, including the newtx_precoding/rx_precodingkeys when present. - orchagent is notified of the
APP_DB:PORT_TABLEchange and runsPortsOrch::parsePortConfig, which populatesPortSerdes_tfrom the FV list — including the two new per-lane vectors. - orchagent creates the port-serdes SAI object with the resulting
PortSerdesAttrMap_t. Whentx_precoding/rx_precodingare set, the map includesSAI_PORT_SERDES_ATTR_{TX,RX}_PRECODINGand SAI programs the ASIC SerDes accordingly.
Key property: only media_settings.json content and orchagent's per-field mapping table change. xcvrd and the Redis schema are reused as-is.
Two new keys are added under each speed:<lane_speed_key> block, using the same per-lane shape as the existing parameters (pre1, main, etc.):
tx_precoding— per-lane Tx precoding (0x0= DISABLE,0x1= ENABLE).rx_precoding— per-lane Rx precoding
Example — one global entry that matches a specific vendor + PN pattern for ports 1–64 at speed 200GAUI-1, programming tx_precoding and rx_precoding to ENABLE on all 8 lanes alongside the existing SI parameters (pre1, main, …):
{
"GLOBAL_MEDIA_SETTINGS": {
"1-64": {
"VENDOR-MODEL-XX[AB]": {
"speed:200GAUI-1": {
"pre1": { "lane0": "0x00000000",
"...": "..."
},
"main": { "lane0": "0x0000003f",
"...": "..."
},
"tx_precoding": {
"lane0": "0x00000001",
"...": "...",
"lane7": "0x00000001"
},
"rx_precoding": {
"lane0": "0x00000001",
"...": "...",
"lane7": "0x00000001"
}
}
}
}
}
}Key shape:
| Element | Meaning |
|---|---|
1-64 |
Front-panel port range the entry applies to. |
VENDOR-MODEL-XX[AB] |
Regex matched against <EEPROM_VENDOR_NAME_UPPER>-<EEPROM_VENDOR_PN> of the inserted module. |
speed:200GAUI-1 |
Lane-speed bucket — speed: + first whitespace-token of CMIS host_electrical_interface_id. |
lane0 … lane<N-1> |
One per-lane value, (for precoding - hex; 0x1 = ENABLE, 0x0 = DISABLE). |
The schema is fully back-compatible — platforms that do not need precoding simply omit the fields. Concrete per-(vendor, PN, speed) values for additional modules are platform-/vendor-specific and live in the platform's media_settings.json; they are not enumerated in this HLD.
When a new module family is qualified for an SPC-6 platform:
- SI/PHY team determines the per-lane
tx_precodingandrx_precoding(if needed) values for that module at each relevant lane-speed bucket. - Platform owner adds a new
<VENDOR_PN_REGEX>entry under the relevant<PORT_RANGE>of the platform'smedia_settings.json, with the per-lane values from step 1 under eachspeed:<key>block (same shape as the example above).
No code change. media_settings_parser.to_db_value() is field-agnostic — it emits a FieldValuePair for every per-lane key in the matched JSON section. tx_precoding / rx_precoding ride the same path as pre1, main, etc.
PortsOrch already owns the SAI port-serdes object for every port. It keeps a per-port in-memory cache with one slot per SI field (pre1, main, idriver, …); each slot stores the per-lane values and an is_set marker. The SAI attributes are CREATE_ONLY, so any change to the cache is applied by remove_port_serdes + create_port_serdes, with the cumulative set of slots currently marked as set.
Adding precoding means giving that cache two new slots — one for tx_precoding, one for rx_precoding — and wiring them into the same machinery. The flow below is the existing PortsOrch pipeline; this HLD plugs in at steps 2 and 3 only.
- Receive change. PortsOrch reads the FV pairs that xcvrd just
HSET-ed intoAPP_DB:PORT_TABLEfor the port. - Parse into cache. PortsOrch matches each field name against its schema; for every known SI field it stores the per-lane values into the matching cache slot and marks the slot as set.
This HLD adds two new field-name matches —
tx_precodingandrx_precoding— each writing into its own new cache slot. - Build attribute list. PortsOrch walks the cache and assembles the SAI attribute list, including only slots that are marked as set.
This HLD adds two new "if marked-set → SAI attribute" entries:
tx_precoding→SAI_PORT_SERDES_ATTR_TX_PRECODING,rx_precoding→SAI_PORT_SERDES_ATTR_RX_PRECODING. - Re-create SAI object. PortsOrch removes the existing port-serdes SAI object and creates a new one with the attribute list from step 3.
- Program ASIC. SAI / SDK translate the attributes into per-lane SerDes register writes.
No new control flow, no new DB consumer, no new object lifecycle.
| APP_DB field | PortSerdes_t member |
SAI attribute |
|---|---|---|
tx_precoding |
serdes.tx_precoding |
SAI_PORT_SERDES_ATTR_TX_PRECODING |
rx_precoding |
serdes.rx_precoding |
SAI_PORT_SERDES_ATTR_RX_PRECODING |
Files touched (each row maps to the step it implements):
| File | Step | Change |
|---|---|---|
orchagent/port/portschema.h |
2 | Two new field-name string constants (PORT_TX_PRECODING, PORT_RX_PRECODING) — the strings the parser matches against when walking the FV list. |
orchagent/port/portcnt.h |
2 | Two new per-lane slots under PortSerdes_t (tx_precoding, rx_precoding) — the in-memory cache entries that hold parsed values + is_set. |
orchagent/port/porthlpr.cpp |
2 | Two new else if branches in the parser dispatch that route the new field names into the slots above, plus the corresponding parsePortSerdes template instantiations. |
orchagent/portsorch.cpp |
3 | Two new if (serdes.{tx,rx}_precoding.is_set) blocks in the SerDes attribute-map builder — each emits the matching SAI attribute (SAI_PORT_SERDES_ATTR_{TX,RX}_PRECODING) only when its slot is marked set. |
—
| # | Test | Validates |
|---|---|---|
| UT1 | portsorch_ut.cpp::PortAdvancedConfig (extended) |
PortHelper::parsePortSerdes accepts tx_precoding / rx_precoding; the resulting SAI attribute map contains SAI_PORT_SERDES_ATTR_TX_PRECODING / RX_PRECODING with the per-lane values from APP_DB. |
System-level link bring-up testing on real SPC-6 hardware is covered by the SI / system test plan and is out of scope for this HLD.