net/mlx5e: Add support for FEC modes based on 50G per lane links
authorAya Levin <ayal@mellanox.com>
Tue, 11 Feb 2020 22:32:53 +0000 (14:32 -0800)
committerSaeed Mahameed <saeedm@mellanox.com>
Wed, 19 Feb 2020 03:17:31 +0000 (19:17 -0800)
Introduce new FEC modes:
- RS-FEC-(544,514)
- LL_RS-FEC-(272,257+1)
Add support in ethtool for set and get callbacks for the new modes
above. While RS-FEC-(544,514) is mapped to exsiting RS FEC mode,
LL_RS-FEC-(272,257+1) is mapped to a new ethtool link mode: LL-RS.

Add support for FEC on 50G per lane link modes up to 400G. The new link
modes uses a u16 fields instead of u8 fields for the legacy link modes.

Signed-off-by: Aya Levin <ayal@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/en/port.c
drivers/net/ethernet/mellanox/mlx5/core/en/port.h
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c

index 16c94950d206aff421cb2afd8c879aba8dbaa918..2c4a670c8ffd4b076460b5b7d6e8b70c7499e5f3 100644 (file)
@@ -349,12 +349,18 @@ enum mlx5e_fec_supported_link_mode {
        MLX5E_FEC_SUPPORTED_LINK_MODES_50G,
        MLX5E_FEC_SUPPORTED_LINK_MODES_56G,
        MLX5E_FEC_SUPPORTED_LINK_MODES_100G,
+       MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X,
+       MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X,
+       MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X,
+       MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X,
        MLX5E_MAX_FEC_SUPPORTED_LINK_MODE,
 };
 
+#define MLX5E_FEC_FIRST_50G_PER_LANE_MODE MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X
+
 #define MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, policy, write, link)                      \
        do {                                                                            \
-               u8 *_policy = &(policy);                                                \
+               u16 *_policy = &(policy);                                               \
                u32 *_buf = buf;                                                        \
                                                                                        \
                if (write)                                                              \
@@ -363,8 +369,21 @@ enum mlx5e_fec_supported_link_mode {
                        *_policy = MLX5_GET(pplm_reg, _buf, fec_override_admin_##link); \
        } while (0)
 
+#define MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(buf, policy, write, link)          \
+       do {                                                                    \
+               u16 *__policy = &(policy);                                      \
+               bool _write = (write);                                          \
+                                                                               \
+               if (_write && *__policy)                                        \
+                       *__policy = find_first_bit((u_long *)__policy,          \
+                                                  sizeof(u16) * BITS_PER_BYTE);\
+               MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, *__policy, _write, link);  \
+               if (!_write && *__policy)                                       \
+                       *__policy = 1 << *__policy;                             \
+       } while (0)
+
 /* get/set FEC admin field for a given speed */
-static int mlx5e_fec_admin_field(u32 *pplm, u8 *fec_policy, bool write,
+static int mlx5e_fec_admin_field(u32 *pplm, u16 *fec_policy, bool write,
                                 enum mlx5e_fec_supported_link_mode link_mode)
 {
        switch (link_mode) {
@@ -383,6 +402,18 @@ static int mlx5e_fec_admin_field(u32 *pplm, u8 *fec_policy, bool write,
        case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
                MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 100g);
                break;
+       case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
+               MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 50g_1x);
+               break;
+       case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
+               MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 100g_2x);
+               break;
+       case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
+               MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 200g_4x);
+               break;
+       case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
+               MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 400g_8x);
+               break;
        default:
                return -EINVAL;
        }
@@ -393,7 +424,7 @@ static int mlx5e_fec_admin_field(u32 *pplm, u8 *fec_policy, bool write,
        MLX5_GET(pplm_reg, buf, fec_override_cap_##link)
 
 /* returns FEC capabilities for a given speed */
-static int mlx5e_get_fec_cap_field(u32 *pplm, u8 *fec_cap,
+static int mlx5e_get_fec_cap_field(u32 *pplm, u16 *fec_cap,
                                   enum mlx5e_fec_supported_link_mode link_mode)
 {
        switch (link_mode) {
@@ -412,6 +443,18 @@ static int mlx5e_get_fec_cap_field(u32 *pplm, u8 *fec_cap,
        case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
                *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g);
                break;
+       case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
+               *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g_1x);
+               break;
+       case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
+               *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g_2x);
+               break;
+       case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
+               *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 200g_4x);
+               break;
+       case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
+               *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 400g_8x);
+               break;
        default:
                return -EINVAL;
        }
@@ -420,6 +463,7 @@ static int mlx5e_get_fec_cap_field(u32 *pplm, u8 *fec_cap,
 
 bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy)
 {
+       bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
        u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
        u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
        int sz = MLX5_ST_SZ_BYTES(pplm_reg);
@@ -438,7 +482,10 @@ bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy)
                return false;
 
        for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
-               u8 fec_caps;
+               u16 fec_caps;
+
+               if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
+                       break;
 
                mlx5e_get_fec_cap_field(out, &fec_caps, i);
                if (fec_caps & fec_policy)
@@ -448,8 +495,9 @@ bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy)
 }
 
 int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
-                      u8 *fec_configured_mode)
+                      u16 *fec_configured_mode)
 {
+       bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
        u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
        u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
        int sz = MLX5_ST_SZ_BYTES(pplm_reg);
@@ -474,6 +522,9 @@ int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
 
        *fec_configured_mode = 0;
        for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
+               if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
+                       break;
+
                mlx5e_fec_admin_field(out, fec_configured_mode, 0, i);
                if (*fec_configured_mode != 0)
                        goto out;
@@ -482,13 +533,13 @@ out:
        return 0;
 }
 
-int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
+int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
 {
+       bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
        u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
        u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
        int sz = MLX5_ST_SZ_BYTES(pplm_reg);
-       u8 fec_policy_auto = 0;
-       u8 fec_caps = 0;
+       u16 fec_policy_auto = 0;
        int err;
        int i;
 
@@ -498,6 +549,9 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
        if (!MLX5_CAP_PCAM_REG(dev, pplm))
                return -EOPNOTSUPP;
 
+       if (fec_policy >= (1 << MLX5E_FEC_LLRS_272_257_1) && !fec_50g_per_lane)
+               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)
@@ -506,10 +560,26 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
        MLX5_SET(pplm_reg, out, local_port, 1);
 
        for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
+               u16 conf_fec = fec_policy;
+               u16 fec_caps = 0;
+
+               if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
+                       break;
+
+               /* RS fec in ethtool is mapped to MLX5E_FEC_RS_528_514
+                * to link modes up to 25G per lane and to
+                * MLX5E_FEC_RS_544_514 in the new link modes based on
+                * 50 G per lane
+                */
+               if (conf_fec == (1 << MLX5E_FEC_RS_528_514) &&
+                   i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE)
+                       conf_fec = (1 << MLX5E_FEC_RS_544_514);
+
                mlx5e_get_fec_cap_field(out, &fec_caps, i);
+
                /* policy supported for link speed */
-               if (fec_caps & fec_policy)
-                       mlx5e_fec_admin_field(out, &fec_policy, 1, i);
+               if (fec_caps & conf_fec)
+                       mlx5e_fec_admin_field(out, &conf_fec, 1, i);
                else
                        /* set FEC to auto*/
                        mlx5e_fec_admin_field(out, &fec_policy_auto, 1, i);
index 025d865775678dd125da8541391d50648fd22794..a2ddd446dd59e66911bb3f55ee0941c855c66c7c 100644 (file)
@@ -62,13 +62,15 @@ int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
 
 bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy);
 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);
+                      u16 *fec_configured_mode);
+int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy);
 
 enum {
        MLX5E_FEC_NOFEC,
        MLX5E_FEC_FIRECODE,
        MLX5E_FEC_RS_528_514,
+       MLX5E_FEC_RS_544_514 = 7,
+       MLX5E_FEC_LLRS_272_257_1 = 9,
 };
 
 #endif
index 6624e0a82cd9e7be6e2ef157b5ec27a642ef3ce9..68b520df07e4694aabdac2bd679fa23a8d73afec 100644 (file)
@@ -633,6 +633,8 @@ static const u32 pplm_fec_2_ethtool[] = {
        [MLX5E_FEC_NOFEC] = ETHTOOL_FEC_OFF,
        [MLX5E_FEC_FIRECODE] = ETHTOOL_FEC_BASER,
        [MLX5E_FEC_RS_528_514] = ETHTOOL_FEC_RS,
+       [MLX5E_FEC_RS_544_514] = ETHTOOL_FEC_RS,
+       [MLX5E_FEC_LLRS_272_257_1] = ETHTOOL_FEC_LLRS,
 };
 
 static u32 pplm2ethtool_fec(u_long fec_mode, unsigned long size)
@@ -661,6 +663,8 @@ static const u32 pplm_fec_2_ethtool_linkmodes[] = {
        [MLX5E_FEC_NOFEC] = ETHTOOL_LINK_MODE_FEC_NONE_BIT,
        [MLX5E_FEC_FIRECODE] = ETHTOOL_LINK_MODE_FEC_BASER_BIT,
        [MLX5E_FEC_RS_528_514] = ETHTOOL_LINK_MODE_FEC_RS_BIT,
+       [MLX5E_FEC_RS_544_514] = ETHTOOL_LINK_MODE_FEC_RS_BIT,
+       [MLX5E_FEC_LLRS_272_257_1] = ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
 };
 
 static int get_fec_supported_advertised(struct mlx5_core_dev *dev,
@@ -680,6 +684,8 @@ static int get_fec_supported_advertised(struct mlx5_core_dev *dev,
                                      ETHTOOL_LINK_MODE_FEC_BASER_BIT);
        MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_RS_528_514,
                                      ETHTOOL_LINK_MODE_FEC_RS_BIT);
+       MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_LLRS_272_257_1,
+                                     ETHTOOL_LINK_MODE_FEC_LLRS_BIT);
 
        /* active fec is a bit set, find out which bit is set and
         * advertise the corresponding ethtool bit
@@ -1510,7 +1516,7 @@ static int mlx5e_get_fecparam(struct net_device *netdev,
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
-       u8 fec_configured = 0;
+       u16 fec_configured = 0;
        u32 fec_active = 0;
        int err;
 
@@ -1526,7 +1532,7 @@ static int mlx5e_get_fecparam(struct net_device *netdev,
                return -EOPNOTSUPP;
 
        fecparam->fec = pplm2ethtool_fec((u_long)fec_configured,
-                                        sizeof(u8) * BITS_PER_BYTE);
+                                        sizeof(u16) * BITS_PER_BYTE);
 
        return 0;
 }
@@ -1536,12 +1542,12 @@ static int mlx5e_set_fecparam(struct net_device *netdev,
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
-       u8 fec_policy = 0;
+       u16 fec_policy = 0;
        int mode;
        int err;
 
        if (bitmap_weight((unsigned long *)&fecparam->fec,
-                         ETHTOOL_FEC_BASER_BIT + 1) > 1)
+                         ETHTOOL_FEC_LLRS_BIT + 1) > 1)
                return -EOPNOTSUPP;
 
        for (mode = 0; mode < ARRAY_SIZE(pplm_fec_2_ethtool); mode++) {