From 4cfd1c450181893a8063588eafd4eadef6a7e235 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Tue, 6 May 2025 02:44:43 -0400 Subject: [PATCH] realtek: proper RTL8214FC fibre/copper detection The RTL8214FC currently uses generic PHY functions. That makes it look like a copper device. Switching to/from fibre works fortunately but the autonegotiation handling still works on MII_LPA (PHY register 5) as if a copper link is used. Fix that by - advertising a superset of TP/FIBRE features - using clause 37 functions when on fibre Additionally enhance the code of the driver to assist further development. - log the speed of the inserted module to detect wrongly inserted 10gbase-r modules - order phy driver functions alphabetically (keep match/name on top) - remove genphy_loopback as the kernel uses it if not provided Remark! The driver internally uses PORT_MII for the TP port. Align with that and report MII to ethtool instead of TP. Other drivers do the same and it can be changed in the future if needed. Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/18724 Signed-off-by: Robert Marko --- .../files-6.6/drivers/net/phy/rtl83xx-phy.c | 69 +++++++++++++++++-- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c b/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c index 94ccbe57692..ffea7421943 100644 --- a/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c +++ b/target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c @@ -1124,6 +1124,52 @@ static int rtl8214fc_get_port(struct phy_device *phydev) return PORT_MII; } +static int rtl8214fc_get_features(struct phy_device *phydev) +{ + int ret = 0; + + ret = genphy_read_abilities(phydev); + if (ret) + return ret; + /* + * The RTL8214FC only advertises TP capabilities in the standard registers. This is + * independent from what fibre/copper combination is currently activated. For now just + * announce the superset of all possible features. + */ + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); + + return 0; +} + +static int rtl8214fc_read_status(struct phy_device *phydev) +{ + bool changed; + int ret; + + if (rtl8214fc_media_is_fibre(phydev)) { + phydev->port = PORT_FIBRE; + ret = genphy_c37_read_status(phydev, &changed); + } else { + phydev->port = PORT_MII; /* for now aligend with rest of code */ + ret = genphy_read_status(phydev); + } + + return ret; +} + +static int rtl8214fc_config_aneg(struct phy_device *phydev) +{ + int ret; + + if (rtl8214fc_media_is_fibre(phydev)) + ret = genphy_c37_config_aneg(phydev); + else + ret = genphy_config_aneg(phydev); + + return ret; +} + /* Enable EEE on the RTL8218B PHYs * The method used is not the preferred way (which would be based on the MAC-EEE state, * but the only way that works since the kernel first enables EEE in the MAC @@ -3713,7 +3759,15 @@ int rtl931x_link_sts_get(u32 sds) static int rtl8214fc_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) { + __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; + DECLARE_PHY_INTERFACE_MASK(interfaces); struct phy_device *phydev = upstream; + phy_interface_t iface; + + sfp_parse_support(phydev->sfp_bus, id, support, interfaces); + iface = sfp_select_interface(phydev->sfp_bus, support); + + dev_info(&phydev->mdio.dev, "%s SFP module inserted\n", phy_modes(iface)); rtl8214fc_media_set(phydev, true); @@ -3914,17 +3968,18 @@ static struct phy_driver rtl83xx_phy_driver[] = { { .match_phy_device = rtl8214fc_match_phy_device, .name = "Realtek RTL8214FC", - .features = PHY_GBIT_FIBRE_FEATURES, + .config_aneg = rtl8214fc_config_aneg, + .get_eee = rtl8214fc_get_eee, + .get_features = rtl8214fc_get_features, + .get_port = rtl8214fc_get_port, .probe = rtl8214fc_phy_probe, .read_page = rtl821x_read_page, - .write_page = rtl821x_write_page, - .suspend = rtl8214fc_suspend, + .read_status = rtl8214fc_read_status, .resume = rtl8214fc_resume, - .set_loopback = genphy_loopback, - .set_port = rtl8214fc_set_port, - .get_port = rtl8214fc_get_port, .set_eee = rtl8214fc_set_eee, - .get_eee = rtl8214fc_get_eee, + .set_port = rtl8214fc_set_port, + .suspend = rtl8214fc_suspend, + .write_page = rtl821x_write_page, }, { .match_phy_device = rtl8218b_ext_match_phy_device, -- 2.47.2