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