net/mlx5e: Add port FEC get/set functions

Added functions to query and set link FEC policy.
To get/set FEC capabilities in PPLM reg we need to query
current link speed.
'mlx5_get_fec_speed_field' queries current link speed and returns
correct field offset.

FEC Query's return value is divided into 'active FEC policy', which is
the FEC policy used by the link, and 'configured FEC policy', which
is the FEC policy requested by the user.
The two values may differ if:
1) FEC policy was configured to 'auto',
   in which case the active FEC policy would be the default FEC policy
   for current link speed.

2) FEC policy was changed, but no link reset is performed. In which case,
   the active FEC policy would become the configured one after a link
   reset.

FEC set function sets FEC policy for all link speeds and perform link
reset.
1) If current link speed doesn't support requested FEC policy,
   the function fails.
2) If a different link speed doesn't support requested FEC policy,
   FEC capbilities for this speed are turned off and a warning message
   is printed.

Signed-off-by: Shay Agroskin <shayag@mellanox.com>
Reviewed-by: Eran Ben Elisha <eranbe@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
This commit is contained in:
Shay Agroskin 2018-10-10 14:50:34 +03:00 committed by Saeed Mahameed
parent 4b5b9c7d97
commit 2095b26414
2 changed files with 220 additions and 0 deletions

View File

@ -235,3 +235,211 @@ int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
kfree(out);
return err;
}
static u32 fec_supported_speeds[] = {
10000,
40000,
25000,
50000,
56000,
100000
};
#define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds)
/* get/set FEC admin field for a given speed */
static int mlx5e_fec_admin_field(u32 *pplm,
u8 *fec_policy,
bool write,
u32 speed)
{
switch (speed) {
case 10000:
case 40000:
if (!write)
*fec_policy = MLX5_GET(pplm_reg, pplm,
fec_override_cap_10g_40g);
else
MLX5_SET(pplm_reg, pplm,
fec_override_admin_10g_40g, *fec_policy);
break;
case 25000:
if (!write)
*fec_policy = MLX5_GET(pplm_reg, pplm,
fec_override_admin_25g);
else
MLX5_SET(pplm_reg, pplm,
fec_override_admin_25g, *fec_policy);
break;
case 50000:
if (!write)
*fec_policy = MLX5_GET(pplm_reg, pplm,
fec_override_admin_50g);
else
MLX5_SET(pplm_reg, pplm,
fec_override_admin_50g, *fec_policy);
break;
case 56000:
if (!write)
*fec_policy = MLX5_GET(pplm_reg, pplm,
fec_override_admin_56g);
else
MLX5_SET(pplm_reg, pplm,
fec_override_admin_56g, *fec_policy);
break;
case 100000:
if (!write)
*fec_policy = MLX5_GET(pplm_reg, pplm,
fec_override_admin_100g);
else
MLX5_SET(pplm_reg, pplm,
fec_override_admin_100g, *fec_policy);
break;
default:
return -EINVAL;
}
return 0;
}
/* returns FEC capabilities for a given speed */
static int mlx5e_get_fec_cap_field(u32 *pplm,
u8 *fec_cap,
u32 speed)
{
switch (speed) {
case 10000:
case 40000:
*fec_cap = MLX5_GET(pplm_reg, pplm,
fec_override_admin_10g_40g);
break;
case 25000:
*fec_cap = MLX5_GET(pplm_reg, pplm,
fec_override_cap_25g);
break;
case 50000:
*fec_cap = MLX5_GET(pplm_reg, pplm,
fec_override_cap_50g);
break;
case 56000:
*fec_cap = MLX5_GET(pplm_reg, pplm,
fec_override_cap_56g);
break;
case 100000:
*fec_cap = MLX5_GET(pplm_reg, pplm,
fec_override_cap_100g);
break;
default:
return -EINVAL;
}
return 0;
}
int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps)
{
u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
int sz = MLX5_ST_SZ_BYTES(pplm_reg);
u32 current_fec_speed;
int err;
if (!MLX5_CAP_GEN(dev, pcam_reg))
return -EOPNOTSUPP;
if (!MLX5_CAP_PCAM_REG(dev, pplm))
return -EOPNOTSUPP;
MLX5_SET(pplm_reg, in, local_port, 1);
err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
if (err)
return err;
err = mlx5e_port_linkspeed(dev, &current_fec_speed);
if (err)
return err;
return mlx5e_get_fec_cap_field(out, fec_caps, current_fec_speed);
}
int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
u8 *fec_configured_mode)
{
u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
int sz = MLX5_ST_SZ_BYTES(pplm_reg);
u32 link_speed;
int err;
if (!MLX5_CAP_GEN(dev, pcam_reg))
return -EOPNOTSUPP;
if (!MLX5_CAP_PCAM_REG(dev, pplm))
return -EOPNOTSUPP;
MLX5_SET(pplm_reg, in, local_port, 1);
err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
if (err)
return err;
*fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active);
if (!fec_configured_mode)
return 0;
err = mlx5e_port_linkspeed(dev, &link_speed);
if (err)
return err;
return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed);
}
int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
{
bool fec_mode_not_supp_in_speed = false;
u8 no_fec_policy = BIT(MLX5E_FEC_NOFEC);
u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
int sz = MLX5_ST_SZ_BYTES(pplm_reg);
u32 current_fec_speed;
u8 fec_caps = 0;
int err;
int i;
if (!MLX5_CAP_GEN(dev, pcam_reg))
return -EOPNOTSUPP;
if (!MLX5_CAP_PCAM_REG(dev, pplm))
return -EOPNOTSUPP;
MLX5_SET(pplm_reg, in, local_port, 1);
err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
if (err)
return err;
err = mlx5e_port_linkspeed(dev, &current_fec_speed);
if (err)
return err;
memset(in, 0, sz);
MLX5_SET(pplm_reg, in, local_port, 1);
for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS && !!fec_policy; i++) {
mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]);
/* policy supported for link speed */
if (!!(fec_caps & fec_policy)) {
mlx5e_fec_admin_field(in, &fec_policy, 1,
fec_supported_speeds[i]);
} else {
if (fec_supported_speeds[i] == current_fec_speed)
return -EOPNOTSUPP;
mlx5e_fec_admin_field(in, &no_fec_policy, 1,
fec_supported_speeds[i]);
fec_mode_not_supp_in_speed = true;
}
}
if (fec_mode_not_supp_in_speed)
mlx5_core_dbg(dev,
"FEC policy 0x%x is not supported for some speeds",
fec_policy);
return mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1);
}

View File

@ -45,4 +45,16 @@ int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out);
int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in);
int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps);
int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
u8 *fec_configured_mode);
int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy);
enum {
MLX5E_FEC_NOFEC,
MLX5E_FEC_FIRECODE,
MLX5E_FEC_RS_528_514,
};
#endif