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