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 26 #include "opt_rss.h" 27 #include "opt_ratelimit.h" 28 29 #include <linux/module.h> 30 #include <dev/mlx5/port.h> 31 #include <dev/mlx5/mlx5_core/mlx5_core.h> 32 33 int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in, 34 int size_in, void *data_out, int size_out, 35 u16 reg_num, int arg, int write) 36 { 37 int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out; 38 int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in; 39 int err = -ENOMEM; 40 u32 *out = NULL; 41 u32 *in = NULL; 42 void *data; 43 44 in = mlx5_vzalloc(inlen); 45 out = mlx5_vzalloc(outlen); 46 if (!in || !out) 47 goto out; 48 49 data = MLX5_ADDR_OF(access_register_in, in, register_data); 50 memcpy(data, data_in, size_in); 51 52 MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG); 53 MLX5_SET(access_register_in, in, op_mod, !write); 54 MLX5_SET(access_register_in, in, argument, arg); 55 MLX5_SET(access_register_in, in, register_id, reg_num); 56 57 err = mlx5_cmd_exec(dev, in, inlen, out, outlen); 58 if (err) 59 goto out; 60 data = MLX5_ADDR_OF(access_register_out, out, register_data); 61 memcpy(data_out, data, size_out); 62 63 out: 64 kvfree(out); 65 kvfree(in); 66 return err; 67 } 68 EXPORT_SYMBOL_GPL(mlx5_core_access_reg); 69 70 int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam, 71 u8 feature_group, u8 access_reg_group) 72 { 73 u32 in[MLX5_ST_SZ_DW(qcam_reg)] = {}; 74 int sz = MLX5_ST_SZ_BYTES(qcam_reg); 75 76 MLX5_SET(qcam_reg, in, feature_group, feature_group); 77 MLX5_SET(qcam_reg, in, access_reg_group, access_reg_group); 78 79 return mlx5_core_access_reg(mdev, in, sz, qcam, sz, MLX5_REG_QCAM, 0, 0); 80 } 81 EXPORT_SYMBOL_GPL(mlx5_query_qcam_reg); 82 83 int mlx5_query_pcam_reg(struct mlx5_core_dev *dev, u32 *pcam, u8 feature_group, 84 u8 access_reg_group) 85 { 86 u32 in[MLX5_ST_SZ_DW(pcam_reg)] = {}; 87 int sz = MLX5_ST_SZ_BYTES(pcam_reg); 88 89 MLX5_SET(pcam_reg, in, feature_group, feature_group); 90 MLX5_SET(pcam_reg, in, access_reg_group, access_reg_group); 91 92 return mlx5_core_access_reg(dev, in, sz, pcam, sz, MLX5_REG_PCAM, 0, 0); 93 } 94 95 int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcam, u8 feature_group, 96 u8 access_reg_group) 97 { 98 u32 in[MLX5_ST_SZ_DW(mcam_reg)] = {}; 99 int sz = MLX5_ST_SZ_BYTES(mcam_reg); 100 101 MLX5_SET(mcam_reg, in, feature_group, feature_group); 102 MLX5_SET(mcam_reg, in, access_reg_group, access_reg_group); 103 104 return mlx5_core_access_reg(dev, in, sz, mcam, sz, MLX5_REG_MCAM, 0, 0); 105 } 106 107 struct mlx5_reg_pcap { 108 u8 rsvd0; 109 u8 port_num; 110 u8 rsvd1[2]; 111 __be32 caps_127_96; 112 __be32 caps_95_64; 113 __be32 caps_63_32; 114 __be32 caps_31_0; 115 }; 116 117 /* This function should be used after setting a port register only */ 118 void mlx5_toggle_port_link(struct mlx5_core_dev *dev) 119 { 120 enum mlx5_port_status ps; 121 122 mlx5_query_port_admin_status(dev, &ps); 123 mlx5_set_port_status(dev, MLX5_PORT_DOWN); 124 if (ps == MLX5_PORT_UP) 125 mlx5_set_port_status(dev, MLX5_PORT_UP); 126 } 127 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link); 128 129 int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps) 130 { 131 struct mlx5_reg_pcap in; 132 struct mlx5_reg_pcap out; 133 int err; 134 135 memset(&in, 0, sizeof(in)); 136 in.caps_127_96 = cpu_to_be32(caps); 137 in.port_num = port_num; 138 139 err = mlx5_core_access_reg(dev, &in, sizeof(in), &out, 140 sizeof(out), MLX5_REG_PCAP, 0, 1); 141 142 return err; 143 } 144 EXPORT_SYMBOL_GPL(mlx5_set_port_caps); 145 146 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys, 147 int ptys_size, int proto_mask, u8 local_port) 148 { 149 u32 in[MLX5_ST_SZ_DW(ptys_reg)]; 150 int err; 151 152 memset(in, 0, sizeof(in)); 153 MLX5_SET(ptys_reg, in, local_port, local_port); 154 MLX5_SET(ptys_reg, in, proto_mask, proto_mask); 155 156 err = mlx5_core_access_reg(dev, in, sizeof(in), ptys, 157 ptys_size, MLX5_REG_PTYS, 0, 0); 158 159 return err; 160 } 161 EXPORT_SYMBOL_GPL(mlx5_query_port_ptys); 162 163 int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev, 164 u32 *proto_cap, int proto_mask) 165 { 166 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 167 int err; 168 169 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); 170 if (err) 171 return err; 172 173 if (proto_mask == MLX5_PTYS_EN) 174 *proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); 175 else 176 *proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability); 177 178 return 0; 179 } 180 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap); 181 182 int mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask, 183 u8 *an_disable_cap, u8 *an_disable_status) 184 { 185 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 186 int err; 187 188 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); 189 if (err) 190 return err; 191 192 *an_disable_status = MLX5_GET(ptys_reg, out, an_disable_admin); 193 *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap); 194 195 return 0; 196 } 197 EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg); 198 199 int mlx5_set_port_autoneg(struct mlx5_core_dev *dev, bool disable, 200 u32 eth_proto_admin, int proto_mask) 201 { 202 u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0}; 203 u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {0}; 204 u8 an_disable_cap; 205 u8 an_disable_status; 206 int err; 207 208 err = mlx5_query_port_autoneg(dev, proto_mask, &an_disable_cap, 209 &an_disable_status); 210 if (err) 211 return err; 212 if (!an_disable_cap) 213 return -EPERM; 214 215 MLX5_SET(ptys_reg, in, local_port, 1); 216 MLX5_SET(ptys_reg, in, an_disable_admin, disable); 217 MLX5_SET(ptys_reg, in, proto_mask, proto_mask); 218 if (proto_mask == MLX5_PTYS_EN) 219 MLX5_SET(ptys_reg, in, eth_proto_admin, eth_proto_admin); 220 221 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 222 sizeof(out), MLX5_REG_PTYS, 0, 1); 223 return err; 224 } 225 EXPORT_SYMBOL_GPL(mlx5_set_port_autoneg); 226 227 int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, 228 u32 *proto_admin, int proto_mask) 229 { 230 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 231 int err; 232 233 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); 234 if (err) 235 return err; 236 237 if (proto_mask == MLX5_PTYS_EN) 238 *proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); 239 else 240 *proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin); 241 242 return 0; 243 } 244 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin); 245 246 int mlx5_query_port_eth_proto_oper(struct mlx5_core_dev *dev, 247 u32 *proto_oper, u8 local_port) 248 { 249 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 250 int err; 251 252 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, 253 local_port); 254 if (err) 255 return err; 256 257 *proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); 258 259 return 0; 260 } 261 EXPORT_SYMBOL(mlx5_query_port_eth_proto_oper); 262 263 int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, 264 int proto_mask, bool ext) 265 { 266 u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0}; 267 u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {0}; 268 int err; 269 270 MLX5_SET(ptys_reg, in, local_port, 1); 271 MLX5_SET(ptys_reg, in, proto_mask, proto_mask); 272 if (proto_mask == MLX5_PTYS_EN) { 273 if (ext) 274 MLX5_SET(ptys_reg, in, ext_eth_proto_admin, proto_admin); 275 else 276 MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin); 277 } else { 278 MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin); 279 } 280 281 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 282 sizeof(out), MLX5_REG_PTYS, 0, 1); 283 return err; 284 } 285 EXPORT_SYMBOL_GPL(mlx5_set_port_proto); 286 287 int mlx5_set_port_status(struct mlx5_core_dev *dev, 288 enum mlx5_port_status status) 289 { 290 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0}; 291 u32 out[MLX5_ST_SZ_DW(paos_reg)] = {0}; 292 int err; 293 294 MLX5_SET(paos_reg, in, local_port, 1); 295 296 MLX5_SET(paos_reg, in, admin_status, status); 297 MLX5_SET(paos_reg, in, ase, 1); 298 299 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 300 sizeof(out), MLX5_REG_PAOS, 0, 1); 301 return err; 302 } 303 304 int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status) 305 { 306 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0}; 307 u32 out[MLX5_ST_SZ_DW(paos_reg)] = {0}; 308 int err; 309 310 MLX5_SET(paos_reg, in, local_port, 1); 311 312 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 313 sizeof(out), MLX5_REG_PAOS, 0, 0); 314 if (err) 315 return err; 316 317 *status = MLX5_GET(paos_reg, out, oper_status); 318 return err; 319 } 320 321 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev, 322 enum mlx5_port_status *status) 323 { 324 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0}; 325 u32 out[MLX5_ST_SZ_DW(paos_reg)]; 326 int err; 327 328 MLX5_SET(paos_reg, in, local_port, 1); 329 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 330 sizeof(out), MLX5_REG_PAOS, 0, 0); 331 if (err) 332 return err; 333 *status = MLX5_GET(paos_reg, out, admin_status); 334 return 0; 335 } 336 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status); 337 338 static int mlx5_query_port_mtu(struct mlx5_core_dev *dev, 339 int *admin_mtu, int *max_mtu, int *oper_mtu) 340 { 341 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; 342 u32 out[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; 343 int err; 344 345 MLX5_SET(pmtu_reg, in, local_port, 1); 346 347 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 348 sizeof(out), MLX5_REG_PMTU, 0, 0); 349 if (err) 350 return err; 351 352 if (max_mtu) 353 *max_mtu = MLX5_GET(pmtu_reg, out, max_mtu); 354 if (oper_mtu) 355 *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu); 356 if (admin_mtu) 357 *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu); 358 359 return err; 360 } 361 362 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu) 363 { 364 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; 365 u32 out[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; 366 367 MLX5_SET(pmtu_reg, in, admin_mtu, mtu); 368 MLX5_SET(pmtu_reg, in, local_port, 1); 369 370 return mlx5_core_access_reg(dev, in, sizeof(in), out, 371 sizeof(out), MLX5_REG_PMTU, 0, 1); 372 } 373 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu); 374 375 int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu) 376 { 377 return mlx5_query_port_mtu(dev, NULL, max_mtu, NULL); 378 } 379 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu); 380 381 int mlx5_set_port_pause_and_pfc(struct mlx5_core_dev *dev, u32 port, 382 u8 rx_pause, u8 tx_pause, 383 u8 pfc_en_rx, u8 pfc_en_tx) 384 { 385 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 386 u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 387 388 if (pfc_en_rx || pfc_en_tx) { 389 /* PFC and global pauseframes are incompatible features */ 390 if (tx_pause || rx_pause) 391 return -EINVAL; 392 } 393 394 MLX5_SET(pfcc_reg, in, local_port, port); 395 MLX5_SET(pfcc_reg, in, pptx, tx_pause); 396 MLX5_SET(pfcc_reg, in, pprx, rx_pause); 397 MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx); 398 MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx); 399 MLX5_SET(pfcc_reg, in, prio_mask_tx, pfc_en_tx); 400 MLX5_SET(pfcc_reg, in, prio_mask_rx, pfc_en_rx); 401 402 return mlx5_core_access_reg(dev, in, sizeof(in), out, 403 sizeof(out), MLX5_REG_PFCC, 0, 1); 404 } 405 406 int mlx5_query_port_pause(struct mlx5_core_dev *dev, u32 port, 407 u32 *rx_pause, u32 *tx_pause) 408 { 409 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 410 u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 411 int err; 412 413 MLX5_SET(pfcc_reg, in, local_port, port); 414 415 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 416 sizeof(out), MLX5_REG_PFCC, 0, 0); 417 if (err) 418 return err; 419 420 *rx_pause = MLX5_GET(pfcc_reg, out, pprx); 421 *tx_pause = MLX5_GET(pfcc_reg, out, pptx); 422 423 return 0; 424 } 425 426 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx) 427 { 428 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {}; 429 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 430 int err; 431 432 MLX5_SET(pfcc_reg, in, local_port, 1); 433 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 434 sizeof(out), MLX5_REG_PFCC, 0, 0); 435 if (err) 436 return err; 437 438 if (pfc_en_tx != NULL) 439 *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx); 440 if (pfc_en_rx != NULL) 441 *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx); 442 return 0; 443 } 444 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc); 445 446 int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu) 447 { 448 return mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu); 449 } 450 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu); 451 452 u8 mlx5_is_wol_supported(struct mlx5_core_dev *dev) 453 { 454 u8 wol_supported = 0; 455 456 if (MLX5_CAP_GEN(dev, wol_s)) 457 wol_supported |= MLX5_WOL_SECURED_MAGIC; 458 if (MLX5_CAP_GEN(dev, wol_g)) 459 wol_supported |= MLX5_WOL_MAGIC; 460 if (MLX5_CAP_GEN(dev, wol_a)) 461 wol_supported |= MLX5_WOL_ARP; 462 if (MLX5_CAP_GEN(dev, wol_b)) 463 wol_supported |= MLX5_WOL_BROADCAST; 464 if (MLX5_CAP_GEN(dev, wol_m)) 465 wol_supported |= MLX5_WOL_MULTICAST; 466 if (MLX5_CAP_GEN(dev, wol_u)) 467 wol_supported |= MLX5_WOL_UNICAST; 468 if (MLX5_CAP_GEN(dev, wol_p)) 469 wol_supported |= MLX5_WOL_PHY_ACTIVITY; 470 471 return wol_supported; 472 } 473 EXPORT_SYMBOL_GPL(mlx5_is_wol_supported); 474 475 int mlx5_set_wol(struct mlx5_core_dev *dev, u8 wol_mode) 476 { 477 u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {0}; 478 u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)] = {0}; 479 480 MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL); 481 MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1); 482 MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode); 483 484 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 485 } 486 EXPORT_SYMBOL_GPL(mlx5_set_wol); 487 488 int mlx5_query_dropless_mode(struct mlx5_core_dev *dev, u16 *timeout) 489 { 490 u32 in[MLX5_ST_SZ_DW(query_delay_drop_params_in)] = {0}; 491 u32 out[MLX5_ST_SZ_DW(query_delay_drop_params_out)] = {0}; 492 int err = 0; 493 494 MLX5_SET(query_delay_drop_params_in, in, opcode, 495 MLX5_CMD_OP_QUERY_DELAY_DROP_PARAMS); 496 497 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 498 if (err) 499 return err; 500 501 *timeout = MLX5_GET(query_delay_drop_params_out, out, 502 delay_drop_timeout); 503 504 return 0; 505 } 506 EXPORT_SYMBOL_GPL(mlx5_query_dropless_mode); 507 508 int mlx5_set_dropless_mode(struct mlx5_core_dev *dev, u16 timeout) 509 { 510 u32 in[MLX5_ST_SZ_DW(set_delay_drop_params_in)] = {0}; 511 u32 out[MLX5_ST_SZ_DW(set_delay_drop_params_out)] = {0}; 512 513 MLX5_SET(set_delay_drop_params_in, in, opcode, 514 MLX5_CMD_OP_SET_DELAY_DROP_PARAMS); 515 MLX5_SET(set_delay_drop_params_in, in, delay_drop_timeout, timeout); 516 517 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 518 } 519 EXPORT_SYMBOL_GPL(mlx5_set_dropless_mode); 520 521 int mlx5_core_access_pvlc(struct mlx5_core_dev *dev, 522 struct mlx5_pvlc_reg *pvlc, int write) 523 { 524 int sz = MLX5_ST_SZ_BYTES(pvlc_reg); 525 u8 in[MLX5_ST_SZ_BYTES(pvlc_reg)] = {0}; 526 u8 out[MLX5_ST_SZ_BYTES(pvlc_reg)] = {0}; 527 int err; 528 529 MLX5_SET(pvlc_reg, in, local_port, pvlc->local_port); 530 if (write) 531 MLX5_SET(pvlc_reg, in, vl_admin, pvlc->vl_admin); 532 533 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PVLC, 0, 534 !!write); 535 if (err) 536 return err; 537 538 if (!write) { 539 pvlc->local_port = MLX5_GET(pvlc_reg, out, local_port); 540 pvlc->vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap); 541 pvlc->vl_admin = MLX5_GET(pvlc_reg, out, vl_admin); 542 pvlc->vl_operational = MLX5_GET(pvlc_reg, out, vl_operational); 543 } 544 545 return 0; 546 } 547 EXPORT_SYMBOL_GPL(mlx5_core_access_pvlc); 548 549 int mlx5_core_access_ptys(struct mlx5_core_dev *dev, 550 struct mlx5_ptys_reg *ptys, int write) 551 { 552 int sz = MLX5_ST_SZ_BYTES(ptys_reg); 553 void *out = NULL; 554 void *in = NULL; 555 int err; 556 557 in = mlx5_vzalloc(sz); 558 if (!in) 559 return -ENOMEM; 560 561 out = mlx5_vzalloc(sz); 562 if (!out) { 563 kfree(in); 564 return -ENOMEM; 565 } 566 567 MLX5_SET(ptys_reg, in, local_port, ptys->local_port); 568 MLX5_SET(ptys_reg, in, proto_mask, ptys->proto_mask); 569 if (write) { 570 MLX5_SET(ptys_reg, in, eth_proto_capability, 571 ptys->eth_proto_cap); 572 MLX5_SET(ptys_reg, in, ib_link_width_capability, 573 ptys->ib_link_width_cap); 574 MLX5_SET(ptys_reg, in, ib_proto_capability, 575 ptys->ib_proto_cap); 576 MLX5_SET(ptys_reg, in, eth_proto_admin, ptys->eth_proto_admin); 577 MLX5_SET(ptys_reg, in, ib_link_width_admin, 578 ptys->ib_link_width_admin); 579 MLX5_SET(ptys_reg, in, ib_proto_admin, ptys->ib_proto_admin); 580 MLX5_SET(ptys_reg, in, eth_proto_oper, ptys->eth_proto_oper); 581 MLX5_SET(ptys_reg, in, ib_link_width_oper, 582 ptys->ib_link_width_oper); 583 MLX5_SET(ptys_reg, in, ib_proto_oper, ptys->ib_proto_oper); 584 MLX5_SET(ptys_reg, in, eth_proto_lp_advertise, 585 ptys->eth_proto_lp_advertise); 586 } 587 588 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PTYS, 0, 589 !!write); 590 if (err) 591 goto out; 592 593 if (!write) { 594 ptys->local_port = MLX5_GET(ptys_reg, out, local_port); 595 ptys->proto_mask = MLX5_GET(ptys_reg, out, proto_mask); 596 ptys->eth_proto_cap = MLX5_GET(ptys_reg, out, 597 eth_proto_capability); 598 ptys->ib_link_width_cap = MLX5_GET(ptys_reg, out, 599 ib_link_width_capability); 600 ptys->ib_proto_cap = MLX5_GET(ptys_reg, out, 601 ib_proto_capability); 602 ptys->eth_proto_admin = MLX5_GET(ptys_reg, out, 603 eth_proto_admin); 604 ptys->ib_link_width_admin = MLX5_GET(ptys_reg, out, 605 ib_link_width_admin); 606 ptys->ib_proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin); 607 ptys->eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); 608 ptys->ib_link_width_oper = MLX5_GET(ptys_reg, out, 609 ib_link_width_oper); 610 ptys->ib_proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper); 611 ptys->eth_proto_lp_advertise = MLX5_GET(ptys_reg, out, 612 eth_proto_lp_advertise); 613 } 614 615 out: 616 kvfree(in); 617 kvfree(out); 618 return err; 619 } 620 EXPORT_SYMBOL_GPL(mlx5_core_access_ptys); 621 622 static int mtu_to_ib_mtu(struct mlx5_core_dev *dev, int mtu) 623 { 624 switch (mtu) { 625 case 256: return 1; 626 case 512: return 2; 627 case 1024: return 3; 628 case 2048: return 4; 629 case 4096: return 5; 630 default: 631 mlx5_core_warn(dev, "invalid mtu\n"); 632 return -1; 633 } 634 } 635 636 int mlx5_core_access_pmtu(struct mlx5_core_dev *dev, 637 struct mlx5_pmtu_reg *pmtu, int write) 638 { 639 int sz = MLX5_ST_SZ_BYTES(pmtu_reg); 640 void *out = NULL; 641 void *in = NULL; 642 int err; 643 644 in = mlx5_vzalloc(sz); 645 if (!in) 646 return -ENOMEM; 647 648 out = mlx5_vzalloc(sz); 649 if (!out) { 650 kfree(in); 651 return -ENOMEM; 652 } 653 654 MLX5_SET(pmtu_reg, in, local_port, pmtu->local_port); 655 if (write) 656 MLX5_SET(pmtu_reg, in, admin_mtu, pmtu->admin_mtu); 657 658 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PMTU, 0, 659 !!write); 660 if (err) 661 goto out; 662 663 if (!write) { 664 pmtu->local_port = MLX5_GET(pmtu_reg, out, local_port); 665 pmtu->max_mtu = mtu_to_ib_mtu(dev, MLX5_GET(pmtu_reg, out, 666 max_mtu)); 667 pmtu->admin_mtu = mtu_to_ib_mtu(dev, MLX5_GET(pmtu_reg, out, 668 admin_mtu)); 669 pmtu->oper_mtu = mtu_to_ib_mtu(dev, MLX5_GET(pmtu_reg, out, 670 oper_mtu)); 671 } 672 673 out: 674 kvfree(in); 675 kvfree(out); 676 return err; 677 } 678 EXPORT_SYMBOL_GPL(mlx5_core_access_pmtu); 679 680 int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num) 681 { 682 u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0}; 683 u32 out[MLX5_ST_SZ_DW(pmlp_reg)] = {0}; 684 int lane = 0; 685 int err; 686 687 MLX5_SET(pmlp_reg, in, local_port, 1); 688 689 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 690 sizeof(out), MLX5_REG_PMLP, 0, 0); 691 if (err) 692 return err; 693 694 lane = MLX5_GET(pmlp_reg, out, lane0_module_mapping); 695 *module_num = lane & MLX5_EEPROM_IDENTIFIER_BYTE_MASK; 696 697 return 0; 698 } 699 EXPORT_SYMBOL_GPL(mlx5_query_module_num); 700 701 int mlx5_query_eeprom(struct mlx5_core_dev *dev, 702 int i2c_addr, int page_num, int device_addr, 703 int size, int module_num, u32 *data, int *size_read) 704 { 705 u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {0}; 706 u32 out[MLX5_ST_SZ_DW(mcia_reg)] = {0}; 707 u32 *ptr = (u32 *)MLX5_ADDR_OF(mcia_reg, out, dword_0); 708 int status; 709 int err; 710 711 size = min_t(int, size, MLX5_EEPROM_MAX_BYTES); 712 713 MLX5_SET(mcia_reg, in, l, 0); 714 MLX5_SET(mcia_reg, in, module, module_num); 715 MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr); 716 MLX5_SET(mcia_reg, in, page_number, page_num); 717 MLX5_SET(mcia_reg, in, device_address, device_addr); 718 MLX5_SET(mcia_reg, in, size, size); 719 720 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 721 sizeof(out), MLX5_REG_MCIA, 0, 0); 722 if (err) 723 return err; 724 725 status = MLX5_GET(mcia_reg, out, status); 726 if (status) 727 return status; 728 729 memcpy(data, ptr, size); 730 *size_read = size; 731 return 0; 732 } 733 EXPORT_SYMBOL_GPL(mlx5_query_eeprom); 734 735 int mlx5_vxlan_udp_port_add(struct mlx5_core_dev *dev, u16 port) 736 { 737 u32 in[MLX5_ST_SZ_DW(add_vxlan_udp_dport_in)] = {0}; 738 u32 out[MLX5_ST_SZ_DW(add_vxlan_udp_dport_out)] = {0}; 739 int err; 740 741 MLX5_SET(add_vxlan_udp_dport_in, in, opcode, 742 MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT); 743 MLX5_SET(add_vxlan_udp_dport_in, in, vxlan_udp_port, port); 744 745 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 746 if (err) { 747 mlx5_core_err(dev, "Failed %s, port %u, err - %d", 748 mlx5_command_str(MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT), 749 port, err); 750 } 751 752 return err; 753 } 754 755 int mlx5_vxlan_udp_port_delete(struct mlx5_core_dev *dev, u16 port) 756 { 757 u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)] = {0}; 758 u32 out[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_out)] = {0}; 759 int err; 760 761 MLX5_SET(delete_vxlan_udp_dport_in, in, opcode, 762 MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT); 763 MLX5_SET(delete_vxlan_udp_dport_in, in, vxlan_udp_port, port); 764 765 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 766 if (err) { 767 mlx5_core_err(dev, "Failed %s, port %u, err - %d", 768 mlx5_command_str(MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT), 769 port, err); 770 } 771 772 return err; 773 } 774 775 int mlx5_query_wol(struct mlx5_core_dev *dev, u8 *wol_mode) 776 { 777 u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {0}; 778 u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {0}; 779 int err; 780 781 MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL); 782 783 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 784 785 if (!err) 786 *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode); 787 788 return err; 789 } 790 EXPORT_SYMBOL_GPL(mlx5_query_wol); 791 792 int mlx5_query_port_cong_status(struct mlx5_core_dev *mdev, int protocol, 793 int priority, int *is_enable) 794 { 795 u32 in[MLX5_ST_SZ_DW(query_cong_status_in)] = {0}; 796 u32 out[MLX5_ST_SZ_DW(query_cong_status_out)] = {0}; 797 int err; 798 799 *is_enable = 0; 800 801 MLX5_SET(query_cong_status_in, in, opcode, 802 MLX5_CMD_OP_QUERY_CONG_STATUS); 803 MLX5_SET(query_cong_status_in, in, cong_protocol, protocol); 804 MLX5_SET(query_cong_status_in, in, priority, priority); 805 806 err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); 807 if (!err) 808 *is_enable = MLX5_GET(query_cong_status_out, out, enable); 809 return err; 810 } 811 812 int mlx5_modify_port_cong_status(struct mlx5_core_dev *mdev, int protocol, 813 int priority, int enable) 814 { 815 u32 in[MLX5_ST_SZ_DW(modify_cong_status_in)] = {0}; 816 u32 out[MLX5_ST_SZ_DW(modify_cong_status_out)] = {0}; 817 818 MLX5_SET(modify_cong_status_in, in, opcode, 819 MLX5_CMD_OP_MODIFY_CONG_STATUS); 820 MLX5_SET(modify_cong_status_in, in, cong_protocol, protocol); 821 MLX5_SET(modify_cong_status_in, in, priority, priority); 822 MLX5_SET(modify_cong_status_in, in, enable, enable); 823 824 return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); 825 } 826 827 int mlx5_query_port_cong_params(struct mlx5_core_dev *mdev, int protocol, 828 void *out, int out_size) 829 { 830 u32 in[MLX5_ST_SZ_DW(query_cong_params_in)] = {0}; 831 832 MLX5_SET(query_cong_params_in, in, opcode, 833 MLX5_CMD_OP_QUERY_CONG_PARAMS); 834 MLX5_SET(query_cong_params_in, in, cong_protocol, protocol); 835 836 return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); 837 } 838 839 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out, 840 int outlen) 841 { 842 u32 in[MLX5_ST_SZ_DW(qetc_reg)]; 843 844 if (!MLX5_CAP_GEN(mdev, ets)) 845 return -ENOTSUPP; 846 847 memset(in, 0, sizeof(in)); 848 return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen, 849 MLX5_REG_QETCR, 0, 0); 850 } 851 852 int mlx5_max_tc(struct mlx5_core_dev *mdev) 853 { 854 u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8; 855 856 return num_tc - 1; 857 } 858 EXPORT_SYMBOL_GPL(mlx5_max_tc); 859 860 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, 861 int inlen) 862 { 863 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 864 865 if (!MLX5_CAP_GEN(mdev, ets)) 866 return -ENOTSUPP; 867 868 return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out), 869 MLX5_REG_QETCR, 0, 1); 870 } 871 872 int mlx5_query_port_tc_rate_limit(struct mlx5_core_dev *mdev, 873 u8 *max_bw_value, 874 u8 *max_bw_units) 875 { 876 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 877 void *ets_tcn_conf; 878 int err; 879 int i; 880 881 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 882 if (err) 883 return err; 884 885 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 886 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]); 887 888 max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 889 max_bw_value); 890 max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 891 max_bw_units); 892 } 893 894 return 0; 895 } 896 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_rate_limit); 897 898 int mlx5_modify_port_tc_rate_limit(struct mlx5_core_dev *mdev, 899 const u8 *max_bw_value, 900 const u8 *max_bw_units) 901 { 902 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {}; 903 void *ets_tcn_conf; 904 int i; 905 906 MLX5_SET(qetc_reg, in, port_number, 1); 907 908 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 909 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]); 910 911 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1); 912 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units, 913 max_bw_units[i]); 914 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value, 915 max_bw_value[i]); 916 } 917 918 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 919 } 920 EXPORT_SYMBOL_GPL(mlx5_modify_port_tc_rate_limit); 921 922 int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev, 923 u8 prio, u8 *tc) 924 { 925 u32 in[MLX5_ST_SZ_DW(qtct_reg)]; 926 u32 out[MLX5_ST_SZ_DW(qtct_reg)]; 927 int err; 928 929 memset(in, 0, sizeof(in)); 930 memset(out, 0, sizeof(out)); 931 932 MLX5_SET(qtct_reg, in, port_number, 1); 933 MLX5_SET(qtct_reg, in, prio, prio); 934 935 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 936 sizeof(out), MLX5_REG_QTCT, 0, 0); 937 if (!err) 938 *tc = MLX5_GET(qtct_reg, out, tclass); 939 940 return err; 941 } 942 EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc); 943 944 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, int prio_index, 945 const u8 prio_tc) 946 { 947 u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {}; 948 u32 out[MLX5_ST_SZ_DW(qtct_reg)]; 949 int err; 950 951 if (prio_tc > mlx5_max_tc(mdev)) 952 return -EINVAL; 953 954 MLX5_SET(qtct_reg, in, prio, prio_index); 955 MLX5_SET(qtct_reg, in, tclass, prio_tc); 956 957 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 958 sizeof(out), MLX5_REG_QTCT, 0, 1); 959 960 return (err); 961 } 962 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc); 963 964 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, const u8 *tc_group) 965 { 966 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {}; 967 int i; 968 969 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 970 MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1); 971 MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]); 972 } 973 974 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 975 } 976 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group); 977 978 int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev, 979 u8 tc, u8 *tc_group) 980 { 981 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 982 void *ets_tcn_conf; 983 int err; 984 985 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 986 if (err) 987 return err; 988 989 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, 990 tc_configuration[tc]); 991 992 *tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 993 group); 994 995 return 0; 996 } 997 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group); 998 999 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, const u8 *tc_bw) 1000 { 1001 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {}; 1002 int i; 1003 1004 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 1005 MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1); 1006 MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]); 1007 } 1008 1009 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 1010 } 1011 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc); 1012 1013 int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *bw_pct) 1014 { 1015 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 1016 void *ets_tcn_conf; 1017 int err; 1018 int i; 1019 1020 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 1021 if (err) 1022 return err; 1023 1024 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 1025 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]); 1026 bw_pct[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, bw_allocation); 1027 } 1028 return 0; 1029 } 1030 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc); 1031 1032 int mlx5_modify_port_cong_params(struct mlx5_core_dev *mdev, 1033 void *in, int in_size) 1034 { 1035 u32 out[MLX5_ST_SZ_DW(modify_cong_params_out)] = {0}; 1036 1037 MLX5_SET(modify_cong_params_in, in, opcode, 1038 MLX5_CMD_OP_MODIFY_CONG_PARAMS); 1039 1040 return mlx5_cmd_exec(mdev, in, in_size, out, sizeof(out)); 1041 } 1042 1043 int mlx5_query_port_cong_statistics(struct mlx5_core_dev *mdev, int clear, 1044 void *out, int out_size) 1045 { 1046 u32 in[MLX5_ST_SZ_DW(query_cong_statistics_in)] = {0}; 1047 1048 MLX5_SET(query_cong_statistics_in, in, opcode, 1049 MLX5_CMD_OP_QUERY_CONG_STATISTICS); 1050 MLX5_SET(query_cong_statistics_in, in, clear, clear); 1051 1052 return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); 1053 } 1054 1055 int mlx5_set_diagnostic_params(struct mlx5_core_dev *mdev, void *in, 1056 int in_size) 1057 { 1058 u32 out[MLX5_ST_SZ_DW(set_diagnostic_params_out)] = {0}; 1059 1060 MLX5_SET(set_diagnostic_params_in, in, opcode, 1061 MLX5_CMD_OP_SET_DIAGNOSTICS); 1062 1063 return mlx5_cmd_exec(mdev, in, in_size, out, sizeof(out)); 1064 } 1065 1066 int mlx5_query_diagnostic_counters(struct mlx5_core_dev *mdev, 1067 u8 num_of_samples, u16 sample_index, 1068 void *out, int out_size) 1069 { 1070 u32 in[MLX5_ST_SZ_DW(query_diagnostic_counters_in)] = {0}; 1071 1072 MLX5_SET(query_diagnostic_counters_in, in, opcode, 1073 MLX5_CMD_OP_QUERY_DIAGNOSTICS); 1074 MLX5_SET(query_diagnostic_counters_in, in, num_of_samples, 1075 num_of_samples); 1076 MLX5_SET(query_diagnostic_counters_in, in, sample_index, sample_index); 1077 1078 return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); 1079 } 1080 1081 int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state) 1082 { 1083 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {}; 1084 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {}; 1085 int err; 1086 1087 MLX5_SET(qpts_reg, in, local_port, 1); 1088 MLX5_SET(qpts_reg, in, trust_state, trust_state); 1089 1090 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 1091 sizeof(out), MLX5_REG_QPTS, 0, 1); 1092 return err; 1093 } 1094 1095 int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state) 1096 { 1097 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {}; 1098 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {}; 1099 int err; 1100 1101 MLX5_SET(qpts_reg, in, local_port, 1); 1102 1103 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 1104 sizeof(out), MLX5_REG_QPTS, 0, 0); 1105 if (!err) 1106 *trust_state = MLX5_GET(qpts_reg, out, trust_state); 1107 1108 return err; 1109 } 1110 1111 int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, const u8 *dscp2prio) 1112 { 1113 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg); 1114 void *qpdpm_dscp; 1115 void *out; 1116 void *in; 1117 int err; 1118 int i; 1119 1120 in = kzalloc(sz, GFP_KERNEL); 1121 out = kzalloc(sz, GFP_KERNEL); 1122 if (!in || !out) { 1123 err = -ENOMEM; 1124 goto out; 1125 } 1126 1127 MLX5_SET(qpdpm_reg, in, local_port, 1); 1128 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0); 1129 if (err) 1130 goto out; 1131 1132 memcpy(in, out, sz); 1133 MLX5_SET(qpdpm_reg, in, local_port, 1); 1134 1135 /* Update the corresponding dscp entry */ 1136 for (i = 0; i < MLX5_MAX_SUPPORTED_DSCP; i++) { 1137 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[i]); 1138 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, dscp2prio[i]); 1139 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1); 1140 } 1141 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1); 1142 out: 1143 kfree(in); 1144 kfree(out); 1145 return err; 1146 } 1147 1148 int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio) 1149 { 1150 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg); 1151 void *qpdpm_dscp; 1152 void *out; 1153 void *in; 1154 int err; 1155 int i; 1156 1157 in = kzalloc(sz, GFP_KERNEL); 1158 out = kzalloc(sz, GFP_KERNEL); 1159 if (!in || !out) { 1160 err = -ENOMEM; 1161 goto out; 1162 } 1163 1164 MLX5_SET(qpdpm_reg, in, local_port, 1); 1165 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0); 1166 if (err) 1167 goto out; 1168 1169 for (i = 0; i < MLX5_MAX_SUPPORTED_DSCP; i++) { 1170 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]); 1171 dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio); 1172 } 1173 out: 1174 kfree(in); 1175 kfree(out); 1176 return err; 1177 } 1178 1179 static int mlx5_query_pddr(struct mlx5_core_dev *mdev, 1180 u8 local_port, int page_select, u32 *out, int outlen) 1181 { 1182 u32 in[MLX5_ST_SZ_DW(pddr_reg)] = {0}; 1183 1184 if (!MLX5_CAP_PCAM_REG(mdev, pddr)) 1185 return -EOPNOTSUPP; 1186 1187 MLX5_SET(pddr_reg, in, local_port, local_port); 1188 MLX5_SET(pddr_reg, in, page_select, page_select); 1189 1190 return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen, MLX5_REG_PDDR, 0, 0); 1191 } 1192 1193 int mlx5_query_pddr_range_info(struct mlx5_core_dev *mdev, u8 local_port, u8 *is_er_type) 1194 { 1195 u32 pddr_reg[MLX5_ST_SZ_DW(pddr_reg)] = {}; 1196 int error; 1197 u8 ecc; 1198 u8 ci; 1199 1200 error = mlx5_query_pddr(mdev, local_port, MLX5_PDDR_MODULE_INFO_PAGE, 1201 pddr_reg, sizeof(pddr_reg)); 1202 if (error != 0) 1203 return (error); 1204 1205 ecc = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.ethernet_compliance_code); 1206 ci = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.cable_identifier); 1207 1208 switch (ci) { 1209 case 0: /* QSFP28 */ 1210 case 1: /* QSFP+ */ 1211 *is_er_type = 0; 1212 break; 1213 case 2: /* SFP28/SFP+ */ 1214 case 3: /* QSA (QSFP->SFP) */ 1215 *is_er_type = ((ecc & (1 << 7)) != 0); 1216 break; 1217 default: 1218 *is_er_type = 0; 1219 break; 1220 } 1221 return (0); 1222 } 1223 EXPORT_SYMBOL_GPL(mlx5_query_pddr_range_info); 1224 1225 int mlx5_query_pddr_cable_type(struct mlx5_core_dev *mdev, u8 local_port, u8 *cable_type) 1226 { 1227 u32 pddr_reg[MLX5_ST_SZ_DW(pddr_reg)] = {}; 1228 int error; 1229 1230 error = mlx5_query_pddr(mdev, local_port, MLX5_PDDR_MODULE_INFO_PAGE, 1231 pddr_reg, sizeof(pddr_reg)); 1232 if (error != 0) 1233 return (error); 1234 1235 *cable_type = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.cable_type); 1236 return (0); 1237 } 1238 EXPORT_SYMBOL_GPL(mlx5_query_pddr_cable_type); 1239 1240 int mlx5_query_pddr_troubleshooting_info(struct mlx5_core_dev *mdev, 1241 u16 *monitor_opcode, u8 *status_message, size_t sm_len) 1242 { 1243 int outlen = MLX5_ST_SZ_BYTES(pddr_reg); 1244 u32 out[MLX5_ST_SZ_DW(pddr_reg)] = {0}; 1245 int err; 1246 1247 err = mlx5_query_pddr(mdev, MLX5_PDDR_TROUBLESHOOTING_INFO_PAGE, 1, 1248 out, outlen); 1249 if (err != 0) 1250 return err; 1251 if (monitor_opcode != NULL) { 1252 *monitor_opcode = MLX5_GET(pddr_reg, out, 1253 page_data.troubleshooting_info_page.status_opcode. 1254 monitor_opcodes); 1255 } 1256 if (status_message != NULL) { 1257 strlcpy(status_message, 1258 MLX5_ADDR_OF(pddr_reg, out, 1259 page_data.troubleshooting_info_page.status_message), 1260 sm_len); 1261 } 1262 return (0); 1263 } 1264 1265 int 1266 mlx5_query_mfrl_reg(struct mlx5_core_dev *mdev, u8 *reset_level) 1267 { 1268 u32 mfrl[MLX5_ST_SZ_DW(mfrl_reg)] = {}; 1269 int sz = MLX5_ST_SZ_BYTES(mfrl_reg); 1270 int err; 1271 1272 err = mlx5_core_access_reg(mdev, mfrl, sz, mfrl, sz, MLX5_REG_MFRL, 1273 0, 0); 1274 if (err == 0) 1275 *reset_level = MLX5_GET(mfrl_reg, mfrl, reset_level); 1276 return (err); 1277 } 1278 1279 int 1280 mlx5_set_mfrl_reg(struct mlx5_core_dev *mdev, u8 reset_level) 1281 { 1282 u32 mfrl[MLX5_ST_SZ_DW(mfrl_reg)] = {}; 1283 int sz = MLX5_ST_SZ_BYTES(mfrl_reg); 1284 1285 MLX5_SET(mfrl_reg, mfrl, reset_level, reset_level); 1286 1287 return (mlx5_core_access_reg(mdev, mfrl, sz, mfrl, sz, MLX5_REG_MFRL, 1288 0, 1)); 1289 } 1290 1291 /* speed in units of 1Mb */ 1292 static const u32 mlx5e_link_speed[/*MLX5E_LINK_MODES_NUMBER*/] = { 1293 [MLX5E_1000BASE_CX_SGMII] = 1000, 1294 [MLX5E_1000BASE_KX] = 1000, 1295 [MLX5E_10GBASE_CX4] = 10000, 1296 [MLX5E_10GBASE_KX4] = 10000, 1297 [MLX5E_10GBASE_KR] = 10000, 1298 [MLX5E_20GBASE_KR2] = 20000, 1299 [MLX5E_40GBASE_CR4] = 40000, 1300 [MLX5E_40GBASE_KR4] = 40000, 1301 [MLX5E_56GBASE_R4] = 56000, 1302 [MLX5E_10GBASE_CR] = 10000, 1303 [MLX5E_10GBASE_SR] = 10000, 1304 [MLX5E_10GBASE_ER_LR] = 10000, 1305 [MLX5E_40GBASE_SR4] = 40000, 1306 [MLX5E_40GBASE_LR4_ER4] = 40000, 1307 [MLX5E_50GBASE_SR2] = 50000, 1308 [MLX5E_100GBASE_CR4] = 100000, 1309 [MLX5E_100GBASE_SR4] = 100000, 1310 [MLX5E_100GBASE_KR4] = 100000, 1311 [MLX5E_100GBASE_LR4] = 100000, 1312 [MLX5E_100BASE_TX] = 100, 1313 [MLX5E_1000BASE_T] = 1000, 1314 [MLX5E_10GBASE_T] = 10000, 1315 [MLX5E_25GBASE_CR] = 25000, 1316 [MLX5E_25GBASE_KR] = 25000, 1317 [MLX5E_25GBASE_SR] = 25000, 1318 [MLX5E_50GBASE_CR2] = 50000, 1319 [MLX5E_50GBASE_KR2] = 50000, 1320 }; 1321 1322 static const u32 mlx5e_ext_link_speed[/*MLX5E_EXT_LINK_MODES_NUMBER*/] = { 1323 [MLX5E_SGMII_100M] = 100, 1324 [MLX5E_1000BASE_X_SGMII] = 1000, 1325 [MLX5E_5GBASE_R] = 5000, 1326 [MLX5E_10GBASE_XFI_XAUI_1] = 10000, 1327 [MLX5E_40GBASE_XLAUI_4_XLPPI_4] = 40000, 1328 [MLX5E_25GAUI_1_25GBASE_CR_KR] = 25000, 1329 [MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2] = 50000, 1330 [MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR] = 50000, 1331 [MLX5E_CAUI_4_100GBASE_CR4_KR4] = 100000, 1332 [MLX5E_200GAUI_4_200GBASE_CR4_KR4] = 200000, 1333 [MLX5E_400GAUI_8] = 400000, 1334 }; 1335 1336 static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev, 1337 const u32 **arr, u32 *size) 1338 { 1339 bool ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); 1340 1341 *size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) : 1342 ARRAY_SIZE(mlx5e_link_speed); 1343 *arr = ext ? mlx5e_ext_link_speed : mlx5e_link_speed; 1344 } 1345 1346 u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper) 1347 { 1348 unsigned long temp = eth_proto_oper; 1349 const u32 *table; 1350 u32 speed = 0; 1351 u32 max_size; 1352 int i; 1353 1354 mlx5e_port_get_speed_arr(mdev, &table, &max_size); 1355 i = find_first_bit(&temp, max_size); 1356 if (i < max_size) 1357 speed = table[i]; 1358 return speed; 1359 } 1360 1361 int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext, 1362 struct mlx5e_port_eth_proto *eproto) 1363 { 1364 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 1365 int err; 1366 1367 if (!eproto) 1368 return -EINVAL; 1369 1370 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port); 1371 if (err) 1372 return err; 1373 1374 eproto->cap = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, 1375 eth_proto_capability); 1376 eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin); 1377 eproto->oper = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper); 1378 return 0; 1379 } 1380 1381 int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 1382 { 1383 struct mlx5e_port_eth_proto eproto; 1384 bool ext; 1385 int err; 1386 1387 ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); 1388 err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto); 1389 if (err) 1390 goto out; 1391 1392 *speed = mlx5e_port_ptys2speed(mdev, eproto.oper); 1393 if (!(*speed)) 1394 err = -EINVAL; 1395 1396 out: 1397 return err; 1398 } 1399 1400 int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out) 1401 { 1402 int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 1403 void *in; 1404 int err; 1405 1406 in = kzalloc(sz, GFP_KERNEL); 1407 if (!in) 1408 return -ENOMEM; 1409 1410 MLX5_SET(pbmc_reg, in, local_port, 1); 1411 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0); 1412 1413 kfree(in); 1414 return err; 1415 } 1416 1417 int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in) 1418 { 1419 int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 1420 void *out; 1421 int err; 1422 1423 out = kzalloc(sz, GFP_KERNEL); 1424 if (!out) 1425 return -ENOMEM; 1426 1427 MLX5_SET(pbmc_reg, in, local_port, 1); 1428 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1); 1429 1430 kfree(out); 1431 return err; 1432 } 1433 1434 /* buffer[i]: buffer that priority i mapped to */ 1435 int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 1436 { 1437 int sz = MLX5_ST_SZ_BYTES(pptb_reg); 1438 u32 prio_x_buff; 1439 void *out; 1440 void *in; 1441 int prio; 1442 int err; 1443 1444 in = kzalloc(sz, GFP_KERNEL); 1445 out = kzalloc(sz, GFP_KERNEL); 1446 if (!in || !out) { 1447 err = -ENOMEM; 1448 goto out; 1449 } 1450 1451 MLX5_SET(pptb_reg, in, local_port, 1); 1452 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 1453 if (err) 1454 goto out; 1455 1456 prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff); 1457 for (prio = 0; prio < 8; prio++) { 1458 buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF; 1459 mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]); 1460 } 1461 out: 1462 kfree(in); 1463 kfree(out); 1464 return err; 1465 } 1466 1467 int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 1468 { 1469 int sz = MLX5_ST_SZ_BYTES(pptb_reg); 1470 u32 prio_x_buff; 1471 void *out; 1472 void *in; 1473 int prio; 1474 int err; 1475 1476 in = kzalloc(sz, GFP_KERNEL); 1477 out = kzalloc(sz, GFP_KERNEL); 1478 if (!in || !out) { 1479 err = -ENOMEM; 1480 goto out; 1481 } 1482 1483 /* First query the pptb register */ 1484 MLX5_SET(pptb_reg, in, local_port, 1); 1485 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 1486 if (err) 1487 goto out; 1488 1489 memcpy(in, out, sz); 1490 MLX5_SET(pptb_reg, in, local_port, 1); 1491 1492 /* Update the pm and prio_x_buff */ 1493 MLX5_SET(pptb_reg, in, pm, 0xFF); 1494 1495 prio_x_buff = 0; 1496 for (prio = 0; prio < 8; prio++) 1497 prio_x_buff |= (buffer[prio] << (4 * prio)); 1498 MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff); 1499 1500 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1); 1501 1502 out: 1503 kfree(in); 1504 kfree(out); 1505 return err; 1506 } 1507