]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
r8152: Add support for 5Gbit Link Speeds and EEE
authorBirger Koblitz <mail@birger-koblitz.de>
Sat, 4 Apr 2026 07:57:42 +0000 (09:57 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 9 Apr 2026 10:16:46 +0000 (12:16 +0200)
The RTL8157 supports 5GBit Link speeds. Add support for this speed
in the setup and setting/getting through ethtool. Also add 5GBit EEE.
Add functionality for setup and ethtool get/set methods.

Signed-off-by: Birger Koblitz <mail@birger-koblitz.de>
Link: https://patch.msgid.link/20260404-rtl8157_next-v7-1-039121318f23@birger-koblitz.de
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/usb/r8152.c

index 1765da5bd6cfbefb57d02d4f22b6d8498ed91e79..c81bb788ac3424bd22108e83a20ff51e21c23f60 100644 (file)
@@ -606,6 +606,7 @@ enum spd_duplex {
        FORCE_100M_FULL,
        FORCE_1000M_FULL,
        NWAY_2500M_FULL,
+       NWAY_5000M_FULL,
 };
 
 /* OCP_ALDPS_CONFIG */
@@ -727,6 +728,7 @@ enum spd_duplex {
 #define BP4_SUPER_ONLY         0x1578  /* RTL_VER_04 only */
 
 enum rtl_register_content {
+       _5000bps        = BIT(12),
        _2500bps        = BIT(10),
        _1250bps        = BIT(9),
        _500bps         = BIT(8),
@@ -740,6 +742,7 @@ enum rtl_register_content {
 };
 
 #define is_speed_2500(_speed)  (((_speed) & (_2500bps | LINK_STATUS)) == (_2500bps | LINK_STATUS))
+#define is_speed_5000(_speed)  (((_speed) & (_5000bps | LINK_STATUS)) == (_5000bps | LINK_STATUS))
 #define is_flow_control(_speed)        (((_speed) & (_tx_flow | _rx_flow)) == (_tx_flow | _rx_flow))
 
 #define RTL8152_MAX_TX         4
@@ -946,6 +949,7 @@ struct r8152 {
        unsigned int pipe_in, pipe_out, pipe_intr, pipe_ctrl_in, pipe_ctrl_out;
 
        u32 support_2500full:1;
+       u32 support_5000full:1;
        u32 lenovo_macpassthru:1;
        u32 dell_tb_rx_agg_bug:1;
        u16 ocp_base;
@@ -1196,6 +1200,7 @@ enum tx_csum_stat {
 #define RTL_ADVERTISED_1000_HALF               BIT(4)
 #define RTL_ADVERTISED_1000_FULL               BIT(5)
 #define RTL_ADVERTISED_2500_FULL               BIT(6)
+#define RTL_ADVERTISED_5000_FULL               BIT(7)
 
 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
  * The RTL chips use a 64 element hash table based on the Ethernet CRC.
@@ -5421,12 +5426,23 @@ static void r8153_eee_en(struct r8152 *tp, bool enable)
 
 static void r8156_eee_en(struct r8152 *tp, bool enable)
 {
+       u16 config;
+
        r8153_eee_en(tp, enable);
 
+       config = ocp_reg_read(tp, OCP_EEE_ADV2);
+
        if (enable && (tp->eee_adv2 & MDIO_EEE_2_5GT))
-               ocp_reg_set_bits(tp, OCP_EEE_ADV2, MDIO_EEE_2_5GT);
+               config |= MDIO_EEE_2_5GT;
        else
-               ocp_reg_clr_bits(tp, OCP_EEE_ADV2, MDIO_EEE_2_5GT);
+               config &= ~MDIO_EEE_2_5GT;
+
+       if (enable && (tp->eee_adv2 & MDIO_EEE_5GT))
+               config |= MDIO_EEE_5GT;
+       else
+               config &= ~MDIO_EEE_5GT;
+
+       ocp_reg_write(tp, OCP_EEE_ADV2, config);
 }
 
 static void rtl_eee_enable(struct r8152 *tp, bool enable)
@@ -6190,9 +6206,13 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
 
                        if (tp->support_2500full)
                                support |= RTL_ADVERTISED_2500_FULL;
+
+                       if (tp->support_5000full)
+                               support |= RTL_ADVERTISED_5000_FULL;
                }
 
-               if (!(advertising & support))
+               advertising &= support;
+               if (!advertising)
                        return -EINVAL;
 
                orig = r8152_mdio_read(tp, MII_ADVERTISE);
@@ -6235,15 +6255,20 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
                                r8152_mdio_write(tp, MII_CTRL1000, new1);
                }
 
-               if (tp->support_2500full) {
+               if (tp->support_2500full || tp->support_5000full) {
                        orig = ocp_reg_read(tp, OCP_10GBT_CTRL);
-                       new1 = orig & ~MDIO_AN_10GBT_CTRL_ADV2_5G;
+                       new1 = orig & ~(MDIO_AN_10GBT_CTRL_ADV2_5G | MDIO_AN_10GBT_CTRL_ADV5G);
 
                        if (advertising & RTL_ADVERTISED_2500_FULL) {
                                new1 |= MDIO_AN_10GBT_CTRL_ADV2_5G;
                                tp->ups_info.speed_duplex = NWAY_2500M_FULL;
                        }
 
+                       if (advertising & RTL_ADVERTISED_5000_FULL) {
+                               new1 |= MDIO_AN_10GBT_CTRL_ADV5G;
+                               tp->ups_info.speed_duplex = NWAY_5000M_FULL;
+                       }
+
                        if (orig != new1)
                                ocp_reg_write(tp, OCP_10GBT_CTRL, new1);
                }
@@ -8220,17 +8245,38 @@ int rtl8152_get_link_ksettings(struct net_device *netdev,
        linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
                         cmd->link_modes.supported, tp->support_2500full);
 
-       if (tp->support_2500full) {
-               linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-                                cmd->link_modes.advertising,
-                                ocp_reg_read(tp, OCP_10GBT_CTRL) & MDIO_AN_10GBT_CTRL_ADV2_5G);
+       linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+                        cmd->link_modes.supported, tp->support_5000full);
+
+       if (tp->support_2500full || tp->support_5000full) {
+               u16 ocp_10gbt_ctrl = ocp_reg_read(tp, OCP_10GBT_CTRL);
+               u16 ocp_10gbt_stat = ocp_reg_read(tp, OCP_10GBT_STAT);
+
+               if (tp->support_2500full) {
+                       linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+                                        cmd->link_modes.advertising,
+                                        ocp_10gbt_ctrl & MDIO_AN_10GBT_CTRL_ADV2_5G);
+
+                       linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+                                        cmd->link_modes.lp_advertising,
+                                        ocp_10gbt_stat & MDIO_AN_10GBT_STAT_LP2_5G);
+
+                       if (is_speed_2500(rtl8152_get_speed(tp)))
+                               cmd->base.speed = SPEED_2500;
+               }
+
+               if (tp->support_5000full) {
+                       linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+                                        cmd->link_modes.advertising,
+                                        ocp_10gbt_ctrl & MDIO_AN_10GBT_CTRL_ADV5G);
 
-               linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-                                cmd->link_modes.lp_advertising,
-                                ocp_reg_read(tp, OCP_10GBT_STAT) & MDIO_AN_10GBT_STAT_LP2_5G);
+                       linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+                                        cmd->link_modes.lp_advertising,
+                                        ocp_10gbt_stat & MDIO_AN_10GBT_STAT_LP5G);
 
-               if (is_speed_2500(rtl8152_get_speed(tp)))
-                       cmd->base.speed = SPEED_2500;
+                       if (is_speed_5000(rtl8152_get_speed(tp)))
+                               cmd->base.speed = SPEED_5000;
+               }
        }
 
        mutex_unlock(&tp->control);
@@ -8280,6 +8326,10 @@ static int rtl8152_set_link_ksettings(struct net_device *dev,
                     cmd->link_modes.advertising))
                advertising |= RTL_ADVERTISED_2500_FULL;
 
+       if (test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+                    cmd->link_modes.advertising))
+               advertising |= RTL_ADVERTISED_5000_FULL;
+
        mutex_lock(&tp->control);
 
        ret = rtl8152_set_speed(tp, cmd->base.autoneg, cmd->base.speed,
@@ -8397,7 +8447,7 @@ static int r8152_set_eee(struct r8152 *tp, struct ethtool_keee *eee)
 
        tp->eee_en = eee->eee_enabled;
        tp->eee_adv = val;
-       if (tp->support_2500full) {
+       if (tp->support_2500full || tp->support_5000full) {
                val = linkmode_to_mii_eee_cap2_t(eee->advertised);
                tp->eee_adv2 = val;
        }
@@ -8421,19 +8471,28 @@ static int r8153_get_eee(struct r8152 *tp, struct ethtool_keee *eee)
        val = ocp_reg_read(tp, OCP_EEE_LPABLE);
        mii_eee_cap1_mod_linkmode_t(eee->lp_advertised, val);
 
-       if (tp->support_2500full) {
-               linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, eee->supported);
-
+       if (tp->support_2500full || tp->support_5000full) {
                val = ocp_reg_read(tp, OCP_EEE_ADV2);
                mii_eee_cap2_mod_linkmode_adv_t(eee->advertised, val);
 
                val = ocp_reg_read(tp, OCP_EEE_LPABLE2);
                mii_eee_cap2_mod_linkmode_adv_t(eee->lp_advertised, val);
+       }
+
+       if (tp->support_2500full) {
+               linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, eee->supported);
 
                if (speed & _2500bps)
                        linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, common);
        }
 
+       if (tp->support_5000full) {
+               linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, eee->supported);
+
+               if (speed & _5000bps)
+                       linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, common);
+       }
+
        eee->eee_enabled = tp->eee_en;
 
        if (speed & _1000bps)
@@ -9374,6 +9433,11 @@ static int rtl8152_probe_once(struct usb_interface *intf,
                } else {
                        tp->speed = SPEED_1000;
                }
+               if (tp->support_5000full &&
+                   tp->udev->speed >= USB_SPEED_SUPER) {
+                       tp->speed = SPEED_5000;
+                       tp->advertising |= RTL_ADVERTISED_5000_FULL;
+               }
                tp->advertising |= RTL_ADVERTISED_1000_FULL;
        }
        tp->duplex = DUPLEX_FULL;