Skip to content

Commit 9584809

Browse files
committed
Merge branch 'stmmac-25gbps'
Michael Sit Wei Hong says: ==================== Enable 2.5Gbps speed for stmmac Intel mGbE supports 2.5Gbps link speed by overclocking the clock rate by 2.5 times to support 2.5Gbps link speed. In this mode, the serdes/PHY operates at a serial baud rate of 3.125 Gbps and the PCS data path and GMII interface of the MAC operate at 312.5 MHz instead of 125 MHz. This is configured in the BIOS during boot up. The kernel driver is not able access to modify the clock rate for 1Gbps/2.5G mode on the fly. The way to determine the current 1G/2.5G mode is by reading a dedicated adhoc register through mdio bus. Changes: v5 -> v6 patch 1/3 - Check if mdio_bus_data is populated to prevent NULL pointer dereferencing when accesing mdio_bus_data member v4 -> v5 patch 1/3 - Rebase to latest code changes after Vladimir's code is merged and fix build warnings v3 -> v4 patch 1/3 - Rebase to latest code and Initialize 'found' to 0 to avoid build warning patch 2/3 - Fix indentation issue from v3 v2 -> v3 patch 1/3 -New patch added to restructure the code. enabling reading the dedicated adhoc register to determine link speed mode. patch 2/3 -Restructure for 2.5G speed to use 2500BaseX configuration as the PHY interface. patch 3/3 -Restructure to read serdes registers to set max_speed and configure to use 2500BaseX in 2.5G speeds. v1 -> v2 patch 1/2 -Remove MAC supported link speed masking patch 2/2 -Add supported link speed masking in the PCS iperf3 and ping for 2.5Gbps and regression test on 10M/100M/1000Mbps is done to prevent regresson issues. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 303597e + 46682cb commit 9584809

File tree

9 files changed

+171
-30
lines changed

9 files changed

+171
-30
lines changed

drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,22 @@ static int intel_serdes_powerup(struct net_device *ndev, void *priv_data)
102102

103103
serdes_phy_addr = intel_priv->mdio_adhoc_addr;
104104

105+
/* Set the serdes rate and the PCLK rate */
106+
data = mdiobus_read(priv->mii, serdes_phy_addr,
107+
SERDES_GCR0);
108+
109+
data &= ~SERDES_RATE_MASK;
110+
data &= ~SERDES_PCLK_MASK;
111+
112+
if (priv->plat->max_speed == 2500)
113+
data |= SERDES_RATE_PCIE_GEN2 << SERDES_RATE_PCIE_SHIFT |
114+
SERDES_PCLK_37p5MHZ << SERDES_PCLK_SHIFT;
115+
else
116+
data |= SERDES_RATE_PCIE_GEN1 << SERDES_RATE_PCIE_SHIFT |
117+
SERDES_PCLK_70MHZ << SERDES_PCLK_SHIFT;
118+
119+
mdiobus_write(priv->mii, serdes_phy_addr, SERDES_GCR0, data);
120+
105121
/* assert clk_req */
106122
data = mdiobus_read(priv->mii, serdes_phy_addr, SERDES_GCR0);
107123
data |= SERDES_PLL_CLK;
@@ -230,6 +246,32 @@ static void intel_serdes_powerdown(struct net_device *ndev, void *intel_data)
230246
}
231247
}
232248

249+
static void intel_speed_mode_2500(struct net_device *ndev, void *intel_data)
250+
{
251+
struct intel_priv_data *intel_priv = intel_data;
252+
struct stmmac_priv *priv = netdev_priv(ndev);
253+
int serdes_phy_addr = 0;
254+
u32 data = 0;
255+
256+
serdes_phy_addr = intel_priv->mdio_adhoc_addr;
257+
258+
/* Determine the link speed mode: 2.5Gbps/1Gbps */
259+
data = mdiobus_read(priv->mii, serdes_phy_addr,
260+
SERDES_GCR);
261+
262+
if (((data & SERDES_LINK_MODE_MASK) >> SERDES_LINK_MODE_SHIFT) ==
263+
SERDES_LINK_MODE_2G5) {
264+
dev_info(priv->device, "Link Speed Mode: 2.5Gbps\n");
265+
priv->plat->max_speed = 2500;
266+
priv->plat->phy_interface = PHY_INTERFACE_MODE_2500BASEX;
267+
priv->plat->mdio_bus_data->xpcs_an_inband = false;
268+
} else {
269+
priv->plat->max_speed = 1000;
270+
priv->plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
271+
priv->plat->mdio_bus_data->xpcs_an_inband = true;
272+
}
273+
}
274+
233275
/* Program PTP Clock Frequency for different variant of
234276
* Intel mGBE that has slightly different GPO mapping
235277
*/
@@ -586,7 +628,7 @@ static int ehl_sgmii_data(struct pci_dev *pdev,
586628
{
587629
plat->bus_id = 1;
588630
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
589-
631+
plat->speed_mode_2500 = intel_speed_mode_2500;
590632
plat->serdes_powerup = intel_serdes_powerup;
591633
plat->serdes_powerdown = intel_serdes_powerdown;
592634

@@ -639,6 +681,7 @@ static int ehl_pse0_sgmii1g_data(struct pci_dev *pdev,
639681
struct plat_stmmacenet_data *plat)
640682
{
641683
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
684+
plat->speed_mode_2500 = intel_speed_mode_2500;
642685
plat->serdes_powerup = intel_serdes_powerup;
643686
plat->serdes_powerdown = intel_serdes_powerdown;
644687
return ehl_pse0_common_data(pdev, plat);
@@ -677,6 +720,7 @@ static int ehl_pse1_sgmii1g_data(struct pci_dev *pdev,
677720
struct plat_stmmacenet_data *plat)
678721
{
679722
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
723+
plat->speed_mode_2500 = intel_speed_mode_2500;
680724
plat->serdes_powerup = intel_serdes_powerup;
681725
plat->serdes_powerdown = intel_serdes_powerdown;
682726
return ehl_pse1_common_data(pdev, plat);
@@ -711,6 +755,7 @@ static int tgl_sgmii_phy0_data(struct pci_dev *pdev,
711755
{
712756
plat->bus_id = 1;
713757
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
758+
plat->speed_mode_2500 = intel_speed_mode_2500;
714759
plat->serdes_powerup = intel_serdes_powerup;
715760
plat->serdes_powerdown = intel_serdes_powerdown;
716761
return tgl_common_data(pdev, plat);
@@ -725,6 +770,7 @@ static int tgl_sgmii_phy1_data(struct pci_dev *pdev,
725770
{
726771
plat->bus_id = 2;
727772
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
773+
plat->speed_mode_2500 = intel_speed_mode_2500;
728774
plat->serdes_powerup = intel_serdes_powerup;
729775
plat->serdes_powerdown = intel_serdes_powerdown;
730776
return tgl_common_data(pdev, plat);

drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define POLL_DELAY_US 8
1010

1111
/* SERDES Register */
12+
#define SERDES_GCR 0x0 /* Global Conguration */
1213
#define SERDES_GSR0 0x5 /* Global Status Reg0 */
1314
#define SERDES_GCR0 0xb /* Global Configuration Reg0 */
1415

@@ -17,8 +18,20 @@
1718
#define SERDES_PHY_RX_CLK BIT(1) /* PSE SGMII PHY rx clk */
1819
#define SERDES_RST BIT(2) /* Serdes Reset */
1920
#define SERDES_PWR_ST_MASK GENMASK(6, 4) /* Serdes Power state*/
21+
#define SERDES_RATE_MASK GENMASK(9, 8)
22+
#define SERDES_PCLK_MASK GENMASK(14, 12) /* PCLK rate to PHY */
23+
#define SERDES_LINK_MODE_MASK GENMASK(2, 1)
24+
#define SERDES_LINK_MODE_SHIFT 1
2025
#define SERDES_PWR_ST_SHIFT 4
2126
#define SERDES_PWR_ST_P0 0x0
2227
#define SERDES_PWR_ST_P3 0x3
28+
#define SERDES_LINK_MODE_2G5 0x3
29+
#define SERSED_LINK_MODE_1G 0x2
30+
#define SERDES_PCLK_37p5MHZ 0x0
31+
#define SERDES_PCLK_70MHZ 0x1
32+
#define SERDES_RATE_PCIE_GEN1 0x0
33+
#define SERDES_RATE_PCIE_GEN2 0x1
34+
#define SERDES_RATE_PCIE_SHIFT 8
35+
#define SERDES_PCLK_SHIFT 12
2336

2437
#endif /* __DWMAC_INTEL_H__ */

drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,7 @@ int dwmac4_setup(struct stmmac_priv *priv)
13581358
mac->link.speed10 = GMAC_CONFIG_PS;
13591359
mac->link.speed100 = GMAC_CONFIG_FES | GMAC_CONFIG_PS;
13601360
mac->link.speed1000 = 0;
1361+
mac->link.speed2500 = GMAC_CONFIG_FES;
13611362
mac->link.speed_mask = GMAC_CONFIG_FES | GMAC_CONFIG_PS;
13621363
mac->mii.addr = GMAC_MDIO_ADDR;
13631364
mac->mii.data = GMAC_MDIO_DATA;

drivers/net/ethernet/stmicro/stmmac/stmmac.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ enum stmmac_state {
311311
int stmmac_mdio_unregister(struct net_device *ndev);
312312
int stmmac_mdio_register(struct net_device *ndev);
313313
int stmmac_mdio_reset(struct mii_bus *mii);
314+
int stmmac_xpcs_setup(struct mii_bus *mii);
314315
void stmmac_set_ethtool_ops(struct net_device *netdev);
315316

316317
void stmmac_ptp_register(struct stmmac_priv *priv);

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,10 @@ static void stmmac_validate(struct phylink_config *config,
931931
if ((max_speed > 0) && (max_speed < 1000)) {
932932
phylink_set(mask, 1000baseT_Full);
933933
phylink_set(mask, 1000baseX_Full);
934+
} else if (priv->plat->has_gmac4) {
935+
if (!max_speed || max_speed >= 2500)
936+
phylink_set(mac_supported, 2500baseT_Full);
937+
phylink_set(mac_supported, 2500baseX_Full);
934938
} else if (priv->plat->has_xgmac) {
935939
if (!max_speed || (max_speed >= 2500)) {
936940
phylink_set(mac_supported, 2500baseT_Full);
@@ -6993,6 +6997,17 @@ int stmmac_dvr_probe(struct device *device,
69936997
}
69946998
}
69956999

7000+
if (priv->plat->speed_mode_2500)
7001+
priv->plat->speed_mode_2500(ndev, priv->plat->bsp_priv);
7002+
7003+
if (priv->plat->mdio_bus_data) {
7004+
if (priv->plat->mdio_bus_data->has_xpcs) {
7005+
ret = stmmac_xpcs_setup(priv->mii);
7006+
if (ret)
7007+
goto error_xpcs_setup;
7008+
}
7009+
}
7010+
69967011
ret = stmmac_phy_setup(priv);
69977012
if (ret) {
69987013
netdev_err(ndev, "failed to setup phy (%d)\n", ret);
@@ -7029,6 +7044,7 @@ int stmmac_dvr_probe(struct device *device,
70297044
unregister_netdev(ndev);
70307045
error_netdev_register:
70317046
phylink_destroy(priv->phylink);
7047+
error_xpcs_setup:
70327048
error_phy_setup:
70337049
if (priv->hw->pcs != STMMAC_PCS_TBI &&
70347050
priv->hw->pcs != STMMAC_PCS_RTBI)

drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,41 @@ int stmmac_mdio_reset(struct mii_bus *bus)
397397
return 0;
398398
}
399399

400+
int stmmac_xpcs_setup(struct mii_bus *bus)
401+
{
402+
int mode, addr;
403+
struct net_device *ndev = bus->priv;
404+
struct mdio_xpcs_args *xpcs;
405+
struct stmmac_priv *priv;
406+
struct mdio_device *mdiodev;
407+
408+
priv = netdev_priv(ndev);
409+
mode = priv->plat->phy_interface;
410+
411+
/* Try to probe the XPCS by scanning all addresses. */
412+
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
413+
mdiodev = mdio_device_create(bus, addr);
414+
if (IS_ERR(mdiodev))
415+
continue;
416+
417+
xpcs = xpcs_create(mdiodev, mode);
418+
if (IS_ERR_OR_NULL(xpcs)) {
419+
mdio_device_free(mdiodev);
420+
continue;
421+
}
422+
423+
priv->hw->xpcs = xpcs;
424+
break;
425+
}
426+
427+
if (!priv->hw->xpcs) {
428+
dev_warn(priv->device, "No xPCS found\n");
429+
return -ENODEV;
430+
}
431+
432+
return 0;
433+
}
434+
400435
/**
401436
* stmmac_mdio_register
402437
* @ndev: net device structure
@@ -501,40 +536,11 @@ int stmmac_mdio_register(struct net_device *ndev)
501536
goto no_phy_found;
502537
}
503538

504-
/* Try to probe the XPCS by scanning all addresses. */
505-
if (mdio_bus_data->has_xpcs) {
506-
int mode = priv->plat->phy_interface;
507-
struct mdio_device *mdiodev;
508-
struct mdio_xpcs_args *xpcs;
509-
510-
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
511-
mdiodev = mdio_device_create(new_bus, addr);
512-
if (IS_ERR(mdiodev))
513-
continue;
514-
515-
xpcs = xpcs_create(mdiodev, mode);
516-
if (IS_ERR_OR_NULL(xpcs)) {
517-
mdio_device_free(mdiodev);
518-
continue;
519-
}
520-
521-
priv->hw->xpcs = xpcs;
522-
break;
523-
}
524-
525-
if (!priv->hw->xpcs) {
526-
dev_warn(dev, "No XPCS found\n");
527-
err = -ENODEV;
528-
goto no_xpcs_found;
529-
}
530-
}
531-
532539
bus_register_done:
533540
priv->mii = new_bus;
534541

535542
return 0;
536543

537-
no_xpcs_found:
538544
no_phy_found:
539545
mdiobus_unregister(new_bus);
540546
bus_register_fail:

drivers/net/pcs/pcs-xpcs.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,12 @@
5757

5858
/* Clause 37 Defines */
5959
/* VR MII MMD registers offsets */
60+
#define DW_VR_MII_MMD_CTRL 0x0000
6061
#define DW_VR_MII_DIG_CTRL1 0x8000
6162
#define DW_VR_MII_AN_CTRL 0x8001
6263
#define DW_VR_MII_AN_INTR_STS 0x8002
64+
/* Enable 2.5G Mode */
65+
#define DW_VR_MII_DIG_CTRL1_2G5_EN BIT(2)
6366
/* EEE Mode Control Register */
6467
#define DW_VR_MII_EEE_MCTRL0 0x8006
6568
#define DW_VR_MII_EEE_MCTRL1 0x800b
@@ -86,6 +89,11 @@
8689
#define DW_VR_MII_C37_ANSGM_SP_1000 0x2
8790
#define DW_VR_MII_C37_ANSGM_SP_LNKSTS BIT(4)
8891

92+
/* SR MII MMD Control defines */
93+
#define AN_CL37_EN BIT(12) /* Enable Clause 37 auto-nego */
94+
#define SGMII_SPEED_SS13 BIT(13) /* SGMII speed along with SS6 */
95+
#define SGMII_SPEED_SS6 BIT(6) /* SGMII speed along with SS13 */
96+
8997
/* VR MII EEE Control 0 defines */
9098
#define DW_VR_MII_EEE_LTX_EN BIT(0) /* LPI Tx Enable */
9199
#define DW_VR_MII_EEE_LRX_EN BIT(1) /* LPI Rx Enable */
@@ -161,6 +169,14 @@ static const int xpcs_sgmii_features[] = {
161169
__ETHTOOL_LINK_MODE_MASK_NBITS,
162170
};
163171

172+
static const int xpcs_2500basex_features[] = {
173+
ETHTOOL_LINK_MODE_Asym_Pause_BIT,
174+
ETHTOOL_LINK_MODE_Autoneg_BIT,
175+
ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
176+
ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
177+
__ETHTOOL_LINK_MODE_MASK_NBITS,
178+
};
179+
164180
static const phy_interface_t xpcs_usxgmii_interfaces[] = {
165181
PHY_INTERFACE_MODE_USXGMII,
166182
};
@@ -177,11 +193,17 @@ static const phy_interface_t xpcs_sgmii_interfaces[] = {
177193
PHY_INTERFACE_MODE_SGMII,
178194
};
179195

196+
static const phy_interface_t xpcs_2500basex_interfaces[] = {
197+
PHY_INTERFACE_MODE_2500BASEX,
198+
PHY_INTERFACE_MODE_MAX,
199+
};
200+
180201
enum {
181202
DW_XPCS_USXGMII,
182203
DW_XPCS_10GKR,
183204
DW_XPCS_XLGMII,
184205
DW_XPCS_SGMII,
206+
DW_XPCS_2500BASEX,
185207
DW_XPCS_INTERFACE_MAX,
186208
};
187209

@@ -306,6 +328,7 @@ static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs,
306328
dev = MDIO_MMD_PCS;
307329
break;
308330
case DW_AN_C37_SGMII:
331+
case DW_2500BASEX:
309332
dev = MDIO_MMD_VEND2;
310333
break;
311334
default:
@@ -804,6 +827,28 @@ static int xpcs_config_aneg_c37_sgmii(struct mdio_xpcs_args *xpcs)
804827
return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
805828
}
806829

830+
static int xpcs_config_2500basex(struct mdio_xpcs_args *xpcs)
831+
{
832+
int ret;
833+
834+
ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
835+
if (ret < 0)
836+
return ret;
837+
ret |= DW_VR_MII_DIG_CTRL1_2G5_EN;
838+
ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
839+
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
840+
if (ret < 0)
841+
return ret;
842+
843+
ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
844+
if (ret < 0)
845+
return ret;
846+
ret &= ~AN_CL37_EN;
847+
ret |= SGMII_SPEED_SS6;
848+
ret &= ~SGMII_SPEED_SS13;
849+
return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, ret);
850+
}
851+
807852
static int xpcs_do_config(struct mdio_xpcs_args *xpcs,
808853
phy_interface_t interface, unsigned int mode)
809854
{
@@ -827,6 +872,11 @@ static int xpcs_do_config(struct mdio_xpcs_args *xpcs,
827872
if (ret)
828873
return ret;
829874
break;
875+
case DW_2500BASEX:
876+
ret = xpcs_config_2500basex(xpcs);
877+
if (ret)
878+
return ret;
879+
break;
830880
default:
831881
return -1;
832882
}
@@ -1023,6 +1073,12 @@ static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
10231073
.num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
10241074
.an_mode = DW_AN_C37_SGMII,
10251075
},
1076+
[DW_XPCS_2500BASEX] = {
1077+
.supported = xpcs_2500basex_features,
1078+
.interface = xpcs_2500basex_interfaces,
1079+
.num_interfaces = ARRAY_SIZE(xpcs_2500basex_features),
1080+
.an_mode = DW_2500BASEX,
1081+
},
10261082
};
10271083

10281084
static const struct xpcs_id xpcs_id_list[] = {

include/linux/pcs/pcs-xpcs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
/* AN mode */
1414
#define DW_AN_C73 1
1515
#define DW_AN_C37_SGMII 2
16+
#define DW_2500BASEX 3
1617

1718
struct xpcs_id;
1819

include/linux/stmmac.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ struct plat_stmmacenet_data {
223223
void (*fix_mac_speed)(void *priv, unsigned int speed);
224224
int (*serdes_powerup)(struct net_device *ndev, void *priv);
225225
void (*serdes_powerdown)(struct net_device *ndev, void *priv);
226+
void (*speed_mode_2500)(struct net_device *ndev, void *priv);
226227
void (*ptp_clk_freq_config)(void *priv);
227228
int (*init)(struct platform_device *pdev, void *priv);
228229
void (*exit)(struct platform_device *pdev, void *priv);

0 commit comments

Comments
 (0)