diff options
author | Raju Rangoju <Raju.Rangoju@amd.com> | 2023-01-09 13:18:19 +0300 |
---|---|---|
committer | Paolo Abeni <pabeni@redhat.com> | 2023-01-10 13:20:30 +0300 |
commit | 07445f3c7ca1cfe490353be52bda91d9e6745ef4 (patch) | |
tree | 2754663d40377a76e864d11413698d69911e2355 | |
parent | cbdbb58b6c796e48ad6346e07bf3ae65cf4dc69b (diff) | |
download | linux-07445f3c7ca1cfe490353be52bda91d9e6745ef4.tar.xz |
amd-xgbe: Add support for 10 Mbps speed
Add the necessary changes to support 10 Mbps speed for BaseT and SFP
port modes. This is supported in MAC ver >= 30H.
Signed-off-by: Raju Rangoju <Raju.Rangoju@amd.com>
Link: https://lore.kernel.org/r/20230109101819.747572-1-Raju.Rangoju@amd.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 24 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 107 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe.h | 2 |
4 files changed, 126 insertions, 10 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 3936543a74d8..e033d6c819f3 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -807,6 +807,9 @@ static int xgbe_set_speed(struct xgbe_prv_data *pdata, int speed) unsigned int ss; switch (speed) { + case SPEED_10: + ss = 0x07; + break; case SPEED_1000: ss = 0x03; break; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 0c5c1b155683..cde0f86791b6 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -274,6 +274,15 @@ static void xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata) pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000); } +static void xgbe_sgmii_10_mode(struct xgbe_prv_data *pdata) +{ + /* Set MAC to 10M speed */ + pdata->hw_if.set_speed(pdata, SPEED_10); + + /* Call PHY implementation support to complete rate change */ + pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_10); +} + static void xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata) { /* Set MAC to 1G speed */ @@ -306,6 +315,9 @@ static void xgbe_change_mode(struct xgbe_prv_data *pdata, case XGBE_MODE_KR: xgbe_kr_mode(pdata); break; + case XGBE_MODE_SGMII_10: + xgbe_sgmii_10_mode(pdata); + break; case XGBE_MODE_SGMII_100: xgbe_sgmii_100_mode(pdata); break; @@ -1074,6 +1086,8 @@ static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata) static const char *xgbe_phy_speed_string(int speed) { switch (speed) { + case SPEED_10: + return "10Mbps"; case SPEED_100: return "100Mbps"; case SPEED_1000: @@ -1161,6 +1175,7 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) case XGBE_MODE_KX_1000: case XGBE_MODE_KX_2500: case XGBE_MODE_KR: + case XGBE_MODE_SGMII_10: case XGBE_MODE_SGMII_100: case XGBE_MODE_SGMII_1000: case XGBE_MODE_X: @@ -1222,6 +1237,8 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode) xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000); } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) { xgbe_set_mode(pdata, XGBE_MODE_SGMII_100); + } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_10)) { + xgbe_set_mode(pdata, XGBE_MODE_SGMII_10); } else { enable_irq(pdata->an_irq); ret = -EINVAL; @@ -1301,6 +1318,9 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) mode = xgbe_phy_status_aneg(pdata); switch (mode) { + case XGBE_MODE_SGMII_10: + pdata->phy.speed = SPEED_10; + break; case XGBE_MODE_SGMII_100: pdata->phy.speed = SPEED_100; break; @@ -1443,6 +1463,8 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata) xgbe_sgmii_1000_mode(pdata); } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) { xgbe_sgmii_100_mode(pdata); + } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_10)) { + xgbe_sgmii_10_mode(pdata); } else { ret = -EINVAL; goto err_irq; @@ -1540,6 +1562,8 @@ static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata) return SPEED_1000; else if (XGBE_ADV(lks, 100baseT_Full)) return SPEED_100; + else if (XGBE_ADV(lks, 10baseT_Full)) + return SPEED_10; return SPEED_UNKNOWN; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index c731a04731f8..de7118cb10b8 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -124,6 +124,7 @@ #include "xgbe.h" #include "xgbe-common.h" +#define XGBE_PHY_PORT_SPEED_10 BIT(0) #define XGBE_PHY_PORT_SPEED_100 BIT(1) #define XGBE_PHY_PORT_SPEED_1000 BIT(2) #define XGBE_PHY_PORT_SPEED_2500 BIT(3) @@ -759,6 +760,8 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) XGBE_SET_SUP(lks, Pause); XGBE_SET_SUP(lks, Asym_Pause); if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) { + if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) + XGBE_SET_SUP(lks, 10baseT_Full); if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) XGBE_SET_SUP(lks, 100baseT_Full); if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) @@ -1542,6 +1545,16 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) xgbe_phy_phydev_flowctrl(pdata); switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) { + case XGBE_SGMII_AN_LINK_SPEED_10: + if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { + XGBE_SET_LP_ADV(lks, 10baseT_Full); + mode = XGBE_MODE_SGMII_10; + } else { + /* Half-duplex not supported */ + XGBE_SET_LP_ADV(lks, 10baseT_Half); + mode = XGBE_MODE_UNKNOWN; + } + break; case XGBE_SGMII_AN_LINK_SPEED_100: if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { XGBE_SET_LP_ADV(lks, 100baseT_Full); @@ -1658,7 +1671,10 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) switch (phy_data->sfp_base) { case XGBE_SFP_BASE_1000_T: if (phy_data->phydev && - (phy_data->phydev->speed == SPEED_100)) + (phy_data->phydev->speed == SPEED_10)) + mode = XGBE_MODE_SGMII_10; + else if (phy_data->phydev && + (phy_data->phydev->speed == SPEED_100)) mode = XGBE_MODE_SGMII_100; else mode = XGBE_MODE_SGMII_1000; @@ -1673,7 +1689,10 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) break; default: if (phy_data->phydev && - (phy_data->phydev->speed == SPEED_100)) + (phy_data->phydev->speed == SPEED_10)) + mode = XGBE_MODE_SGMII_10; + else if (phy_data->phydev && + (phy_data->phydev->speed == SPEED_100)) mode = XGBE_MODE_SGMII_100; else mode = XGBE_MODE_SGMII_1000; @@ -2127,6 +2146,20 @@ static void xgbe_phy_sgmii_100_mode(struct xgbe_prv_data *pdata) netif_dbg(pdata, link, pdata->netdev, "100MbE SGMII mode set\n"); } +static void xgbe_phy_sgmii_10_mode(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + + xgbe_phy_set_redrv_mode(pdata); + + /* 10M/SGMII */ + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_10MBITS); + + phy_data->cur_mode = XGBE_MODE_SGMII_10; + + netif_dbg(pdata, link, pdata->netdev, "10MbE SGMII mode set\n"); +} + static void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; @@ -2185,6 +2218,7 @@ static enum xgbe_mode xgbe_phy_switch_baset_mode(struct xgbe_prv_data *pdata) return xgbe_phy_cur_mode(pdata); switch (xgbe_phy_cur_mode(pdata)) { + case XGBE_MODE_SGMII_10: case XGBE_MODE_SGMII_100: case XGBE_MODE_SGMII_1000: return XGBE_MODE_KR; @@ -2252,6 +2286,8 @@ static enum xgbe_mode xgbe_phy_get_baset_mode(struct xgbe_phy_data *phy_data, int speed) { switch (speed) { + case SPEED_10: + return XGBE_MODE_SGMII_10; case SPEED_100: return XGBE_MODE_SGMII_100; case SPEED_1000: @@ -2269,6 +2305,8 @@ static enum xgbe_mode xgbe_phy_get_sfp_mode(struct xgbe_phy_data *phy_data, int speed) { switch (speed) { + case SPEED_10: + return XGBE_MODE_SGMII_10; case SPEED_100: return XGBE_MODE_SGMII_100; case SPEED_1000: @@ -2343,6 +2381,9 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) case XGBE_MODE_KR: xgbe_phy_kr_mode(pdata); break; + case XGBE_MODE_SGMII_10: + xgbe_phy_sgmii_10_mode(pdata); + break; case XGBE_MODE_SGMII_100: xgbe_phy_sgmii_100_mode(pdata); break; @@ -2399,6 +2440,9 @@ static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata, struct ethtool_link_ksettings *lks = &pdata->phy.lks; switch (mode) { + case XGBE_MODE_SGMII_10: + return xgbe_phy_check_mode(pdata, mode, + XGBE_ADV(lks, 10baseT_Full)); case XGBE_MODE_SGMII_100: return xgbe_phy_check_mode(pdata, mode, XGBE_ADV(lks, 100baseT_Full)); @@ -2428,6 +2472,11 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, return false; return xgbe_phy_check_mode(pdata, mode, XGBE_ADV(lks, 1000baseX_Full)); + case XGBE_MODE_SGMII_10: + if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) + return false; + return xgbe_phy_check_mode(pdata, mode, + XGBE_ADV(lks, 10baseT_Full)); case XGBE_MODE_SGMII_100: if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) return false; @@ -2520,10 +2569,17 @@ static bool xgbe_phy_valid_speed_basex_mode(struct xgbe_phy_data *phy_data, } } -static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_phy_data *phy_data, +static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_prv_data *pdata, int speed) { + struct xgbe_phy_data *phy_data = pdata->phy_data; + unsigned int ver; + switch (speed) { + case SPEED_10: + /* Supported in ver >= 30H */ + ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER); + return (ver >= 0x30) ? true : false; case SPEED_100: case SPEED_1000: return true; @@ -2536,10 +2592,17 @@ static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_phy_data *phy_data, } } -static bool xgbe_phy_valid_speed_sfp_mode(struct xgbe_phy_data *phy_data, +static bool xgbe_phy_valid_speed_sfp_mode(struct xgbe_prv_data *pdata, int speed) { + struct xgbe_phy_data *phy_data = pdata->phy_data; + unsigned int ver; + switch (speed) { + case SPEED_10: + /* Supported in ver >= 30H */ + ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER); + return (ver >= 0x30) && (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000); case SPEED_100: return (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000); case SPEED_1000: @@ -2586,12 +2649,12 @@ static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed) case XGBE_PORT_MODE_1000BASE_T: case XGBE_PORT_MODE_NBASE_T: case XGBE_PORT_MODE_10GBASE_T: - return xgbe_phy_valid_speed_baset_mode(phy_data, speed); + return xgbe_phy_valid_speed_baset_mode(pdata, speed); case XGBE_PORT_MODE_1000BASE_X: case XGBE_PORT_MODE_10GBASE_R: return xgbe_phy_valid_speed_basex_mode(phy_data, speed); case XGBE_PORT_MODE_SFP: - return xgbe_phy_valid_speed_sfp_mode(phy_data, speed); + return xgbe_phy_valid_speed_sfp_mode(pdata, speed); default: return false; } @@ -2862,6 +2925,12 @@ static int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata) static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; + unsigned int ver; + + /* 10 Mbps speed is not supported in ver < 30H */ + ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER); + if (ver < 0x30 && (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10)) + return true; switch (phy_data->port_mode) { case XGBE_PORT_MODE_BACKPLANE: @@ -2875,7 +2944,8 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata) return false; break; case XGBE_PORT_MODE_1000BASE_T: - if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || + if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) || + (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)) return false; break; @@ -2884,13 +2954,15 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata) return false; break; case XGBE_PORT_MODE_NBASE_T: - if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || + if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) || + (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500)) return false; break; case XGBE_PORT_MODE_10GBASE_T: - if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || + if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) || + (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)) return false; @@ -2900,7 +2972,8 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata) return false; break; case XGBE_PORT_MODE_SFP: - if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || + if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) || + (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) || (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) || (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)) return false; @@ -3269,6 +3342,10 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) XGBE_SET_SUP(lks, Pause); XGBE_SET_SUP(lks, Asym_Pause); XGBE_SET_SUP(lks, TP); + if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) { + XGBE_SET_SUP(lks, 10baseT_Full); + phy_data->start_mode = XGBE_MODE_SGMII_10; + } if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { XGBE_SET_SUP(lks, 100baseT_Full); phy_data->start_mode = XGBE_MODE_SGMII_100; @@ -3299,6 +3376,10 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) XGBE_SET_SUP(lks, Pause); XGBE_SET_SUP(lks, Asym_Pause); XGBE_SET_SUP(lks, TP); + if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) { + XGBE_SET_SUP(lks, 10baseT_Full); + phy_data->start_mode = XGBE_MODE_SGMII_10; + } if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { XGBE_SET_SUP(lks, 100baseT_Full); phy_data->start_mode = XGBE_MODE_SGMII_100; @@ -3321,6 +3402,10 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) XGBE_SET_SUP(lks, Pause); XGBE_SET_SUP(lks, Asym_Pause); XGBE_SET_SUP(lks, TP); + if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) { + XGBE_SET_SUP(lks, 10baseT_Full); + phy_data->start_mode = XGBE_MODE_SGMII_10; + } if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { XGBE_SET_SUP(lks, 100baseT_Full); phy_data->start_mode = XGBE_MODE_SGMII_100; @@ -3361,6 +3446,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) XGBE_SET_SUP(lks, Asym_Pause); XGBE_SET_SUP(lks, TP); XGBE_SET_SUP(lks, FIBRE); + if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10) + phy_data->start_mode = XGBE_MODE_SGMII_10; if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) phy_data->start_mode = XGBE_MODE_SGMII_100; if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 71f24cb47935..da37476a2848 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -293,6 +293,7 @@ #define XGBE_SGMII_AN_LINK_STATUS BIT(1) #define XGBE_SGMII_AN_LINK_SPEED (BIT(2) | BIT(3)) +#define XGBE_SGMII_AN_LINK_SPEED_10 0x00 #define XGBE_SGMII_AN_LINK_SPEED_100 0x04 #define XGBE_SGMII_AN_LINK_SPEED_1000 0x08 #define XGBE_SGMII_AN_LINK_DUPLEX BIT(4) @@ -594,6 +595,7 @@ enum xgbe_mode { XGBE_MODE_KX_2500, XGBE_MODE_KR, XGBE_MODE_X, + XGBE_MODE_SGMII_10, XGBE_MODE_SGMII_100, XGBE_MODE_SGMII_1000, XGBE_MODE_SFI, |