]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: pcs: reject SerDes modes unsupported by the instance 23608/head
authorJonas Jelonek <jelonek.jonas@gmail.com>
Sun, 31 May 2026 20:38:00 +0000 (20:38 +0000)
committerJonas Jelonek <jelonek.jonas@gmail.com>
Mon, 1 Jun 2026 07:17:15 +0000 (09:17 +0200)
Add a per-SerDes supported_modes bitmap, filled at probe by each
variant from the SerDes id or type, and reject unsupported modes in
determine_hw_mode() via test_bit().

This replaces the rtl838x is_hw_mode_supported() switch and adds the
same gating to rtl839x/rtl93xx, which previously relied only on the
per-variant mode-value table. Unlike that table, the bitmap is per
SerDes instance, so it also rejects modes the table can encode but that
a given SerDes cannot actually use. Rejection uses the uapi -EOPNOTSUPP
instead of the internal -ENOTSUPP.

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

index 92c7c06f1056dfc757dca2338d53f5c1ba5d36d7..ea1c445289f592461474feb4000fdfc76a47c9a3 100644 (file)
@@ -215,6 +215,7 @@ struct rtpcs_serdes {
        const struct rtpcs_sds_ops *ops;
        const struct rtpcs_sds_regs *regs;
        enum rtpcs_sds_type type;
+       DECLARE_BITMAP(supported_modes, RTPCS_SDS_MODE_MAX);
        struct {
                struct regmap_field *mac_mode;
                struct regmap_field *mac_mode_force;    /* nullable, 931x only */
@@ -493,10 +494,11 @@ static int rtpcs_sds_determine_hw_mode(struct rtpcs_serdes *sds,
                *hw_mode = RTPCS_SDS_MODE_USXGMII_10GQXGMII;
                break;
        default:
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
 
-       /* TODO: check if the particular SerDes supports the mode */
+       if (!test_bit(*hw_mode, sds->supported_modes))
+               return -EOPNOTSUPP;
 
        return 0;
 }
@@ -784,21 +786,16 @@ static void rtpcs_838x_sds_reset(struct rtpcs_serdes *sds)
        dev_info(sds->ctrl->dev, "SerDes %d reset\n", sds->id);
 }
 
-static bool rtpcs_838x_sds_is_hw_mode_supported(struct rtpcs_serdes *sds,
-                                               enum rtpcs_sds_mode hw_mode)
+static void rtpcs_838x_sds_fill_caps(struct rtpcs_serdes *sds)
 {
-       switch (sds->id) {
-       case 0 ... 3:
-               return hw_mode == RTPCS_SDS_MODE_QSGMII;
-       case 4:
-               return hw_mode == RTPCS_SDS_MODE_QSGMII ||
-                      hw_mode == RTPCS_SDS_MODE_SGMII ||
-                      hw_mode == RTPCS_SDS_MODE_1000BASEX;
-       case 5:
-               return hw_mode == RTPCS_SDS_MODE_SGMII ||
-                      hw_mode == RTPCS_SDS_MODE_1000BASEX;
-       default:
-               return false;
+       __set_bit(RTPCS_SDS_MODE_OFF, sds->supported_modes);
+
+       if (sds->id <= 4)
+               __set_bit(RTPCS_SDS_MODE_QSGMII, sds->supported_modes);
+
+       if (sds->id >= 4) {
+               __set_bit(RTPCS_SDS_MODE_SGMII, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_1000BASEX, sds->supported_modes);
        }
 }
 
@@ -914,6 +911,8 @@ static int rtpcs_838x_sds_probe(struct rtpcs_serdes *sds)
 
        sds->type = RTPCS_SDS_TYPE_5G;
 
+       rtpcs_838x_sds_fill_caps(sds);
+
        /*
         * SDS_MODE_SEL packs 5-bit fields in reverse order: SDS 0 at [25:29],
         * SDS 5 at [0:4].
@@ -937,9 +936,6 @@ static int rtpcs_838x_setup_serdes(struct rtpcs_serdes *sds,
 {
        int ret;
 
-       if (!rtpcs_838x_sds_is_hw_mode_supported(sds, hw_mode))
-               return -ENOTSUPP;
-
        rtpcs_838x_sds_deactivate(sds);
 
        /* take reset */
@@ -1034,6 +1030,22 @@ static void rtpcs_839x_sds_reset(struct rtpcs_serdes *sds)
        rtpcs_sds_write(odd_sds, 0x0, 0x3, 0x7106);
 }
 
+static void rtpcs_839x_sds_fill_caps(struct rtpcs_serdes *sds)
+{
+       __set_bit(RTPCS_SDS_MODE_OFF, sds->supported_modes);
+
+       if (sds->id <= 12)
+               __set_bit(RTPCS_SDS_MODE_QSGMII, sds->supported_modes);
+
+       /* Uncomment this when modes are supported
+       if (sds->id >= 12) {
+               __set_bit(RTPCS_SDS_MODE_SGMII, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_100BASEX, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_1000BASEX, sds->supported_modes);
+       }
+       */
+}
+
 static int rtpcs_839x_sds_probe(struct rtpcs_serdes *sds)
 {
        u8 id = sds->id;
@@ -1052,6 +1064,8 @@ static int rtpcs_839x_sds_probe(struct rtpcs_serdes *sds)
        else
                sds->type = RTPCS_SDS_TYPE_5G;
 
+       rtpcs_839x_sds_fill_caps(sds);
+
        /*
         * This function is quite "mystic". It has been taken over from the vendor SDK function
         * rtl839x_serdes_patch_init(). There is not much documentation about it but one could
@@ -1530,6 +1544,34 @@ static int rtpcs_93xx_sds_set_ip_mode(struct rtpcs_serdes *sds, enum rtpcs_sds_m
        return rtpcs_sds_write_bits(sds, 0x1f, 0x09, 11, 6, raw << 1 | BIT(0));
 }
 
+static void rtpcs_93xx_sds_fill_caps(struct rtpcs_serdes *sds)
+{
+       __set_bit(RTPCS_SDS_MODE_OFF, sds->supported_modes);
+
+       switch (sds->type) {
+       case RTPCS_SDS_TYPE_5G:
+               __set_bit(RTPCS_SDS_MODE_QSGMII, sds->supported_modes);
+               break;
+       case RTPCS_SDS_TYPE_10G:
+               __set_bit(RTPCS_SDS_MODE_SGMII, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_XSGMII, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_USXGMII_10GSXGMII, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_USXGMII_10GDXGMII, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_USXGMII_10GQXGMII, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_USXGMII_5GSXGMII, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_USXGMII_5GDXGMII, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_USXGMII_2_5GSXGMII, sds->supported_modes);
+
+               __set_bit(RTPCS_SDS_MODE_1000BASEX, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_2500BASEX, sds->supported_modes);
+               __set_bit(RTPCS_SDS_MODE_10GBASER, sds->supported_modes);
+               break;
+       case RTPCS_SDS_TYPE_UNKNOWN:
+       default:
+               break;
+       }
+}
+
 /* RTL930X */
 
 /* This mapping is not coherent so it cannot be expressed arithmetically */
@@ -3117,6 +3159,8 @@ static int rtpcs_930x_sds_probe(struct rtpcs_serdes *sds)
        else
                sds->type = RTPCS_SDS_TYPE_UNKNOWN;
 
+       rtpcs_93xx_sds_fill_caps(sds);
+
        sds->swcore_regs.mac_mode = devm_regmap_field_alloc(dev, map,
                                                            rtpcs_930x_mac_mode_fields[id]);
        if (IS_ERR(sds->swcore_regs.mac_mode))
@@ -3937,6 +3981,8 @@ static int rtpcs_931x_sds_probe(struct rtpcs_serdes *sds)
        else
                sds->type = RTPCS_SDS_TYPE_UNKNOWN;
 
+       rtpcs_93xx_sds_fill_caps(sds);
+
        /*
         * Width is 7 bits (lsb..lsb+6) so every MAC mode write also clears
         * bit 5 (FEC enable) and bit 6 (10G speedup). These are mode-dependent