From: Jonas Jelonek Date: Sun, 31 May 2026 20:38:00 +0000 (+0000) Subject: realtek: pcs: reject SerDes modes unsupported by the instance X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=80a44d6a52ba7464b8ccc4975588a86ad4f9f73e;p=thirdparty%2Fopenwrt.git realtek: pcs: reject SerDes modes unsupported by the instance 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 --- diff --git a/target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c b/target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c index 92c7c06f105..ea1c445289f 100644 --- a/target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c +++ b/target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c @@ -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