linux/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2018, Mellanox Technologies. All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the
   8 * OpenIB.org BSD license below:
   9 *
  10 *     Redistribution and use in source and binary forms, with or
  11 *     without modification, are permitted provided that the following
  12 *     conditions are met:
  13 *
  14 *      - Redistributions of source code must retain the above
  15 *        copyright notice, this list of conditions and the following
  16 *        disclaimer.
  17 *
  18 *      - Redistributions in binary form must reproduce the above
  19 *        copyright notice, this list of conditions and the following
  20 *        disclaimer in the documentation and/or other materials
  21 *        provided with the distribution.
  22 *
  23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30 * SOFTWARE.
  31 */
  32
  33#include "port.h"
  34
  35/* speed in units of 1Mb */
  36static const u32 mlx5e_link_speed[MLX5E_LINK_MODES_NUMBER] = {
  37        [MLX5E_1000BASE_CX_SGMII] = 1000,
  38        [MLX5E_1000BASE_KX]       = 1000,
  39        [MLX5E_10GBASE_CX4]       = 10000,
  40        [MLX5E_10GBASE_KX4]       = 10000,
  41        [MLX5E_10GBASE_KR]        = 10000,
  42        [MLX5E_20GBASE_KR2]       = 20000,
  43        [MLX5E_40GBASE_CR4]       = 40000,
  44        [MLX5E_40GBASE_KR4]       = 40000,
  45        [MLX5E_56GBASE_R4]        = 56000,
  46        [MLX5E_10GBASE_CR]        = 10000,
  47        [MLX5E_10GBASE_SR]        = 10000,
  48        [MLX5E_10GBASE_ER]        = 10000,
  49        [MLX5E_40GBASE_SR4]       = 40000,
  50        [MLX5E_40GBASE_LR4]       = 40000,
  51        [MLX5E_50GBASE_SR2]       = 50000,
  52        [MLX5E_100GBASE_CR4]      = 100000,
  53        [MLX5E_100GBASE_SR4]      = 100000,
  54        [MLX5E_100GBASE_KR4]      = 100000,
  55        [MLX5E_100GBASE_LR4]      = 100000,
  56        [MLX5E_100BASE_TX]        = 100,
  57        [MLX5E_1000BASE_T]        = 1000,
  58        [MLX5E_10GBASE_T]         = 10000,
  59        [MLX5E_25GBASE_CR]        = 25000,
  60        [MLX5E_25GBASE_KR]        = 25000,
  61        [MLX5E_25GBASE_SR]        = 25000,
  62        [MLX5E_50GBASE_CR2]       = 50000,
  63        [MLX5E_50GBASE_KR2]       = 50000,
  64};
  65
  66static const u32 mlx5e_ext_link_speed[MLX5E_EXT_LINK_MODES_NUMBER] = {
  67        [MLX5E_SGMII_100M]                      = 100,
  68        [MLX5E_1000BASE_X_SGMII]                = 1000,
  69        [MLX5E_5GBASE_R]                        = 5000,
  70        [MLX5E_10GBASE_XFI_XAUI_1]              = 10000,
  71        [MLX5E_40GBASE_XLAUI_4_XLPPI_4]         = 40000,
  72        [MLX5E_25GAUI_1_25GBASE_CR_KR]          = 25000,
  73        [MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2] = 50000,
  74        [MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR]   = 50000,
  75        [MLX5E_CAUI_4_100GBASE_CR4_KR4]         = 100000,
  76        [MLX5E_100GAUI_2_100GBASE_CR2_KR2]      = 100000,
  77        [MLX5E_200GAUI_4_200GBASE_CR4_KR4]      = 200000,
  78        [MLX5E_400GAUI_8]                       = 400000,
  79        [MLX5E_100GAUI_1_100GBASE_CR_KR]        = 100000,
  80        [MLX5E_200GAUI_2_200GBASE_CR2_KR2]      = 200000,
  81        [MLX5E_400GAUI_4_400GBASE_CR4_KR4]      = 400000,
  82};
  83
  84bool mlx5e_ptys_ext_supported(struct mlx5_core_dev *mdev)
  85{
  86        struct mlx5e_port_eth_proto eproto;
  87        int err;
  88
  89        if (MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet))
  90                return true;
  91
  92        err = mlx5_port_query_eth_proto(mdev, 1, true, &eproto);
  93        if (err)
  94                return false;
  95
  96        return !!eproto.cap;
  97}
  98
  99static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
 100                                     const u32 **arr, u32 *size,
 101                                     bool force_legacy)
 102{
 103        bool ext = force_legacy ? false : mlx5e_ptys_ext_supported(mdev);
 104
 105        *size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
 106                      ARRAY_SIZE(mlx5e_link_speed);
 107        *arr  = ext ? mlx5e_ext_link_speed : mlx5e_link_speed;
 108}
 109
 110int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext,
 111                              struct mlx5e_port_eth_proto *eproto)
 112{
 113        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 114        int err;
 115
 116        if (!eproto)
 117                return -EINVAL;
 118
 119        err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port);
 120        if (err)
 121                return err;
 122
 123        eproto->cap   = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
 124                                           eth_proto_capability);
 125        eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin);
 126        eproto->oper  = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper);
 127        return 0;
 128}
 129
 130void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status,
 131                                 u8 *an_disable_cap, u8 *an_disable_admin)
 132{
 133        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 134
 135        *an_status = 0;
 136        *an_disable_cap = 0;
 137        *an_disable_admin = 0;
 138
 139        if (mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, 1))
 140                return;
 141
 142        *an_status = MLX5_GET(ptys_reg, out, an_status);
 143        *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
 144        *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
 145}
 146
 147int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable,
 148                           u32 proto_admin, bool ext)
 149{
 150        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 151        u32 in[MLX5_ST_SZ_DW(ptys_reg)];
 152        u8 an_disable_admin;
 153        u8 an_disable_cap;
 154        u8 an_status;
 155
 156        mlx5_port_query_eth_autoneg(dev, &an_status, &an_disable_cap,
 157                                    &an_disable_admin);
 158        if (!an_disable_cap && an_disable)
 159                return -EPERM;
 160
 161        memset(in, 0, sizeof(in));
 162
 163        MLX5_SET(ptys_reg, in, local_port, 1);
 164        MLX5_SET(ptys_reg, in, an_disable_admin, an_disable);
 165        MLX5_SET(ptys_reg, in, proto_mask, MLX5_PTYS_EN);
 166        if (ext)
 167                MLX5_SET(ptys_reg, in, ext_eth_proto_admin, proto_admin);
 168        else
 169                MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
 170
 171        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 172                            sizeof(out), MLX5_REG_PTYS, 0, 1);
 173}
 174
 175u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper,
 176                          bool force_legacy)
 177{
 178        unsigned long temp = eth_proto_oper;
 179        const u32 *table;
 180        u32 speed = 0;
 181        u32 max_size;
 182        int i;
 183
 184        mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
 185        i = find_first_bit(&temp, max_size);
 186        if (i < max_size)
 187                speed = table[i];
 188        return speed;
 189}
 190
 191int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
 192{
 193        struct mlx5e_port_eth_proto eproto;
 194        bool force_legacy = false;
 195        bool ext;
 196        int err;
 197
 198        ext = mlx5e_ptys_ext_supported(mdev);
 199        err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
 200        if (err)
 201                goto out;
 202        if (ext && !eproto.admin) {
 203                force_legacy = true;
 204                err = mlx5_port_query_eth_proto(mdev, 1, false, &eproto);
 205                if (err)
 206                        goto out;
 207        }
 208        *speed = mlx5e_port_ptys2speed(mdev, eproto.oper, force_legacy);
 209        if (!(*speed))
 210                err = -EINVAL;
 211
 212out:
 213        return err;
 214}
 215
 216int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
 217{
 218        struct mlx5e_port_eth_proto eproto;
 219        u32 max_speed = 0;
 220        const u32 *table;
 221        u32 max_size;
 222        bool ext;
 223        int err;
 224        int i;
 225
 226        ext = mlx5e_ptys_ext_supported(mdev);
 227        err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
 228        if (err)
 229                return err;
 230
 231        mlx5e_port_get_speed_arr(mdev, &table, &max_size, false);
 232        for (i = 0; i < max_size; ++i)
 233                if (eproto.cap & MLX5E_PROT_MASK(i))
 234                        max_speed = max(max_speed, table[i]);
 235
 236        *speed = max_speed;
 237        return 0;
 238}
 239
 240u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
 241                               bool force_legacy)
 242{
 243        u32 link_modes = 0;
 244        const u32 *table;
 245        u32 max_size;
 246        int i;
 247
 248        mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
 249        for (i = 0; i < max_size; ++i) {
 250                if (table[i] == speed)
 251                        link_modes |= MLX5E_PROT_MASK(i);
 252        }
 253        return link_modes;
 254}
 255
 256int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out)
 257{
 258        int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
 259        void *in;
 260        int err;
 261
 262        in = kzalloc(sz, GFP_KERNEL);
 263        if (!in)
 264                return -ENOMEM;
 265
 266        MLX5_SET(pbmc_reg, in, local_port, 1);
 267        err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0);
 268
 269        kfree(in);
 270        return err;
 271}
 272
 273int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in)
 274{
 275        int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
 276        void *out;
 277        int err;
 278
 279        out = kzalloc(sz, GFP_KERNEL);
 280        if (!out)
 281                return -ENOMEM;
 282
 283        MLX5_SET(pbmc_reg, in, local_port, 1);
 284        err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1);
 285
 286        kfree(out);
 287        return err;
 288}
 289
 290/* buffer[i]: buffer that priority i mapped to */
 291int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
 292{
 293        int sz = MLX5_ST_SZ_BYTES(pptb_reg);
 294        u32 prio_x_buff;
 295        void *out;
 296        void *in;
 297        int prio;
 298        int err;
 299
 300        in = kzalloc(sz, GFP_KERNEL);
 301        out = kzalloc(sz, GFP_KERNEL);
 302        if (!in || !out) {
 303                err = -ENOMEM;
 304                goto out;
 305        }
 306
 307        MLX5_SET(pptb_reg, in, local_port, 1);
 308        err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
 309        if (err)
 310                goto out;
 311
 312        prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff);
 313        for (prio = 0; prio < 8; prio++) {
 314                buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF;
 315                mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]);
 316        }
 317out:
 318        kfree(in);
 319        kfree(out);
 320        return err;
 321}
 322
 323int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
 324{
 325        int sz = MLX5_ST_SZ_BYTES(pptb_reg);
 326        u32 prio_x_buff;
 327        void *out;
 328        void *in;
 329        int prio;
 330        int err;
 331
 332        in = kzalloc(sz, GFP_KERNEL);
 333        out = kzalloc(sz, GFP_KERNEL);
 334        if (!in || !out) {
 335                err = -ENOMEM;
 336                goto out;
 337        }
 338
 339        /* First query the pptb register */
 340        MLX5_SET(pptb_reg, in, local_port, 1);
 341        err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
 342        if (err)
 343                goto out;
 344
 345        memcpy(in, out, sz);
 346        MLX5_SET(pptb_reg, in, local_port, 1);
 347
 348        /* Update the pm and prio_x_buff */
 349        MLX5_SET(pptb_reg, in, pm, 0xFF);
 350
 351        prio_x_buff = 0;
 352        for (prio = 0; prio < 8; prio++)
 353                prio_x_buff |= (buffer[prio] << (4 * prio));
 354        MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff);
 355
 356        err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1);
 357
 358out:
 359        kfree(in);
 360        kfree(out);
 361        return err;
 362}
 363
 364enum mlx5e_fec_supported_link_mode {
 365        MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G,
 366        MLX5E_FEC_SUPPORTED_LINK_MODES_25G,
 367        MLX5E_FEC_SUPPORTED_LINK_MODES_50G,
 368        MLX5E_FEC_SUPPORTED_LINK_MODES_56G,
 369        MLX5E_FEC_SUPPORTED_LINK_MODES_100G,
 370        MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X,
 371        MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X,
 372        MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X,
 373        MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X,
 374        MLX5E_MAX_FEC_SUPPORTED_LINK_MODE,
 375};
 376
 377#define MLX5E_FEC_FIRST_50G_PER_LANE_MODE MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X
 378
 379#define MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, policy, write, link)                       \
 380        do {                                                                            \
 381                u16 *_policy = &(policy);                                               \
 382                u32 *_buf = buf;                                                        \
 383                                                                                        \
 384                if (write)                                                              \
 385                        MLX5_SET(pplm_reg, _buf, fec_override_admin_##link, *_policy);  \
 386                else                                                                    \
 387                        *_policy = MLX5_GET(pplm_reg, _buf, fec_override_admin_##link); \
 388        } while (0)
 389
 390/* get/set FEC admin field for a given speed */
 391static int mlx5e_fec_admin_field(u32 *pplm, u16 *fec_policy, bool write,
 392                                 enum mlx5e_fec_supported_link_mode link_mode)
 393{
 394        switch (link_mode) {
 395        case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G:
 396                MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 10g_40g);
 397                break;
 398        case MLX5E_FEC_SUPPORTED_LINK_MODES_25G:
 399                MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 25g);
 400                break;
 401        case MLX5E_FEC_SUPPORTED_LINK_MODES_50G:
 402                MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 50g);
 403                break;
 404        case MLX5E_FEC_SUPPORTED_LINK_MODES_56G:
 405                MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 56g);
 406                break;
 407        case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
 408                MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 100g);
 409                break;
 410        case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
 411                MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 50g_1x);
 412                break;
 413        case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
 414                MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 100g_2x);
 415                break;
 416        case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
 417                MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 200g_4x);
 418                break;
 419        case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
 420                MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 400g_8x);
 421                break;
 422        default:
 423                return -EINVAL;
 424        }
 425        return 0;
 426}
 427
 428#define MLX5E_GET_FEC_OVERRIDE_CAP(buf, link)  \
 429        MLX5_GET(pplm_reg, buf, fec_override_cap_##link)
 430
 431/* returns FEC capabilities for a given speed */
 432static int mlx5e_get_fec_cap_field(u32 *pplm, u16 *fec_cap,
 433                                   enum mlx5e_fec_supported_link_mode link_mode)
 434{
 435        switch (link_mode) {
 436        case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G:
 437                *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 10g_40g);
 438                break;
 439        case MLX5E_FEC_SUPPORTED_LINK_MODES_25G:
 440                *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 25g);
 441                break;
 442        case MLX5E_FEC_SUPPORTED_LINK_MODES_50G:
 443                *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g);
 444                break;
 445        case MLX5E_FEC_SUPPORTED_LINK_MODES_56G:
 446                *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 56g);
 447                break;
 448        case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
 449                *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g);
 450                break;
 451        case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
 452                *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g_1x);
 453                break;
 454        case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
 455                *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g_2x);
 456                break;
 457        case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
 458                *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 200g_4x);
 459                break;
 460        case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
 461                *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 400g_8x);
 462                break;
 463        default:
 464                return -EINVAL;
 465        }
 466        return 0;
 467}
 468
 469bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy)
 470{
 471        bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
 472        u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
 473        u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
 474        int sz = MLX5_ST_SZ_BYTES(pplm_reg);
 475        int err;
 476        int i;
 477
 478        if (!MLX5_CAP_GEN(dev, pcam_reg) || !MLX5_CAP_PCAM_REG(dev, pplm))
 479                return false;
 480
 481        MLX5_SET(pplm_reg, in, local_port, 1);
 482        err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
 483        if (err)
 484                return false;
 485
 486        for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
 487                u16 fec_caps;
 488
 489                if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
 490                        break;
 491
 492                mlx5e_get_fec_cap_field(out, &fec_caps, i);
 493                if (fec_caps & fec_policy)
 494                        return true;
 495        }
 496        return false;
 497}
 498
 499int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
 500                       u16 *fec_configured_mode)
 501{
 502        bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
 503        u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
 504        u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
 505        int sz = MLX5_ST_SZ_BYTES(pplm_reg);
 506        int err;
 507        int i;
 508
 509        if (!MLX5_CAP_GEN(dev, pcam_reg))
 510                return -EOPNOTSUPP;
 511
 512        if (!MLX5_CAP_PCAM_REG(dev, pplm))
 513                return -EOPNOTSUPP;
 514
 515        MLX5_SET(pplm_reg, in, local_port, 1);
 516        err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
 517        if (err)
 518                return err;
 519
 520        *fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active);
 521
 522        if (!fec_configured_mode)
 523                goto out;
 524
 525        *fec_configured_mode = 0;
 526        for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
 527                if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
 528                        break;
 529
 530                mlx5e_fec_admin_field(out, fec_configured_mode, 0, i);
 531                if (*fec_configured_mode != 0)
 532                        goto out;
 533        }
 534out:
 535        return 0;
 536}
 537
 538int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
 539{
 540        bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
 541        u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
 542        u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
 543        int sz = MLX5_ST_SZ_BYTES(pplm_reg);
 544        u16 fec_policy_auto = 0;
 545        int err;
 546        int i;
 547
 548        if (!MLX5_CAP_GEN(dev, pcam_reg))
 549                return -EOPNOTSUPP;
 550
 551        if (!MLX5_CAP_PCAM_REG(dev, pplm))
 552                return -EOPNOTSUPP;
 553
 554        if (fec_policy >= (1 << MLX5E_FEC_LLRS_272_257_1) && !fec_50g_per_lane)
 555                return -EOPNOTSUPP;
 556
 557        if (fec_policy && !mlx5e_fec_in_caps(dev, fec_policy))
 558                return -EOPNOTSUPP;
 559
 560        MLX5_SET(pplm_reg, in, local_port, 1);
 561        err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
 562        if (err)
 563                return err;
 564
 565        MLX5_SET(pplm_reg, out, local_port, 1);
 566
 567        for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
 568                u16 conf_fec = fec_policy;
 569                u16 fec_caps = 0;
 570
 571                if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
 572                        break;
 573
 574                /* RS fec in ethtool is mapped to MLX5E_FEC_RS_528_514
 575                 * to link modes up to 25G per lane and to
 576                 * MLX5E_FEC_RS_544_514 in the new link modes based on
 577                 * 50 G per lane
 578                 */
 579                if (conf_fec == (1 << MLX5E_FEC_RS_528_514) &&
 580                    i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE)
 581                        conf_fec = (1 << MLX5E_FEC_RS_544_514);
 582
 583                mlx5e_get_fec_cap_field(out, &fec_caps, i);
 584
 585                /* policy supported for link speed */
 586                if (fec_caps & conf_fec)
 587                        mlx5e_fec_admin_field(out, &conf_fec, 1, i);
 588                else
 589                        /* set FEC to auto*/
 590                        mlx5e_fec_admin_field(out, &fec_policy_auto, 1, i);
 591        }
 592
 593        return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1);
 594}
 595