linux/drivers/net/ethernet/mellanox/mlx5/core/port.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013-2015, 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 <linux/module.h>
  34#include <linux/mlx5/driver.h>
  35#include <linux/mlx5/port.h>
  36#include <linux/mlx5/cmd.h>
  37#include "mlx5_core.h"
  38
  39int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
  40                         int size_in, void *data_out, int size_out,
  41                         u16 reg_num, int arg, int write)
  42{
  43        struct mlx5_access_reg_mbox_in *in = NULL;
  44        struct mlx5_access_reg_mbox_out *out = NULL;
  45        int err = -ENOMEM;
  46
  47        in = mlx5_vzalloc(sizeof(*in) + size_in);
  48        if (!in)
  49                return -ENOMEM;
  50
  51        out = mlx5_vzalloc(sizeof(*out) + size_out);
  52        if (!out)
  53                goto ex1;
  54
  55        memcpy(in->data, data_in, size_in);
  56        in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ACCESS_REG);
  57        in->hdr.opmod = cpu_to_be16(!write);
  58        in->arg = cpu_to_be32(arg);
  59        in->register_id = cpu_to_be16(reg_num);
  60        err = mlx5_cmd_exec(dev, in, sizeof(*in) + size_in, out,
  61                            sizeof(*out) + size_out);
  62        if (err)
  63                goto ex2;
  64
  65        if (out->hdr.status)
  66                err = mlx5_cmd_status_to_err(&out->hdr);
  67
  68        if (!err)
  69                memcpy(data_out, out->data, size_out);
  70
  71ex2:
  72        kvfree(out);
  73ex1:
  74        kvfree(in);
  75        return err;
  76}
  77EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
  78
  79
  80struct mlx5_reg_pcap {
  81        u8                      rsvd0;
  82        u8                      port_num;
  83        u8                      rsvd1[2];
  84        __be32                  caps_127_96;
  85        __be32                  caps_95_64;
  86        __be32                  caps_63_32;
  87        __be32                  caps_31_0;
  88};
  89
  90int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
  91{
  92        struct mlx5_reg_pcap in;
  93        struct mlx5_reg_pcap out;
  94
  95        memset(&in, 0, sizeof(in));
  96        in.caps_127_96 = cpu_to_be32(caps);
  97        in.port_num = port_num;
  98
  99        return mlx5_core_access_reg(dev, &in, sizeof(in), &out,
 100                                    sizeof(out), MLX5_REG_PCAP, 0, 1);
 101}
 102EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
 103
 104int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
 105                         int ptys_size, int proto_mask, u8 local_port)
 106{
 107        u32 in[MLX5_ST_SZ_DW(ptys_reg)];
 108
 109        memset(in, 0, sizeof(in));
 110        MLX5_SET(ptys_reg, in, local_port, local_port);
 111        MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
 112
 113        return mlx5_core_access_reg(dev, in, sizeof(in), ptys,
 114                                    ptys_size, MLX5_REG_PTYS, 0, 0);
 115}
 116EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
 117
 118int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration)
 119{
 120        u32 out[MLX5_ST_SZ_DW(mlcr_reg)];
 121        u32 in[MLX5_ST_SZ_DW(mlcr_reg)];
 122
 123        memset(in, 0, sizeof(in));
 124        MLX5_SET(mlcr_reg, in, local_port, 1);
 125        MLX5_SET(mlcr_reg, in, beacon_duration, beacon_duration);
 126
 127        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 128                                    sizeof(out), MLX5_REG_MLCR, 0, 1);
 129}
 130
 131int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev,
 132                              u32 *proto_cap, int proto_mask)
 133{
 134        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 135        int err;
 136
 137        err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
 138        if (err)
 139                return err;
 140
 141        if (proto_mask == MLX5_PTYS_EN)
 142                *proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability);
 143        else
 144                *proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability);
 145
 146        return 0;
 147}
 148EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap);
 149
 150int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev,
 151                                u32 *proto_admin, int proto_mask)
 152{
 153        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 154        int err;
 155
 156        err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
 157        if (err)
 158                return err;
 159
 160        if (proto_mask == MLX5_PTYS_EN)
 161                *proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin);
 162        else
 163                *proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin);
 164
 165        return 0;
 166}
 167EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin);
 168
 169int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev,
 170                                    u8 *link_width_oper, u8 local_port)
 171{
 172        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 173        int err;
 174
 175        err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB, local_port);
 176        if (err)
 177                return err;
 178
 179        *link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper);
 180
 181        return 0;
 182}
 183EXPORT_SYMBOL_GPL(mlx5_query_port_link_width_oper);
 184
 185int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev,
 186                               u8 *proto_oper, int proto_mask,
 187                               u8 local_port)
 188{
 189        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 190        int err;
 191
 192        err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, local_port);
 193        if (err)
 194                return err;
 195
 196        if (proto_mask == MLX5_PTYS_EN)
 197                *proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
 198        else
 199                *proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
 200
 201        return 0;
 202}
 203EXPORT_SYMBOL_GPL(mlx5_query_port_proto_oper);
 204
 205int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable,
 206                       u32 proto_admin, int proto_mask)
 207{
 208        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 209        u32 in[MLX5_ST_SZ_DW(ptys_reg)];
 210        u8 an_disable_admin;
 211        u8 an_disable_cap;
 212        u8 an_status;
 213
 214        mlx5_query_port_autoneg(dev, proto_mask, &an_status,
 215                                &an_disable_cap, &an_disable_admin);
 216        if (!an_disable_cap && an_disable)
 217                return -EPERM;
 218
 219        memset(in, 0, sizeof(in));
 220
 221        MLX5_SET(ptys_reg, in, local_port, 1);
 222        MLX5_SET(ptys_reg, in, an_disable_admin, an_disable);
 223        MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
 224        if (proto_mask == MLX5_PTYS_EN)
 225                MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
 226        else
 227                MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin);
 228
 229        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 230                                    sizeof(out), MLX5_REG_PTYS, 0, 1);
 231}
 232EXPORT_SYMBOL_GPL(mlx5_set_port_ptys);
 233
 234/* This function should be used after setting a port register only */
 235void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
 236{
 237        enum mlx5_port_status ps;
 238
 239        mlx5_query_port_admin_status(dev, &ps);
 240        mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN);
 241        if (ps == MLX5_PORT_UP)
 242                mlx5_set_port_admin_status(dev, MLX5_PORT_UP);
 243}
 244EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
 245
 246int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
 247                               enum mlx5_port_status status)
 248{
 249        u32 in[MLX5_ST_SZ_DW(paos_reg)];
 250        u32 out[MLX5_ST_SZ_DW(paos_reg)];
 251
 252        memset(in, 0, sizeof(in));
 253
 254        MLX5_SET(paos_reg, in, local_port, 1);
 255        MLX5_SET(paos_reg, in, admin_status, status);
 256        MLX5_SET(paos_reg, in, ase, 1);
 257
 258        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 259                                    sizeof(out), MLX5_REG_PAOS, 0, 1);
 260}
 261EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status);
 262
 263int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
 264                                 enum mlx5_port_status *status)
 265{
 266        u32 in[MLX5_ST_SZ_DW(paos_reg)];
 267        u32 out[MLX5_ST_SZ_DW(paos_reg)];
 268        int err;
 269
 270        memset(in, 0, sizeof(in));
 271
 272        MLX5_SET(paos_reg, in, local_port, 1);
 273
 274        err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 275                                   sizeof(out), MLX5_REG_PAOS, 0, 0);
 276        if (err)
 277                return err;
 278
 279        *status = MLX5_GET(paos_reg, out, admin_status);
 280        return 0;
 281}
 282EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
 283
 284static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu,
 285                                u16 *max_mtu, u16 *oper_mtu, u8 port)
 286{
 287        u32 in[MLX5_ST_SZ_DW(pmtu_reg)];
 288        u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
 289
 290        memset(in, 0, sizeof(in));
 291
 292        MLX5_SET(pmtu_reg, in, local_port, port);
 293
 294        mlx5_core_access_reg(dev, in, sizeof(in), out,
 295                             sizeof(out), MLX5_REG_PMTU, 0, 0);
 296
 297        if (max_mtu)
 298                *max_mtu  = MLX5_GET(pmtu_reg, out, max_mtu);
 299        if (oper_mtu)
 300                *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
 301        if (admin_mtu)
 302                *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
 303}
 304
 305int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port)
 306{
 307        u32 in[MLX5_ST_SZ_DW(pmtu_reg)];
 308        u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
 309
 310        memset(in, 0, sizeof(in));
 311
 312        MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
 313        MLX5_SET(pmtu_reg, in, local_port, port);
 314
 315        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 316                                   sizeof(out), MLX5_REG_PMTU, 0, 1);
 317}
 318EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
 319
 320void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu,
 321                             u8 port)
 322{
 323        mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
 324}
 325EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
 326
 327void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
 328                              u8 port)
 329{
 330        mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
 331}
 332EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
 333
 334static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
 335{
 336        u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
 337        u32 in[MLX5_ST_SZ_DW(pmlp_reg)];
 338        int module_mapping;
 339        int err;
 340
 341        memset(in, 0, sizeof(in));
 342
 343        MLX5_SET(pmlp_reg, in, local_port, 1);
 344
 345        err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
 346                                   MLX5_REG_PMLP, 0, 0);
 347        if (err)
 348                return err;
 349
 350        module_mapping = MLX5_GET(pmlp_reg, out, lane0_module_mapping);
 351        *module_num = module_mapping & MLX5_EEPROM_IDENTIFIER_BYTE_MASK;
 352
 353        return 0;
 354}
 355
 356int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
 357                             u16 offset, u16 size, u8 *data)
 358{
 359        u32 out[MLX5_ST_SZ_DW(mcia_reg)];
 360        u32 in[MLX5_ST_SZ_DW(mcia_reg)];
 361        int module_num;
 362        u16 i2c_addr;
 363        int status;
 364        int err;
 365        void *ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
 366
 367        err = mlx5_query_module_num(dev, &module_num);
 368        if (err)
 369                return err;
 370
 371        memset(in, 0, sizeof(in));
 372        size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
 373
 374        if (offset < MLX5_EEPROM_PAGE_LENGTH &&
 375            offset + size > MLX5_EEPROM_PAGE_LENGTH)
 376                /* Cross pages read, read until offset 256 in low page */
 377                size -= offset + size - MLX5_EEPROM_PAGE_LENGTH;
 378
 379        i2c_addr = MLX5_I2C_ADDR_LOW;
 380        if (offset >= MLX5_EEPROM_PAGE_LENGTH) {
 381                i2c_addr = MLX5_I2C_ADDR_HIGH;
 382                offset -= MLX5_EEPROM_PAGE_LENGTH;
 383        }
 384
 385        MLX5_SET(mcia_reg, in, l, 0);
 386        MLX5_SET(mcia_reg, in, module, module_num);
 387        MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr);
 388        MLX5_SET(mcia_reg, in, page_number, 0);
 389        MLX5_SET(mcia_reg, in, device_address, offset);
 390        MLX5_SET(mcia_reg, in, size, size);
 391
 392        err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 393                                   sizeof(out), MLX5_REG_MCIA, 0, 0);
 394        if (err)
 395                return err;
 396
 397        status = MLX5_GET(mcia_reg, out, status);
 398        if (status) {
 399                mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
 400                              status);
 401                return -EIO;
 402        }
 403
 404        memcpy(data, ptr, size);
 405
 406        return size;
 407}
 408EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom);
 409
 410static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
 411                                int pvlc_size,  u8 local_port)
 412{
 413        u32 in[MLX5_ST_SZ_DW(pvlc_reg)];
 414
 415        memset(in, 0, sizeof(in));
 416        MLX5_SET(pvlc_reg, in, local_port, local_port);
 417
 418        return mlx5_core_access_reg(dev, in, sizeof(in), pvlc,
 419                                    pvlc_size, MLX5_REG_PVLC, 0, 0);
 420}
 421
 422int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
 423                              u8 *vl_hw_cap, u8 local_port)
 424{
 425        u32 out[MLX5_ST_SZ_DW(pvlc_reg)];
 426        int err;
 427
 428        err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port);
 429        if (err)
 430                return err;
 431
 432        *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
 433
 434        return 0;
 435}
 436EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap);
 437
 438int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev,
 439                             u8 port_num, void *out, size_t sz)
 440{
 441        u32 *in;
 442        int err;
 443
 444        in  = mlx5_vzalloc(sz);
 445        if (!in) {
 446                err = -ENOMEM;
 447                return err;
 448        }
 449
 450        MLX5_SET(ppcnt_reg, in, local_port, port_num);
 451
 452        MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP);
 453        err = mlx5_core_access_reg(dev, in, sz, out,
 454                                   sz, MLX5_REG_PPCNT, 0, 0);
 455
 456        kvfree(in);
 457        return err;
 458}
 459EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt);
 460
 461int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)
 462{
 463        u32 in[MLX5_ST_SZ_DW(pfcc_reg)];
 464        u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 465
 466        memset(in, 0, sizeof(in));
 467        MLX5_SET(pfcc_reg, in, local_port, 1);
 468        MLX5_SET(pfcc_reg, in, pptx, tx_pause);
 469        MLX5_SET(pfcc_reg, in, pprx, rx_pause);
 470
 471        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 472                                    sizeof(out), MLX5_REG_PFCC, 0, 1);
 473}
 474EXPORT_SYMBOL_GPL(mlx5_set_port_pause);
 475
 476int mlx5_query_port_pause(struct mlx5_core_dev *dev,
 477                          u32 *rx_pause, u32 *tx_pause)
 478{
 479        u32 in[MLX5_ST_SZ_DW(pfcc_reg)];
 480        u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 481        int err;
 482
 483        memset(in, 0, sizeof(in));
 484        MLX5_SET(pfcc_reg, in, local_port, 1);
 485
 486        err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 487                                   sizeof(out), MLX5_REG_PFCC, 0, 0);
 488        if (err)
 489                return err;
 490
 491        if (rx_pause)
 492                *rx_pause = MLX5_GET(pfcc_reg, out, pprx);
 493
 494        if (tx_pause)
 495                *tx_pause = MLX5_GET(pfcc_reg, out, pptx);
 496
 497        return 0;
 498}
 499EXPORT_SYMBOL_GPL(mlx5_query_port_pause);
 500
 501int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
 502{
 503        u32 in[MLX5_ST_SZ_DW(pfcc_reg)];
 504        u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 505
 506        memset(in, 0, sizeof(in));
 507        MLX5_SET(pfcc_reg, in, local_port, 1);
 508        MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
 509        MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
 510        MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
 511        MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
 512
 513        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 514                                    sizeof(out), MLX5_REG_PFCC, 0, 1);
 515}
 516EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
 517
 518int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
 519{
 520        u32 in[MLX5_ST_SZ_DW(pfcc_reg)];
 521        u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 522        int err;
 523
 524        memset(in, 0, sizeof(in));
 525        MLX5_SET(pfcc_reg, in, local_port, 1);
 526
 527        err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 528                                   sizeof(out), MLX5_REG_PFCC, 0, 0);
 529        if (err)
 530                return err;
 531
 532        if (pfc_en_tx)
 533                *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
 534
 535        if (pfc_en_rx)
 536                *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
 537
 538        return 0;
 539}
 540EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
 541
 542void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask,
 543                             u8 *an_status,
 544                             u8 *an_disable_cap, u8 *an_disable_admin)
 545{
 546        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 547
 548        *an_status = 0;
 549        *an_disable_cap = 0;
 550        *an_disable_admin = 0;
 551
 552        if (mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1))
 553                return;
 554
 555        *an_status = MLX5_GET(ptys_reg, out, an_status);
 556        *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
 557        *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
 558}
 559EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg);
 560
 561int mlx5_max_tc(struct mlx5_core_dev *mdev)
 562{
 563        u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
 564
 565        return num_tc - 1;
 566}
 567
 568int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
 569{
 570        u32 in[MLX5_ST_SZ_DW(qtct_reg)];
 571        u32 out[MLX5_ST_SZ_DW(qtct_reg)];
 572        int err;
 573        int i;
 574
 575        memset(in, 0, sizeof(in));
 576        for (i = 0; i < 8; i++) {
 577                if (prio_tc[i] > mlx5_max_tc(mdev))
 578                        return -EINVAL;
 579
 580                MLX5_SET(qtct_reg, in, prio, i);
 581                MLX5_SET(qtct_reg, in, tclass, prio_tc[i]);
 582
 583                err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
 584                                           sizeof(out), MLX5_REG_QTCT, 0, 1);
 585                if (err)
 586                        return err;
 587        }
 588
 589        return 0;
 590}
 591EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
 592
 593static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
 594                                   int inlen)
 595{
 596        u32 out[MLX5_ST_SZ_DW(qtct_reg)];
 597
 598        if (!MLX5_CAP_GEN(mdev, ets))
 599                return -ENOTSUPP;
 600
 601        return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
 602                                    MLX5_REG_QETCR, 0, 1);
 603}
 604
 605static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
 606                                     int outlen)
 607{
 608        u32 in[MLX5_ST_SZ_DW(qtct_reg)];
 609
 610        if (!MLX5_CAP_GEN(mdev, ets))
 611                return -ENOTSUPP;
 612
 613        memset(in, 0, sizeof(in));
 614        return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
 615                                    MLX5_REG_QETCR, 0, 0);
 616}
 617
 618int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
 619{
 620        u32 in[MLX5_ST_SZ_DW(qetc_reg)];
 621        int i;
 622
 623        memset(in, 0, sizeof(in));
 624
 625        for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 626                MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
 627                MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
 628        }
 629
 630        return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
 631}
 632EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
 633
 634int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
 635{
 636        u32 in[MLX5_ST_SZ_DW(qetc_reg)];
 637        int i;
 638
 639        memset(in, 0, sizeof(in));
 640
 641        for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 642                MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
 643                MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
 644        }
 645
 646        return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
 647}
 648EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
 649
 650int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
 651                                    u8 *max_bw_value,
 652                                    u8 *max_bw_units)
 653{
 654        u32 in[MLX5_ST_SZ_DW(qetc_reg)];
 655        void *ets_tcn_conf;
 656        int i;
 657
 658        memset(in, 0, sizeof(in));
 659
 660        MLX5_SET(qetc_reg, in, port_number, 1);
 661
 662        for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 663                ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
 664
 665                MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
 666                MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
 667                         max_bw_units[i]);
 668                MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
 669                         max_bw_value[i]);
 670        }
 671
 672        return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
 673}
 674EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit);
 675
 676int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
 677                                   u8 *max_bw_value,
 678                                   u8 *max_bw_units)
 679{
 680        u32 out[MLX5_ST_SZ_DW(qetc_reg)];
 681        void *ets_tcn_conf;
 682        int err;
 683        int i;
 684
 685        err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
 686        if (err)
 687                return err;
 688
 689        for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 690                ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
 691
 692                max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
 693                                           max_bw_value);
 694                max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
 695                                           max_bw_units);
 696        }
 697
 698        return 0;
 699}
 700EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit);
 701
 702int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode)
 703{
 704        u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)];
 705        u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)];
 706
 707        memset(in, 0, sizeof(in));
 708        memset(out, 0, sizeof(out));
 709
 710        MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
 711        MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
 712        MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
 713
 714        return mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
 715                                          out, sizeof(out));
 716}
 717EXPORT_SYMBOL_GPL(mlx5_set_port_wol);
 718
 719int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
 720{
 721        u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)];
 722        u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)];
 723        int err;
 724
 725        memset(in, 0, sizeof(in));
 726        memset(out, 0, sizeof(out));
 727
 728        MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
 729
 730        err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
 731                                         out, sizeof(out));
 732
 733        if (!err)
 734                *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
 735
 736        return err;
 737}
 738EXPORT_SYMBOL_GPL(mlx5_query_port_wol);
 739
 740static int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out,
 741                                  int outlen)
 742{
 743        u32 in[MLX5_ST_SZ_DW(pcmr_reg)];
 744
 745        memset(in, 0, sizeof(in));
 746        MLX5_SET(pcmr_reg, in, local_port, 1);
 747
 748        return mlx5_core_access_reg(mdev, in, sizeof(in), out,
 749                                    outlen, MLX5_REG_PCMR, 0, 0);
 750}
 751
 752static int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
 753{
 754        u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
 755
 756        return mlx5_core_access_reg(mdev, in, inlen, out,
 757                                    sizeof(out), MLX5_REG_PCMR, 0, 1);
 758}
 759
 760int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable)
 761{
 762        u32 in[MLX5_ST_SZ_DW(pcmr_reg)];
 763
 764        memset(in, 0, sizeof(in));
 765        MLX5_SET(pcmr_reg, in, local_port, 1);
 766        MLX5_SET(pcmr_reg, in, fcs_chk, enable);
 767
 768        return mlx5_set_ports_check(mdev, in, sizeof(in));
 769}
 770
 771void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
 772                         bool *enabled)
 773{
 774        u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
 775        /* Default values for FW which do not support MLX5_REG_PCMR */
 776        *supported = false;
 777        *enabled = true;
 778
 779        if (!MLX5_CAP_GEN(mdev, ports_check))
 780                return;
 781
 782        if (mlx5_query_ports_check(mdev, out, sizeof(out)))
 783                return;
 784
 785        *supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap));
 786        *enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
 787}
 788