Skip to content

Support SAI_PORT_SERDES_ATTR_CUSTOM_COLLECTION#3764

Merged
prsunny merged 11 commits intosonic-net:masterfrom
longhuan-cisco:support_custom_serdes
Nov 26, 2025
Merged

Support SAI_PORT_SERDES_ATTR_CUSTOM_COLLECTION#3764
prsunny merged 11 commits intosonic-net:masterfrom
longhuan-cisco:support_custom_serdes

Conversation

@longhuan-cisco
Copy link
Copy Markdown
Contributor

@longhuan-cisco longhuan-cisco commented Jul 14, 2025

sonic-platform-daemon side change: sonic-net/sonic-platform-daemons#643

What I did
Support SAI_PORT_SERDES_ATTR_CUSTOM_COLLECTION (i.e. custom serdes attributes represented in JSON based string format)

Use boost::variant for the serdes_attr map value to support both std::vector<uint32_t> and std::string in a type-safe way, with easy extensibility to add more types later.

Why I did it

How I verified it
Tested end-to-end xcvrd->OA->SAI/SDK

Covered below 3 scenarios:

  1. attr_list only contains traditional (non-JSON based) serdes attributes
  2. attr_list only contains custom (JSON based) serdes attributes
  3. attr_list contains a mixed of both

Details if related

@longhuan-cisco longhuan-cisco requested a review from prsunny as a code owner July 14, 2025 23:04
@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@longhuan-cisco
Copy link
Copy Markdown
Contributor Author

@prgeor @mihirpat1 could you please review, thanks

@longhuan-cisco longhuan-cisco requested a review from prgeor July 27, 2025 07:19
@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@longhuan-cisco longhuan-cisco requested a review from prgeor October 27, 2025 07:32
@prgeor
Copy link
Copy Markdown
Contributor

prgeor commented Oct 27, 2025

@prsunny can you merge?

@longhuan-cisco
Copy link
Copy Markdown
Contributor Author

@prsunny can you merge?

@prsunny kindly reminder, thanks

@prsunny
Copy link
Copy Markdown
Collaborator

prsunny commented Nov 10, 2025

@longhuan-cisco , i see new boost library added, can you provide description of why its added?

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@prgeor
Copy link
Copy Markdown
Contributor

prgeor commented Nov 15, 2025

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@longhuan-cisco
Copy link
Copy Markdown
Contributor Author

Looks like, Azure.sonic-swss failure was due to base line issue, which was hit on other PRs also

@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@longhuan-cisco
Copy link
Copy Markdown
Contributor Author

I saw Semgrep pre-commit run got stuck in "Waiting for status to be reported" state for quite some time, not sure if it's due to some issue in Azure Pipelines

cc @prsunny

@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@longhuan-cisco
Copy link
Copy Markdown
Contributor Author

@prsunny kindly reminder for approval/merge. all pre-commit checks passed.

@prsunny prsunny merged commit a2decc5 into sonic-net:master Nov 26, 2025
15 checks passed
@balanokia
Copy link
Copy Markdown

@prsunny @prgeor @lguohan : Pls shared review comments. We made this PR to introduce boost:variant type but it changes keywords in a non-functional way.
Hi @longhuan-cisco
Tx FIR Pre-emphasis is the key word for Tx FIR Equalization with certain number of taps and Pre-emphasis keyword is used in IEEE or all OEM datasheets in a functional meaning. Lets not change the keyword from pre-emphasis to generic keyword "serdes_attrs" and "serdes_attr" does not signify Tx FIR (tap) value set. Lets keep the code understanding in a functional meaning. Kindly share your views.
Thanks
Bala

@longhuan-cisco
Copy link
Copy Markdown
Contributor Author

Hi @longhuan-cisco
Tx FIR Pre-emphasis is the key word for Tx FIR Equalization with certain number of taps and Pre-emphasis keyword is used in IEEE or all OEM datasheets in a functional meaning. Lets not change the keyword from pre-emphasis to generic keyword "serdes_attrs" and "serdes_attr" does not signify Tx FIR (tap) value set. Lets keep the code understanding in a functional meaning. Kindly share your views.
Thanks
Bala

Hi @balanokia
In the existing code before this PR, this variable had been used to cover many different serdes attributes for quite long time, including SAI_PORT_SERDES_ATTR_PREEMPHASIS, SAI_PORT_SERDES_ATTR_IDRIVER, SAI_PORT_SERDES_ATTR_IPREDRIVER and etc.
It's generic, not just for SAI_PORT_SERDES_ATTR_PREEMPHASIS

Please refer to below old code snapshot (before this PR merged):

static void getPortSerdesAttr(PortSerdesAttrMap_t &map, const PortConfig &port)
{
if (port.serdes.preemphasis.is_set)
{
map[SAI_PORT_SERDES_ATTR_PREEMPHASIS] = port.serdes.preemphasis.value;
}
if (port.serdes.idriver.is_set)
{
map[SAI_PORT_SERDES_ATTR_IDRIVER] = port.serdes.idriver.value;
}
if (port.serdes.ipredriver.is_set)
{
map[SAI_PORT_SERDES_ATTR_IPREDRIVER] = port.serdes.ipredriver.value;
}
if (port.serdes.pre1.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_PRE1] = port.serdes.pre1.value;
}
if (port.serdes.pre2.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_PRE2] = port.serdes.pre2.value;
}
if (port.serdes.pre3.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_PRE3] = port.serdes.pre3.value;
}
if (port.serdes.main.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_MAIN] = port.serdes.main.value;
}
if (port.serdes.post1.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_POST1] = port.serdes.post1.value;
}
if (port.serdes.post2.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_POST2] = port.serdes.post2.value;
}
if (port.serdes.post3.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_POST3] = port.serdes.post3.value;
}
if (port.serdes.attn.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_ATTN] = port.serdes.attn.value;
}
if (port.serdes.ob_m2lp.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_PAM4_RATIO] = port.serdes.ob_m2lp.value;
}
if (port.serdes.ob_alev_out.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_OUT_COMMON_MODE] = port.serdes.ob_alev_out.value;
}
if (port.serdes.obplev.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_PMOS_COMMON_MODE] = port.serdes.obplev.value;
}
if (port.serdes.obnlev.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_NMOS_COMMON_MODE] = port.serdes.obnlev.value;
}
if (port.serdes.regn_bfm1p.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_PMOS_VLTG_REG] = port.serdes.regn_bfm1p.value;
}
if (port.serdes.regn_bfm1n.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_NMOS_VLTG_REG] = port.serdes.regn_bfm1n.value;
}
}

#define PORT_PREEMPHASIS "preemphasis"
#define PORT_IDRIVER "idriver"
#define PORT_IPREDRIVER "ipredriver"
#define PORT_PRE1 "pre1"
#define PORT_PRE2 "pre2"
#define PORT_PRE3 "pre3"
#define PORT_MAIN "main"
#define PORT_POST1 "post1"
#define PORT_POST2 "post2"
#define PORT_POST3 "post3"
#define PORT_ATTN "attn"
#define PORT_OB_M2LP "ob_m2lp"
#define PORT_OB_ALEV_OUT "ob_alev_out"
#define PORT_OBPLEV "obplev"
#define PORT_OBNLEV "obnlev"
#define PORT_REGN_BFM1P "regn_bfm1p"
#define PORT_REGN_BFM1N "regn_bfm1n"

PortSerdesAttrMap_t serdes_attr;
getPortSerdesAttr(serdes_attr, pCfg);

p.m_preemphasis = serdes_attr;

kalash-nexthop pushed a commit to kalash-nexthop/sonic-swss that referenced this pull request Dec 16, 2025
sonic-platform-daemon side change: sonic-net/sonic-platform-daemons#643

What I did
Support SAI_PORT_SERDES_ATTR_CUSTOM_COLLECTION (i.e. custom serdes attributes represented in JSON based string format)

Use boost::variant for the serdes_attr map value to support both std::vector<uint32_t> and std::string in a type-safe way, with easy extensibility to add more types later.

Signed-off-by: Kalash Nainwal <kalash@nexthop.ai>
@balanokia
Copy link
Copy Markdown

Hi @longhuan-cisco
Tx FIR Pre-emphasis is the key word for Tx FIR Equalization with certain number of taps and Pre-emphasis keyword is used in IEEE or all OEM datasheets in a functional meaning. Lets not change the keyword from pre-emphasis to generic keyword "serdes_attrs" and "serdes_attr" does not signify Tx FIR (tap) value set. Lets keep the code understanding in a functional meaning. Kindly share your views.
Thanks
Bala

Hi @balanokia In the existing code before this PR, this variable had been used to cover many different serdes attributes for quite long time, including SAI_PORT_SERDES_ATTR_PREEMPHASIS, SAI_PORT_SERDES_ATTR_IDRIVER, SAI_PORT_SERDES_ATTR_IPREDRIVER and etc. It's generic, not just for SAI_PORT_SERDES_ATTR_PREEMPHASIS

Please refer to below old code snapshot (before this PR merged):

static void getPortSerdesAttr(PortSerdesAttrMap_t &map, const PortConfig &port)
{
if (port.serdes.preemphasis.is_set)
{
map[SAI_PORT_SERDES_ATTR_PREEMPHASIS] = port.serdes.preemphasis.value;
}
if (port.serdes.idriver.is_set)
{
map[SAI_PORT_SERDES_ATTR_IDRIVER] = port.serdes.idriver.value;
}
if (port.serdes.ipredriver.is_set)
{
map[SAI_PORT_SERDES_ATTR_IPREDRIVER] = port.serdes.ipredriver.value;
}
if (port.serdes.pre1.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_PRE1] = port.serdes.pre1.value;
}
if (port.serdes.pre2.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_PRE2] = port.serdes.pre2.value;
}
if (port.serdes.pre3.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_PRE3] = port.serdes.pre3.value;
}
if (port.serdes.main.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_MAIN] = port.serdes.main.value;
}
if (port.serdes.post1.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_POST1] = port.serdes.post1.value;
}
if (port.serdes.post2.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_POST2] = port.serdes.post2.value;
}
if (port.serdes.post3.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_POST3] = port.serdes.post3.value;
}
if (port.serdes.attn.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_FIR_ATTN] = port.serdes.attn.value;
}
if (port.serdes.ob_m2lp.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_PAM4_RATIO] = port.serdes.ob_m2lp.value;
}
if (port.serdes.ob_alev_out.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_OUT_COMMON_MODE] = port.serdes.ob_alev_out.value;
}
if (port.serdes.obplev.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_PMOS_COMMON_MODE] = port.serdes.obplev.value;
}
if (port.serdes.obnlev.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_NMOS_COMMON_MODE] = port.serdes.obnlev.value;
}
if (port.serdes.regn_bfm1p.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_PMOS_VLTG_REG] = port.serdes.regn_bfm1p.value;
}
if (port.serdes.regn_bfm1n.is_set)
{
map[SAI_PORT_SERDES_ATTR_TX_NMOS_VLTG_REG] = port.serdes.regn_bfm1n.value;
}
}

#define PORT_PREEMPHASIS "preemphasis"
#define PORT_IDRIVER "idriver"
#define PORT_IPREDRIVER "ipredriver"
#define PORT_PRE1 "pre1"
#define PORT_PRE2 "pre2"
#define PORT_PRE3 "pre3"
#define PORT_MAIN "main"
#define PORT_POST1 "post1"
#define PORT_POST2 "post2"
#define PORT_POST3 "post3"
#define PORT_ATTN "attn"
#define PORT_OB_M2LP "ob_m2lp"
#define PORT_OB_ALEV_OUT "ob_alev_out"
#define PORT_OBPLEV "obplev"
#define PORT_OBNLEV "obnlev"
#define PORT_REGN_BFM1P "regn_bfm1p"
#define PORT_REGN_BFM1N "regn_bfm1n"

PortSerdesAttrMap_t serdes_attr;
getPortSerdesAttr(serdes_attr, pCfg);

p.m_preemphasis = serdes_attr;

Hi @longhuan-cisco
Thanks for clarifying. Its good to have abstraction of serdes attributes under one bucket. When we invoke to apply a specific type of serdes attributes, we know what significant parameters that we update and hence it would be better to keep the variable names or atleast keep the log messages as-is in the past like "SWSS_LOG_NOTICE("Save port %s preemphasis for LT", p.m_alias.c_str())". It would help us to debug port bringup sequences (LT, FEC, Tx FIR, etc) especially external PHY stages.

Thanks
Bala

@longhuan-cisco
Copy link
Copy Markdown
Contributor Author

Hi @longhuan-cisco Thanks for clarifying. Its good to have abstraction of serdes attributes under one bucket. When we invoke to apply a specific type of serdes attributes, we know what significant parameters that we update and hence it would be better to keep the variable names or atleast keep the log messages as-is in the past like "SWSS_LOG_NOTICE("Save port %s preemphasis for LT", p.m_alias.c_str())". It would help us to debug port bringup sequences (LT, FEC, Tx FIR, etc) especially external PHY stages.

Thanks
Bala

Hi @balanokia, thanks for the context on PHY terminology.

In general PHY literature, “pre‑emphasis” is indeed often used to refer to TX equalization and is sometimes implemented/expressed via TX‑FIR/FFE taps.

However, in SONiC orchagent this saved/restored bucket has historically been a generic SERDES attribute bucket, not strictly “pre‑emphasis only”. It can include multiple SAI_PORT_SERDES_ATTR_* knobs depending on platform media_settings.json/config (e.g., PREEMPHASIS, IDRIVER/IPREDRIVER, TX_FIR_* taps, PAM4 ratio/common-mode controls, precoding, etc.). SAI itself defines these as distinct SERDES attributes, where PREEMPHASIS is just one item in the list.

Because the bucket is not guaranteed to contain PREEMPHASIS on every platform/vendor/module, keeping “preemphasis” as the generic bucket/variable/log keyword is semantically misleading and can oversimplify what is actually being saved/restored. Renaming it to serdes_attrs improves correctness without changing behavior or reducing log informativeness—the previous logs did not actually confirm whether PREEMPHASIS was present either.

For debuggability, a more robust community-wide improvement would be to log which SERDES attributes are being set/saved/restored (e.g., list attr IDs/names at NOTICE, and optionally values at DEBUG), so anyone can grep for a stable tag and still see the exact contents. This makes the behavior transparent across all vendors/platforms/config combinations.

Thanks,
Longyin

Pterosaur pushed a commit to Janetxxx/sonic-swss that referenced this pull request Jan 6, 2026
sonic-platform-daemon side change: sonic-net/sonic-platform-daemons#643

What I did
Support SAI_PORT_SERDES_ATTR_CUSTOM_COLLECTION (i.e. custom serdes attributes represented in JSON based string format)

Use boost::variant for the serdes_attr map value to support both std::vector<uint32_t> and std::string in a type-safe way, with easy extensibility to add more types later.
yehjunying pushed a commit to yehjunying/sonic-swss that referenced this pull request Jan 16, 2026
sonic-platform-daemon side change: sonic-net/sonic-platform-daemons#643

What I did
Support SAI_PORT_SERDES_ATTR_CUSTOM_COLLECTION (i.e. custom serdes attributes represented in JSON based string format)

Use boost::variant for the serdes_attr map value to support both std::vector<uint32_t> and std::string in a type-safe way, with easy extensibility to add more types later.
baorliu pushed a commit to baorliu/sonic-swss that referenced this pull request Feb 23, 2026
sonic-platform-daemon side change: sonic-net/sonic-platform-daemons#643

What I did
Support SAI_PORT_SERDES_ATTR_CUSTOM_COLLECTION (i.e. custom serdes attributes represented in JSON based string format)

Use boost::variant for the serdes_attr map value to support both std::vector<uint32_t> and std::string in a type-safe way, with easy extensibility to add more types later.

Signed-off-by: Baorong Liu <96146196+baorliu@users.noreply.github.com>
@longhuan-cisco
Copy link
Copy Markdown
Contributor Author

@prgeor Could we cherry-pick this to 202511

@balanokia
Copy link
Copy Markdown

@longhuan-cisco @prgeor Pls suggest if we plan to take this PR to 202511 branch. I already see @longhuan-cisco already raised it for merge to 202511.

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.

5 participants