]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: pcs: revive dead ports after RTL8382M start main master 21956/head
authorMarkus Stockhausen <markus.stockhausen@gmx.de>
Wed, 11 Feb 2026 15:20:32 +0000 (16:20 +0100)
committerRobert Marko <robimarko@gmail.com>
Thu, 12 Feb 2026 15:58:46 +0000 (16:58 +0100)
SerDes attached ports that are connected during switch
boot might not be able to transmit any data after SerDes
setup. Especially ports that passed traffic before (e.g.
for tftp initramfs boot) seem to be affected. Ports that
are connected later do not show this issue.

It turns out that the old SerDes setup never really worked
on RTL8382 and the pcs refactoring (with dynamic SerDes
start and stop) totally changed the order of network bringup
in contrast to Realtek SDK.

Fix this by restaring the switch queue whenever a SerDes
goes up for the first time.

Fixes: e956adf ("realtek: rtl838x: setup SDS in PCS driver")
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/21956
Signed-off-by: Robert Marko <robimarko@gmail.com>
target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c

index 98d099d1bc05742d6f2c20d1fd57dde9c3f7f29a..713abf68b9ceb08744eaf1123a21831ce5e98d91 100644 (file)
@@ -179,6 +179,7 @@ struct rtpcs_serdes {
        enum rtpcs_sds_mode hw_mode;
        u8 id;
        u8 num_of_links;
+       bool first_start;
 
        bool rx_pol_inv;
        bool tx_pol_inv;
@@ -766,6 +767,20 @@ static int rtpcs_838x_setup_serdes(struct rtpcs_serdes *sds,
        rtpcs_sds_write(sds, 0, 3, 0x7106);
 
        rtpcs_838x_sds_power(sds, true);
+
+       /*
+        * Run a switch queue reset after the first start of a SerDes. This recovers ports that
+        * were already connected during boot and will not pass traffic. Sometimes the bug can
+        * be seen in registers INGR_DBG_REG0-INGR_DBG_REG2 but this is quite erratic. The SDK
+        * seems to have no issues because it starts all SerDes then PHYs and runs a queue reset
+        * finally during NIC start.
+        *
+        * Of course this is totally wrong here and should be part of the DSA driver. But
+        * implementing it over there requires more tricks than this (e.g. delayed work).
+        */
+       if (sds->first_start)
+               regmap_write(sds->ctrl->map, RTPCS_838X_RST_GLB_CTRL_0, 0x4);
+
        return 0;
 }
 
@@ -3779,6 +3794,8 @@ static int rtpcs_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
                ret = ctrl->cfg->setup_serdes(sds, hw_mode);
                if (ret < 0)
                        goto out;
+
+               sds->first_start = false;
        } else {
                dev_dbg(ctrl->dev, "SerDes %u already in mode %s, no change\n",
                         sds->id, phy_modes(interface));
@@ -3915,9 +3932,10 @@ static int rtpcs_probe(struct platform_device *pdev)
 
        for (i = 0; i < ctrl->cfg->serdes_count; i++) {
                sds = &ctrl->serdes[i];
+
                sds->ctrl = ctrl;
+               sds->first_start = true;
                sds->id = i;
-
                sds->ops = ctrl->cfg->sds_ops;
        }