]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: pcs: rtl931x: gate symErr success on actual link status
authorJonas Jelonek <jelonek.jonas@gmail.com>
Mon, 27 Jul 2026 20:29:37 +0000 (20:29 +0000)
committerJonas Jelonek <jelonek.jonas@gmail.com>
Tue, 4 Aug 2026 07:51:29 +0000 (09:51 +0200)
symErr reads 0 both when the link is clean and when there's no signal
at all to decode errors from - the counter only increments when the
PCS is actively decoding something and finds a mismatch, so a dead
link and a healthy one are indistinguishable from symErr alone.
Confirmed on hardware: symErr read 0x0 while the port had no link.

Add rtpcs_931x_sds_10gr_link_up(), reading the same status bit as the
vendor SDK's _phy_rtl9310_linkSts_get() default case, and require it
alongside a low symErr count before declaring a calibration check
successful. A link that isn't actually up yet now keeps the retry
loop going instead of being misread as a clean, working link.

Also observed on hardware: the retry budget sometimes runs out while
symErr is still nonzero, but the link comes up and works fine anyway -
the count just hasn't fully settled within the budget. Since that's
not an actual problem, keep the final message at dev_dbg when
link_up is true; only warn when the link genuinely never came up.

Link: https://github.com/openwrt/openwrt/pull/24542
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c

index 767d5ad5a1688b3db8effb6ce02646c954a67a8b..58c86cb9bb5788dc537bb42769c9c270e5aebca2 100644 (file)
@@ -3089,6 +3089,11 @@ static int rtpcs_931x_sds_fiber_get_symerr(struct rtpcs_serdes *sds,
        return symerr;
 }
 
+static bool rtpcs_931x_sds_10gr_link_up(struct rtpcs_serdes *sds)
+{
+       return rtpcs_sds_read_bits(sds, PAGE_TGR_STD_1, 0x0, 12, 12) == 1;
+}
+
 static void rtpcs_931x_sds_clear_symerr(struct rtpcs_serdes *sds,
                                        enum rtpcs_sds_mode hw_mode)
 {
@@ -3438,6 +3443,7 @@ static void rtpcs_931x_sds_rxcal_fiber_adapt(struct rtpcs_serdes *sds)
        unsigned int vth_p = 0, vth_n = 0, sum_p = 0, sum_n = 0;
        struct device *dev = sds->ctrl->dev;
        int i, samples = 0, symerr = -1;
+       bool link_up = false;
 
        dev_dbg(dev, "SerDes %u fiber RX calibration...\n", sds->id);
        /* per-port calibration offset in the SDK, kept 0 here */
@@ -3488,18 +3494,28 @@ static void rtpcs_931x_sds_rxcal_fiber_adapt(struct rtpcs_serdes *sds)
                rtpcs_931x_sds_clear_symerr(sds, RTPCS_SDS_MODE_10GBASER);
                msleep(300);
                symerr = rtpcs_931x_sds_fiber_get_symerr(sds, RTPCS_SDS_MODE_10GBASER);
+               link_up = rtpcs_931x_sds_10gr_link_up(sds);
+               dev_dbg(dev, "SerDes %u symErr check %d: linkUp=%d symErr=0x%x\n", sds->id,
+                       i + 1, link_up, symerr);
 
-               dev_dbg(dev, "SerDes %u symErr check %d: 0x%x\n", sds->id, i + 1, symerr);
-
-               if (symerr >= 0 && symerr <= 5) {
+               /*
+                * symErr also reads 0 with no signal at all, not just a clean
+                * link - don't trust it without link_up confirming there's
+                * actually something being decoded.
+                */
+               if (link_up && symerr >= 0 && symerr <= 5) {
                        dev_dbg(dev, "SerDes %u fiber RX calibration OK (check %d)\n",
                                sds->id, i + 1);
                        return;
                }
        }
 
-       dev_warn(dev, "SerDes %u fiber RX calibration failed after %d symErr checks\n",
-                sds->id, i);
+       if (link_up)
+               dev_dbg(dev, "SerDes %u fiber RX calibration: symErr still 0x%x after %d checks, link up anyway\n",
+                       sds->id, symerr, i);
+       else
+               dev_warn(dev, "SerDes %u fiber RX calibration failed after %d symErr checks\n",
+                        sds->id, i);
 }
 
 static int rtpcs_931x_sds_get_pll_select(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type *pll)