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_id, int arg, int write)
  42{
  43        int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out;
  44        int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in;
  45        int err = -ENOMEM;
  46        u32 *out = NULL;
  47        u32 *in = NULL;
  48        void *data;
  49
  50        in = kvzalloc(inlen, GFP_KERNEL);
  51        out = kvzalloc(outlen, GFP_KERNEL);
  52        if (!in || !out)
  53                goto out;
  54
  55        data = MLX5_ADDR_OF(access_register_in, in, register_data);
  56        memcpy(data, data_in, size_in);
  57
  58        MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG);
  59        MLX5_SET(access_register_in, in, op_mod, !write);
  60        MLX5_SET(access_register_in, in, argument, arg);
  61        MLX5_SET(access_register_in, in, register_id, reg_id);
  62
  63        err = mlx5_cmd_exec(dev, in, inlen, out, outlen);
  64        if (err)
  65                goto out;
  66
  67        data = MLX5_ADDR_OF(access_register_out, out, register_data);
  68        memcpy(data_out, data, size_out);
  69
  70out:
  71        kvfree(out);
  72        kvfree(in);
  73        return err;
  74}
  75EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
  76
  77int mlx5_query_pcam_reg(struct mlx5_core_dev *dev, u32 *pcam, u8 feature_group,
  78                        u8 access_reg_group)
  79{
  80        u32 in[MLX5_ST_SZ_DW(pcam_reg)] = {0};
  81        int sz = MLX5_ST_SZ_BYTES(pcam_reg);
  82
  83        MLX5_SET(pcam_reg, in, feature_group, feature_group);
  84        MLX5_SET(pcam_reg, in, access_reg_group, access_reg_group);
  85
  86        return mlx5_core_access_reg(dev, in, sz, pcam, sz, MLX5_REG_PCAM, 0, 0);
  87}
  88
  89int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcam, u8 feature_group,
  90                        u8 access_reg_group)
  91{
  92        u32 in[MLX5_ST_SZ_DW(mcam_reg)] = {0};
  93        int sz = MLX5_ST_SZ_BYTES(mcam_reg);
  94
  95        MLX5_SET(mcam_reg, in, feature_group, feature_group);
  96        MLX5_SET(mcam_reg, in, access_reg_group, access_reg_group);
  97
  98        return mlx5_core_access_reg(dev, in, sz, mcam, sz, MLX5_REG_MCAM, 0, 0);
  99}
 100
 101struct mlx5_reg_pcap {
 102        u8                      rsvd0;
 103        u8                      port_num;
 104        u8                      rsvd1[2];
 105        __be32                  caps_127_96;
 106        __be32                  caps_95_64;
 107        __be32                  caps_63_32;
 108        __be32                  caps_31_0;
 109};
 110
 111int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
 112{
 113        struct mlx5_reg_pcap in;
 114        struct mlx5_reg_pcap out;
 115
 116        memset(&in, 0, sizeof(in));
 117        in.caps_127_96 = cpu_to_be32(caps);
 118        in.port_num = port_num;
 119
 120        return mlx5_core_access_reg(dev, &in, sizeof(in), &out,
 121                                    sizeof(out), MLX5_REG_PCAP, 0, 1);
 122}
 123EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
 124
 125int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
 126                         int ptys_size, int proto_mask, u8 local_port)
 127{
 128        u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0};
 129
 130        MLX5_SET(ptys_reg, in, local_port, local_port);
 131        MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
 132        return mlx5_core_access_reg(dev, in, sizeof(in), ptys,
 133                                    ptys_size, MLX5_REG_PTYS, 0, 0);
 134}
 135EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
 136
 137int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration)
 138{
 139        u32 in[MLX5_ST_SZ_DW(mlcr_reg)]  = {0};
 140        u32 out[MLX5_ST_SZ_DW(mlcr_reg)];
 141
 142        MLX5_SET(mlcr_reg, in, local_port, 1);
 143        MLX5_SET(mlcr_reg, in, beacon_duration, beacon_duration);
 144        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 145                                    sizeof(out), MLX5_REG_MLCR, 0, 1);
 146}
 147
 148int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev,
 149                              u32 *proto_cap, int proto_mask)
 150{
 151        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 152        int err;
 153
 154        err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
 155        if (err)
 156                return err;
 157
 158        if (proto_mask == MLX5_PTYS_EN)
 159                *proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability);
 160        else
 161                *proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability);
 162
 163        return 0;
 164}
 165EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap);
 166
 167int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev,
 168                                u32 *proto_admin, int proto_mask)
 169{
 170        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 171        int err;
 172
 173        err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
 174        if (err)
 175                return err;
 176
 177        if (proto_mask == MLX5_PTYS_EN)
 178                *proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin);
 179        else
 180                *proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin);
 181
 182        return 0;
 183}
 184EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin);
 185
 186int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev,
 187                                    u8 *link_width_oper, 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), MLX5_PTYS_IB, local_port);
 193        if (err)
 194                return err;
 195
 196        *link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper);
 197
 198        return 0;
 199}
 200EXPORT_SYMBOL_GPL(mlx5_query_port_link_width_oper);
 201
 202int mlx5_query_port_eth_proto_oper(struct mlx5_core_dev *dev,
 203                                   u32 *proto_oper, u8 local_port)
 204{
 205        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 206        int err;
 207
 208        err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN,
 209                                   local_port);
 210        if (err)
 211                return err;
 212
 213        *proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
 214
 215        return 0;
 216}
 217EXPORT_SYMBOL(mlx5_query_port_eth_proto_oper);
 218
 219int mlx5_query_port_ib_proto_oper(struct mlx5_core_dev *dev,
 220                                  u8 *proto_oper, u8 local_port)
 221{
 222        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 223        int err;
 224
 225        err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB,
 226                                   local_port);
 227        if (err)
 228                return err;
 229
 230        *proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
 231
 232        return 0;
 233}
 234EXPORT_SYMBOL(mlx5_query_port_ib_proto_oper);
 235
 236int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable,
 237                       u32 proto_admin, int proto_mask)
 238{
 239        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 240        u32 in[MLX5_ST_SZ_DW(ptys_reg)];
 241        u8 an_disable_admin;
 242        u8 an_disable_cap;
 243        u8 an_status;
 244
 245        mlx5_query_port_autoneg(dev, proto_mask, &an_status,
 246                                &an_disable_cap, &an_disable_admin);
 247        if (!an_disable_cap && an_disable)
 248                return -EPERM;
 249
 250        memset(in, 0, sizeof(in));
 251
 252        MLX5_SET(ptys_reg, in, local_port, 1);
 253        MLX5_SET(ptys_reg, in, an_disable_admin, an_disable);
 254        MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
 255        if (proto_mask == MLX5_PTYS_EN)
 256                MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
 257        else
 258                MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin);
 259
 260        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 261                                    sizeof(out), MLX5_REG_PTYS, 0, 1);
 262}
 263EXPORT_SYMBOL_GPL(mlx5_set_port_ptys);
 264
 265/* This function should be used after setting a port register only */
 266void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
 267{
 268        enum mlx5_port_status ps;
 269
 270        mlx5_query_port_admin_status(dev, &ps);
 271        mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN);
 272        if (ps == MLX5_PORT_UP)
 273                mlx5_set_port_admin_status(dev, MLX5_PORT_UP);
 274}
 275EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
 276
 277int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
 278                               enum mlx5_port_status status)
 279{
 280        u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
 281        u32 out[MLX5_ST_SZ_DW(paos_reg)];
 282
 283        MLX5_SET(paos_reg, in, local_port, 1);
 284        MLX5_SET(paos_reg, in, admin_status, status);
 285        MLX5_SET(paos_reg, in, ase, 1);
 286        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 287                                    sizeof(out), MLX5_REG_PAOS, 0, 1);
 288}
 289EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status);
 290
 291int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
 292                                 enum mlx5_port_status *status)
 293{
 294        u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
 295        u32 out[MLX5_ST_SZ_DW(paos_reg)];
 296        int err;
 297
 298        MLX5_SET(paos_reg, in, local_port, 1);
 299        err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 300                                   sizeof(out), MLX5_REG_PAOS, 0, 0);
 301        if (err)
 302                return err;
 303        *status = MLX5_GET(paos_reg, out, admin_status);
 304        return 0;
 305}
 306EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
 307
 308static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu,
 309                                u16 *max_mtu, u16 *oper_mtu, u8 port)
 310{
 311        u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
 312        u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
 313
 314        MLX5_SET(pmtu_reg, in, local_port, port);
 315        mlx5_core_access_reg(dev, in, sizeof(in), out,
 316                             sizeof(out), MLX5_REG_PMTU, 0, 0);
 317
 318        if (max_mtu)
 319                *max_mtu  = MLX5_GET(pmtu_reg, out, max_mtu);
 320        if (oper_mtu)
 321                *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
 322        if (admin_mtu)
 323                *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
 324}
 325
 326int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port)
 327{
 328        u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
 329        u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
 330
 331        MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
 332        MLX5_SET(pmtu_reg, in, local_port, port);
 333        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 334                                   sizeof(out), MLX5_REG_PMTU, 0, 1);
 335}
 336EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
 337
 338void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu,
 339                             u8 port)
 340{
 341        mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
 342}
 343EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
 344
 345void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
 346                              u8 port)
 347{
 348        mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
 349}
 350EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
 351
 352static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
 353{
 354        u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
 355        u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
 356        int module_mapping;
 357        int err;
 358
 359        MLX5_SET(pmlp_reg, in, local_port, 1);
 360        err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
 361                                   MLX5_REG_PMLP, 0, 0);
 362        if (err)
 363                return err;
 364
 365        module_mapping = MLX5_GET(pmlp_reg, out, lane0_module_mapping);
 366        *module_num = module_mapping & MLX5_EEPROM_IDENTIFIER_BYTE_MASK;
 367
 368        return 0;
 369}
 370
 371int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
 372                             u16 offset, u16 size, u8 *data)
 373{
 374        u32 out[MLX5_ST_SZ_DW(mcia_reg)];
 375        u32 in[MLX5_ST_SZ_DW(mcia_reg)];
 376        int module_num;
 377        u16 i2c_addr;
 378        int status;
 379        int err;
 380        void *ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
 381
 382        err = mlx5_query_module_num(dev, &module_num);
 383        if (err)
 384                return err;
 385
 386        memset(in, 0, sizeof(in));
 387        size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
 388
 389        if (offset < MLX5_EEPROM_PAGE_LENGTH &&
 390            offset + size > MLX5_EEPROM_PAGE_LENGTH)
 391                /* Cross pages read, read until offset 256 in low page */
 392                size -= offset + size - MLX5_EEPROM_PAGE_LENGTH;
 393
 394        i2c_addr = MLX5_I2C_ADDR_LOW;
 395        if (offset >= MLX5_EEPROM_PAGE_LENGTH) {
 396                i2c_addr = MLX5_I2C_ADDR_HIGH;
 397                offset -= MLX5_EEPROM_PAGE_LENGTH;
 398        }
 399
 400        MLX5_SET(mcia_reg, in, l, 0);
 401        MLX5_SET(mcia_reg, in, module, module_num);
 402        MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr);
 403        MLX5_SET(mcia_reg, in, page_number, 0);
 404        MLX5_SET(mcia_reg, in, device_address, offset);
 405        MLX5_SET(mcia_reg, in, size, size);
 406
 407        err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 408                                   sizeof(out), MLX5_REG_MCIA, 0, 0);
 409        if (err)
 410                return err;
 411
 412        status = MLX5_GET(mcia_reg, out, status);
 413        if (status) {
 414                mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
 415                              status);
 416                return -EIO;
 417        }
 418
 419        memcpy(data, ptr, size);
 420
 421        return size;
 422}
 423EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom);
 424
 425static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
 426                                int pvlc_size,  u8 local_port)
 427{
 428        u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0};
 429
 430        MLX5_SET(pvlc_reg, in, local_port, local_port);
 431        return mlx5_core_access_reg(dev, in, sizeof(in), pvlc,
 432                                    pvlc_size, MLX5_REG_PVLC, 0, 0);
 433}
 434
 435int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
 436                              u8 *vl_hw_cap, u8 local_port)
 437{
 438        u32 out[MLX5_ST_SZ_DW(pvlc_reg)];
 439        int err;
 440
 441        err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port);
 442        if (err)
 443                return err;
 444
 445        *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
 446
 447        return 0;
 448}
 449EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap);
 450
 451int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev,
 452                             u8 port_num, void *out, size_t sz)
 453{
 454        u32 *in;
 455        int err;
 456
 457        in  = kvzalloc(sz, GFP_KERNEL);
 458        if (!in) {
 459                err = -ENOMEM;
 460                return err;
 461        }
 462
 463        MLX5_SET(ppcnt_reg, in, local_port, port_num);
 464
 465        MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP);
 466        err = mlx5_core_access_reg(dev, in, sz, out,
 467                                   sz, MLX5_REG_PPCNT, 0, 0);
 468
 469        kvfree(in);
 470        return err;
 471}
 472EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt);
 473
 474int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)
 475{
 476        u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
 477        u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 478
 479        MLX5_SET(pfcc_reg, in, local_port, 1);
 480        MLX5_SET(pfcc_reg, in, pptx, tx_pause);
 481        MLX5_SET(pfcc_reg, in, pprx, rx_pause);
 482
 483        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 484                                    sizeof(out), MLX5_REG_PFCC, 0, 1);
 485}
 486EXPORT_SYMBOL_GPL(mlx5_set_port_pause);
 487
 488int mlx5_query_port_pause(struct mlx5_core_dev *dev,
 489                          u32 *rx_pause, u32 *tx_pause)
 490{
 491        u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
 492        u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 493        int err;
 494
 495        MLX5_SET(pfcc_reg, in, local_port, 1);
 496        err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 497                                   sizeof(out), MLX5_REG_PFCC, 0, 0);
 498        if (err)
 499                return err;
 500
 501        if (rx_pause)
 502                *rx_pause = MLX5_GET(pfcc_reg, out, pprx);
 503
 504        if (tx_pause)
 505                *tx_pause = MLX5_GET(pfcc_reg, out, pptx);
 506
 507        return 0;
 508}
 509EXPORT_SYMBOL_GPL(mlx5_query_port_pause);
 510
 511int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
 512{
 513        u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
 514        u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 515
 516        MLX5_SET(pfcc_reg, in, local_port, 1);
 517        MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
 518        MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
 519        MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
 520        MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
 521
 522        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 523                                    sizeof(out), MLX5_REG_PFCC, 0, 1);
 524}
 525EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
 526
 527int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
 528{
 529        u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
 530        u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
 531        int err;
 532
 533        MLX5_SET(pfcc_reg, in, local_port, 1);
 534        err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 535                                   sizeof(out), MLX5_REG_PFCC, 0, 0);
 536        if (err)
 537                return err;
 538
 539        if (pfc_en_tx)
 540                *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
 541
 542        if (pfc_en_rx)
 543                *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
 544
 545        return 0;
 546}
 547EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
 548
 549void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask,
 550                             u8 *an_status,
 551                             u8 *an_disable_cap, u8 *an_disable_admin)
 552{
 553        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
 554
 555        *an_status = 0;
 556        *an_disable_cap = 0;
 557        *an_disable_admin = 0;
 558
 559        if (mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1))
 560                return;
 561
 562        *an_status = MLX5_GET(ptys_reg, out, an_status);
 563        *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
 564        *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
 565}
 566EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg);
 567
 568int mlx5_max_tc(struct mlx5_core_dev *mdev)
 569{
 570        u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
 571
 572        return num_tc - 1;
 573}
 574
 575int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out)
 576{
 577        u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0};
 578
 579        MLX5_SET(dcbx_param, in, port_number, 1);
 580
 581        return  mlx5_core_access_reg(mdev, in, sizeof(in), out,
 582                                    sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0);
 583}
 584
 585int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in)
 586{
 587        u32 out[MLX5_ST_SZ_DW(dcbx_param)];
 588
 589        MLX5_SET(dcbx_param, in, port_number, 1);
 590
 591        return mlx5_core_access_reg(mdev, in, sizeof(out), out,
 592                                    sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1);
 593}
 594
 595int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
 596{
 597        u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0};
 598        u32 out[MLX5_ST_SZ_DW(qtct_reg)];
 599        int err;
 600        int i;
 601
 602        for (i = 0; i < 8; i++) {
 603                if (prio_tc[i] > mlx5_max_tc(mdev))
 604                        return -EINVAL;
 605
 606                MLX5_SET(qtct_reg, in, prio, i);
 607                MLX5_SET(qtct_reg, in, tclass, prio_tc[i]);
 608
 609                err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
 610                                           sizeof(out), MLX5_REG_QTCT, 0, 1);
 611                if (err)
 612                        return err;
 613        }
 614
 615        return 0;
 616}
 617EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
 618
 619int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
 620                            u8 prio, u8 *tc)
 621{
 622        u32 in[MLX5_ST_SZ_DW(qtct_reg)];
 623        u32 out[MLX5_ST_SZ_DW(qtct_reg)];
 624        int err;
 625
 626        memset(in, 0, sizeof(in));
 627        memset(out, 0, sizeof(out));
 628
 629        MLX5_SET(qtct_reg, in, port_number, 1);
 630        MLX5_SET(qtct_reg, in, prio, prio);
 631
 632        err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
 633                                   sizeof(out), MLX5_REG_QTCT, 0, 0);
 634        if (!err)
 635                *tc = MLX5_GET(qtct_reg, out, tclass);
 636
 637        return err;
 638}
 639EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
 640
 641static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
 642                                   int inlen)
 643{
 644        u32 out[MLX5_ST_SZ_DW(qtct_reg)];
 645
 646        if (!MLX5_CAP_GEN(mdev, ets))
 647                return -EOPNOTSUPP;
 648
 649        return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
 650                                    MLX5_REG_QETCR, 0, 1);
 651}
 652
 653static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
 654                                     int outlen)
 655{
 656        u32 in[MLX5_ST_SZ_DW(qtct_reg)];
 657
 658        if (!MLX5_CAP_GEN(mdev, ets))
 659                return -EOPNOTSUPP;
 660
 661        memset(in, 0, sizeof(in));
 662        return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
 663                                    MLX5_REG_QETCR, 0, 0);
 664}
 665
 666int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
 667{
 668        u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
 669        int i;
 670
 671        for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 672                MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
 673                MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
 674        }
 675
 676        return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
 677}
 678EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
 679
 680int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
 681                             u8 tc, u8 *tc_group)
 682{
 683        u32 out[MLX5_ST_SZ_DW(qetc_reg)];
 684        void *ets_tcn_conf;
 685        int err;
 686
 687        err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
 688        if (err)
 689                return err;
 690
 691        ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
 692                                    tc_configuration[tc]);
 693
 694        *tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
 695                             group);
 696
 697        return 0;
 698}
 699EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
 700
 701int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
 702{
 703        u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
 704        int i;
 705
 706        for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 707                MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
 708                MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
 709        }
 710
 711        return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
 712}
 713EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
 714
 715int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
 716                                u8 tc, u8 *bw_pct)
 717{
 718        u32 out[MLX5_ST_SZ_DW(qetc_reg)];
 719        void *ets_tcn_conf;
 720        int err;
 721
 722        err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
 723        if (err)
 724                return err;
 725
 726        ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
 727                                    tc_configuration[tc]);
 728
 729        *bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
 730                           bw_allocation);
 731
 732        return 0;
 733}
 734EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
 735
 736int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
 737                                    u8 *max_bw_value,
 738                                    u8 *max_bw_units)
 739{
 740        u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
 741        void *ets_tcn_conf;
 742        int i;
 743
 744        MLX5_SET(qetc_reg, in, port_number, 1);
 745
 746        for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 747                ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
 748
 749                MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
 750                MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
 751                         max_bw_units[i]);
 752                MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
 753                         max_bw_value[i]);
 754        }
 755
 756        return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
 757}
 758EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit);
 759
 760int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
 761                                   u8 *max_bw_value,
 762                                   u8 *max_bw_units)
 763{
 764        u32 out[MLX5_ST_SZ_DW(qetc_reg)];
 765        void *ets_tcn_conf;
 766        int err;
 767        int i;
 768
 769        err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
 770        if (err)
 771                return err;
 772
 773        for (i = 0; i <= mlx5_max_tc(mdev); i++) {
 774                ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
 775
 776                max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
 777                                           max_bw_value);
 778                max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
 779                                           max_bw_units);
 780        }
 781
 782        return 0;
 783}
 784EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit);
 785
 786int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode)
 787{
 788        u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)]   = {0};
 789        u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)] = {0};
 790
 791        MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
 792        MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
 793        MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
 794        return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
 795}
 796EXPORT_SYMBOL_GPL(mlx5_set_port_wol);
 797
 798int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
 799{
 800        u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)]   = {0};
 801        u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {0};
 802        int err;
 803
 804        MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
 805        err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
 806        if (!err)
 807                *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
 808
 809        return err;
 810}
 811EXPORT_SYMBOL_GPL(mlx5_query_port_wol);
 812
 813static int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out,
 814                                  int outlen)
 815{
 816        u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
 817
 818        MLX5_SET(pcmr_reg, in, local_port, 1);
 819        return mlx5_core_access_reg(mdev, in, sizeof(in), out,
 820                                    outlen, MLX5_REG_PCMR, 0, 0);
 821}
 822
 823static int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
 824{
 825        u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
 826
 827        return mlx5_core_access_reg(mdev, in, inlen, out,
 828                                    sizeof(out), MLX5_REG_PCMR, 0, 1);
 829}
 830
 831int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable)
 832{
 833        u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
 834
 835        MLX5_SET(pcmr_reg, in, local_port, 1);
 836        MLX5_SET(pcmr_reg, in, fcs_chk, enable);
 837        return mlx5_set_ports_check(mdev, in, sizeof(in));
 838}
 839
 840void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
 841                         bool *enabled)
 842{
 843        u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
 844        /* Default values for FW which do not support MLX5_REG_PCMR */
 845        *supported = false;
 846        *enabled = true;
 847
 848        if (!MLX5_CAP_GEN(mdev, ports_check))
 849                return;
 850
 851        if (mlx5_query_ports_check(mdev, out, sizeof(out)))
 852                return;
 853
 854        *supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap));
 855        *enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
 856}
 857
 858static const char *mlx5_pme_status[MLX5_MODULE_STATUS_NUM] = {
 859        "Cable plugged",   /* MLX5_MODULE_STATUS_PLUGGED    = 0x1 */
 860        "Cable unplugged", /* MLX5_MODULE_STATUS_UNPLUGGED  = 0x2 */
 861        "Cable error",     /* MLX5_MODULE_STATUS_ERROR      = 0x3 */
 862};
 863
 864static const char *mlx5_pme_error[MLX5_MODULE_EVENT_ERROR_NUM] = {
 865        "Power budget exceeded",
 866        "Long Range for non MLNX cable",
 867        "Bus stuck(I2C or data shorted)",
 868        "No EEPROM/retry timeout",
 869        "Enforce part number list",
 870        "Unknown identifier",
 871        "High Temperature",
 872        "Bad or shorted cable/module",
 873        "Unknown status",
 874};
 875
 876void mlx5_port_module_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe)
 877{
 878        enum port_module_event_status_type module_status;
 879        enum port_module_event_error_type error_type;
 880        struct mlx5_eqe_port_module *module_event_eqe;
 881        struct mlx5_priv *priv = &dev->priv;
 882        u8 module_num;
 883
 884        module_event_eqe = &eqe->data.port_module;
 885        module_num = module_event_eqe->module;
 886        module_status = module_event_eqe->module_status &
 887                        PORT_MODULE_EVENT_MODULE_STATUS_MASK;
 888        error_type = module_event_eqe->error_type &
 889                     PORT_MODULE_EVENT_ERROR_TYPE_MASK;
 890
 891        if (module_status < MLX5_MODULE_STATUS_ERROR) {
 892                priv->pme_stats.status_counters[module_status - 1]++;
 893        } else if (module_status == MLX5_MODULE_STATUS_ERROR) {
 894                if (error_type >= MLX5_MODULE_EVENT_ERROR_UNKNOWN)
 895                        /* Unknown error type */
 896                        error_type = MLX5_MODULE_EVENT_ERROR_UNKNOWN;
 897                priv->pme_stats.error_counters[error_type]++;
 898        }
 899
 900        if (!printk_ratelimit())
 901                return;
 902
 903        if (module_status < MLX5_MODULE_STATUS_ERROR)
 904                mlx5_core_info(dev,
 905                               "Port module event: module %u, %s\n",
 906                               module_num, mlx5_pme_status[module_status - 1]);
 907
 908        else if (module_status == MLX5_MODULE_STATUS_ERROR)
 909                mlx5_core_info(dev,
 910                               "Port module event[error]: module %u, %s, %s\n",
 911                               module_num, mlx5_pme_status[module_status - 1],
 912                               mlx5_pme_error[error_type]);
 913}
 914
 915int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
 916{
 917        u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
 918
 919        return mlx5_core_access_reg(mdev, in, sizeof(in), mtpps,
 920                                    mtpps_size, MLX5_REG_MTPPS, 0, 0);
 921}
 922
 923int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
 924{
 925        u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
 926
 927        return mlx5_core_access_reg(mdev, mtpps, mtpps_size, out,
 928                                    sizeof(out), MLX5_REG_MTPPS, 0, 1);
 929}
 930
 931int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode)
 932{
 933        u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
 934        u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
 935        int err = 0;
 936
 937        MLX5_SET(mtppse_reg, in, pin, pin);
 938
 939        err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
 940                                   sizeof(out), MLX5_REG_MTPPSE, 0, 0);
 941        if (err)
 942                return err;
 943
 944        *arm = MLX5_GET(mtppse_reg, in, event_arm);
 945        *mode = MLX5_GET(mtppse_reg, in, event_generation_mode);
 946
 947        return err;
 948}
 949
 950int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode)
 951{
 952        u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
 953        u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
 954
 955        MLX5_SET(mtppse_reg, in, pin, pin);
 956        MLX5_SET(mtppse_reg, in, event_arm, arm);
 957        MLX5_SET(mtppse_reg, in, event_generation_mode, mode);
 958
 959        return mlx5_core_access_reg(mdev, in, sizeof(in), out,
 960                                    sizeof(out), MLX5_REG_MTPPSE, 0, 1);
 961}
 962