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 <jelonek.jonas@gmail.com>
This commit is contained in:
parent
e74d236e07
commit
80a44d6a52
@ -215,6 +215,7 @@ struct rtpcs_serdes {
|
|||||||
const struct rtpcs_sds_ops *ops;
|
const struct rtpcs_sds_ops *ops;
|
||||||
const struct rtpcs_sds_regs *regs;
|
const struct rtpcs_sds_regs *regs;
|
||||||
enum rtpcs_sds_type type;
|
enum rtpcs_sds_type type;
|
||||||
|
DECLARE_BITMAP(supported_modes, RTPCS_SDS_MODE_MAX);
|
||||||
struct {
|
struct {
|
||||||
struct regmap_field *mac_mode;
|
struct regmap_field *mac_mode;
|
||||||
struct regmap_field *mac_mode_force; /* nullable, 931x only */
|
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;
|
*hw_mode = RTPCS_SDS_MODE_USXGMII_10GQXGMII;
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
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);
|
dev_info(sds->ctrl->dev, "SerDes %d reset\n", sds->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool rtpcs_838x_sds_is_hw_mode_supported(struct rtpcs_serdes *sds,
|
static void rtpcs_838x_sds_fill_caps(struct rtpcs_serdes *sds)
|
||||||
enum rtpcs_sds_mode hw_mode)
|
|
||||||
{
|
{
|
||||||
switch (sds->id) {
|
__set_bit(RTPCS_SDS_MODE_OFF, sds->supported_modes);
|
||||||
case 0 ... 3:
|
|
||||||
return hw_mode == RTPCS_SDS_MODE_QSGMII;
|
if (sds->id <= 4)
|
||||||
case 4:
|
__set_bit(RTPCS_SDS_MODE_QSGMII, sds->supported_modes);
|
||||||
return hw_mode == RTPCS_SDS_MODE_QSGMII ||
|
|
||||||
hw_mode == RTPCS_SDS_MODE_SGMII ||
|
if (sds->id >= 4) {
|
||||||
hw_mode == RTPCS_SDS_MODE_1000BASEX;
|
__set_bit(RTPCS_SDS_MODE_SGMII, sds->supported_modes);
|
||||||
case 5:
|
__set_bit(RTPCS_SDS_MODE_1000BASEX, sds->supported_modes);
|
||||||
return hw_mode == RTPCS_SDS_MODE_SGMII ||
|
|
||||||
hw_mode == RTPCS_SDS_MODE_1000BASEX;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,6 +911,8 @@ static int rtpcs_838x_sds_probe(struct rtpcs_serdes *sds)
|
|||||||
|
|
||||||
sds->type = RTPCS_SDS_TYPE_5G;
|
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_MODE_SEL packs 5-bit fields in reverse order: SDS 0 at [25:29],
|
||||||
* SDS 5 at [0:4].
|
* SDS 5 at [0:4].
|
||||||
@ -937,9 +936,6 @@ static int rtpcs_838x_setup_serdes(struct rtpcs_serdes *sds,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!rtpcs_838x_sds_is_hw_mode_supported(sds, hw_mode))
|
|
||||||
return -ENOTSUPP;
|
|
||||||
|
|
||||||
rtpcs_838x_sds_deactivate(sds);
|
rtpcs_838x_sds_deactivate(sds);
|
||||||
|
|
||||||
/* take reset */
|
/* take reset */
|
||||||
@ -1034,6 +1030,22 @@ static void rtpcs_839x_sds_reset(struct rtpcs_serdes *sds)
|
|||||||
rtpcs_sds_write(odd_sds, 0x0, 0x3, 0x7106);
|
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)
|
static int rtpcs_839x_sds_probe(struct rtpcs_serdes *sds)
|
||||||
{
|
{
|
||||||
u8 id = sds->id;
|
u8 id = sds->id;
|
||||||
@ -1052,6 +1064,8 @@ static int rtpcs_839x_sds_probe(struct rtpcs_serdes *sds)
|
|||||||
else
|
else
|
||||||
sds->type = RTPCS_SDS_TYPE_5G;
|
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
|
* 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
|
* 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));
|
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 */
|
/* RTL930X */
|
||||||
|
|
||||||
/* This mapping is not coherent so it cannot be expressed arithmetically */
|
/* 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
|
else
|
||||||
sds->type = RTPCS_SDS_TYPE_UNKNOWN;
|
sds->type = RTPCS_SDS_TYPE_UNKNOWN;
|
||||||
|
|
||||||
|
rtpcs_93xx_sds_fill_caps(sds);
|
||||||
|
|
||||||
sds->swcore_regs.mac_mode = devm_regmap_field_alloc(dev, map,
|
sds->swcore_regs.mac_mode = devm_regmap_field_alloc(dev, map,
|
||||||
rtpcs_930x_mac_mode_fields[id]);
|
rtpcs_930x_mac_mode_fields[id]);
|
||||||
if (IS_ERR(sds->swcore_regs.mac_mode))
|
if (IS_ERR(sds->swcore_regs.mac_mode))
|
||||||
@ -3937,6 +3981,8 @@ static int rtpcs_931x_sds_probe(struct rtpcs_serdes *sds)
|
|||||||
else
|
else
|
||||||
sds->type = RTPCS_SDS_TYPE_UNKNOWN;
|
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
|
* 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
|
* bit 5 (FEC enable) and bit 6 (10G speedup). These are mode-dependent
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user