Skip to content

Commit 4b95840

Browse files
ayalevin123Saeed Mahameed
authored andcommitted
net/mlx5e: Fix matching of speed to PRM link modes
Speed translation is performed based on legacy or extended PTYS register. Translate speed with respect to: 1) Capability bit of extended PTYS table. 2) User request: a) When auto-negotiation is turned on, inspect advertisement whether it contains extended link modes. b) When auto-negotiation is turned off, speed > 100Gbps (maximal speed supported in legacy mode). With both conditions fulfilled translation is done with extended PTYS table otherwise use legacy PTYS table. Without this patch 25/50/100 Gbps speed cannot be set, since try to configure in extended mode but read from legacy mode. Fixes: dd1b9e0 ("net/mlx5: ethtool, Allow legacy link-modes configuration via non-extended ptys") Signed-off-by: Aya Levin <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent 694826e commit 4b95840

File tree

3 files changed

+68
-32
lines changed

3 files changed

+68
-32
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en/port.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,10 @@ static const u32 mlx5e_ext_link_speed[MLX5E_EXT_LINK_MODES_NUMBER] = {
7878
};
7979

8080
static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
81-
const u32 **arr, u32 *size)
81+
const u32 **arr, u32 *size,
82+
bool force_legacy)
8283
{
83-
bool ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
84+
bool ext = force_legacy ? false : MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
8485

8586
*size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
8687
ARRAY_SIZE(mlx5e_link_speed);
@@ -152,15 +153,16 @@ int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable,
152153
sizeof(out), MLX5_REG_PTYS, 0, 1);
153154
}
154155

155-
u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper)
156+
u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper,
157+
bool force_legacy)
156158
{
157159
unsigned long temp = eth_proto_oper;
158160
const u32 *table;
159161
u32 speed = 0;
160162
u32 max_size;
161163
int i;
162164

163-
mlx5e_port_get_speed_arr(mdev, &table, &max_size);
165+
mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
164166
i = find_first_bit(&temp, max_size);
165167
if (i < max_size)
166168
speed = table[i];
@@ -170,15 +172,21 @@ u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper)
170172
int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
171173
{
172174
struct mlx5e_port_eth_proto eproto;
175+
bool force_legacy = false;
173176
bool ext;
174177
int err;
175178

176179
ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
177180
err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
178181
if (err)
179182
goto out;
180-
181-
*speed = mlx5e_port_ptys2speed(mdev, eproto.oper);
183+
if (ext && !eproto.admin) {
184+
force_legacy = true;
185+
err = mlx5_port_query_eth_proto(mdev, 1, false, &eproto);
186+
if (err)
187+
goto out;
188+
}
189+
*speed = mlx5e_port_ptys2speed(mdev, eproto.oper, force_legacy);
182190
if (!(*speed))
183191
err = -EINVAL;
184192

@@ -201,7 +209,7 @@ int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
201209
if (err)
202210
return err;
203211

204-
mlx5e_port_get_speed_arr(mdev, &table, &max_size);
212+
mlx5e_port_get_speed_arr(mdev, &table, &max_size, false);
205213
for (i = 0; i < max_size; ++i)
206214
if (eproto.cap & MLX5E_PROT_MASK(i))
207215
max_speed = max(max_speed, table[i]);
@@ -210,14 +218,15 @@ int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
210218
return 0;
211219
}
212220

213-
u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed)
221+
u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
222+
bool force_legacy)
214223
{
215224
u32 link_modes = 0;
216225
const u32 *table;
217226
u32 max_size;
218227
int i;
219228

220-
mlx5e_port_get_speed_arr(mdev, &table, &max_size);
229+
mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
221230
for (i = 0; i < max_size; ++i) {
222231
if (table[i] == speed)
223232
link_modes |= MLX5E_PROT_MASK(i);

drivers/net/ethernet/mellanox/mlx5/core/en/port.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@ void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status,
4848
u8 *an_disable_cap, u8 *an_disable_admin);
4949
int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable,
5050
u32 proto_admin, bool ext);
51-
u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper);
51+
u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper,
52+
bool force_legacy);
5253
int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
5354
int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
54-
u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed);
55+
u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
56+
bool force_legacy);
5557

5658
int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out);
5759
int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in);

drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings
785785
}
786786

787787
static void get_speed_duplex(struct net_device *netdev,
788-
u32 eth_proto_oper,
788+
u32 eth_proto_oper, bool force_legacy,
789789
struct ethtool_link_ksettings *link_ksettings)
790790
{
791791
struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -795,7 +795,7 @@ static void get_speed_duplex(struct net_device *netdev,
795795
if (!netif_carrier_ok(netdev))
796796
goto out;
797797

798-
speed = mlx5e_port_ptys2speed(priv->mdev, eth_proto_oper);
798+
speed = mlx5e_port_ptys2speed(priv->mdev, eth_proto_oper, force_legacy);
799799
if (!speed) {
800800
speed = SPEED_UNKNOWN;
801801
goto out;
@@ -914,8 +914,8 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
914914
/* Fields: eth_proto_admin and ext_eth_proto_admin are
915915
* mutually exclusive. Hence try reading legacy advertising
916916
* when extended advertising is zero.
917-
* admin_ext indicates how eth_proto_admin should be
918-
* interpreted
917+
* admin_ext indicates which proto_admin (ext vs. legacy)
918+
* should be read and interpreted
919919
*/
920920
admin_ext = ext;
921921
if (ext && !eth_proto_admin) {
@@ -924,7 +924,7 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
924924
admin_ext = false;
925925
}
926926

927-
eth_proto_oper = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
927+
eth_proto_oper = MLX5_GET_ETH_PROTO(ptys_reg, out, admin_ext,
928928
eth_proto_oper);
929929
eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise);
930930
an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
@@ -939,7 +939,8 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
939939
get_supported(mdev, eth_proto_cap, link_ksettings);
940940
get_advertising(eth_proto_admin, tx_pause, rx_pause, link_ksettings,
941941
admin_ext);
942-
get_speed_duplex(priv->netdev, eth_proto_oper, link_ksettings);
942+
get_speed_duplex(priv->netdev, eth_proto_oper, !admin_ext,
943+
link_ksettings);
943944

944945
eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap;
945946

@@ -1016,45 +1017,69 @@ static u32 mlx5e_ethtool2ptys_ext_adver_link(const unsigned long *link_modes)
10161017
return ptys_modes;
10171018
}
10181019

1020+
static bool ext_link_mode_requested(const unsigned long *adver)
1021+
{
1022+
#define MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT ETHTOOL_LINK_MODE_50000baseKR_Full_BIT
1023+
int size = __ETHTOOL_LINK_MODE_MASK_NBITS - MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT;
1024+
__ETHTOOL_DECLARE_LINK_MODE_MASK(modes);
1025+
1026+
bitmap_set(modes, MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT, size);
1027+
return bitmap_intersects(modes, adver, __ETHTOOL_LINK_MODE_MASK_NBITS);
1028+
}
1029+
1030+
static bool ext_speed_requested(u32 speed)
1031+
{
1032+
#define MLX5E_MAX_PTYS_LEGACY_SPEED 100000
1033+
return !!(speed > MLX5E_MAX_PTYS_LEGACY_SPEED);
1034+
}
1035+
1036+
static bool ext_requested(u8 autoneg, const unsigned long *adver, u32 speed)
1037+
{
1038+
bool ext_link_mode = ext_link_mode_requested(adver);
1039+
bool ext_speed = ext_speed_requested(speed);
1040+
1041+
return autoneg == AUTONEG_ENABLE ? ext_link_mode : ext_speed;
1042+
}
1043+
10191044
int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
10201045
const struct ethtool_link_ksettings *link_ksettings)
10211046
{
10221047
struct mlx5_core_dev *mdev = priv->mdev;
10231048
struct mlx5e_port_eth_proto eproto;
1049+
const unsigned long *adver;
10241050
bool an_changes = false;
10251051
u8 an_disable_admin;
10261052
bool ext_supported;
1027-
bool ext_requested;
10281053
u8 an_disable_cap;
10291054
bool an_disable;
10301055
u32 link_modes;
10311056
u8 an_status;
1057+
u8 autoneg;
10321058
u32 speed;
1059+
bool ext;
10331060
int err;
10341061

10351062
u32 (*ethtool2ptys_adver_func)(const unsigned long *adver);
10361063

1037-
#define MLX5E_PTYS_EXT ((1ULL << ETHTOOL_LINK_MODE_50000baseKR_Full_BIT) - 1)
1064+
adver = link_ksettings->link_modes.advertising;
1065+
autoneg = link_ksettings->base.autoneg;
1066+
speed = link_ksettings->base.speed;
10381067

1039-
ext_requested = !!(link_ksettings->link_modes.advertising[0] >
1040-
MLX5E_PTYS_EXT ||
1041-
link_ksettings->link_modes.advertising[1]);
1068+
ext = ext_requested(autoneg, adver, speed),
10421069
ext_supported = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
1043-
ext_requested &= ext_supported;
1070+
if (!ext_supported && ext)
1071+
return -EOPNOTSUPP;
10441072

1045-
speed = link_ksettings->base.speed;
1046-
ethtool2ptys_adver_func = ext_requested ?
1047-
mlx5e_ethtool2ptys_ext_adver_link :
1073+
ethtool2ptys_adver_func = ext ? mlx5e_ethtool2ptys_ext_adver_link :
10481074
mlx5e_ethtool2ptys_adver_link;
1049-
err = mlx5_port_query_eth_proto(mdev, 1, ext_requested, &eproto);
1075+
err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
10501076
if (err) {
10511077
netdev_err(priv->netdev, "%s: query port eth proto failed: %d\n",
10521078
__func__, err);
10531079
goto out;
10541080
}
1055-
link_modes = link_ksettings->base.autoneg == AUTONEG_ENABLE ?
1056-
ethtool2ptys_adver_func(link_ksettings->link_modes.advertising) :
1057-
mlx5e_port_speed2linkmodes(mdev, speed);
1081+
link_modes = autoneg == AUTONEG_ENABLE ? ethtool2ptys_adver_func(adver) :
1082+
mlx5e_port_speed2linkmodes(mdev, speed, !ext);
10581083

10591084
link_modes = link_modes & eproto.cap;
10601085
if (!link_modes) {
@@ -1067,14 +1092,14 @@ int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
10671092
mlx5_port_query_eth_autoneg(mdev, &an_status, &an_disable_cap,
10681093
&an_disable_admin);
10691094

1070-
an_disable = link_ksettings->base.autoneg == AUTONEG_DISABLE;
1095+
an_disable = autoneg == AUTONEG_DISABLE;
10711096
an_changes = ((!an_disable && an_disable_admin) ||
10721097
(an_disable && !an_disable_admin));
10731098

10741099
if (!an_changes && link_modes == eproto.admin)
10751100
goto out;
10761101

1077-
mlx5_port_set_eth_ptys(mdev, an_disable, link_modes, ext_requested);
1102+
mlx5_port_set_eth_ptys(mdev, an_disable, link_modes, ext);
10781103
mlx5_toggle_port_link(mdev);
10791104

10801105
out:

0 commit comments

Comments
 (0)