1 /*- 2 * Copyright (c) 2013-2018, Mellanox Technologies, Ltd. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 * $FreeBSD$ 26 */ 27 28 #include <linux/module.h> 29 #include <dev/mlx5/port.h> 30 #include "mlx5_core.h" 31 32 int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in, 33 int size_in, void *data_out, int size_out, 34 u16 reg_num, int arg, int write) 35 { 36 int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out; 37 int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in; 38 int err = -ENOMEM; 39 u32 *out = NULL; 40 u32 *in = NULL; 41 void *data; 42 43 in = mlx5_vzalloc(inlen); 44 out = mlx5_vzalloc(outlen); 45 if (!in || !out) 46 goto out; 47 48 data = MLX5_ADDR_OF(access_register_in, in, register_data); 49 memcpy(data, data_in, size_in); 50 51 MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG); 52 MLX5_SET(access_register_in, in, op_mod, !write); 53 MLX5_SET(access_register_in, in, argument, arg); 54 MLX5_SET(access_register_in, in, register_id, reg_num); 55 56 err = mlx5_cmd_exec(dev, in, inlen, out, outlen); 57 if (err) 58 goto out; 59 data = MLX5_ADDR_OF(access_register_out, out, register_data); 60 memcpy(data_out, data, size_out); 61 62 out: 63 kvfree(out); 64 kvfree(in); 65 return err; 66 } 67 EXPORT_SYMBOL_GPL(mlx5_core_access_reg); 68 69 int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam, 70 u8 feature_group, u8 access_reg_group) 71 { 72 u32 in[MLX5_ST_SZ_DW(qcam_reg)] = {}; 73 int sz = MLX5_ST_SZ_BYTES(qcam_reg); 74 75 MLX5_SET(qcam_reg, in, feature_group, feature_group); 76 MLX5_SET(qcam_reg, in, access_reg_group, access_reg_group); 77 78 return mlx5_core_access_reg(mdev, in, sz, qcam, sz, MLX5_REG_QCAM, 0, 0); 79 } 80 EXPORT_SYMBOL_GPL(mlx5_query_qcam_reg); 81 82 struct mlx5_reg_pcap { 83 u8 rsvd0; 84 u8 port_num; 85 u8 rsvd1[2]; 86 __be32 caps_127_96; 87 __be32 caps_95_64; 88 __be32 caps_63_32; 89 __be32 caps_31_0; 90 }; 91 92 /* This function should be used after setting a port register only */ 93 void mlx5_toggle_port_link(struct mlx5_core_dev *dev) 94 { 95 enum mlx5_port_status ps; 96 97 mlx5_query_port_admin_status(dev, &ps); 98 mlx5_set_port_status(dev, MLX5_PORT_DOWN); 99 if (ps == MLX5_PORT_UP) 100 mlx5_set_port_status(dev, MLX5_PORT_UP); 101 } 102 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link); 103 104 int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps) 105 { 106 struct mlx5_reg_pcap in; 107 struct mlx5_reg_pcap out; 108 int err; 109 110 memset(&in, 0, sizeof(in)); 111 in.caps_127_96 = cpu_to_be32(caps); 112 in.port_num = port_num; 113 114 err = mlx5_core_access_reg(dev, &in, sizeof(in), &out, 115 sizeof(out), MLX5_REG_PCAP, 0, 1); 116 117 return err; 118 } 119 EXPORT_SYMBOL_GPL(mlx5_set_port_caps); 120 121 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys, 122 int ptys_size, int proto_mask, u8 local_port) 123 { 124 u32 in[MLX5_ST_SZ_DW(ptys_reg)]; 125 int err; 126 127 memset(in, 0, sizeof(in)); 128 MLX5_SET(ptys_reg, in, local_port, local_port); 129 MLX5_SET(ptys_reg, in, proto_mask, proto_mask); 130 131 err = mlx5_core_access_reg(dev, in, sizeof(in), ptys, 132 ptys_size, MLX5_REG_PTYS, 0, 0); 133 134 return err; 135 } 136 EXPORT_SYMBOL_GPL(mlx5_query_port_ptys); 137 138 int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev, 139 u32 *proto_cap, int proto_mask) 140 { 141 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 142 int err; 143 144 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); 145 if (err) 146 return err; 147 148 if (proto_mask == MLX5_PTYS_EN) 149 *proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); 150 else 151 *proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability); 152 153 return 0; 154 } 155 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap); 156 157 int mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask, 158 u8 *an_disable_cap, u8 *an_disable_status) 159 { 160 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 161 int err; 162 163 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); 164 if (err) 165 return err; 166 167 *an_disable_status = MLX5_GET(ptys_reg, out, an_disable_admin); 168 *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap); 169 170 return 0; 171 } 172 EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg); 173 174 int mlx5_set_port_autoneg(struct mlx5_core_dev *dev, bool disable, 175 u32 eth_proto_admin, int proto_mask) 176 { 177 u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0}; 178 u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {0}; 179 u8 an_disable_cap; 180 u8 an_disable_status; 181 int err; 182 183 err = mlx5_query_port_autoneg(dev, proto_mask, &an_disable_cap, 184 &an_disable_status); 185 if (err) 186 return err; 187 if (!an_disable_cap) 188 return -EPERM; 189 190 MLX5_SET(ptys_reg, in, local_port, 1); 191 MLX5_SET(ptys_reg, in, an_disable_admin, disable); 192 MLX5_SET(ptys_reg, in, proto_mask, proto_mask); 193 if (proto_mask == MLX5_PTYS_EN) 194 MLX5_SET(ptys_reg, in, eth_proto_admin, eth_proto_admin); 195 196 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 197 sizeof(out), MLX5_REG_PTYS, 0, 1); 198 return err; 199 } 200 EXPORT_SYMBOL_GPL(mlx5_set_port_autoneg); 201 202 int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, 203 u32 *proto_admin, int proto_mask) 204 { 205 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 206 int err; 207 208 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); 209 if (err) 210 return err; 211 212 if (proto_mask == MLX5_PTYS_EN) 213 *proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); 214 else 215 *proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin); 216 217 return 0; 218 } 219 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin); 220 221 int mlx5_query_port_eth_proto_oper(struct mlx5_core_dev *dev, 222 u32 *proto_oper, u8 local_port) 223 { 224 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 225 int err; 226 227 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, 228 local_port); 229 if (err) 230 return err; 231 232 *proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); 233 234 return 0; 235 } 236 EXPORT_SYMBOL(mlx5_query_port_eth_proto_oper); 237 238 int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, 239 int proto_mask) 240 { 241 u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0}; 242 u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {0}; 243 int err; 244 245 MLX5_SET(ptys_reg, in, local_port, 1); 246 MLX5_SET(ptys_reg, in, proto_mask, proto_mask); 247 if (proto_mask == MLX5_PTYS_EN) 248 MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin); 249 else 250 MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin); 251 252 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 253 sizeof(out), MLX5_REG_PTYS, 0, 1); 254 return err; 255 } 256 EXPORT_SYMBOL_GPL(mlx5_set_port_proto); 257 258 int mlx5_set_port_status(struct mlx5_core_dev *dev, 259 enum mlx5_port_status status) 260 { 261 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0}; 262 u32 out[MLX5_ST_SZ_DW(paos_reg)] = {0}; 263 int err; 264 265 MLX5_SET(paos_reg, in, local_port, 1); 266 267 MLX5_SET(paos_reg, in, admin_status, status); 268 MLX5_SET(paos_reg, in, ase, 1); 269 270 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 271 sizeof(out), MLX5_REG_PAOS, 0, 1); 272 return err; 273 } 274 275 int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status) 276 { 277 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0}; 278 u32 out[MLX5_ST_SZ_DW(paos_reg)] = {0}; 279 int err; 280 281 MLX5_SET(paos_reg, in, local_port, 1); 282 283 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 284 sizeof(out), MLX5_REG_PAOS, 0, 0); 285 if (err) 286 return err; 287 288 *status = MLX5_GET(paos_reg, out, oper_status); 289 return err; 290 } 291 292 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev, 293 enum mlx5_port_status *status) 294 { 295 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0}; 296 u32 out[MLX5_ST_SZ_DW(paos_reg)]; 297 int err; 298 299 MLX5_SET(paos_reg, in, local_port, 1); 300 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 301 sizeof(out), MLX5_REG_PAOS, 0, 0); 302 if (err) 303 return err; 304 *status = MLX5_GET(paos_reg, out, admin_status); 305 return 0; 306 } 307 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status); 308 309 static int mlx5_query_port_mtu(struct mlx5_core_dev *dev, 310 int *admin_mtu, int *max_mtu, int *oper_mtu) 311 { 312 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; 313 u32 out[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; 314 int err; 315 316 MLX5_SET(pmtu_reg, in, local_port, 1); 317 318 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 319 sizeof(out), MLX5_REG_PMTU, 0, 0); 320 if (err) 321 return err; 322 323 if (max_mtu) 324 *max_mtu = MLX5_GET(pmtu_reg, out, max_mtu); 325 if (oper_mtu) 326 *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu); 327 if (admin_mtu) 328 *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu); 329 330 return err; 331 } 332 333 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu) 334 { 335 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; 336 u32 out[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; 337 338 MLX5_SET(pmtu_reg, in, admin_mtu, mtu); 339 MLX5_SET(pmtu_reg, in, local_port, 1); 340 341 return mlx5_core_access_reg(dev, in, sizeof(in), out, 342 sizeof(out), MLX5_REG_PMTU, 0, 1); 343 } 344 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu); 345 346 int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu) 347 { 348 return mlx5_query_port_mtu(dev, NULL, max_mtu, NULL); 349 } 350 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu); 351 352 int mlx5_set_port_pause_and_pfc(struct mlx5_core_dev *dev, u32 port, 353 u8 rx_pause, u8 tx_pause, 354 u8 pfc_en_rx, u8 pfc_en_tx) 355 { 356 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 357 u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 358 359 if (pfc_en_rx || pfc_en_tx) { 360 /* PFC and global pauseframes are incompatible features */ 361 if (tx_pause || rx_pause) 362 return -EINVAL; 363 } 364 365 MLX5_SET(pfcc_reg, in, local_port, port); 366 MLX5_SET(pfcc_reg, in, pptx, tx_pause); 367 MLX5_SET(pfcc_reg, in, pprx, rx_pause); 368 MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx); 369 MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx); 370 MLX5_SET(pfcc_reg, in, prio_mask_tx, pfc_en_tx); 371 MLX5_SET(pfcc_reg, in, prio_mask_rx, pfc_en_rx); 372 373 return mlx5_core_access_reg(dev, in, sizeof(in), out, 374 sizeof(out), MLX5_REG_PFCC, 0, 1); 375 } 376 377 int mlx5_query_port_pause(struct mlx5_core_dev *dev, u32 port, 378 u32 *rx_pause, u32 *tx_pause) 379 { 380 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 381 u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 382 int err; 383 384 MLX5_SET(pfcc_reg, in, local_port, port); 385 386 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 387 sizeof(out), MLX5_REG_PFCC, 0, 0); 388 if (err) 389 return err; 390 391 *rx_pause = MLX5_GET(pfcc_reg, out, pprx); 392 *tx_pause = MLX5_GET(pfcc_reg, out, pptx); 393 394 return 0; 395 } 396 397 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx) 398 { 399 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {}; 400 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 401 int err; 402 403 MLX5_SET(pfcc_reg, in, local_port, 1); 404 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 405 sizeof(out), MLX5_REG_PFCC, 0, 0); 406 if (err) 407 return err; 408 409 if (pfc_en_tx != NULL) 410 *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx); 411 if (pfc_en_rx != NULL) 412 *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx); 413 return 0; 414 } 415 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc); 416 417 int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu) 418 { 419 return mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu); 420 } 421 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu); 422 423 u8 mlx5_is_wol_supported(struct mlx5_core_dev *dev) 424 { 425 u8 wol_supported = 0; 426 427 if (MLX5_CAP_GEN(dev, wol_s)) 428 wol_supported |= MLX5_WOL_SECURED_MAGIC; 429 if (MLX5_CAP_GEN(dev, wol_g)) 430 wol_supported |= MLX5_WOL_MAGIC; 431 if (MLX5_CAP_GEN(dev, wol_a)) 432 wol_supported |= MLX5_WOL_ARP; 433 if (MLX5_CAP_GEN(dev, wol_b)) 434 wol_supported |= MLX5_WOL_BROADCAST; 435 if (MLX5_CAP_GEN(dev, wol_m)) 436 wol_supported |= MLX5_WOL_MULTICAST; 437 if (MLX5_CAP_GEN(dev, wol_u)) 438 wol_supported |= MLX5_WOL_UNICAST; 439 if (MLX5_CAP_GEN(dev, wol_p)) 440 wol_supported |= MLX5_WOL_PHY_ACTIVITY; 441 442 return wol_supported; 443 } 444 EXPORT_SYMBOL_GPL(mlx5_is_wol_supported); 445 446 int mlx5_set_wol(struct mlx5_core_dev *dev, u8 wol_mode) 447 { 448 u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {0}; 449 u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)] = {0}; 450 451 MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL); 452 MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1); 453 MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode); 454 455 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 456 } 457 EXPORT_SYMBOL_GPL(mlx5_set_wol); 458 459 int mlx5_query_dropless_mode(struct mlx5_core_dev *dev, u16 *timeout) 460 { 461 u32 in[MLX5_ST_SZ_DW(query_delay_drop_params_in)] = {0}; 462 u32 out[MLX5_ST_SZ_DW(query_delay_drop_params_out)] = {0}; 463 int err = 0; 464 465 MLX5_SET(query_delay_drop_params_in, in, opcode, 466 MLX5_CMD_OP_QUERY_DELAY_DROP_PARAMS); 467 468 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 469 if (err) 470 return err; 471 472 *timeout = MLX5_GET(query_delay_drop_params_out, out, 473 delay_drop_timeout); 474 475 return 0; 476 } 477 EXPORT_SYMBOL_GPL(mlx5_query_dropless_mode); 478 479 int mlx5_set_dropless_mode(struct mlx5_core_dev *dev, u16 timeout) 480 { 481 u32 in[MLX5_ST_SZ_DW(set_delay_drop_params_in)] = {0}; 482 u32 out[MLX5_ST_SZ_DW(set_delay_drop_params_out)] = {0}; 483 484 MLX5_SET(set_delay_drop_params_in, in, opcode, 485 MLX5_CMD_OP_SET_DELAY_DROP_PARAMS); 486 MLX5_SET(set_delay_drop_params_in, in, delay_drop_timeout, timeout); 487 488 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 489 } 490 EXPORT_SYMBOL_GPL(mlx5_set_dropless_mode); 491 492 int mlx5_core_access_pvlc(struct mlx5_core_dev *dev, 493 struct mlx5_pvlc_reg *pvlc, int write) 494 { 495 int sz = MLX5_ST_SZ_BYTES(pvlc_reg); 496 u8 in[MLX5_ST_SZ_BYTES(pvlc_reg)] = {0}; 497 u8 out[MLX5_ST_SZ_BYTES(pvlc_reg)] = {0}; 498 int err; 499 500 MLX5_SET(pvlc_reg, in, local_port, pvlc->local_port); 501 if (write) 502 MLX5_SET(pvlc_reg, in, vl_admin, pvlc->vl_admin); 503 504 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PVLC, 0, 505 !!write); 506 if (err) 507 return err; 508 509 if (!write) { 510 pvlc->local_port = MLX5_GET(pvlc_reg, out, local_port); 511 pvlc->vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap); 512 pvlc->vl_admin = MLX5_GET(pvlc_reg, out, vl_admin); 513 pvlc->vl_operational = MLX5_GET(pvlc_reg, out, vl_operational); 514 } 515 516 return 0; 517 } 518 EXPORT_SYMBOL_GPL(mlx5_core_access_pvlc); 519 520 int mlx5_core_access_ptys(struct mlx5_core_dev *dev, 521 struct mlx5_ptys_reg *ptys, int write) 522 { 523 int sz = MLX5_ST_SZ_BYTES(ptys_reg); 524 void *out = NULL; 525 void *in = NULL; 526 int err; 527 528 in = mlx5_vzalloc(sz); 529 if (!in) 530 return -ENOMEM; 531 532 out = mlx5_vzalloc(sz); 533 if (!out) { 534 kfree(in); 535 return -ENOMEM; 536 } 537 538 MLX5_SET(ptys_reg, in, local_port, ptys->local_port); 539 MLX5_SET(ptys_reg, in, proto_mask, ptys->proto_mask); 540 if (write) { 541 MLX5_SET(ptys_reg, in, eth_proto_capability, 542 ptys->eth_proto_cap); 543 MLX5_SET(ptys_reg, in, ib_link_width_capability, 544 ptys->ib_link_width_cap); 545 MLX5_SET(ptys_reg, in, ib_proto_capability, 546 ptys->ib_proto_cap); 547 MLX5_SET(ptys_reg, in, eth_proto_admin, ptys->eth_proto_admin); 548 MLX5_SET(ptys_reg, in, ib_link_width_admin, 549 ptys->ib_link_width_admin); 550 MLX5_SET(ptys_reg, in, ib_proto_admin, ptys->ib_proto_admin); 551 MLX5_SET(ptys_reg, in, eth_proto_oper, ptys->eth_proto_oper); 552 MLX5_SET(ptys_reg, in, ib_link_width_oper, 553 ptys->ib_link_width_oper); 554 MLX5_SET(ptys_reg, in, ib_proto_oper, ptys->ib_proto_oper); 555 MLX5_SET(ptys_reg, in, eth_proto_lp_advertise, 556 ptys->eth_proto_lp_advertise); 557 } 558 559 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PTYS, 0, 560 !!write); 561 if (err) 562 goto out; 563 564 if (!write) { 565 ptys->local_port = MLX5_GET(ptys_reg, out, local_port); 566 ptys->proto_mask = MLX5_GET(ptys_reg, out, proto_mask); 567 ptys->eth_proto_cap = MLX5_GET(ptys_reg, out, 568 eth_proto_capability); 569 ptys->ib_link_width_cap = MLX5_GET(ptys_reg, out, 570 ib_link_width_capability); 571 ptys->ib_proto_cap = MLX5_GET(ptys_reg, out, 572 ib_proto_capability); 573 ptys->eth_proto_admin = MLX5_GET(ptys_reg, out, 574 eth_proto_admin); 575 ptys->ib_link_width_admin = MLX5_GET(ptys_reg, out, 576 ib_link_width_admin); 577 ptys->ib_proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin); 578 ptys->eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); 579 ptys->ib_link_width_oper = MLX5_GET(ptys_reg, out, 580 ib_link_width_oper); 581 ptys->ib_proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper); 582 ptys->eth_proto_lp_advertise = MLX5_GET(ptys_reg, out, 583 eth_proto_lp_advertise); 584 } 585 586 out: 587 kvfree(in); 588 kvfree(out); 589 return err; 590 } 591 EXPORT_SYMBOL_GPL(mlx5_core_access_ptys); 592 593 static int mtu_to_ib_mtu(int mtu) 594 { 595 switch (mtu) { 596 case 256: return 1; 597 case 512: return 2; 598 case 1024: return 3; 599 case 2048: return 4; 600 case 4096: return 5; 601 default: 602 printf("mlx5_core: WARN: ""invalid mtu\n"); 603 return -1; 604 } 605 } 606 607 int mlx5_core_access_pmtu(struct mlx5_core_dev *dev, 608 struct mlx5_pmtu_reg *pmtu, int write) 609 { 610 int sz = MLX5_ST_SZ_BYTES(pmtu_reg); 611 void *out = NULL; 612 void *in = NULL; 613 int err; 614 615 in = mlx5_vzalloc(sz); 616 if (!in) 617 return -ENOMEM; 618 619 out = mlx5_vzalloc(sz); 620 if (!out) { 621 kfree(in); 622 return -ENOMEM; 623 } 624 625 MLX5_SET(pmtu_reg, in, local_port, pmtu->local_port); 626 if (write) 627 MLX5_SET(pmtu_reg, in, admin_mtu, pmtu->admin_mtu); 628 629 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PMTU, 0, 630 !!write); 631 if (err) 632 goto out; 633 634 if (!write) { 635 pmtu->local_port = MLX5_GET(pmtu_reg, out, local_port); 636 pmtu->max_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out, 637 max_mtu)); 638 pmtu->admin_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out, 639 admin_mtu)); 640 pmtu->oper_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out, 641 oper_mtu)); 642 } 643 644 out: 645 kvfree(in); 646 kvfree(out); 647 return err; 648 } 649 EXPORT_SYMBOL_GPL(mlx5_core_access_pmtu); 650 651 int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num) 652 { 653 u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0}; 654 u32 out[MLX5_ST_SZ_DW(pmlp_reg)] = {0}; 655 int lane = 0; 656 int err; 657 658 MLX5_SET(pmlp_reg, in, local_port, 1); 659 660 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 661 sizeof(out), MLX5_REG_PMLP, 0, 0); 662 if (err) 663 return err; 664 665 lane = MLX5_GET(pmlp_reg, out, lane0_module_mapping); 666 *module_num = lane & MLX5_EEPROM_IDENTIFIER_BYTE_MASK; 667 668 return 0; 669 } 670 EXPORT_SYMBOL_GPL(mlx5_query_module_num); 671 672 int mlx5_query_eeprom(struct mlx5_core_dev *dev, 673 int i2c_addr, int page_num, int device_addr, 674 int size, int module_num, u32 *data, int *size_read) 675 { 676 u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {0}; 677 u32 out[MLX5_ST_SZ_DW(mcia_reg)] = {0}; 678 u32 *ptr = (u32 *)MLX5_ADDR_OF(mcia_reg, out, dword_0); 679 int status; 680 int err; 681 682 size = min_t(int, size, MLX5_EEPROM_MAX_BYTES); 683 684 MLX5_SET(mcia_reg, in, l, 0); 685 MLX5_SET(mcia_reg, in, module, module_num); 686 MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr); 687 MLX5_SET(mcia_reg, in, page_number, page_num); 688 MLX5_SET(mcia_reg, in, device_address, device_addr); 689 MLX5_SET(mcia_reg, in, size, size); 690 691 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 692 sizeof(out), MLX5_REG_MCIA, 0, 0); 693 if (err) 694 return err; 695 696 status = MLX5_GET(mcia_reg, out, status); 697 if (status) 698 return status; 699 700 memcpy(data, ptr, size); 701 *size_read = size; 702 return 0; 703 } 704 EXPORT_SYMBOL_GPL(mlx5_query_eeprom); 705 706 int mlx5_vxlan_udp_port_add(struct mlx5_core_dev *dev, u16 port) 707 { 708 u32 in[MLX5_ST_SZ_DW(add_vxlan_udp_dport_in)] = {0}; 709 u32 out[MLX5_ST_SZ_DW(add_vxlan_udp_dport_out)] = {0}; 710 int err; 711 712 MLX5_SET(add_vxlan_udp_dport_in, in, opcode, 713 MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT); 714 MLX5_SET(add_vxlan_udp_dport_in, in, vxlan_udp_port, port); 715 716 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 717 if (err) { 718 mlx5_core_err(dev, "Failed %s, port %u, err - %d", 719 mlx5_command_str(MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT), 720 port, err); 721 } 722 723 return err; 724 } 725 726 int mlx5_vxlan_udp_port_delete(struct mlx5_core_dev *dev, u16 port) 727 { 728 u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)] = {0}; 729 u32 out[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_out)] = {0}; 730 int err; 731 732 MLX5_SET(delete_vxlan_udp_dport_in, in, opcode, 733 MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT); 734 MLX5_SET(delete_vxlan_udp_dport_in, in, vxlan_udp_port, port); 735 736 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 737 if (err) { 738 mlx5_core_err(dev, "Failed %s, port %u, err - %d", 739 mlx5_command_str(MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT), 740 port, err); 741 } 742 743 return err; 744 } 745 746 int mlx5_query_wol(struct mlx5_core_dev *dev, u8 *wol_mode) 747 { 748 u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {0}; 749 u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {0}; 750 int err; 751 752 MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL); 753 754 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 755 756 if (!err) 757 *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode); 758 759 return err; 760 } 761 EXPORT_SYMBOL_GPL(mlx5_query_wol); 762 763 int mlx5_query_port_cong_status(struct mlx5_core_dev *mdev, int protocol, 764 int priority, int *is_enable) 765 { 766 u32 in[MLX5_ST_SZ_DW(query_cong_status_in)] = {0}; 767 u32 out[MLX5_ST_SZ_DW(query_cong_status_out)] = {0}; 768 int err; 769 770 *is_enable = 0; 771 772 MLX5_SET(query_cong_status_in, in, opcode, 773 MLX5_CMD_OP_QUERY_CONG_STATUS); 774 MLX5_SET(query_cong_status_in, in, cong_protocol, protocol); 775 MLX5_SET(query_cong_status_in, in, priority, priority); 776 777 err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); 778 if (!err) 779 *is_enable = MLX5_GET(query_cong_status_out, out, enable); 780 return err; 781 } 782 783 int mlx5_modify_port_cong_status(struct mlx5_core_dev *mdev, int protocol, 784 int priority, int enable) 785 { 786 u32 in[MLX5_ST_SZ_DW(modify_cong_status_in)] = {0}; 787 u32 out[MLX5_ST_SZ_DW(modify_cong_status_out)] = {0}; 788 789 MLX5_SET(modify_cong_status_in, in, opcode, 790 MLX5_CMD_OP_MODIFY_CONG_STATUS); 791 MLX5_SET(modify_cong_status_in, in, cong_protocol, protocol); 792 MLX5_SET(modify_cong_status_in, in, priority, priority); 793 MLX5_SET(modify_cong_status_in, in, enable, enable); 794 795 return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); 796 } 797 798 int mlx5_query_port_cong_params(struct mlx5_core_dev *mdev, int protocol, 799 void *out, int out_size) 800 { 801 u32 in[MLX5_ST_SZ_DW(query_cong_params_in)] = {0}; 802 803 MLX5_SET(query_cong_params_in, in, opcode, 804 MLX5_CMD_OP_QUERY_CONG_PARAMS); 805 MLX5_SET(query_cong_params_in, in, cong_protocol, protocol); 806 807 return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); 808 } 809 810 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out, 811 int outlen) 812 { 813 u32 in[MLX5_ST_SZ_DW(qetc_reg)]; 814 815 if (!MLX5_CAP_GEN(mdev, ets)) 816 return -ENOTSUPP; 817 818 memset(in, 0, sizeof(in)); 819 return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen, 820 MLX5_REG_QETCR, 0, 0); 821 } 822 823 int mlx5_max_tc(struct mlx5_core_dev *mdev) 824 { 825 u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8; 826 827 return num_tc - 1; 828 } 829 EXPORT_SYMBOL_GPL(mlx5_max_tc); 830 831 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, 832 int inlen) 833 { 834 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 835 836 if (!MLX5_CAP_GEN(mdev, ets)) 837 return -ENOTSUPP; 838 839 return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out), 840 MLX5_REG_QETCR, 0, 1); 841 } 842 843 int mlx5_query_port_tc_rate_limit(struct mlx5_core_dev *mdev, 844 u8 *max_bw_value, 845 u8 *max_bw_units) 846 { 847 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 848 void *ets_tcn_conf; 849 int err; 850 int i; 851 852 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 853 if (err) 854 return err; 855 856 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 857 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]); 858 859 max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 860 max_bw_value); 861 max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 862 max_bw_units); 863 } 864 865 return 0; 866 } 867 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_rate_limit); 868 869 int mlx5_modify_port_tc_rate_limit(struct mlx5_core_dev *mdev, 870 const u8 *max_bw_value, 871 const u8 *max_bw_units) 872 { 873 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {}; 874 void *ets_tcn_conf; 875 int i; 876 877 MLX5_SET(qetc_reg, in, port_number, 1); 878 879 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 880 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]); 881 882 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1); 883 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units, 884 max_bw_units[i]); 885 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value, 886 max_bw_value[i]); 887 } 888 889 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 890 } 891 EXPORT_SYMBOL_GPL(mlx5_modify_port_tc_rate_limit); 892 893 int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev, 894 u8 prio, u8 *tc) 895 { 896 u32 in[MLX5_ST_SZ_DW(qtct_reg)]; 897 u32 out[MLX5_ST_SZ_DW(qtct_reg)]; 898 int err; 899 900 memset(in, 0, sizeof(in)); 901 memset(out, 0, sizeof(out)); 902 903 MLX5_SET(qtct_reg, in, port_number, 1); 904 MLX5_SET(qtct_reg, in, prio, prio); 905 906 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 907 sizeof(out), MLX5_REG_QTCT, 0, 0); 908 if (!err) 909 *tc = MLX5_GET(qtct_reg, out, tclass); 910 911 return err; 912 } 913 EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc); 914 915 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, int prio_index, 916 const u8 prio_tc) 917 { 918 u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {}; 919 u32 out[MLX5_ST_SZ_DW(qtct_reg)]; 920 int err; 921 922 if (prio_tc > mlx5_max_tc(mdev)) 923 return -EINVAL; 924 925 MLX5_SET(qtct_reg, in, prio, prio_index); 926 MLX5_SET(qtct_reg, in, tclass, prio_tc); 927 928 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 929 sizeof(out), MLX5_REG_QTCT, 0, 1); 930 931 return (err); 932 } 933 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc); 934 935 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, const u8 *tc_group) 936 { 937 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {}; 938 int i; 939 940 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 941 MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1); 942 MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]); 943 } 944 945 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 946 } 947 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group); 948 949 int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev, 950 u8 tc, u8 *tc_group) 951 { 952 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 953 void *ets_tcn_conf; 954 int err; 955 956 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 957 if (err) 958 return err; 959 960 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, 961 tc_configuration[tc]); 962 963 *tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 964 group); 965 966 return 0; 967 } 968 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group); 969 970 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, const u8 *tc_bw) 971 { 972 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {}; 973 int i; 974 975 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 976 MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1); 977 MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]); 978 } 979 980 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 981 } 982 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc); 983 984 int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *bw_pct) 985 { 986 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 987 void *ets_tcn_conf; 988 int err; 989 int i; 990 991 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 992 if (err) 993 return err; 994 995 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 996 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]); 997 bw_pct[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, bw_allocation); 998 } 999 return 0; 1000 } 1001 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc); 1002 1003 int mlx5_modify_port_cong_params(struct mlx5_core_dev *mdev, 1004 void *in, int in_size) 1005 { 1006 u32 out[MLX5_ST_SZ_DW(modify_cong_params_out)] = {0}; 1007 1008 MLX5_SET(modify_cong_params_in, in, opcode, 1009 MLX5_CMD_OP_MODIFY_CONG_PARAMS); 1010 1011 return mlx5_cmd_exec(mdev, in, in_size, out, sizeof(out)); 1012 } 1013 1014 int mlx5_query_port_cong_statistics(struct mlx5_core_dev *mdev, int clear, 1015 void *out, int out_size) 1016 { 1017 u32 in[MLX5_ST_SZ_DW(query_cong_statistics_in)] = {0}; 1018 1019 MLX5_SET(query_cong_statistics_in, in, opcode, 1020 MLX5_CMD_OP_QUERY_CONG_STATISTICS); 1021 MLX5_SET(query_cong_statistics_in, in, clear, clear); 1022 1023 return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); 1024 } 1025 1026 int mlx5_set_diagnostic_params(struct mlx5_core_dev *mdev, void *in, 1027 int in_size) 1028 { 1029 u32 out[MLX5_ST_SZ_DW(set_diagnostic_params_out)] = {0}; 1030 1031 MLX5_SET(set_diagnostic_params_in, in, opcode, 1032 MLX5_CMD_OP_SET_DIAGNOSTICS); 1033 1034 return mlx5_cmd_exec(mdev, in, in_size, out, sizeof(out)); 1035 } 1036 1037 int mlx5_query_diagnostic_counters(struct mlx5_core_dev *mdev, 1038 u8 num_of_samples, u16 sample_index, 1039 void *out, int out_size) 1040 { 1041 u32 in[MLX5_ST_SZ_DW(query_diagnostic_counters_in)] = {0}; 1042 1043 MLX5_SET(query_diagnostic_counters_in, in, opcode, 1044 MLX5_CMD_OP_QUERY_DIAGNOSTICS); 1045 MLX5_SET(query_diagnostic_counters_in, in, num_of_samples, 1046 num_of_samples); 1047 MLX5_SET(query_diagnostic_counters_in, in, sample_index, sample_index); 1048 1049 return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); 1050 } 1051 1052 int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state) 1053 { 1054 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {}; 1055 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {}; 1056 int err; 1057 1058 MLX5_SET(qpts_reg, in, local_port, 1); 1059 MLX5_SET(qpts_reg, in, trust_state, trust_state); 1060 1061 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 1062 sizeof(out), MLX5_REG_QPTS, 0, 1); 1063 return err; 1064 } 1065 1066 int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state) 1067 { 1068 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {}; 1069 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {}; 1070 int err; 1071 1072 MLX5_SET(qpts_reg, in, local_port, 1); 1073 1074 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 1075 sizeof(out), MLX5_REG_QPTS, 0, 0); 1076 if (!err) 1077 *trust_state = MLX5_GET(qpts_reg, out, trust_state); 1078 1079 return err; 1080 } 1081 1082 int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, const u8 *dscp2prio) 1083 { 1084 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg); 1085 void *qpdpm_dscp; 1086 void *out; 1087 void *in; 1088 int err; 1089 int i; 1090 1091 in = kzalloc(sz, GFP_KERNEL); 1092 out = kzalloc(sz, GFP_KERNEL); 1093 if (!in || !out) { 1094 err = -ENOMEM; 1095 goto out; 1096 } 1097 1098 MLX5_SET(qpdpm_reg, in, local_port, 1); 1099 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0); 1100 if (err) 1101 goto out; 1102 1103 memcpy(in, out, sz); 1104 MLX5_SET(qpdpm_reg, in, local_port, 1); 1105 1106 /* Update the corresponding dscp entry */ 1107 for (i = 0; i < MLX5_MAX_SUPPORTED_DSCP; i++) { 1108 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[i]); 1109 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, dscp2prio[i]); 1110 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1); 1111 } 1112 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1); 1113 out: 1114 kfree(in); 1115 kfree(out); 1116 return err; 1117 } 1118 1119 int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio) 1120 { 1121 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg); 1122 void *qpdpm_dscp; 1123 void *out; 1124 void *in; 1125 int err; 1126 int i; 1127 1128 in = kzalloc(sz, GFP_KERNEL); 1129 out = kzalloc(sz, GFP_KERNEL); 1130 if (!in || !out) { 1131 err = -ENOMEM; 1132 goto out; 1133 } 1134 1135 MLX5_SET(qpdpm_reg, in, local_port, 1); 1136 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0); 1137 if (err) 1138 goto out; 1139 1140 for (i = 0; i < MLX5_MAX_SUPPORTED_DSCP; i++) { 1141 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]); 1142 dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio); 1143 } 1144 out: 1145 kfree(in); 1146 kfree(out); 1147 return err; 1148 } 1149 1150 int mlx5_query_pddr_range_info(struct mlx5_core_dev *mdev, u8 local_port, u8 *is_er_type) 1151 { 1152 u32 pddr_reg[MLX5_ST_SZ_DW(pddr_reg)] = {}; 1153 int sz = MLX5_ST_SZ_BYTES(pddr_reg); 1154 int error; 1155 u8 ecc; 1156 u8 ci; 1157 1158 MLX5_SET(pddr_reg, pddr_reg, local_port, local_port); 1159 MLX5_SET(pddr_reg, pddr_reg, page_select, 3 /* module info page */); 1160 1161 error = mlx5_core_access_reg(mdev, pddr_reg, sz, pddr_reg, sz, 1162 MLX5_ACCESS_REG_SUMMARY_CTRL_ID_PDDR, 0, 0); 1163 if (error != 0) 1164 return (error); 1165 1166 ecc = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.ethernet_compliance_code); 1167 ci = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.cable_identifier); 1168 1169 switch (ci) { 1170 case 0: /* QSFP28 */ 1171 case 1: /* QSFP+ */ 1172 *is_er_type = 0; 1173 break; 1174 case 2: /* SFP28/SFP+ */ 1175 case 3: /* QSA (QSFP->SFP) */ 1176 *is_er_type = ((ecc & (1 << 7)) != 0); 1177 break; 1178 default: 1179 *is_er_type = 0; 1180 break; 1181 } 1182 return (0); 1183 } 1184 EXPORT_SYMBOL_GPL(mlx5_query_pddr_range_info); 1185