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_200GAUI_4_200GBASE_CR4_KR4]      = 200000,
  77        [MLX5E_400GAUI_8]                       = 400000,
  78};
  79
  80static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
  81                                     const u32 **arr, u32 *size,
  82                                     bool force_legacy)
  83{
  84        bool ext = force_legacy ? false : MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
  85
  86        *size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
  87                      ARRAY_SIZE(mlx5e_link_speed);
  88        *arr  = ext ? mlx5e_ext_link_speed : mlx5e_link_speed;
  89}
  90
  91int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext,
  92                              struct mlx5e_port_eth_proto *eproto)
  93{
  94        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
  95        int err;
  96
  97        if (!eproto)
  98                return -EINVAL;
  99
 100        err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port);
 101        if (err)
 102                return err;
 103
 104        eproto->cap   = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
 105                                           eth_proto_capability);
 106        eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin);
 107        eproto->oper  = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper);
 108        return 0;
 109}
 110
 111void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status,
 112                                 u8 *an_disable_cap, u8 *an_disable_admin)
 113{
 114        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 115
 116        *an_status = 0;
 117        *an_disable_cap = 0;
 118        *an_disable_admin = 0;
 119
 120        if (mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, 1))
 121                return;
 122
 123        *an_status = MLX5_GET(ptys_reg, out, an_status);
 124        *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
 125        *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
 126}
 127
 128int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable,
 129                           u32 proto_admin, bool ext)
 130{
 131        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 132        u32 in[MLX5_ST_SZ_DW(ptys_reg)];
 133        u8 an_disable_admin;
 134        u8 an_disable_cap;
 135        u8 an_status;
 136
 137        mlx5_port_query_eth_autoneg(dev, &an_status, &an_disable_cap,
 138                                    &an_disable_admin);
 139        if (!an_disable_cap && an_disable)
 140                return -EPERM;
 141
 142        memset(in, 0, sizeof(in));
 143
 144        MLX5_SET(ptys_reg, in, local_port, 1);
 145        MLX5_SET(ptys_reg, in, an_disable_admin, an_disable);
 146        MLX5_SET(ptys_reg, in, proto_mask, MLX5_PTYS_EN);
 147        if (ext)
 148                MLX5_SET(ptys_reg, in, ext_eth_proto_admin, proto_admin);
 149        else
 150                MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
 151
 152        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 153                            sizeof(out), MLX5_REG_PTYS, 0, 1);
 154}
 155
 156u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper,
 157                          bool force_legacy)
 158{
 159        unsigned long temp = eth_proto_oper;
 160        const u32 *table;
 161        u32 speed = 0;
 162        u32 max_size;
 163        int i;
 164
 165        mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
 166        i = find_first_bit(&temp, max_size);
 167        if (i < max_size)
 168                speed = table[i];
 169        return speed;
 170}
 171
 172int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
 173{
 174        struct mlx5e_port_eth_proto eproto;
 175        bool force_legacy = false;
 176        bool ext;
 177        int err;
 178
 179        ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
 180        err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
 181        if (err)
 182                goto out;
 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);
 190        if (!(*speed))
 191                err = -EINVAL;
 192
 193out:
 194        return err;
 195}
 196
 197int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
 198{
 199        struct mlx5e_port_eth_proto eproto;
 200        u32 max_speed = 0;
 201        const u32 *table;
 202        u32 max_size;
 203        bool ext;
 204        int err;
 205        int i;
 206
 207        ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
 208        err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
 209        if (err)
 210                return err;
 211
 212        mlx5e_port_get_speed_arr(mdev, &table, &max_size, false);
 213        for (i = 0; i < max_size; ++i)
 214                if (eproto.cap & MLX5E_PROT_MASK(i))
 215                        max_speed = max(max_speed, table[i]);
 216
 217        *speed = max_speed;
 218        return 0;
 219}
 220
 221u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
 222                               bool force_legacy)
 223{
 224        u32 link_modes = 0;
 225        const u32 *table;
 226        u32 max_size;
 227        int i;
 228
 229        mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
 230        for (i = 0; i < max_size; ++i) {
 231                if (table[i] == speed)
 232                        link_modes |= MLX5E_PROT_MASK(i);
 233        }
 234        return link_modes;
 235}
 236
 237int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out)
 238{
 239        int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
 240        void *in;
 241        int err;
 242
 243        in = kzalloc(sz, GFP_KERNEL);
 244        if (!in)
 245                return -ENOMEM;
 246
 247        MLX5_SET(pbmc_reg, in, local_port, 1);
 248        err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0);
 249
 250        kfree(in);
 251        return err;
 252}
 253
 254int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in)
 255{
 256        int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
 257        void *out;
 258        int err;
 259
 260        out = kzalloc(sz, GFP_KERNEL);
 261        if (!out)
 262                return -ENOMEM;
 263
 264        MLX5_SET(pbmc_reg, in, local_port, 1);
 265        err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1);
 266
 267        kfree(out);
 268        return err;
 269}
 270
 271/* buffer[i]: buffer that priority i mapped to */
 272int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
 273{
 274        int sz = MLX5_ST_SZ_BYTES(pptb_reg);
 275        u32 prio_x_buff;
 276        void *out;
 277        void *in;
 278        int prio;
 279        int err;
 280
 281        in = kzalloc(sz, GFP_KERNEL);
 282        out = kzalloc(sz, GFP_KERNEL);
 283        if (!in || !out) {
 284                err = -ENOMEM;
 285                goto out;
 286        }
 287
 288        MLX5_SET(pptb_reg, in, local_port, 1);
 289        err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
 290        if (err)
 291                goto out;
 292
 293        prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff);
 294        for (prio = 0; prio < 8; prio++) {
 295                buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF;
 296                mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]);
 297        }
 298out:
 299        kfree(in);
 300        kfree(out);
 301        return err;
 302}
 303
 304int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
 305{
 306        int sz = MLX5_ST_SZ_BYTES(pptb_reg);
 307        u32 prio_x_buff;
 308        void *out;
 309        void *in;
 310        int prio;
 311        int err;
 312
 313        in = kzalloc(sz, GFP_KERNEL);
 314        out = kzalloc(sz, GFP_KERNEL);
 315        if (!in || !out) {
 316                err = -ENOMEM;
 317                goto out;
 318        }
 319
 320        /* First query the pptb register */
 321        MLX5_SET(pptb_reg, in, local_port, 1);
 322        err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
 323        if (err)
 324                goto out;
 325
 326        memcpy(in, out, sz);
 327        MLX5_SET(pptb_reg, in, local_port, 1);
 328
 329        /* Update the pm and prio_x_buff */
 330        MLX5_SET(pptb_reg, in, pm, 0xFF);
 331
 332        prio_x_buff = 0;
 333        for (prio = 0; prio < 8; prio++)
 334                prio_x_buff |= (buffer[prio] << (4 * prio));
 335        MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff);
 336
 337        err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1);
 338
 339out:
 340        kfree(in);
 341        kfree(out);
 342        return err;
 343}
 344
 345static u32 fec_supported_speeds[] = {
 346        10000,
 347        40000,
 348        25000,
 349        50000,
 350        56000,
 351        100000
 352};
 353
 354#define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds)
 355
 356/* get/set FEC admin field for a given speed */
 357static int mlx5e_fec_admin_field(u32 *pplm,
 358                                 u8 *fec_policy,
 359                                 bool write,
 360                                 u32 speed)
 361{
 362        switch (speed) {
 363        case 10000:
 364        case 40000:
 365                if (!write)
 366                        *fec_policy = MLX5_GET(pplm_reg, pplm,
 367                                               fec_override_admin_10g_40g);
 368                else
 369                        MLX5_SET(pplm_reg, pplm,
 370                                 fec_override_admin_10g_40g, *fec_policy);
 371                break;
 372        case 25000:
 373                if (!write)
 374                        *fec_policy = MLX5_GET(pplm_reg, pplm,
 375                                               fec_override_admin_25g);
 376                else
 377                        MLX5_SET(pplm_reg, pplm,
 378                                 fec_override_admin_25g, *fec_policy);
 379                break;
 380        case 50000:
 381                if (!write)
 382                        *fec_policy = MLX5_GET(pplm_reg, pplm,
 383                                               fec_override_admin_50g);
 384                else
 385                        MLX5_SET(pplm_reg, pplm,
 386                                 fec_override_admin_50g, *fec_policy);
 387                break;
 388        case 56000:
 389                if (!write)
 390                        *fec_policy = MLX5_GET(pplm_reg, pplm,
 391                                               fec_override_admin_56g);
 392                else
 393                        MLX5_SET(pplm_reg, pplm,
 394                                 fec_override_admin_56g, *fec_policy);
 395                break;
 396        case 100000:
 397                if (!write)
 398                        *fec_policy = MLX5_GET(pplm_reg, pplm,
 399                                               fec_override_admin_100g);
 400                else
 401                        MLX5_SET(pplm_reg, pplm,
 402                                 fec_override_admin_100g, *fec_policy);
 403                break;
 404        default:
 405                return -EINVAL;
 406        }
 407        return 0;
 408}
 409
 410/* returns FEC capabilities for a given speed */
 411static int mlx5e_get_fec_cap_field(u32 *pplm,
 412                                   u8 *fec_cap,
 413                                   u32 speed)
 414{
 415        switch (speed) {
 416        case 10000:
 417        case 40000:
 418                *fec_cap = MLX5_GET(pplm_reg, pplm,
 419                                    fec_override_cap_10g_40g);
 420                break;
 421        case 25000:
 422                *fec_cap = MLX5_GET(pplm_reg, pplm,
 423                                    fec_override_cap_25g);
 424                break;
 425        case 50000:
 426                *fec_cap = MLX5_GET(pplm_reg, pplm,
 427                                    fec_override_cap_50g);
 428                break;
 429        case 56000:
 430                *fec_cap = MLX5_GET(pplm_reg, pplm,
 431                                    fec_override_cap_56g);
 432                break;
 433        case 100000:
 434                *fec_cap = MLX5_GET(pplm_reg, pplm,
 435                                    fec_override_cap_100g);
 436                break;
 437        default:
 438                return -EINVAL;
 439        }
 440        return 0;
 441}
 442
 443int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps)
 444{
 445        u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
 446        u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
 447        int sz = MLX5_ST_SZ_BYTES(pplm_reg);
 448        u32 current_fec_speed;
 449        int err;
 450
 451        if (!MLX5_CAP_GEN(dev, pcam_reg))
 452                return -EOPNOTSUPP;
 453
 454        if (!MLX5_CAP_PCAM_REG(dev, pplm))
 455                return -EOPNOTSUPP;
 456
 457        MLX5_SET(pplm_reg, in, local_port, 1);
 458        err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
 459        if (err)
 460                return err;
 461
 462        err = mlx5e_port_linkspeed(dev, &current_fec_speed);
 463        if (err)
 464                return err;
 465
 466        return mlx5e_get_fec_cap_field(out, fec_caps, current_fec_speed);
 467}
 468
 469int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
 470                       u8 *fec_configured_mode)
 471{
 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        u32 link_speed;
 476        int err;
 477
 478        if (!MLX5_CAP_GEN(dev, pcam_reg))
 479                return -EOPNOTSUPP;
 480
 481        if (!MLX5_CAP_PCAM_REG(dev, pplm))
 482                return -EOPNOTSUPP;
 483
 484        MLX5_SET(pplm_reg, in, local_port, 1);
 485        err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
 486        if (err)
 487                return err;
 488
 489        *fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active);
 490
 491        if (!fec_configured_mode)
 492                return 0;
 493
 494        err = mlx5e_port_linkspeed(dev, &link_speed);
 495        if (err)
 496                return err;
 497
 498        return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed);
 499}
 500
 501int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
 502{
 503        u8 fec_policy_nofec = BIT(MLX5E_FEC_NOFEC);
 504        bool fec_mode_not_supp_in_speed = false;
 505        u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
 506        u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
 507        int sz = MLX5_ST_SZ_BYTES(pplm_reg);
 508        u8 fec_policy_auto = 0;
 509        u8 fec_caps = 0;
 510        int err;
 511        int i;
 512
 513        if (!MLX5_CAP_GEN(dev, pcam_reg))
 514                return -EOPNOTSUPP;
 515
 516        if (!MLX5_CAP_PCAM_REG(dev, pplm))
 517                return -EOPNOTSUPP;
 518
 519        MLX5_SET(pplm_reg, in, local_port, 1);
 520        err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
 521        if (err)
 522                return err;
 523
 524        MLX5_SET(pplm_reg, out, local_port, 1);
 525
 526        for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS; i++) {
 527                mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]);
 528                /* policy supported for link speed, or policy is auto */
 529                if (fec_caps & fec_policy || fec_policy == fec_policy_auto) {
 530                        mlx5e_fec_admin_field(out, &fec_policy, 1,
 531                                              fec_supported_speeds[i]);
 532                } else {
 533                        /* turn off FEC if supported. Else, leave it the same */
 534                        if (fec_caps & fec_policy_nofec)
 535                                mlx5e_fec_admin_field(out, &fec_policy_nofec, 1,
 536                                                      fec_supported_speeds[i]);
 537                        fec_mode_not_supp_in_speed = true;
 538                }
 539        }
 540
 541        if (fec_mode_not_supp_in_speed)
 542                mlx5_core_dbg(dev,
 543                              "FEC policy 0x%x is not supported for some speeds",
 544                              fec_policy);
 545
 546        return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1);
 547}
 548