[PATCH net-next 2/6] net: pcs: xpcs: combine C37 SGMII AN and 2500BASEX for Intel mGbE controller

From: Choong Yong Liang
Date: Thu Jun 22 2023 - 00:20:24 EST


From: "Tan, Tee Min" <tee.min.tan@xxxxxxxxxxxxxxx>

This commit introduces xpcs_sgmii_2500basex_features[] that combine
xpcs_sgmii_features[] and xpcs_2500basex_features[] for Intel mGbE
controller that desire to interchange the speed mode of
10/100/1000/2500Mbps at runtime.

Also, we introduce xpcs_config_aneg_c37_sgmii_2500basex() function
which is called by the xpcs_do_config() with the new AN mode:
DW_SGMII_2500BASEX, and this new function will proceed next-level
calling to perform C37 SGMII AN/2500BASEX configuration based on
the PHY interface updated by PHY driver.

Signed-off-by: Tan, Tee Min <tee.min.tan@xxxxxxxxxxxxxxx>
Signed-off-by: Choong Yong Liang <yong.liang.choong@xxxxxxxxxxxxxxx>
---
drivers/net/pcs/pcs-xpcs.c | 72 ++++++++++++++++++++++++++++++------
include/linux/pcs/pcs-xpcs.h | 1 +
2 files changed, 62 insertions(+), 11 deletions(-)

diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index e4e59aa9faf7..cd1dc09c422f 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -104,6 +104,21 @@ static const int xpcs_2500basex_features[] = {
__ETHTOOL_LINK_MODE_MASK_NBITS,
};

+static const int xpcs_sgmii_2500basex_features[] = {
+ ETHTOOL_LINK_MODE_Pause_BIT,
+ ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ ETHTOOL_LINK_MODE_Autoneg_BIT,
+ ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+ ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+ ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+ ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+ ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+
static const phy_interface_t xpcs_usxgmii_interfaces[] = {
PHY_INTERFACE_MODE_USXGMII,
};
@@ -133,6 +148,12 @@ static const phy_interface_t xpcs_2500basex_interfaces[] = {
PHY_INTERFACE_MODE_MAX,
};

+static const phy_interface_t xpcs_sgmii_2500basex_interfaces[] = {
+ PHY_INTERFACE_MODE_SGMII,
+ PHY_INTERFACE_MODE_2500BASEX,
+ PHY_INTERFACE_MODE_MAX,
+};
+
enum {
DW_XPCS_USXGMII,
DW_XPCS_10GKR,
@@ -141,6 +162,7 @@ enum {
DW_XPCS_SGMII,
DW_XPCS_1000BASEX,
DW_XPCS_2500BASEX,
+ DW_XPCS_SGMII_2500BASEX,
DW_XPCS_INTERFACE_MAX,
};

@@ -267,6 +289,7 @@ static int xpcs_soft_reset(struct dw_xpcs *xpcs,
case DW_AN_C37_SGMII:
case DW_2500BASEX:
case DW_AN_C37_1000BASEX:
+ case DW_SGMII_2500BASEX:
dev = MDIO_MMD_VEND2;
break;
default:
@@ -712,6 +735,8 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode)
else
ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;

+ /* Disable 2.5G GMII for SGMII C37 mode */
+ ret &= ~DW_VR_MII_DIG_CTRL1_2G5_EN;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
if (ret < 0)
return ret;
@@ -807,6 +832,26 @@ static int xpcs_config_2500basex(struct dw_xpcs *xpcs)
return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, ret);
}

+static int xpcs_config_aneg_c37_sgmii_2500basex(struct dw_xpcs *xpcs,
+ unsigned int mode,
+ phy_interface_t interface)
+{
+ int ret = -EOPNOTSUPP;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ ret = xpcs_config_aneg_c37_sgmii(xpcs, mode);
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ ret = xpcs_config_2500basex(xpcs);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
unsigned int mode, const unsigned long *advertising)
{
@@ -843,6 +888,12 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
if (ret)
return ret;
break;
+ case DW_SGMII_2500BASEX:
+ ret = xpcs_config_aneg_c37_sgmii_2500basex(xpcs, mode,
+ interface);
+ if (ret)
+ return ret;
+ break;
default:
return -1;
}
@@ -1028,6 +1079,11 @@ static void xpcs_get_state(struct phylink_pcs *pcs,
}
break;
case DW_AN_C37_SGMII:
+ case DW_SGMII_2500BASEX:
+ /* 2500BASEX is not supported for in-band AN mode. */
+ if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
+ break;
+
ret = xpcs_get_state_c37_sgmii(xpcs, state);
if (ret) {
pr_err("xpcs_get_state_c37_sgmii returned %pe\n",
@@ -1180,23 +1236,17 @@ static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
.num_interfaces = ARRAY_SIZE(xpcs_10gbaser_interfaces),
.an_mode = DW_10GBASER,
},
- [DW_XPCS_SGMII] = {
- .supported = xpcs_sgmii_features,
- .interface = xpcs_sgmii_interfaces,
- .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
- .an_mode = DW_AN_C37_SGMII,
- },
[DW_XPCS_1000BASEX] = {
.supported = xpcs_1000basex_features,
.interface = xpcs_1000basex_interfaces,
.num_interfaces = ARRAY_SIZE(xpcs_1000basex_interfaces),
.an_mode = DW_AN_C37_1000BASEX,
},
- [DW_XPCS_2500BASEX] = {
- .supported = xpcs_2500basex_features,
- .interface = xpcs_2500basex_interfaces,
- .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces),
- .an_mode = DW_2500BASEX,
+ [DW_XPCS_SGMII_2500BASEX] = {
+ .supported = xpcs_sgmii_2500basex_features,
+ .interface = xpcs_sgmii_2500basex_interfaces,
+ .num_interfaces = ARRAY_SIZE(xpcs_sgmii_2500basex_features),
+ .an_mode = DW_SGMII_2500BASEX,
},
};

diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h
index ec8175b847cc..3e2265ca9e22 100644
--- a/include/linux/pcs/pcs-xpcs.h
+++ b/include/linux/pcs/pcs-xpcs.h
@@ -19,6 +19,7 @@
#define DW_2500BASEX 3
#define DW_AN_C37_1000BASEX 4
#define DW_10GBASER 5
+#define DW_SGMII_2500BASEX 6

struct xpcs_id;

--
2.25.1