Add sysctl(8) to get and set forward error correction, FEC, configuration

in mlx5en(4).

MFC after:	3 days
Sponsored by:	Mellanox Technologies
This commit is contained in:
hselasky 2019-10-02 10:22:15 +00:00
parent b00ae50aae
commit 7a5500af8b
6 changed files with 405 additions and 22 deletions

View File

@ -1053,6 +1053,9 @@ enum mlx5_mcam_feature_groups {
#define MLX5_CAP_PCAM_FEATURE(mdev, fld) \
MLX5_GET(pcam_reg, (mdev)->caps.pcam, feature_cap_mask.enhanced_features.fld)
#define MLX5_CAP_PCAM_REG(mdev, reg) \
MLX5_GET(pcam_reg, (mdev)->caps.pcam, port_access_reg_cap_mask.regs_5000_to_507f.reg)
#define MLX5_CAP_MCAM_FEATURE(mdev, fld) \
MLX5_GET(mcam_reg, (mdev)->caps.mcam, mng_feature_cap_mask.enhanced_features.fld)

View File

@ -144,6 +144,7 @@ enum {
MLX5_REG_PVLC = 0x500F,
MLX5_REG_PMPE = 0x5010,
MLX5_REG_PMAOS = 0x5012,
MLX5_REG_PPLM = 0x5023,
MLX5_REG_PBSR = 0x5038,
MLX5_REG_PCAM = 0x507f,
MLX5_REG_NODE_DESC = 0x6001,

View File

@ -76,6 +76,9 @@
#define MLX5E_MAX_PRIORITY 8
#define MLX5E_MAX_FEC_10X_25X 4
#define MLX5E_MAX_FEC_50X 4
/* IEEE 802.1Qaz standard supported values */
#define IEEE_8021QAZ_MAX_TCS 8
@ -712,6 +715,11 @@ struct mlx5e_params_ethtool {
u8 prio_tc[MLX5E_MAX_PRIORITY];
u8 dscp2prio[MLX5_MAX_SUPPORTED_DSCP];
u8 trust_state;
u8 fec_mask_10x_25x[MLX5E_MAX_FEC_10X_25X];
u16 fec_mask_50x[MLX5E_MAX_FEC_50X];
u8 fec_avail_10x_25x[MLX5E_MAX_FEC_10X_25X];
u16 fec_avail_50x[MLX5E_MAX_FEC_50X];
u32 fec_mode_active;
};
struct mlx5e_cq {
@ -1175,5 +1183,6 @@ void mlx5e_resume_sq(struct mlx5e_sq *sq);
void mlx5e_update_sq_inline(struct mlx5e_sq *sq);
void mlx5e_refresh_sq_inline(struct mlx5e_priv *priv);
int mlx5e_update_buf_lossy(struct mlx5e_priv *priv);
int mlx5e_fec_update(struct mlx5e_priv *priv);
#endif /* _MLX5_EN_H_ */

View File

@ -346,6 +346,285 @@ mlx5e_prio_to_tc_handler(SYSCTL_HANDLER_ARGS)
return (err);
}
int
mlx5e_fec_update(struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
const int sz = MLX5_ST_SZ_BYTES(pplm_reg);
int err;
if (!MLX5_CAP_GEN(mdev, pcam_reg))
return (EOPNOTSUPP);
if (!MLX5_CAP_PCAM_REG(mdev, pplm))
return (EOPNOTSUPP);
MLX5_SET(pplm_reg, in, local_port, 1);
err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0);
if (err)
return (err);
/* get 10x..25x mask */
priv->params_ethtool.fec_mask_10x_25x[0] =
MLX5_GET(pplm_reg, in, fec_override_admin_10g_40g);
priv->params_ethtool.fec_mask_10x_25x[1] =
MLX5_GET(pplm_reg, in, fec_override_admin_25g) &
MLX5_GET(pplm_reg, in, fec_override_admin_50g);
priv->params_ethtool.fec_mask_10x_25x[2] =
MLX5_GET(pplm_reg, in, fec_override_admin_56g);
priv->params_ethtool.fec_mask_10x_25x[3] =
MLX5_GET(pplm_reg, in, fec_override_admin_100g);
/* get 10x..25x available bits */
priv->params_ethtool.fec_avail_10x_25x[0] =
MLX5_GET(pplm_reg, in, fec_override_cap_10g_40g);
priv->params_ethtool.fec_avail_10x_25x[1] =
MLX5_GET(pplm_reg, in, fec_override_cap_25g) &
MLX5_GET(pplm_reg, in, fec_override_cap_50g);
priv->params_ethtool.fec_avail_10x_25x[2] =
MLX5_GET(pplm_reg, in, fec_override_cap_56g);
priv->params_ethtool.fec_avail_10x_25x[3] =
MLX5_GET(pplm_reg, in, fec_override_cap_100g);
/* get 50x mask */
priv->params_ethtool.fec_mask_50x[0] =
MLX5_GET(pplm_reg, in, fec_override_admin_50g_1x);
priv->params_ethtool.fec_mask_50x[1] =
MLX5_GET(pplm_reg, in, fec_override_admin_100g_2x);
priv->params_ethtool.fec_mask_50x[2] =
MLX5_GET(pplm_reg, in, fec_override_admin_200g_4x);
priv->params_ethtool.fec_mask_50x[3] =
MLX5_GET(pplm_reg, in, fec_override_admin_400g_8x);
/* get 50x available bits */
priv->params_ethtool.fec_avail_50x[0] =
MLX5_GET(pplm_reg, in, fec_override_cap_50g_1x);
priv->params_ethtool.fec_avail_50x[1] =
MLX5_GET(pplm_reg, in, fec_override_cap_100g_2x);
priv->params_ethtool.fec_avail_50x[2] =
MLX5_GET(pplm_reg, in, fec_override_cap_200g_4x);
priv->params_ethtool.fec_avail_50x[3] =
MLX5_GET(pplm_reg, in, fec_override_cap_400g_8x);
/* get current FEC mask */
priv->params_ethtool.fec_mode_active =
MLX5_GET(pplm_reg, in, fec_mode_active);
return (0);
}
static int
mlx5e_fec_mask_10x_25x_handler(SYSCTL_HANDLER_ARGS)
{
struct mlx5e_priv *priv = arg1;
struct mlx5_core_dev *mdev = priv->mdev;
u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
const int sz = MLX5_ST_SZ_BYTES(pplm_reg);
u8 fec_mask_10x_25x[MLX5E_MAX_FEC_10X_25X];
u8 fec_cap_changed = 0;
u8 x;
int err;
PRIV_LOCK(priv);
err = SYSCTL_OUT(req, priv->params_ethtool.fec_mask_10x_25x,
sizeof(priv->params_ethtool.fec_mask_10x_25x));
if (err || !req->newptr)
goto done;
err = SYSCTL_IN(req, fec_mask_10x_25x,
sizeof(fec_mask_10x_25x));
if (err)
goto done;
if (!MLX5_CAP_GEN(mdev, pcam_reg)) {
err = EOPNOTSUPP;
goto done;
}
if (!MLX5_CAP_PCAM_REG(mdev, pplm)) {
err = EOPNOTSUPP;
goto done;
}
MLX5_SET(pplm_reg, in, local_port, 1);
err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0);
if (err)
goto done;
/* range check input value */
for (x = 0; x != MLX5E_MAX_FEC_10X_25X; x++) {
/* check only one bit is set, if any */
if (fec_mask_10x_25x[x] & (fec_mask_10x_25x[x] - 1)) {
err = ERANGE;
goto done;
}
/* check a supported bit is set, if any */
if (fec_mask_10x_25x[x] &
~priv->params_ethtool.fec_avail_10x_25x[x]) {
err = ERANGE;
goto done;
}
fec_cap_changed |= (fec_mask_10x_25x[x] ^
priv->params_ethtool.fec_mask_10x_25x[x]);
}
/* check for no changes */
if (fec_cap_changed == 0)
goto done;
memset(in, 0, sizeof(in));
MLX5_SET(pplm_reg, in, local_port, 1);
/* set new values */
MLX5_SET(pplm_reg, in, fec_override_admin_10g_40g, fec_mask_10x_25x[0]);
MLX5_SET(pplm_reg, in, fec_override_admin_25g, fec_mask_10x_25x[1]);
MLX5_SET(pplm_reg, in, fec_override_admin_50g, fec_mask_10x_25x[1]);
MLX5_SET(pplm_reg, in, fec_override_admin_56g, fec_mask_10x_25x[2]);
MLX5_SET(pplm_reg, in, fec_override_admin_100g, fec_mask_10x_25x[3]);
/* preserve other values */
MLX5_SET(pplm_reg, in, fec_override_admin_50g_1x, priv->params_ethtool.fec_mask_50x[0]);
MLX5_SET(pplm_reg, in, fec_override_admin_100g_2x, priv->params_ethtool.fec_mask_50x[1]);
MLX5_SET(pplm_reg, in, fec_override_admin_200g_4x, priv->params_ethtool.fec_mask_50x[2]);
MLX5_SET(pplm_reg, in, fec_override_admin_400g_8x, priv->params_ethtool.fec_mask_50x[3]);
/* send new value to the firmware */
err = -mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1);
if (err)
goto done;
memcpy(priv->params_ethtool.fec_mask_10x_25x, fec_mask_10x_25x,
sizeof(priv->params_ethtool.fec_mask_10x_25x));
mlx5_toggle_port_link(priv->mdev);
done:
PRIV_UNLOCK(priv);
return (err);
}
static int
mlx5e_fec_avail_10x_25x_handler(SYSCTL_HANDLER_ARGS)
{
struct mlx5e_priv *priv = arg1;
int err;
PRIV_LOCK(priv);
err = SYSCTL_OUT(req, priv->params_ethtool.fec_avail_10x_25x,
sizeof(priv->params_ethtool.fec_avail_10x_25x));
PRIV_UNLOCK(priv);
return (err);
}
static int
mlx5e_fec_mask_50x_handler(SYSCTL_HANDLER_ARGS)
{
struct mlx5e_priv *priv = arg1;
struct mlx5_core_dev *mdev = priv->mdev;
u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
const int sz = MLX5_ST_SZ_BYTES(pplm_reg);
u16 fec_mask_50x[MLX5E_MAX_FEC_50X];
u16 fec_cap_changed = 0;
u8 x;
int err;
PRIV_LOCK(priv);
err = SYSCTL_OUT(req, priv->params_ethtool.fec_mask_50x,
sizeof(priv->params_ethtool.fec_mask_50x));
if (err || !req->newptr)
goto done;
err = SYSCTL_IN(req, fec_mask_50x,
sizeof(fec_mask_50x));
if (err)
goto done;
if (!MLX5_CAP_GEN(mdev, pcam_reg)) {
err = EOPNOTSUPP;
goto done;
}
if (!MLX5_CAP_PCAM_REG(mdev, pplm)) {
err = EOPNOTSUPP;
goto done;
}
MLX5_SET(pplm_reg, in, local_port, 1);
err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0);
if (err)
goto done;
/* range check input value */
for (x = 0; x != MLX5E_MAX_FEC_50X; x++) {
/* check only one bit is set, if any */
if (fec_mask_50x[x] & (fec_mask_50x[x] - 1)) {
err = ERANGE;
goto done;
}
/* check a supported bit is set, if any */
if (fec_mask_50x[x] &
~priv->params_ethtool.fec_avail_50x[x]) {
err = ERANGE;
goto done;
}
fec_cap_changed |= (fec_mask_50x[x] ^
priv->params_ethtool.fec_mask_50x[x]);
}
/* check for no changes */
if (fec_cap_changed == 0)
goto done;
memset(in, 0, sizeof(in));
MLX5_SET(pplm_reg, in, local_port, 1);
/* set new values */
MLX5_SET(pplm_reg, in, fec_override_admin_50g_1x, fec_mask_50x[0]);
MLX5_SET(pplm_reg, in, fec_override_admin_100g_2x, fec_mask_50x[1]);
MLX5_SET(pplm_reg, in, fec_override_admin_200g_4x, fec_mask_50x[2]);
MLX5_SET(pplm_reg, in, fec_override_admin_400g_8x, fec_mask_50x[3]);
/* preserve other values */
MLX5_SET(pplm_reg, in, fec_override_admin_10g_40g, priv->params_ethtool.fec_mask_10x_25x[0]);
MLX5_SET(pplm_reg, in, fec_override_admin_25g, priv->params_ethtool.fec_mask_10x_25x[1]);
MLX5_SET(pplm_reg, in, fec_override_admin_50g, priv->params_ethtool.fec_mask_10x_25x[1]);
MLX5_SET(pplm_reg, in, fec_override_admin_56g, priv->params_ethtool.fec_mask_10x_25x[2]);
MLX5_SET(pplm_reg, in, fec_override_admin_100g, priv->params_ethtool.fec_mask_10x_25x[3]);
/* send new value to the firmware */
err = -mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1);
if (err)
goto done;
memcpy(priv->params_ethtool.fec_mask_50x, fec_mask_50x,
sizeof(priv->params_ethtool.fec_mask_50x));
mlx5_toggle_port_link(priv->mdev);
done:
PRIV_UNLOCK(priv);
return (err);
}
static int
mlx5e_fec_avail_50x_handler(SYSCTL_HANDLER_ARGS)
{
struct mlx5e_priv *priv = arg1;
int err;
PRIV_LOCK(priv);
err = SYSCTL_OUT(req, priv->params_ethtool.fec_avail_50x,
sizeof(priv->params_ethtool.fec_avail_50x));
PRIV_UNLOCK(priv);
return (err);
}
static int
mlx5e_trust_state_handler(SYSCTL_HANDLER_ARGS)
{
@ -1047,7 +1326,9 @@ mlx5e_create_diagnostics(struct mlx5e_priv *priv)
void
mlx5e_create_ethtool(struct mlx5e_priv *priv)
{
struct sysctl_oid *node, *qos_node;
struct sysctl_oid *fec_node;
struct sysctl_oid *qos_node;
struct sysctl_oid *node;
const char *pnameunit;
struct mlx5e_port_buffer port_buffer;
unsigned x;
@ -1128,6 +1409,54 @@ mlx5e_create_ethtool(struct mlx5e_priv *priv)
}
}
/* create fec node */
fec_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
SYSCTL_CHILDREN(node), OID_AUTO,
"fec", CTLFLAG_RW, NULL, "Forward Error Correction");
if (fec_node == NULL)
return;
if (mlx5e_fec_update(priv) == 0) {
SYSCTL_ADD_U32(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
"mode_active", CTLFLAG_RD | CTLFLAG_MPSAFE,
&priv->params_ethtool.fec_mode_active, 0,
"Current FEC mode bit, if any.");
SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
"mask_10x_25x", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
priv, 0, &mlx5e_fec_mask_10x_25x_handler, "CU",
"Set FEC masks for 10G_40G, 25G_50G, 56G, 100G respectivly. "
"0:Auto "
"1:NOFEC "
"2:FIRECODE "
"4:RS");
SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
"avail_10x_25x", CTLTYPE_U8 | CTLFLAG_RD | CTLFLAG_MPSAFE,
priv, 0, &mlx5e_fec_avail_10x_25x_handler, "CU",
"Get available FEC bits for 10G_40G, 25G_50G, 56G, 100G respectivly. "
"0:Auto "
"1:NOFEC "
"2:FIRECODE "
"4:RS");
SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
"mask_50x", CTLTYPE_U16 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
priv, 0, &mlx5e_fec_mask_50x_handler, "SU",
"Set FEC masks for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. "
"0:Auto "
"128:RS "
"512:LL RS");
SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
"avail_50x", CTLTYPE_U16 | CTLFLAG_RD | CTLFLAG_MPSAFE,
priv, 0, &mlx5e_fec_avail_50x_handler, "SU",
"Get available FEC bits for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. "
"0:Auto "
"128:RS "
"512:LL RS");
}
SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
"debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");

View File

@ -860,6 +860,7 @@ mlx5e_update_stats_locked(struct mlx5e_priv *priv)
u64 rx_packets = 0;
u64 rx_bytes = 0;
u32 rx_out_of_buffer = 0;
int error;
int i;
int j;
@ -1016,13 +1017,20 @@ mlx5e_update_stats_locked(struct mlx5e_priv *priv)
/* Update diagnostics, if any */
if (priv->params_ethtool.diag_pci_enable ||
priv->params_ethtool.diag_general_enable) {
int error = mlx5_core_get_diagnostics_full(mdev,
error = mlx5_core_get_diagnostics_full(mdev,
priv->params_ethtool.diag_pci_enable ? &priv->params_pci : NULL,
priv->params_ethtool.diag_general_enable ? &priv->params_general : NULL);
if (error != 0)
mlx5_en_err(priv->ifp,
"Failed reading diagnostics: %d\n", error);
}
/* Update FEC, if any */
error = mlx5e_fec_update(priv);
if (error != 0 && error != EOPNOTSUPP) {
mlx5_en_err(priv->ifp,
"Updating FEC failed: %d\n", error);
}
}
static void

View File

@ -7992,31 +7992,47 @@ struct mlx5_ifc_pplr_reg_bits {
};
struct mlx5_ifc_pplm_reg_bits {
u8 reserved_0[0x8];
u8 local_port[0x8];
u8 reserved_1[0x10];
u8 reserved_at_0[0x8];
u8 local_port[0x8];
u8 reserved_at_10[0x10];
u8 reserved_2[0x20];
u8 reserved_at_20[0x20];
u8 port_profile_mode[0x8];
u8 static_port_profile[0x8];
u8 active_port_profile[0x8];
u8 reserved_3[0x8];
u8 port_profile_mode[0x8];
u8 static_port_profile[0x8];
u8 active_port_profile[0x8];
u8 reserved_at_58[0x8];
u8 retransmission_active[0x8];
u8 fec_mode_active[0x18];
u8 retransmission_active[0x8];
u8 fec_mode_active[0x18];
u8 reserved_4[0x10];
u8 v_100g_fec_override_cap[0x4];
u8 v_50g_fec_override_cap[0x4];
u8 v_25g_fec_override_cap[0x4];
u8 v_10g_40g_fec_override_cap[0x4];
u8 rs_fec_correction_bypass_cap[0x4];
u8 reserved_at_84[0x8];
u8 fec_override_cap_56g[0x4];
u8 fec_override_cap_100g[0x4];
u8 fec_override_cap_50g[0x4];
u8 fec_override_cap_25g[0x4];
u8 fec_override_cap_10g_40g[0x4];
u8 reserved_5[0x10];
u8 v_100g_fec_override_admin[0x4];
u8 v_50g_fec_override_admin[0x4];
u8 v_25g_fec_override_admin[0x4];
u8 v_10g_40g_fec_override_admin[0x4];
u8 rs_fec_correction_bypass_admin[0x4];
u8 reserved_at_a4[0x8];
u8 fec_override_admin_56g[0x4];
u8 fec_override_admin_100g[0x4];
u8 fec_override_admin_50g[0x4];
u8 fec_override_admin_25g[0x4];
u8 fec_override_admin_10g_40g[0x4];
u8 fec_override_cap_400g_8x[0x10];
u8 fec_override_cap_200g_4x[0x10];
u8 fec_override_cap_100g_2x[0x10];
u8 fec_override_cap_50g_1x[0x10];
u8 fec_override_admin_400g_8x[0x10];
u8 fec_override_admin_200g_4x[0x10];
u8 fec_override_admin_100g_2x[0x10];
u8 fec_override_admin_50g_1x[0x10];
u8 reserved_at_140[0xC0];
};
struct mlx5_ifc_ppll_reg_bits {
@ -8610,6 +8626,22 @@ struct mlx5_ifc_pcam_enhanced_features_bits {
u8 ppcnt_statistical_group[0x1];
};
struct mlx5_ifc_pcam_regs_5000_to_507f_bits {
u8 port_access_reg_cap_mask_127_to_96[0x20];
u8 port_access_reg_cap_mask_95_to_64[0x20];
u8 port_access_reg_cap_mask_63_to_36[0x1c];
u8 pplm[0x1];
u8 port_access_reg_cap_mask_34_to_32[0x3];
u8 port_access_reg_cap_mask_31_to_13[0x13];
u8 pbmc[0x1];
u8 pptb[0x1];
u8 port_access_reg_cap_mask_10_to_09[0x2];
u8 ppcnt[0x1];
u8 port_access_reg_cap_mask_07_to_00[0x8];
};
struct mlx5_ifc_pcam_reg_bits {
u8 reserved_at_0[0x8];
u8 feature_group[0x8];
@ -8619,6 +8651,7 @@ struct mlx5_ifc_pcam_reg_bits {
u8 reserved_at_20[0x20];
union {
struct mlx5_ifc_pcam_regs_5000_to_507f_bits regs_5000_to_507f;
u8 reserved_at_0[0x80];
} port_access_reg_cap_mask;