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>
---
drivers/net/usb/r8152.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 53 insertions(+), 3 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 3b6d4252d34c63ead8f11a120e212325a5f7d505..bab8e10e5f99afcb332e333c2739ed7509b03419 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -604,6 +604,7 @@ enum spd_duplex {
FORCE_100M_FULL,
FORCE_1000M_FULL,
NWAY_2500M_FULL,
+ NWAY_5000M_FULL,
};
/* OCP_ALDPS_CONFIG */
@@ -725,6 +726,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),
@@ -738,6 +740,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
@@ -944,6 +947,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;
@@ -1194,6 +1198,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.
@@ -5400,6 +5405,11 @@ static void r8156_eee_en(struct r8152 *tp, bool enable)
else
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);
}
@@ -6298,6 +6308,9 @@ 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))
@@ -6343,15 +6356,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);
}
@@ -8780,6 +8798,9 @@ 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);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+ cmd->link_modes.supported, tp->support_5000full);
+
if (tp->support_2500full) {
linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
cmd->link_modes.advertising,
@@ -8793,6 +8814,19 @@ int rtl8152_get_link_ksettings(struct net_device *netdev,
cmd->base.speed = SPEED_2500;
}
+ if (tp->support_5000full) {
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+ cmd->link_modes.advertising,
+ ocp_reg_read(tp, OCP_10GBT_CTRL) & MDIO_AN_10GBT_CTRL_ADV5G);
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+ cmd->link_modes.lp_advertising,
+ ocp_reg_read(tp, OCP_10GBT_STAT) & MDIO_AN_10GBT_STAT_LP5G);
+
+ if (is_speed_5000(rtl8152_get_speed(tp)))
+ cmd->base.speed = SPEED_5000;
+ }
+
mutex_unlock(&tp->control);
usb_autopm_put_interface(tp->intf);
@@ -8840,6 +8874,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,
@@ -8957,7 +8995,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;
}
@@ -8994,6 +9032,13 @@ static int r8153_get_eee(struct r8152 *tp, struct ethtool_keee *eee)
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)
@@ -9934,6 +9979,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;
--
2.47.3
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
---
r8152: Add support for 5Gbit Link Speeds and EEE
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.
> diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
> index 3b6d4252d34c..bab8e10e5f99 100644
> --- a/drivers/net/usb/r8152.c
> +++ b/drivers/net/usb/r8152.c
[ ... ]
> @@ -6343,15 +6356,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);
> }
Does r8156_ups_flags() correctly handle the new NWAY_5000M_FULL value?
When 5000M is advertised, rtl8152_set_speed() stores NWAY_5000M_FULL
(enum value 11) in tp->ups_info.speed_duplex. However, r8156_ups_flags()
has a switch statement that only handles values up to NWAY_2500M_FULL
(value 10):
drivers/net/usb/r8152.c:r8156_ups_flags() {
switch (tp->ups_info.speed_duplex) {
case NWAY_10M_HALF:
return ups_flags_speed(UPS_FLAGS_SPEED_10);
case NWAY_10M_FULL:
return ups_flags_speed(UPS_FLAGS_SPEED_10);
case NWAY_100M_HALF:
return ups_flags_speed(UPS_FLAGS_SPEED_100);
case NWAY_100M_FULL:
return ups_flags_speed(UPS_FLAGS_SPEED_100);
case NWAY_1000M_FULL:
return ups_flags_speed(UPS_FLAGS_SPEED_1000);
case NWAY_2500M_FULL:
return ups_flags_speed(UPS_FLAGS_SPEED_2500);
default:
break;
}
}
The new NWAY_5000M_FULL falls through to 'default: break;', which means
ups_flags_speed() is never called. This results in incorrect UPS flags
(speed bits = 0) being written to the USB_UPS_FLAGS hardware register via
ocp_write_dword().
When the device enters UPS power saving mode at 5000M link speed, will the
hardware receive correct speed information?
The follow-up commit defca1127dd51 ('r8152: Add support for the RTL8157
hardware') enables support_5000full for RTL_VER_16 but also does not add a
NWAY_5000M_FULL case to r8156_ups_flags().
Hi Paolo,
thanks for reviewing the patch.
On 24/03/2026 11:55 am, Paolo Abeni wrote:
>
> The new NWAY_5000M_FULL falls through to 'default: break;', which means
> ups_flags_speed() is never called. This results in incorrect UPS flags
> (speed bits = 0) being written to the USB_UPS_FLAGS hardware register via
> ocp_write_dword().
>
> When the device enters UPS power saving mode at 5000M link speed, will the
> hardware receive correct speed information?
>
> The follow-up commit defca1127dd51 ('r8152: Add support for the RTL8157
> hardware') enables support_5000full for RTL_VER_16 but also does not add a
> NWAY_5000M_FULL case to r8156_ups_flags().
>
The exact same point was raised before:
https://lkml.org/lkml/2026/3/19/1765
it was answered by me here: https://lkml.org/lkml/2026/3/20/242 and
the answer was accepted here: https://lkml.org/lkml/2026/3/20/464
B.
© 2016 - 2026 Red Hat, Inc.