]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: proper RTL8214FC fibre/copper detection 18724/head
authorMarkus Stockhausen <markus.stockhausen@gmx.de>
Tue, 6 May 2025 06:44:43 +0000 (02:44 -0400)
committerRobert Marko <robimarko@gmail.com>
Fri, 9 May 2025 08:24:16 +0000 (10:24 +0200)
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 <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/18724
Signed-off-by: Robert Marko <robimarko@gmail.com>
target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c

index 94ccbe576920def7129335a3bee74ef17c6c40a7..ffea742194354d0e004e995a03ff0e055fc2af1e 100644 (file)
@@ -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,