From e6c43c95009035a63091cd49736886f883127510 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 21 Nov 2025 08:39:55 -0800 Subject: net: phy: Add MDIO_PMA_CTRL1_SPEED for 2.5G and 5G to reflect PMA values The 2.5G and 5G values are not consistent between the PCS CTRL1 and PMA CTRL1 values. In order to avoid confusion between the two I am updating the values to include "PMA" in the name similar to values used in similar places. To avoid breaking UAPI I have retained the original macros and just defined them as the new PMA based defines. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/176374319569.959489.6610469879021800710.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- include/uapi/linux/mdio.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h index 6975f182b22c..9ee6eeae64b8 100644 --- a/include/uapi/linux/mdio.h +++ b/include/uapi/linux/mdio.h @@ -116,10 +116,18 @@ #define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) /* 10PASS-TS/2BASE-TL */ #define MDIO_CTRL1_SPEED10P2B (MDIO_CTRL1_SPEEDSELEXT | 0x04) +/* Note: the MDIO_CTRL1_SPEED_XXX values for everything past 10PASS-TS/2BASE-TL + * do not match between the PCS and PMA values. Any additions past this point + * should be PMA or PCS specific. The following 2 defines are workarounds for + * values added before this was caught. They should be considered deprecated. + */ +#define MDIO_CTRL1_SPEED2_5G MDIO_PMA_CTRL1_SPEED2_5G +#define MDIO_CTRL1_SPEED5G MDIO_PMA_CTRL1_SPEED5G /* 2.5 Gb/s */ -#define MDIO_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18) +#define MDIO_PMA_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18) /* 5 Gb/s */ -#define MDIO_CTRL1_SPEED5G (MDIO_CTRL1_SPEEDSELEXT | 0x1c) +#define MDIO_PMA_CTRL1_SPEED5G (MDIO_CTRL1_SPEEDSELEXT | 0x1c) + /* Status register 1. */ #define MDIO_STAT1_LPOWERABLE 0x0002 /* Low-power ability */ -- cgit v1.2.3 From 7622d55276932bfeb947b7b6cbf7ea0aa41feeb8 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 21 Nov 2025 08:40:02 -0800 Subject: net: pcs: xpcs: Add support for 25G, 50G, and 100G interfaces With this change we are adding support for 25G, 50G, and 100G interface types to the XPCS driver. This had supposedly been enabled with the addition of XLGMII but I don't see any capability for configuration there so I suspect it may need to be refactored in the future. With this change we can enable the XPCS driver with the selected interface and it should be able to detect link, speed, and report the link status to the phylink interface. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/176374320248.959489.11649590675011158859.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- drivers/net/pcs/pcs-xpcs.c | 105 +++++++++++++++++++++++++++++++++++++++++++-- include/uapi/linux/mdio.h | 6 +++ 2 files changed, 107 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 3d1bd5aac093..9fb9d4fd2a5b 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -37,6 +37,16 @@ static const int xpcs_10gkr_features[] = { __ETHTOOL_LINK_MODE_MASK_NBITS, }; +static const int xpcs_25gbaser_features[] = { + ETHTOOL_LINK_MODE_MII_BIT, + ETHTOOL_LINK_MODE_Pause_BIT, + ETHTOOL_LINK_MODE_Asym_Pause_BIT, + ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, + ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, + ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, + __ETHTOOL_LINK_MODE_MASK_NBITS, +}; + static const int xpcs_xlgmii_features[] = { ETHTOOL_LINK_MODE_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT, @@ -67,6 +77,40 @@ static const int xpcs_xlgmii_features[] = { __ETHTOOL_LINK_MODE_MASK_NBITS, }; +static const int xpcs_50gbaser_features[] = { + ETHTOOL_LINK_MODE_MII_BIT, + ETHTOOL_LINK_MODE_Pause_BIT, + ETHTOOL_LINK_MODE_Asym_Pause_BIT, + ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, + ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, + ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, + ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, + ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, + __ETHTOOL_LINK_MODE_MASK_NBITS, +}; + +static const int xpcs_50gbaser2_features[] = { + ETHTOOL_LINK_MODE_MII_BIT, + ETHTOOL_LINK_MODE_Pause_BIT, + ETHTOOL_LINK_MODE_Asym_Pause_BIT, + ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, + ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, + ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, + __ETHTOOL_LINK_MODE_MASK_NBITS, +}; + +static const int xpcs_100gbasep_features[] = { + ETHTOOL_LINK_MODE_MII_BIT, + ETHTOOL_LINK_MODE_Pause_BIT, + ETHTOOL_LINK_MODE_Asym_Pause_BIT, + ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, + ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, + ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, + ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, + ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, + __ETHTOOL_LINK_MODE_MASK_NBITS, +}; + static const int xpcs_10gbaser_features[] = { ETHTOOL_LINK_MODE_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT, @@ -523,9 +567,38 @@ static int xpcs_get_max_xlgmii_speed(struct dw_xpcs *xpcs, return speed; } -static void xpcs_resolve_pma(struct dw_xpcs *xpcs, - struct phylink_link_state *state) +static int xpcs_c45_read_pcs_speed(struct dw_xpcs *xpcs, + struct phylink_link_state *state) { + int pcs_ctrl1; + + pcs_ctrl1 = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL1); + if (pcs_ctrl1 < 0) + return pcs_ctrl1; + + switch (pcs_ctrl1 & MDIO_CTRL1_SPEEDSEL) { + case MDIO_PCS_CTRL1_SPEED25G: + state->speed = SPEED_25000; + break; + case MDIO_PCS_CTRL1_SPEED50G: + state->speed = SPEED_50000; + break; + case MDIO_PCS_CTRL1_SPEED100G: + state->speed = SPEED_100000; + break; + default: + state->speed = SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int xpcs_resolve_pma(struct dw_xpcs *xpcs, + struct phylink_link_state *state) +{ + int err = 0; + state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX; state->duplex = DUPLEX_FULL; @@ -536,10 +609,18 @@ static void xpcs_resolve_pma(struct dw_xpcs *xpcs, case PHY_INTERFACE_MODE_XLGMII: state->speed = xpcs_get_max_xlgmii_speed(xpcs, state); break; + case PHY_INTERFACE_MODE_100GBASEP: + case PHY_INTERFACE_MODE_LAUI: + case PHY_INTERFACE_MODE_50GBASER: + case PHY_INTERFACE_MODE_25GBASER: + err = xpcs_c45_read_pcs_speed(xpcs, state); + break; default: state->speed = SPEED_UNKNOWN; break; } + + return err; } static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, @@ -945,10 +1026,10 @@ static int xpcs_get_state_c73(struct dw_xpcs *xpcs, phylink_resolve_c73(state); } else { - xpcs_resolve_pma(xpcs, state); + ret = xpcs_resolve_pma(xpcs, state); } - return 0; + return ret; } static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs, @@ -1312,10 +1393,26 @@ static const struct dw_xpcs_compat synopsys_xpcs_compat[] = { .interface = PHY_INTERFACE_MODE_10GKR, .supported = xpcs_10gkr_features, .an_mode = DW_AN_C73, + }, { + .interface = PHY_INTERFACE_MODE_25GBASER, + .supported = xpcs_25gbaser_features, + .an_mode = DW_AN_C73, }, { .interface = PHY_INTERFACE_MODE_XLGMII, .supported = xpcs_xlgmii_features, .an_mode = DW_AN_C73, + }, { + .interface = PHY_INTERFACE_MODE_50GBASER, + .supported = xpcs_50gbaser_features, + .an_mode = DW_AN_C73, + }, { + .interface = PHY_INTERFACE_MODE_LAUI, + .supported = xpcs_50gbaser2_features, + .an_mode = DW_AN_C73, + }, { + .interface = PHY_INTERFACE_MODE_100GBASEP, + .supported = xpcs_100gbasep_features, + .an_mode = DW_AN_C73, }, { .interface = PHY_INTERFACE_MODE_10GBASER, .supported = xpcs_10gbaser_features, diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h index 9ee6eeae64b8..f23cab33e586 100644 --- a/include/uapi/linux/mdio.h +++ b/include/uapi/linux/mdio.h @@ -123,6 +123,12 @@ */ #define MDIO_CTRL1_SPEED2_5G MDIO_PMA_CTRL1_SPEED2_5G #define MDIO_CTRL1_SPEED5G MDIO_PMA_CTRL1_SPEED5G +/* 100 Gb/s */ +#define MDIO_PCS_CTRL1_SPEED100G (MDIO_CTRL1_SPEEDSELEXT | 0x10) +/* 25 Gb/s */ +#define MDIO_PCS_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14) +/* 50 Gb/s */ +#define MDIO_PCS_CTRL1_SPEED50G (MDIO_CTRL1_SPEEDSELEXT | 0x18) /* 2.5 Gb/s */ #define MDIO_PMA_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18) /* 5 Gb/s */ -- cgit v1.2.3 From 39e138173ae7641e952b456d2de7ad2ac03e8d88 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 21 Nov 2025 08:40:09 -0800 Subject: net: pcs: xpcs: Fix PMA identifier handling in XPCS The XPCS driver was mangling the PMA identifier as the original code appears to have been focused on just capturing the OUI. Rather than store a mangled ID it is better to work with the actual PMA ID and instead just mask out the values that don't apply rather than shifting them and reordering them as you still don't get the original OUI for the NIC without having to bitswap the values as per the definition of the layout in IEEE 802.3-2022 22.2.4.3.1. By laying it out as it was in the hardware it is also less likely for us to have an unintentional collision as the enum values will occupy the revision number area while the OUI occupies the upper 22 bits. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/176374320920.959489.17267159479370601070.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- drivers/net/pcs/pcs-xpcs.c | 9 ++++----- include/linux/pcs/pcs-xpcs.h | 2 +- include/uapi/linux/mdio.h | 5 +++++ 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 9fb9d4fd2a5b..a94a7cb93664 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -1365,17 +1365,16 @@ static int xpcs_read_ids(struct dw_xpcs *xpcs) if (ret < 0) return ret; - id = ret; + id = ret << 16; ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID2); if (ret < 0) return ret; - /* Note the inverted dword order and masked out Model/Revision numbers - * with respect to what is done with the PCS ID... + /* For now we only record the OUI for the PMAPMD, we may want to + * add the model number at some point in the future. */ - ret = (ret >> 10) & 0x3F; - id |= ret << 16; + id |= ret & MDIO_DEVID2_OUI; /* Set the PMA ID if it hasn't been pre-initialized */ if (xpcs->info.pma == DW_XPCS_PMA_ID_NATIVE) diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index e40f554ff717..4cf6bd611e5a 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -38,7 +38,7 @@ enum dw_xpcs_pma_id { DW_XPCS_PMA_GEN4_6G_ID, DW_XPCS_PMA_GEN5_10G_ID, DW_XPCS_PMA_GEN5_12G_ID, - WX_TXGBE_XPCS_PMA_10G_ID = 0x0018fc80, + WX_TXGBE_XPCS_PMA_10G_ID = 0xfc806000, }; struct dw_xpcs_info { diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h index f23cab33e586..8d769f100de6 100644 --- a/include/uapi/linux/mdio.h +++ b/include/uapi/linux/mdio.h @@ -147,6 +147,11 @@ #define MDIO_AN_STAT1_PAGE 0x0040 /* Page received */ #define MDIO_AN_STAT1_XNP 0x0080 /* Extended next page status */ +/* Device Identifier 2 */ +#define MDIO_DEVID2_OUI 0xfc00 /* OUI Portion of PHY ID */ +#define MDIO_DEVID2_MODEL_NUM 0x03f0 /* Manufacturer's Model Number */ +#define MDIO_DEVID2_REV_NUM 0x000f /* Revision Number */ + /* Speed register. */ #define MDIO_SPEED_10G 0x0001 /* 10G capable */ #define MDIO_PMA_SPEED_2B 0x0002 /* 2BASE-TL capable */ -- cgit v1.2.3 From 3f29dd34f75a09ee7f8333305618edb44617d835 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 21 Nov 2025 08:40:16 -0800 Subject: net: pcs: xpcs: Add support for FBNIC 25G, 50G, 100G PMD The fbnic driver is planning to make use of the XPCS driver to enable support for PCS and better integration with phylink. To do this though we will need to enable several workarounds since the PMD interface for fbnic is likely to be unique since it is a mix of two different vendor products with a unique wrapper around the IP. I have generated a PHY identifier based on IEEE 802.3-2022 22.2.4.3.1 using an OUI belonging to Meta Platforms and used with our NICs. Using this we will provide it as the PMD ID via the SW based MDIO interface so that the fbnic device can be identified and necessary workarounds enabled in the XPCS driver. As an initial workaround this change adds an exception so that soft_reset is not set when the driver is initially bound to the PCS. In addition I have added logic to integrate the PMD Rx signal detect state into the link state for the PCS. With this we can avoid the link coming up too soon on the FBNIC PMD and as a result of it being in the training state so we can avoid link flaps. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/176374321695.959489.6648161125012056619.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- drivers/net/pcs/pcs-xpcs.c | 24 ++++++++++++++++++++++-- include/linux/pcs/pcs-xpcs.h | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index a94a7cb93664..9679f2b35a44 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -597,7 +597,26 @@ static int xpcs_c45_read_pcs_speed(struct dw_xpcs *xpcs, static int xpcs_resolve_pma(struct dw_xpcs *xpcs, struct phylink_link_state *state) { - int err = 0; + int pmd_rxdet, err = 0; + + /* The Meta Platforms FBNIC PMD will go into a training state for + * about 4 seconds when the link first comes up. During this time the + * PCS link will bounce. To avoid reporting link up too soon we include + * the PMD state provided by the driver. + */ + if (xpcs->info.pma == MP_FBNIC_XPCS_PMA_100G_ID) { + pmd_rxdet = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_PMA_RXDET); + if (pmd_rxdet < 0) { + state->link = false; + return pmd_rxdet; + } + + /* Verify Rx lanes are trained before reporting link up */ + if (!(pmd_rxdet & MDIO_PMD_RXDET_GLOBAL)) { + state->link = false; + return 0; + } + } state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX; state->duplex = DUPLEX_FULL; @@ -1591,7 +1610,8 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev) xpcs_get_interfaces(xpcs, xpcs->pcs.supported_interfaces); - if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) + if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID || + xpcs->info.pma == MP_FBNIC_XPCS_PMA_100G_ID) xpcs->pcs.poll = false; else xpcs->need_reset = true; diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index 4cf6bd611e5a..36073f7b6bb4 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -39,6 +39,8 @@ enum dw_xpcs_pma_id { DW_XPCS_PMA_GEN5_10G_ID, DW_XPCS_PMA_GEN5_12G_ID, WX_TXGBE_XPCS_PMA_10G_ID = 0xfc806000, + /* Meta Platforms OUI 88:25:08, model 0, revision 0 */ + MP_FBNIC_XPCS_PMA_100G_ID = 0x46904000, }; struct dw_xpcs_info { -- cgit v1.2.3