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