From ebfc2be12ec599e3504ad2c1eaa9fc5892c94c9d Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 23 Feb 2026 09:34:15 +0000 Subject: [PATCH 01/10] net: stmmac: qcom-ethqos: rename "por" members to "rgmii_por" Rename the "por" and "num_por" members to indicate that they are for RGMII mode only as ethqos_configure_rgmii() is the only place that the values are programmed into the registers. Reviewed-by: Mohd Ayaan Anwar Tested-by: Mohd Ayaan Anwar Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vuSKV-0000000ASbg-28JK@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../stmicro/stmmac/dwmac-qcom-ethqos.c | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index af8204c0e188..690bd5c7e1a6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -87,8 +87,8 @@ struct ethqos_emac_por { }; struct ethqos_emac_driver_data { - const struct ethqos_emac_por *por; - unsigned int num_por; + const struct ethqos_emac_por *rgmii_por; + unsigned int num_rgmii_por; bool rgmii_config_loopback_en; bool has_emac_ge_3; const char *link_clk_name; @@ -108,8 +108,8 @@ struct qcom_ethqos { int serdes_speed; phy_interface_t phy_mode; - const struct ethqos_emac_por *por; - unsigned int num_por; + const struct ethqos_emac_por *rgmii_por; + unsigned int num_rgmii_por; bool rgmii_config_loopback_en; bool has_emac_ge_3; bool needs_sgmii_loopback; @@ -218,8 +218,8 @@ static const struct ethqos_emac_por emac_v2_3_0_por[] = { }; static const struct ethqos_emac_driver_data emac_v2_3_0_data = { - .por = emac_v2_3_0_por, - .num_por = ARRAY_SIZE(emac_v2_3_0_por), + .rgmii_por = emac_v2_3_0_por, + .num_rgmii_por = ARRAY_SIZE(emac_v2_3_0_por), .rgmii_config_loopback_en = true, .has_emac_ge_3 = false, }; @@ -234,8 +234,8 @@ static const struct ethqos_emac_por emac_v2_1_0_por[] = { }; static const struct ethqos_emac_driver_data emac_v2_1_0_data = { - .por = emac_v2_1_0_por, - .num_por = ARRAY_SIZE(emac_v2_1_0_por), + .rgmii_por = emac_v2_1_0_por, + .num_rgmii_por = ARRAY_SIZE(emac_v2_1_0_por), .rgmii_config_loopback_en = false, .has_emac_ge_3 = false, }; @@ -250,8 +250,8 @@ static const struct ethqos_emac_por emac_v3_0_0_por[] = { }; static const struct ethqos_emac_driver_data emac_v3_0_0_data = { - .por = emac_v3_0_0_por, - .num_por = ARRAY_SIZE(emac_v3_0_0_por), + .rgmii_por = emac_v3_0_0_por, + .num_rgmii_por = ARRAY_SIZE(emac_v3_0_0_por), .rgmii_config_loopback_en = false, .has_emac_ge_3 = true, .dwmac4_addrs = { @@ -282,8 +282,8 @@ static const struct ethqos_emac_por emac_v4_0_0_por[] = { }; static const struct ethqos_emac_driver_data emac_v4_0_0_data = { - .por = emac_v4_0_0_por, - .num_por = ARRAY_SIZE(emac_v4_0_0_por), + .rgmii_por = emac_v4_0_0_por, + .num_rgmii_por = ARRAY_SIZE(emac_v4_0_0_por), .rgmii_config_loopback_en = false, .has_emac_ge_3 = true, .link_clk_name = "phyaux", @@ -522,9 +522,9 @@ static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos, int speed) u32 val; /* Reset to POR values and enable clk */ - for (i = 0; i < ethqos->num_por; i++) - rgmii_writel(ethqos, ethqos->por[i].value, - ethqos->por[i].offset); + for (i = 0; i < ethqos->num_rgmii_por; i++) + rgmii_writel(ethqos, ethqos->rgmii_por[i].value, + ethqos->rgmii_por[i].offset); ethqos_set_func_clk_en(ethqos); /* Initialize the DLL first */ @@ -780,8 +780,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev) "Failed to map rgmii resource\n"); data = of_device_get_match_data(dev); - ethqos->por = data->por; - ethqos->num_por = data->num_por; + ethqos->rgmii_por = data->rgmii_por; + ethqos->num_rgmii_por = data->num_rgmii_por; ethqos->rgmii_config_loopback_en = data->rgmii_config_loopback_en; ethqos->has_emac_ge_3 = data->has_emac_ge_3; ethqos->needs_sgmii_loopback = data->needs_sgmii_loopback; From e6f43a41ba6206b691c8e9a301f0b4528b8f2278 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 23 Feb 2026 09:34:20 +0000 Subject: [PATCH 02/10] net: stmmac: qcom-ethqos: remove register field value obfuscations Convert the register field values to something more human readable. For example, using (BIT(29) | BIT(27)) to update a register field that consists of bits 29:27 is an obfuscated way of writing decimal 5 for this field. The comment above needs to explain that this value is 5. Worse still is BIT(12) | GENMASK(9, 8), which is used to hide the decimal value 19 for the bitfield 16:8. Fix these, and a few others by using FIELD_PREP(). While it means we have bare numeric constants, this is more preferable than having the obfuscation. Reviewed-by: Mohd Ayaan Anwar Tested-by: Mohd Ayaan Anwar Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vuSKa-0000000ASbo-2zQg@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../stmicro/stmmac/dwmac-qcom-ethqos.c | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 690bd5c7e1a6..50b95fd19f9d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -361,10 +361,12 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) SDCC_HC_REG_DLL_CONFIG2); rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, - 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); + FIELD_PREP(SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, 26), + SDCC_HC_REG_DLL_CONFIG2); rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, - BIT(2), SDCC_HC_REG_DLL_CONFIG2); + FIELD_PREP(SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, + 1), SDCC_HC_REG_DLL_CONFIG2); rgmii_setmask(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, SDCC_HC_REG_DLL_CONFIG2); @@ -425,11 +427,13 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) if (ethqos->has_emac_ge_3) { /* 0.9 ns */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, - 115, SDCC_HC_REG_DDR_CONFIG); + FIELD_PREP(SDCC_DDR_CONFIG_PRG_RCLK_DLY, + 115), SDCC_HC_REG_DDR_CONFIG); } else { /* 1.8 ns */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, - 57, SDCC_HC_REG_DDR_CONFIG); + FIELD_PREP(SDCC_DDR_CONFIG_PRG_RCLK_DLY, + 57), SDCC_HC_REG_DDR_CONFIG); } rgmii_setmask(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN, SDCC_HC_REG_DDR_CONFIG); @@ -451,7 +455,8 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, phase_shift, RGMII_IO_MACRO_CONFIG2); rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_2, - BIT(6), RGMII_IO_MACRO_CONFIG); + FIELD_PREP(RGMII_CONFIG_MAX_SPD_PRG_2, 1), + RGMII_IO_MACRO_CONFIG); rgmii_clrmask(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, RGMII_IO_MACRO_CONFIG2); @@ -464,7 +469,8 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) /* Write 0x5 to PRG_RCLK_DLY_CODE */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, - (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); + FIELD_PREP(SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, + 5), SDCC_HC_REG_DDR_CONFIG); rgmii_setmask(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, SDCC_HC_REG_DDR_CONFIG); rgmii_setmask(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, @@ -487,7 +493,7 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, phase_shift, RGMII_IO_MACRO_CONFIG2); rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_9, - BIT(12) | GENMASK(9, 8), + FIELD_PREP(RGMII_CONFIG_MAX_SPD_PRG_9, 19), RGMII_IO_MACRO_CONFIG); rgmii_clrmask(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, RGMII_IO_MACRO_CONFIG2); @@ -499,7 +505,8 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) RGMII_IO_MACRO_CONFIG2); /* Write 0x5 to PRG_RCLK_DLY_CODE */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, - (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); + FIELD_PREP(SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, + 5), SDCC_HC_REG_DDR_CONFIG); rgmii_setmask(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, SDCC_HC_REG_DDR_CONFIG); rgmii_setmask(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, From 649a00c3926fd3a52fc59bc52769ddb94a746bf8 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 23 Feb 2026 09:34:26 +0000 Subject: [PATCH 03/10] net: stmmac: qcom-ethqos: change ethqos_configure*() to return void The ethqos_configure*() family of functions always return zero, and the return value is never checked. Change the int return type to void. Reviewed-by: Mohd Ayaan Anwar Tested-by: Mohd Ayaan Anwar Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vuSKg-0000000ASbv-0iWL@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 50b95fd19f9d..168f0fed68c0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -100,7 +100,7 @@ struct ethqos_emac_driver_data { struct qcom_ethqos { struct platform_device *pdev; void __iomem *rgmii_base; - int (*configure_func)(struct qcom_ethqos *ethqos, int speed); + void (*configure_func)(struct qcom_ethqos *ethqos, int speed); unsigned int link_clk_rate; struct clk *link_clk; @@ -522,7 +522,7 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) return 0; } -static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos, int speed) +static void ethqos_configure_rgmii(struct qcom_ethqos *ethqos, int speed) { struct device *dev = ðqos->pdev->dev; unsigned int i; @@ -587,8 +587,6 @@ static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos, int speed) ethqos_dll_configure(ethqos); ethqos_rgmii_macro_init(ethqos, speed); - - return 0; } static void ethqos_set_serdes_speed(struct qcom_ethqos *ethqos, int speed) @@ -607,7 +605,7 @@ static void ethqos_pcs_set_inband(struct stmmac_priv *priv, bool enable) /* On interface toggle MAC registers gets reset. * Configure MAC block for SGMII on ethernet phy link up */ -static int ethqos_configure_sgmii(struct qcom_ethqos *ethqos, int speed) +static void ethqos_configure_sgmii(struct qcom_ethqos *ethqos, int speed) { struct net_device *dev = platform_get_drvdata(ethqos->pdev); struct stmmac_priv *priv = netdev_priv(dev); @@ -638,11 +636,9 @@ static int ethqos_configure_sgmii(struct qcom_ethqos *ethqos, int speed) ethqos_pcs_set_inband(priv, true); break; } - - return 0; } -static int ethqos_configure(struct qcom_ethqos *ethqos, int speed) +static void ethqos_configure(struct qcom_ethqos *ethqos, int speed) { return ethqos->configure_func(ethqos, speed); } From 3baa791f19be6a4701047fa23058e84fe4ccc1c4 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 23 Feb 2026 09:34:31 +0000 Subject: [PATCH 04/10] net: stmmac: qcom-ethqos: move qcom_ethqos_set_sgmii_loopback() up ethqos_set_func_clk_en() configures both SGMII loopback and the RGMII functional clock setting. qcom_ethqos_set_sgmii_loopback() is only called from within ethqos_set_func_clk_en(), and checks for PHY_INTERFACE_MODE_2500BASEX. Move qcom_ethqos_set_sgmii_loopback() to the callers of ethqos_set_func_clk_en() except for ethqos_configure_rgmii() where we know that ethqos->phy_mode will not be PHY_INTERFACE_MODE_2500BASEX. Reviewed-by: Mohd Ayaan Anwar Tested-by: Mohd Ayaan Anwar Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vuSKl-0000000ASc1-18ka@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 168f0fed68c0..964eca46a653 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -204,7 +204,6 @@ qcom_ethqos_set_sgmii_loopback(struct qcom_ethqos *ethqos, bool enable) static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos) { - qcom_ethqos_set_sgmii_loopback(ethqos, true); rgmii_setmask(ethqos, RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG); } @@ -532,6 +531,7 @@ static void ethqos_configure_rgmii(struct qcom_ethqos *ethqos, int speed) for (i = 0; i < ethqos->num_rgmii_por; i++) rgmii_writel(ethqos, ethqos->rgmii_por[i].value, ethqos->rgmii_por[i].offset); + ethqos_set_func_clk_en(ethqos); /* Initialize the DLL first */ @@ -701,6 +701,7 @@ static int ethqos_clks_config(void *priv, bool enabled) * cycled. The actual configuration will be adjusted once * ethqos_fix_mac_speed() is invoked. */ + qcom_ethqos_set_sgmii_loopback(ethqos, true); ethqos_set_func_clk_en(ethqos); } else { clk_disable_unprepare(ethqos->link_clk); @@ -809,6 +810,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos->serdes_speed = SPEED_1000; ethqos_update_link_clk(ethqos, SPEED_1000); + + qcom_ethqos_set_sgmii_loopback(ethqos, true); ethqos_set_func_clk_en(ethqos); plat_dat->bsp_priv = ethqos; From 834c72ca306cf4c8dc84b39447fee316c9f868ab Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 23 Feb 2026 09:34:36 +0000 Subject: [PATCH 05/10] net: stmmac: qcom-ethqos: move loopback disable to .mac_finish() Loopback is enabled to allow the dwmac soft reset to succeed. This is enabled when clocks are enabled in ethqos_clks_config(), which happens at driver probe and runtime PM resume - e.g. when the network device is administratively brought up. Currently, the loopback is disabled when the link comes up (via .mac_link_up() calling this driver's .fix_mac_speed().) Move the qcom_ethqos_set_sgmii_loopback() call which disables loopback from ethqos_fix_mac_speed() into ethqos' SerDes specific .mac_finish() method so that loopback is disabled a little earlier after reset has completed, and dwmac setup has completed. Reviewed-by: Mohd Ayaan Anwar Tested-by: Mohd Ayaan Anwar Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vuSKq-0000000AScA-1Wh3@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 964eca46a653..bd5d3bf90400 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -647,7 +647,6 @@ static void ethqos_fix_mac_speed(void *priv, int speed, unsigned int mode) { struct qcom_ethqos *ethqos = priv; - qcom_ethqos_set_sgmii_loopback(ethqos, false); ethqos_update_link_clk(ethqos, speed); ethqos_configure(ethqos, speed); } @@ -684,6 +683,17 @@ static void qcom_ethqos_serdes_powerdown(struct net_device *ndev, void *priv) phy_exit(ethqos->serdes_phy); } +static int ethqos_mac_finish_serdes(struct net_device *ndev, void *priv, + unsigned int mode, + phy_interface_t interface) +{ + struct qcom_ethqos *ethqos = priv; + + qcom_ethqos_set_sgmii_loopback(ethqos, false); + + return 0; +} + static int ethqos_clks_config(void *priv, bool enabled) { struct qcom_ethqos *ethqos = priv; @@ -770,6 +780,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) case PHY_INTERFACE_MODE_2500BASEX: case PHY_INTERFACE_MODE_SGMII: ethqos->configure_func = ethqos_configure_sgmii; + plat_dat->mac_finish = ethqos_mac_finish_serdes; break; default: dev_err(dev, "Unsupported phy mode %s\n", From cd0aa651535092afd5d776bfe94e4fdf750f89c3 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 23 Feb 2026 09:34:41 +0000 Subject: [PATCH 06/10] net: stmmac: pass interface mode into fix_mac_speed() method Pass the current interface mode reported by phylink into the fix_mac_speed() method. This will be used by qcom-ethqos for its "SGMII" configuration. Reviewed-by: Maxime Chevallier Tested-by: Mohd Ayaan Anwar Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vuSKv-0000000AScG-1zv6@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c | 3 ++- drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c | 11 +++++++---- drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c | 3 ++- .../net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 3 ++- drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 3 ++- drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c | 11 +++++++---- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 ++- include/linux/stmmac.h | 3 ++- 8 files changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c index d043bad4a862..0495437d3a6e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c @@ -112,7 +112,8 @@ static int dwc_qos_probe(struct platform_device *pdev, #define AUTO_CAL_STATUS 0x880c #define AUTO_CAL_STATUS_ACTIVE BIT(31) -static void tegra_eqos_fix_speed(void *bsp_priv, int speed, unsigned int mode) +static void tegra_eqos_fix_speed(void *bsp_priv, phy_interface_t interface, + int speed, unsigned int mode) { struct tegra_eqos *eqos = bsp_priv; bool needs_calibration = false; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c index c4e85197629d..9f5a15b81f8a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c @@ -48,7 +48,8 @@ struct imx_dwmac_ops { int (*fix_soc_reset)(struct stmmac_priv *priv); int (*set_intf_mode)(struct imx_priv_data *dwmac, u8 phy_intf_sel); - void (*fix_mac_speed)(void *priv, int speed, unsigned int mode); + void (*fix_mac_speed)(void *priv, phy_interface_t interface, + int speed, unsigned int mode); }; struct imx_priv_data { @@ -160,7 +161,8 @@ static int imx_dwmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, return stmmac_set_clk_tx_rate(bsp_priv, clk_tx_i, interface, speed); } -static void imx_dwmac_fix_speed(void *priv, int speed, unsigned int mode) +static void imx_dwmac_fix_speed(void *priv, phy_interface_t interface, + int speed, unsigned int mode) { struct plat_stmmacenet_data *plat_dat; struct imx_priv_data *dwmac = priv; @@ -185,13 +187,14 @@ static void imx_dwmac_fix_speed(void *priv, int speed, unsigned int mode) dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate); } -static void imx93_dwmac_fix_speed(void *priv, int speed, unsigned int mode) +static void imx93_dwmac_fix_speed(void *priv, phy_interface_t interface, + int speed, unsigned int mode) { struct imx_priv_data *dwmac = priv; unsigned int iface; int ctrl, old_ctrl; - imx_dwmac_fix_speed(priv, speed, mode); + imx_dwmac_fix_speed(priv, interface, speed, mode); if (!dwmac || mode != MLO_AN_FIXED) return; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c index 815213223583..9c51c96223ad 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c @@ -143,7 +143,8 @@ static struct stmmac_pci_info loongson_gmac_pci_info = { .setup = loongson_gmac_data, }; -static void loongson_gnet_fix_speed(void *priv, int speed, unsigned int mode) +static void loongson_gnet_fix_speed(void *priv, phy_interface_t interface, + int speed, unsigned int mode) { struct loongson_data *ld = (struct loongson_data *)priv; struct net_device *ndev = dev_get_drvdata(ld->dev); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index bd5d3bf90400..9b29516a5a7c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -643,7 +643,8 @@ static void ethqos_configure(struct qcom_ethqos *ethqos, int speed) return ethqos->configure_func(ethqos, speed); } -static void ethqos_fix_mac_speed(void *priv, int speed, unsigned int mode) +static void ethqos_fix_mac_speed(void *priv, phy_interface_t interface, + int speed, unsigned int mode) { struct qcom_ethqos *ethqos = priv; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 4c8991f3b38d..c6b99814d391 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -72,7 +72,8 @@ struct socfpga_dwmac { const struct socfpga_dwmac_ops *ops; }; -static void socfpga_dwmac_fix_mac_speed(void *bsp_priv, int speed, +static void socfpga_dwmac_fix_mac_speed(void *bsp_priv, + phy_interface_t interface, int speed, unsigned int mode) { struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)bsp_priv; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index f50547b67fbc..6ebbf95d158f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -91,11 +91,13 @@ struct sti_dwmac { struct regmap *regmap; bool gmac_en; int speed; - void (*fix_retime_src)(void *priv, int speed, unsigned int mode); + void (*fix_retime_src)(void *priv, phy_interface_t interface, + int speed, unsigned int mode); }; struct sti_dwmac_of_data { - void (*fix_retime_src)(void *priv, int speed, unsigned int mode); + void (*fix_retime_src)(void *priv, phy_interface_t interface, + int speed, unsigned int mode); }; enum { @@ -114,7 +116,8 @@ static u32 stih4xx_tx_retime_val[] = { | STIH4XX_ETH_SEL_INTERNAL_NOTEXT_PHYCLK, }; -static void stih4xx_fix_retime_src(void *priv, int spd, unsigned int mode) +static void stih4xx_fix_retime_src(void *priv, phy_interface_t interface, + int spd, unsigned int mode) { struct sti_dwmac *dwmac = priv; u32 src = dwmac->tx_retime_src; @@ -170,7 +173,7 @@ static int sti_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel) val = (dwmac->interface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII; regmap_update_bits(regmap, reg, ENMII_MASK, val); - dwmac->fix_retime_src(dwmac, dwmac->speed, 0); + dwmac->fix_retime_src(dwmac, dwmac->interface, dwmac->speed, 0); return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 82375d34ad57..d7c730179a7f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1071,7 +1071,8 @@ static void stmmac_mac_link_up(struct phylink_config *config, } if (priv->plat->fix_mac_speed) - priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed, mode); + priv->plat->fix_mac_speed(priv->plat->bsp_priv, interface, + speed, mode); if (!duplex) ctrl &= ~priv->hw->link.duplex; diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 32352a216567..b96ae9dadfab 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -256,7 +256,8 @@ struct plat_stmmacenet_data { int (*set_phy_intf_sel)(void *priv, u8 phy_intf_sel); int (*set_clk_tx_rate)(void *priv, struct clk *clk_tx_i, phy_interface_t interface, int speed); - void (*fix_mac_speed)(void *priv, int speed, unsigned int mode); + void (*fix_mac_speed)(void *priv, phy_interface_t interface, + int speed, unsigned int mode); int (*fix_soc_reset)(struct stmmac_priv *priv); int (*serdes_powerup)(struct net_device *ndev, void *priv); void (*serdes_powerdown)(struct net_device *ndev, void *priv); From b560938163db801d5ba27fa55a1aa68ccaf1ef2e Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 23 Feb 2026 09:34:46 +0000 Subject: [PATCH 07/10] net: stmmac: qcom-ethqos: pass phy interface mode to configs Pass the current phylink phy interface mode to the RGMII and "SGMII" configuration functions. Reviewed-by: Mohd Ayaan Anwar Tested-by: Mohd Ayaan Anwar Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vuSL0-0000000AScM-2TN0@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 9b29516a5a7c..e2dd334ffd31 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -100,7 +100,8 @@ struct ethqos_emac_driver_data { struct qcom_ethqos { struct platform_device *pdev; void __iomem *rgmii_base; - void (*configure_func)(struct qcom_ethqos *ethqos, int speed); + void (*configure_func)(struct qcom_ethqos *ethqos, + phy_interface_t interface, int speed); unsigned int link_clk_rate; struct clk *link_clk; @@ -521,7 +522,8 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) return 0; } -static void ethqos_configure_rgmii(struct qcom_ethqos *ethqos, int speed) +static void ethqos_configure_rgmii(struct qcom_ethqos *ethqos, + phy_interface_t interface, int speed) { struct device *dev = ðqos->pdev->dev; unsigned int i; @@ -605,7 +607,8 @@ static void ethqos_pcs_set_inband(struct stmmac_priv *priv, bool enable) /* On interface toggle MAC registers gets reset. * Configure MAC block for SGMII on ethernet phy link up */ -static void ethqos_configure_sgmii(struct qcom_ethqos *ethqos, int speed) +static void ethqos_configure_sgmii(struct qcom_ethqos *ethqos, + phy_interface_t interface, int speed) { struct net_device *dev = platform_get_drvdata(ethqos->pdev); struct stmmac_priv *priv = netdev_priv(dev); @@ -638,9 +641,10 @@ static void ethqos_configure_sgmii(struct qcom_ethqos *ethqos, int speed) } } -static void ethqos_configure(struct qcom_ethqos *ethqos, int speed) +static void ethqos_configure(struct qcom_ethqos *ethqos, + phy_interface_t interface, int speed) { - return ethqos->configure_func(ethqos, speed); + return ethqos->configure_func(ethqos, interface, speed); } static void ethqos_fix_mac_speed(void *priv, phy_interface_t interface, @@ -649,7 +653,7 @@ static void ethqos_fix_mac_speed(void *priv, phy_interface_t interface, struct qcom_ethqos *ethqos = priv; ethqos_update_link_clk(ethqos, speed); - ethqos_configure(ethqos, speed); + ethqos_configure(ethqos, interface, speed); } static int qcom_ethqos_serdes_powerup(struct net_device *ndev, void *priv) From b8ab32315e22c0ef2c466d4f5ef4de0b5852e735 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 23 Feb 2026 09:34:51 +0000 Subject: [PATCH 08/10] net: stmmac: qcom-ethqos: use phy interface mode for inband qcom-ethqos currently forces inband to be enabled for the Cisco SGMII speeds (1G, 100M and 10M) but not for 2500BASE-X (2.5G). Rather than using the speed to determine the forced inband state, use phylink's PHY interface mode which will switch between SGMII for the 10M, 100M and 1G speeds, and 2500BASE-X for 2.5G. Reviewed-by: Mohd Ayaan Anwar Tested-by: Mohd Ayaan Anwar Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vuSL5-0000000AScX-2wuM@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../stmicro/stmmac/dwmac-qcom-ethqos.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index e2dd334ffd31..cd6d1660bdb2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -615,30 +615,26 @@ static void ethqos_configure_sgmii(struct qcom_ethqos *ethqos, switch (speed) { case SPEED_2500: - rgmii_setmask(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, - RGMII_IO_MACRO_CONFIG2); - ethqos_set_serdes_speed(ethqos, SPEED_2500); - ethqos_pcs_set_inband(priv, false); - break; case SPEED_1000: rgmii_setmask(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, RGMII_IO_MACRO_CONFIG2); - ethqos_set_serdes_speed(ethqos, SPEED_1000); - ethqos_pcs_set_inband(priv, true); break; case SPEED_100: - ethqos_set_serdes_speed(ethqos, SPEED_1000); - ethqos_pcs_set_inband(priv, true); break; case SPEED_10: rgmii_updatel(ethqos, RGMII_CONFIG_SGMII_CLK_DVDR, FIELD_PREP(RGMII_CONFIG_SGMII_CLK_DVDR, SGMII_10M_RX_CLK_DVDR), RGMII_IO_MACRO_CONFIG); - ethqos_set_serdes_speed(ethqos, SPEED_1000); - ethqos_pcs_set_inband(priv, true); break; } + + if (interface == PHY_INTERFACE_MODE_SGMII) + ethqos_set_serdes_speed(ethqos, SPEED_1000); + else + ethqos_set_serdes_speed(ethqos, SPEED_2500); + + ethqos_pcs_set_inband(priv, interface == PHY_INTERFACE_MODE_SGMII); } static void ethqos_configure(struct qcom_ethqos *ethqos, From fb42f19e671f831bab406d795664f98e1242d478 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 23 Feb 2026 09:34:56 +0000 Subject: [PATCH 09/10] net: stmmac: qcom-ethqos: move SerDes speed configuration Move the SerDes speed configuration to phylink's .mac_finish() stage so that the SerDes is appropriately configured for the interface mode prior to the link coming up. Reviewed-by: Mohd Ayaan Anwar Tested-by: Mohd Ayaan Anwar Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vuSLA-0000000AScc-3RFf@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index cd6d1660bdb2..153f6abc77cd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -629,11 +629,6 @@ static void ethqos_configure_sgmii(struct qcom_ethqos *ethqos, break; } - if (interface == PHY_INTERFACE_MODE_SGMII) - ethqos_set_serdes_speed(ethqos, SPEED_1000); - else - ethqos_set_serdes_speed(ethqos, SPEED_2500); - ethqos_pcs_set_inband(priv, interface == PHY_INTERFACE_MODE_SGMII); } @@ -692,6 +687,11 @@ static int ethqos_mac_finish_serdes(struct net_device *ndev, void *priv, qcom_ethqos_set_sgmii_loopback(ethqos, false); + if (interface == PHY_INTERFACE_MODE_SGMII) + ethqos_set_serdes_speed(ethqos, SPEED_1000); + else if (interface == PHY_INTERFACE_MODE_2500BASEX) + ethqos_set_serdes_speed(ethqos, SPEED_2500); + return 0; } From 9192320a65b7b1496fa9d39f7207d6d1fca48b06 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 23 Feb 2026 09:35:01 +0000 Subject: [PATCH 10/10] net: stmmac: qcom-ethqos: convert to set_clk_tx_rate() method Set the RGMII link clock using the set_clk_tx_rate() method rather than coding it into the .fix_mac_speed() method. This simplifies ethqos's ethqos_fix_mac_speed(). Tested-by: Mohd Ayaan Anwar Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vuSLF-0000000ASci-42kh@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../stmicro/stmmac/dwmac-qcom-ethqos.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 153f6abc77cd..ad5b5d950fff 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -103,7 +103,6 @@ struct qcom_ethqos { void (*configure_func)(struct qcom_ethqos *ethqos, phy_interface_t interface, int speed); - unsigned int link_clk_rate; struct clk *link_clk; struct phy *serdes_phy; int serdes_speed; @@ -175,19 +174,20 @@ static void rgmii_dump(void *priv) rgmii_readl(ethqos, EMAC_SYSTEM_LOW_POWER_DEBUG)); } -static void -ethqos_update_link_clk(struct qcom_ethqos *ethqos, int speed) +static int ethqos_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed) { + struct qcom_ethqos *ethqos = bsp_priv; long rate; - if (!phy_interface_mode_is_rgmii(ethqos->phy_mode)) - return; + if (!phy_interface_mode_is_rgmii(interface)) + return 0; rate = rgmii_clock(speed); - if (rate > 0) - ethqos->link_clk_rate = rate * 2; + if (rate < 0) + return rate; - clk_set_rate(ethqos->link_clk, ethqos->link_clk_rate); + return clk_set_rate(ethqos->link_clk, rate * 2); } static void @@ -643,7 +643,6 @@ static void ethqos_fix_mac_speed(void *priv, phy_interface_t interface, { struct qcom_ethqos *ethqos = priv; - ethqos_update_link_clk(ethqos, speed); ethqos_configure(ethqos, interface, speed); } @@ -821,12 +820,14 @@ static int qcom_ethqos_probe(struct platform_device *pdev) "Failed to get serdes phy\n"); ethqos->serdes_speed = SPEED_1000; - ethqos_update_link_clk(ethqos, SPEED_1000); + ethqos_set_clk_tx_rate(ethqos, NULL, plat_dat->phy_interface, + SPEED_1000); qcom_ethqos_set_sgmii_loopback(ethqos, true); ethqos_set_func_clk_en(ethqos); plat_dat->bsp_priv = ethqos; + plat_dat->set_clk_tx_rate = ethqos_set_clk_tx_rate; plat_dat->fix_mac_speed = ethqos_fix_mac_speed; plat_dat->dump_debug_regs = rgmii_dump; plat_dat->ptp_clk_freq_config = ethqos_ptp_clk_freq_config;