]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: pcs: xpcs: Add support for 25G, 50G, and 100G interfaces
authorAlexander Duyck <alexanderduyck@fb.com>
Fri, 21 Nov 2025 16:40:02 +0000 (08:40 -0800)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 27 Nov 2025 09:41:30 +0000 (10:41 +0100)
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 <alexanderduyck@fb.com>
Link: https://patch.msgid.link/176374320248.959489.11649590675011158859.stgit@ahduyck-xeon-server.home.arpa
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/pcs/pcs-xpcs.c
include/uapi/linux/mdio.h

index 3d1bd5aac09376deef2179fa958a580b5afcb197..9fb9d4fd2a5b07f909f1d8456d35c507bff7c6c8 100644 (file)
@@ -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,
index 9ee6eeae64b8b236db8f8d7560406eaabc990b77..f23cab33e5866b2959bf82fd09a370baf8283e36 100644 (file)
  */
 #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 */