[openwrt/openwrt] realtek: dsa: enhance pcs_get_state() for RTL83xx

LEDE Commits lede-commits at lists.infradead.org
Sat Jul 26 04:23:46 PDT 2025


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/ded18a3683908e4121500e394278342f63764906

commit ded18a3683908e4121500e394278342f63764906
Author: Markus Stockhausen <markus.stockhausen at gmx.de>
AuthorDate: Fri Jul 25 02:31:11 2025 -0400

    realtek: dsa: enhance pcs_get_state() for RTL83xx
    
    Currently the SerDes driven SFP ports give strange ethtool readings
    on RTL83xx devices. Especially duplex and speed are shown even if
    no link is up and running. That leads to confusion because the MAC
    reports arbitrary values.
    
    Enhance the readout by refactoring the pcs_get_state() function.
    Calculate speed/duplex/pause only if link is detected. Additionally
    add reporting of 10G for SFP+ on RTL839x.
    
    ethtool for empty SFP cage before/after
    
    root at OpenWrt:~# ethtool lan9
    Settings for lan9:
            Supported ports: [ MII ]
            Supported link modes:   1000baseT/Full
                                    1000baseKX/Full
                                    1000baseX/Full
                                    1000baseT1/Full
            Supported pause frame use: Symmetric Receive-only
            Supports auto-negotiation: Yes
            Supported FEC modes: Not reported
            Advertised link modes:  1000baseT/Full
                                    1000baseKX/Full
                                    1000baseX/Full
                                    1000baseT1/Full
            Advertised pause frame use: Symmetric Receive-only
            Advertised auto-negotiation: Yes
            Advertised FEC modes: Not reported
            Speed: 10Mb/s
            Duplex: Half
            Port: MII
            PHYAD: 0
            Transceiver: internal
            Auto-negotiation: on
            Supports Wake-on: d
            Wake-on: d
            Link detected: no
    
    root at OpenWrt:~# ethtool lan9
    Settings for lan9:
            Supported ports: [ MII ]
            Supported link modes:   1000baseT/Full
                                    1000baseKX/Full
                                    1000baseX/Full
                                    1000baseT1/Full
            Supported pause frame use: Symmetric Receive-only
            Supports auto-negotiation: Yes
            Supported FEC modes: Not reported
            Advertised link modes:  1000baseT/Full
                                    1000baseKX/Full
                                    1000baseX/Full
                                    1000baseT1/Full
            Advertised pause frame use: Symmetric Receive-only
            Advertised auto-negotiation: Yes
            Advertised FEC modes: Not reported
            Speed: Unknown!
            Duplex: Unknown! (255)
            Port: MII
            PHYAD: 0
            Transceiver: internal
            Auto-negotiation: on
            Supports Wake-on: d
            Wake-on: d
            Link detected: no
    
    ethtool with inserted but NOT connected 1G module before/after
    
    root at OpenWrt:~# ethtool lan9
    Settings for lan9:
            Supported ports: [ FIBRE ]
            Supported link modes:   1000baseX/Full
            Supported pause frame use: Symmetric Receive-only
            Supports auto-negotiation: Yes
            Supported FEC modes: Not reported
            Advertised link modes:  1000baseX/Full
            Advertised pause frame use: Symmetric Receive-only
            Advertised auto-negotiation: Yes
            Advertised FEC modes: Not reported
            Speed: 1000Mb/s
            Duplex: Full
            Port: FIBRE
            PHYAD: 0
            Transceiver: internal
            Auto-negotiation: on
            Supports Wake-on: d
            Wake-on: d
            Link detected: no
    
    root at OpenWrt:~# ethtool lan9
    Settings for lan9:
            Supported ports: [ FIBRE ]
            Supported link modes:   1000baseX/Full
            Supported pause frame use: Symmetric Receive-only
            Supports auto-negotiation: Yes
            Supported FEC modes: Not reported
            Advertised link modes:  1000baseX/Full
            Advertised pause frame use: Symmetric Receive-only
            Advertised auto-negotiation: Yes
            Advertised FEC modes: Not reported
            Speed: Unknown!
            Duplex: Unknown! (255)
            Port: FIBRE
            PHYAD: 0
            Transceiver: internal
            Auto-negotiation: on
            Supports Wake-on: d
            Wake-on: d
            Link detected: no
    
    Signed-off-by: Markus Stockhausen <markus.stockhausen at gmx.de>
    Link: https://github.com/openwrt/openwrt/pull/19524
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 .../files-6.12/drivers/net/dsa/rtl83xx/dsa.c       | 55 ++++++++++++----------
 1 file changed, 30 insertions(+), 25 deletions(-)

diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c
index 1af34b4c5f..fd89105ae1 100644
--- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c
+++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c
@@ -340,51 +340,56 @@ static int rtl93xx_get_sds(struct phy_device *phydev)
 	return sds_num;
 }
 
-static void rtl83xx_pcs_get_state(struct phylink_pcs *pcs,
-				  struct phylink_link_state *state)
+static void rtldsa_83xx_pcs_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state)
 {
 	struct rtl838x_pcs *rtpcs = container_of(pcs, struct rtl838x_pcs, pcs);
 	struct rtl838x_switch_priv *priv = rtpcs->priv;
 	int port = rtpcs->port;
 	u64 speed;
-	u64 link;
 
-	if (port < 0 || port > priv->cpu_port) {
-		state->link = false;
+	state->link = 0;
+	state->speed = SPEED_UNKNOWN;
+	state->duplex = DUPLEX_UNKNOWN;
+	state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
+
+	if (port < 0 || port > priv->cpu_port)
 		return;
-	}
 
-	state->link = 0;
-	link = priv->r->get_port_reg_le(priv->r->mac_link_sts);
-	if (link & BIT_ULL(port))
-		state->link = 1;
-	pr_debug("%s: link state port %d: %llx\n", __func__, port, link & BIT_ULL(port));
+	if (!(priv->r->get_port_reg_le(priv->r->mac_link_sts) & BIT_ULL(port)))
+		return;
+
+	state->link = 1;
 
-	state->duplex = 0;
 	if (priv->r->get_port_reg_le(priv->r->mac_link_dup_sts) & BIT_ULL(port))
-		state->duplex = 1;
+		state->duplex = DUPLEX_FULL;
+	else
+		state->duplex = DUPLEX_HALF;
 
 	speed = priv->r->get_port_reg_le(priv->r->mac_link_spd_sts(port));
-	speed >>= (port % 16) << 1;
-	switch (speed & 0x3) {
-	case 0:
+	speed = (speed >> ((port % 16) << 1)) & 0x3;
+
+	switch (speed) {
+	case RTL_SPEED_10:
 		state->speed = SPEED_10;
 		break;
-	case 1:
+	case RTL_SPEED_100:
 		state->speed = SPEED_100;
 		break;
-	case 2:
+	case RTL_SPEED_1000:
 		state->speed = SPEED_1000;
 		break;
 	case 3:
-		if (priv->family_id == RTL9300_FAMILY_ID
-			&& (port == 24 || port == 26)) /* Internal serdes */
-			state->speed = SPEED_2500;
-		else
-			state->speed = SPEED_100; /* Is in fact 500Mbit */
+		/*
+		 * This is ok so far but with minor inconsistencies. On RTL838x this setting is
+		 * for either 500M or 2G. It might be that MAC_GLITE_STS register tells more. On
+		 * RTL839x these vendor specifics are derived from MAC_LINK_500M_STS and mode 3
+		 * is 10G. This is of interest so resolve to it. Sadly it is off by one for the
+		 * current RTL_SPEED_10000 (=4) definition for RTL93xx.
+		 */
+		state->speed = SPEED_10000;
+		break;
 	}
 
-	state->pause &= (MLO_PAUSE_RX | MLO_PAUSE_TX);
 	if (priv->r->get_port_reg_le(priv->r->mac_rx_pause_sts) & BIT_ULL(port))
 		state->pause |= MLO_PAUSE_RX;
 	if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port))
@@ -2046,7 +2051,7 @@ static int rtl83xx_dsa_phy_write(struct dsa_switch *ds, int phy_addr, int phy_re
 
 const struct phylink_pcs_ops rtl83xx_pcs_ops = {
 	.pcs_an_restart		= rtl83xx_pcs_an_restart,
-	.pcs_get_state		= rtl83xx_pcs_get_state,
+	.pcs_get_state		= rtldsa_83xx_pcs_get_state,
 	.pcs_config		= rtl83xx_pcs_config,
 };
 




More information about the lede-commits mailing list