]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: dsa: enhance pcs_get_state() for RTL93xx 19575/head
authorHarshal Gohel <hg@simonwunderlich.de>
Mon, 14 Jul 2025 08:37:28 +0000 (10:37 +0200)
committerHauke Mehrtens <hauke@hauke-m.de>
Thu, 7 Aug 2025 13:50:01 +0000 (15:50 +0200)
Currently the SerDes driven SFP ports give strange ethtool readings
on RTL93xx 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.

Suggested-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Signed-off-by: Harshal Gohel <hg@simonwunderlich.de>
Signed-off-by: Sharadanand Karanjkar <sk@simonwunderlich.de>
Link: https://github.com/openwrt/openwrt/pull/19575
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c

index 10438298adca74258ff5d0da6f4bd5dcf57b9671..a14b502cf108249af20633afbc0a6b62ad3298f7 100644 (file)
@@ -621,8 +621,8 @@ static void rtldsa_83xx_pcs_get_state(struct phylink_pcs *pcs, struct phylink_li
                state->pause |= MLO_PAUSE_TX;
 }
 
-static void rtl93xx_pcs_get_state(struct phylink_pcs *pcs,
-                                 struct phylink_link_state *state)
+static void rtldsa_93xx_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;
@@ -631,21 +631,25 @@ static void rtl93xx_pcs_get_state(struct phylink_pcs *pcs,
        u64 link;
        u64 media;
 
-       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;
-       }
 
        /* On the RTL9300 for at least the RTL8226B PHY, the MAC-side link
         * state needs to be read twice in order to read a correct result.
         * This would not be necessary for ports connected e.g. to RTL8218D
         * PHYs.
         */
-       state->link = 0;
        link = priv->r->get_port_reg_le(priv->r->mac_link_sts);
        link = priv->r->get_port_reg_le(priv->r->mac_link_sts);
-       if (link & BIT_ULL(port))
-               state->link = 1;
+       if (!(link & BIT_ULL(port)))
+               return;
+
+       state->link = 1;
 
        if (priv->family_id == RTL9310_FAMILY_ID)
                media = priv->r->get_port_reg_le(RTL931X_MAC_LINK_MEDIA_STS);
@@ -656,46 +660,37 @@ static void rtl93xx_pcs_get_state(struct phylink_pcs *pcs,
        pr_debug("%s: link state port %d: %llx, media %llx\n", __func__, port,
                 link & BIT_ULL(port), media);
 
-       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 % 8) << 2;
-       switch (speed & 0xf) {
-       case 0:
+       speed = (speed >> ((port % 8) << 2)) & 0xf;
+       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 7:
+       case RTL_SPEED_1000:
                state->speed = SPEED_1000;
                break;
-       case 4:
+       case RTL_SPEED_10000:
                state->speed = SPEED_10000;
                break;
-       case 5:
-       case 8:
+       case RTL_SPEED_2500:
                state->speed = SPEED_2500;
                break;
-       case 6:
+       case RTL_SPEED_5000:
                state->speed = SPEED_5000;
                break;
        default:
                pr_err("%s: unknown speed: %d\n", __func__, (u32)speed & 0xf);
        }
 
-       if (priv->family_id == RTL9310_FAMILY_ID
-               && (port >= 52 && port <= 55)) { /* Internal serdes */
-                       state->speed = SPEED_10000;
-                       state->link = 1;
-                       state->duplex = 1;
-       }
-
        pr_debug("%s: speed is: %d %d\n", __func__, (u32)speed & 0xf, state->speed);
-       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))
@@ -2750,7 +2745,7 @@ const struct dsa_switch_ops rtl83xx_switch_ops = {
 
 const struct phylink_pcs_ops rtl93xx_pcs_ops = {
        .pcs_an_restart         = rtl83xx_pcs_an_restart,
-       .pcs_get_state          = rtl93xx_pcs_get_state,
+       .pcs_get_state          = rtldsa_93xx_pcs_get_state,
        .pcs_config             = rtl83xx_pcs_config,
 };