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_num, int arg, int write) 42 { 43 struct mlx5_access_reg_mbox_in *in = NULL; 44 struct mlx5_access_reg_mbox_out *out = NULL; 45 int err = -ENOMEM; 46 47 in = mlx5_vzalloc(sizeof(*in) + size_in); 48 if (!in) 49 return -ENOMEM; 50 51 out = mlx5_vzalloc(sizeof(*out) + size_out); 52 if (!out) 53 goto ex1; 54 55 memcpy(in->data, data_in, size_in); 56 in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ACCESS_REG); 57 in->hdr.opmod = cpu_to_be16(!write); 58 in->arg = cpu_to_be32(arg); 59 in->register_id = cpu_to_be16(reg_num); 60 err = mlx5_cmd_exec(dev, in, sizeof(*in) + size_in, out, 61 sizeof(*out) + size_out); 62 if (err) 63 goto ex2; 64 65 if (out->hdr.status) 66 err = mlx5_cmd_status_to_err(&out->hdr); 67 68 if (!err) 69 memcpy(data_out, out->data, size_out); 70 71 ex2: 72 kvfree(out); 73 ex1: 74 kvfree(in); 75 return err; 76 } 77 EXPORT_SYMBOL_GPL(mlx5_core_access_reg); 78 79 80 struct mlx5_reg_pcap { 81 u8 rsvd0; 82 u8 port_num; 83 u8 rsvd1[2]; 84 __be32 caps_127_96; 85 __be32 caps_95_64; 86 __be32 caps_63_32; 87 __be32 caps_31_0; 88 }; 89 90 int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps) 91 { 92 struct mlx5_reg_pcap in; 93 struct mlx5_reg_pcap out; 94 95 memset(&in, 0, sizeof(in)); 96 in.caps_127_96 = cpu_to_be32(caps); 97 in.port_num = port_num; 98 99 return mlx5_core_access_reg(dev, &in, sizeof(in), &out, 100 sizeof(out), MLX5_REG_PCAP, 0, 1); 101 } 102 EXPORT_SYMBOL_GPL(mlx5_set_port_caps); 103 104 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys, 105 int ptys_size, int proto_mask, u8 local_port) 106 { 107 u32 in[MLX5_ST_SZ_DW(ptys_reg)]; 108 109 memset(in, 0, sizeof(in)); 110 MLX5_SET(ptys_reg, in, local_port, local_port); 111 MLX5_SET(ptys_reg, in, proto_mask, proto_mask); 112 113 return mlx5_core_access_reg(dev, in, sizeof(in), ptys, 114 ptys_size, MLX5_REG_PTYS, 0, 0); 115 } 116 EXPORT_SYMBOL_GPL(mlx5_query_port_ptys); 117 118 int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration) 119 { 120 u32 out[MLX5_ST_SZ_DW(mlcr_reg)]; 121 u32 in[MLX5_ST_SZ_DW(mlcr_reg)]; 122 123 memset(in, 0, sizeof(in)); 124 MLX5_SET(mlcr_reg, in, local_port, 1); 125 MLX5_SET(mlcr_reg, in, beacon_duration, beacon_duration); 126 127 return mlx5_core_access_reg(dev, in, sizeof(in), out, 128 sizeof(out), MLX5_REG_MLCR, 0, 1); 129 } 130 131 int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev, 132 u32 *proto_cap, int proto_mask) 133 { 134 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 135 int err; 136 137 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); 138 if (err) 139 return err; 140 141 if (proto_mask == MLX5_PTYS_EN) 142 *proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); 143 else 144 *proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability); 145 146 return 0; 147 } 148 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap); 149 150 int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, 151 u32 *proto_admin, int proto_mask) 152 { 153 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 154 int err; 155 156 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); 157 if (err) 158 return err; 159 160 if (proto_mask == MLX5_PTYS_EN) 161 *proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); 162 else 163 *proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin); 164 165 return 0; 166 } 167 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin); 168 169 int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev, 170 u8 *link_width_oper, u8 local_port) 171 { 172 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 173 int err; 174 175 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB, local_port); 176 if (err) 177 return err; 178 179 *link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper); 180 181 return 0; 182 } 183 EXPORT_SYMBOL_GPL(mlx5_query_port_link_width_oper); 184 185 int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev, 186 u8 *proto_oper, int proto_mask, 187 u8 local_port) 188 { 189 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 190 int err; 191 192 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, local_port); 193 if (err) 194 return err; 195 196 if (proto_mask == MLX5_PTYS_EN) 197 *proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); 198 else 199 *proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper); 200 201 return 0; 202 } 203 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_oper); 204 205 int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable, 206 u32 proto_admin, int proto_mask) 207 { 208 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 209 u32 in[MLX5_ST_SZ_DW(ptys_reg)]; 210 u8 an_disable_admin; 211 u8 an_disable_cap; 212 u8 an_status; 213 214 mlx5_query_port_autoneg(dev, proto_mask, &an_status, 215 &an_disable_cap, &an_disable_admin); 216 if (!an_disable_cap && an_disable) 217 return -EPERM; 218 219 memset(in, 0, sizeof(in)); 220 221 MLX5_SET(ptys_reg, in, local_port, 1); 222 MLX5_SET(ptys_reg, in, an_disable_admin, an_disable); 223 MLX5_SET(ptys_reg, in, proto_mask, proto_mask); 224 if (proto_mask == MLX5_PTYS_EN) 225 MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin); 226 else 227 MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin); 228 229 return mlx5_core_access_reg(dev, in, sizeof(in), out, 230 sizeof(out), MLX5_REG_PTYS, 0, 1); 231 } 232 EXPORT_SYMBOL_GPL(mlx5_set_port_ptys); 233 234 /* This function should be used after setting a port register only */ 235 void mlx5_toggle_port_link(struct mlx5_core_dev *dev) 236 { 237 enum mlx5_port_status ps; 238 239 mlx5_query_port_admin_status(dev, &ps); 240 mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN); 241 if (ps == MLX5_PORT_UP) 242 mlx5_set_port_admin_status(dev, MLX5_PORT_UP); 243 } 244 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link); 245 246 int mlx5_set_port_admin_status(struct mlx5_core_dev *dev, 247 enum mlx5_port_status status) 248 { 249 u32 in[MLX5_ST_SZ_DW(paos_reg)]; 250 u32 out[MLX5_ST_SZ_DW(paos_reg)]; 251 252 memset(in, 0, sizeof(in)); 253 254 MLX5_SET(paos_reg, in, local_port, 1); 255 MLX5_SET(paos_reg, in, admin_status, status); 256 MLX5_SET(paos_reg, in, ase, 1); 257 258 return mlx5_core_access_reg(dev, in, sizeof(in), out, 259 sizeof(out), MLX5_REG_PAOS, 0, 1); 260 } 261 EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status); 262 263 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev, 264 enum mlx5_port_status *status) 265 { 266 u32 in[MLX5_ST_SZ_DW(paos_reg)]; 267 u32 out[MLX5_ST_SZ_DW(paos_reg)]; 268 int err; 269 270 memset(in, 0, sizeof(in)); 271 272 MLX5_SET(paos_reg, in, local_port, 1); 273 274 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 275 sizeof(out), MLX5_REG_PAOS, 0, 0); 276 if (err) 277 return err; 278 279 *status = MLX5_GET(paos_reg, out, admin_status); 280 return 0; 281 } 282 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status); 283 284 static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu, 285 u16 *max_mtu, u16 *oper_mtu, u8 port) 286 { 287 u32 in[MLX5_ST_SZ_DW(pmtu_reg)]; 288 u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; 289 290 memset(in, 0, sizeof(in)); 291 292 MLX5_SET(pmtu_reg, in, local_port, port); 293 294 mlx5_core_access_reg(dev, in, sizeof(in), out, 295 sizeof(out), MLX5_REG_PMTU, 0, 0); 296 297 if (max_mtu) 298 *max_mtu = MLX5_GET(pmtu_reg, out, max_mtu); 299 if (oper_mtu) 300 *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu); 301 if (admin_mtu) 302 *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu); 303 } 304 305 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port) 306 { 307 u32 in[MLX5_ST_SZ_DW(pmtu_reg)]; 308 u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; 309 310 memset(in, 0, sizeof(in)); 311 312 MLX5_SET(pmtu_reg, in, admin_mtu, mtu); 313 MLX5_SET(pmtu_reg, in, local_port, port); 314 315 return mlx5_core_access_reg(dev, in, sizeof(in), out, 316 sizeof(out), MLX5_REG_PMTU, 0, 1); 317 } 318 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu); 319 320 void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu, 321 u8 port) 322 { 323 mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port); 324 } 325 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu); 326 327 void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu, 328 u8 port) 329 { 330 mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port); 331 } 332 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu); 333 334 static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num) 335 { 336 u32 out[MLX5_ST_SZ_DW(pmlp_reg)]; 337 u32 in[MLX5_ST_SZ_DW(pmlp_reg)]; 338 int module_mapping; 339 int err; 340 341 memset(in, 0, sizeof(in)); 342 343 MLX5_SET(pmlp_reg, in, local_port, 1); 344 345 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), 346 MLX5_REG_PMLP, 0, 0); 347 if (err) 348 return err; 349 350 module_mapping = MLX5_GET(pmlp_reg, out, lane0_module_mapping); 351 *module_num = module_mapping & MLX5_EEPROM_IDENTIFIER_BYTE_MASK; 352 353 return 0; 354 } 355 356 int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, 357 u16 offset, u16 size, u8 *data) 358 { 359 u32 out[MLX5_ST_SZ_DW(mcia_reg)]; 360 u32 in[MLX5_ST_SZ_DW(mcia_reg)]; 361 int module_num; 362 u16 i2c_addr; 363 int status; 364 int err; 365 void *ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0); 366 367 err = mlx5_query_module_num(dev, &module_num); 368 if (err) 369 return err; 370 371 memset(in, 0, sizeof(in)); 372 size = min_t(int, size, MLX5_EEPROM_MAX_BYTES); 373 374 if (offset < MLX5_EEPROM_PAGE_LENGTH && 375 offset + size > MLX5_EEPROM_PAGE_LENGTH) 376 /* Cross pages read, read until offset 256 in low page */ 377 size -= offset + size - MLX5_EEPROM_PAGE_LENGTH; 378 379 i2c_addr = MLX5_I2C_ADDR_LOW; 380 if (offset >= MLX5_EEPROM_PAGE_LENGTH) { 381 i2c_addr = MLX5_I2C_ADDR_HIGH; 382 offset -= MLX5_EEPROM_PAGE_LENGTH; 383 } 384 385 MLX5_SET(mcia_reg, in, l, 0); 386 MLX5_SET(mcia_reg, in, module, module_num); 387 MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr); 388 MLX5_SET(mcia_reg, in, page_number, 0); 389 MLX5_SET(mcia_reg, in, device_address, offset); 390 MLX5_SET(mcia_reg, in, size, size); 391 392 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 393 sizeof(out), MLX5_REG_MCIA, 0, 0); 394 if (err) 395 return err; 396 397 status = MLX5_GET(mcia_reg, out, status); 398 if (status) { 399 mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n", 400 status); 401 return -EIO; 402 } 403 404 memcpy(data, ptr, size); 405 406 return size; 407 } 408 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom); 409 410 static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc, 411 int pvlc_size, u8 local_port) 412 { 413 u32 in[MLX5_ST_SZ_DW(pvlc_reg)]; 414 415 memset(in, 0, sizeof(in)); 416 MLX5_SET(pvlc_reg, in, local_port, local_port); 417 418 return mlx5_core_access_reg(dev, in, sizeof(in), pvlc, 419 pvlc_size, MLX5_REG_PVLC, 0, 0); 420 } 421 422 int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev, 423 u8 *vl_hw_cap, u8 local_port) 424 { 425 u32 out[MLX5_ST_SZ_DW(pvlc_reg)]; 426 int err; 427 428 err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port); 429 if (err) 430 return err; 431 432 *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap); 433 434 return 0; 435 } 436 EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap); 437 438 int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev, 439 u8 port_num, void *out, size_t sz) 440 { 441 u32 *in; 442 int err; 443 444 in = mlx5_vzalloc(sz); 445 if (!in) { 446 err = -ENOMEM; 447 return err; 448 } 449 450 MLX5_SET(ppcnt_reg, in, local_port, port_num); 451 452 MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP); 453 err = mlx5_core_access_reg(dev, in, sz, out, 454 sz, MLX5_REG_PPCNT, 0, 0); 455 456 kvfree(in); 457 return err; 458 } 459 EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt); 460 461 int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause) 462 { 463 u32 in[MLX5_ST_SZ_DW(pfcc_reg)]; 464 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 465 466 memset(in, 0, sizeof(in)); 467 MLX5_SET(pfcc_reg, in, local_port, 1); 468 MLX5_SET(pfcc_reg, in, pptx, tx_pause); 469 MLX5_SET(pfcc_reg, in, pprx, rx_pause); 470 471 return mlx5_core_access_reg(dev, in, sizeof(in), out, 472 sizeof(out), MLX5_REG_PFCC, 0, 1); 473 } 474 EXPORT_SYMBOL_GPL(mlx5_set_port_pause); 475 476 int mlx5_query_port_pause(struct mlx5_core_dev *dev, 477 u32 *rx_pause, u32 *tx_pause) 478 { 479 u32 in[MLX5_ST_SZ_DW(pfcc_reg)]; 480 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 481 int err; 482 483 memset(in, 0, sizeof(in)); 484 MLX5_SET(pfcc_reg, in, local_port, 1); 485 486 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 487 sizeof(out), MLX5_REG_PFCC, 0, 0); 488 if (err) 489 return err; 490 491 if (rx_pause) 492 *rx_pause = MLX5_GET(pfcc_reg, out, pprx); 493 494 if (tx_pause) 495 *tx_pause = MLX5_GET(pfcc_reg, out, pptx); 496 497 return 0; 498 } 499 EXPORT_SYMBOL_GPL(mlx5_query_port_pause); 500 501 int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx) 502 { 503 u32 in[MLX5_ST_SZ_DW(pfcc_reg)]; 504 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 505 506 memset(in, 0, sizeof(in)); 507 MLX5_SET(pfcc_reg, in, local_port, 1); 508 MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx); 509 MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx); 510 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx); 511 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx); 512 513 return mlx5_core_access_reg(dev, in, sizeof(in), out, 514 sizeof(out), MLX5_REG_PFCC, 0, 1); 515 } 516 EXPORT_SYMBOL_GPL(mlx5_set_port_pfc); 517 518 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx) 519 { 520 u32 in[MLX5_ST_SZ_DW(pfcc_reg)]; 521 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 522 int err; 523 524 memset(in, 0, sizeof(in)); 525 MLX5_SET(pfcc_reg, in, local_port, 1); 526 527 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 528 sizeof(out), MLX5_REG_PFCC, 0, 0); 529 if (err) 530 return err; 531 532 if (pfc_en_tx) 533 *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx); 534 535 if (pfc_en_rx) 536 *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx); 537 538 return 0; 539 } 540 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc); 541 542 void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask, 543 u8 *an_status, 544 u8 *an_disable_cap, u8 *an_disable_admin) 545 { 546 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 547 548 *an_status = 0; 549 *an_disable_cap = 0; 550 *an_disable_admin = 0; 551 552 if (mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1)) 553 return; 554 555 *an_status = MLX5_GET(ptys_reg, out, an_status); 556 *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap); 557 *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); 558 } 559 EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg); 560 561 int mlx5_max_tc(struct mlx5_core_dev *mdev) 562 { 563 u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8; 564 565 return num_tc - 1; 566 } 567 568 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc) 569 { 570 u32 in[MLX5_ST_SZ_DW(qtct_reg)]; 571 u32 out[MLX5_ST_SZ_DW(qtct_reg)]; 572 int err; 573 int i; 574 575 memset(in, 0, sizeof(in)); 576 for (i = 0; i < 8; i++) { 577 if (prio_tc[i] > mlx5_max_tc(mdev)) 578 return -EINVAL; 579 580 MLX5_SET(qtct_reg, in, prio, i); 581 MLX5_SET(qtct_reg, in, tclass, prio_tc[i]); 582 583 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 584 sizeof(out), MLX5_REG_QTCT, 0, 1); 585 if (err) 586 return err; 587 } 588 589 return 0; 590 } 591 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc); 592 593 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, 594 int inlen) 595 { 596 u32 out[MLX5_ST_SZ_DW(qtct_reg)]; 597 598 if (!MLX5_CAP_GEN(mdev, ets)) 599 return -ENOTSUPP; 600 601 return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out), 602 MLX5_REG_QETCR, 0, 1); 603 } 604 605 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out, 606 int outlen) 607 { 608 u32 in[MLX5_ST_SZ_DW(qtct_reg)]; 609 610 if (!MLX5_CAP_GEN(mdev, ets)) 611 return -ENOTSUPP; 612 613 memset(in, 0, sizeof(in)); 614 return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen, 615 MLX5_REG_QETCR, 0, 0); 616 } 617 618 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group) 619 { 620 u32 in[MLX5_ST_SZ_DW(qetc_reg)]; 621 int i; 622 623 memset(in, 0, sizeof(in)); 624 625 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 626 MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1); 627 MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]); 628 } 629 630 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 631 } 632 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group); 633 634 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw) 635 { 636 u32 in[MLX5_ST_SZ_DW(qetc_reg)]; 637 int i; 638 639 memset(in, 0, sizeof(in)); 640 641 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 642 MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1); 643 MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]); 644 } 645 646 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 647 } 648 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc); 649 650 int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev, 651 u8 *max_bw_value, 652 u8 *max_bw_units) 653 { 654 u32 in[MLX5_ST_SZ_DW(qetc_reg)]; 655 void *ets_tcn_conf; 656 int i; 657 658 memset(in, 0, sizeof(in)); 659 660 MLX5_SET(qetc_reg, in, port_number, 1); 661 662 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 663 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]); 664 665 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1); 666 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units, 667 max_bw_units[i]); 668 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value, 669 max_bw_value[i]); 670 } 671 672 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 673 } 674 EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit); 675 676 int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev, 677 u8 *max_bw_value, 678 u8 *max_bw_units) 679 { 680 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 681 void *ets_tcn_conf; 682 int err; 683 int i; 684 685 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 686 if (err) 687 return err; 688 689 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 690 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]); 691 692 max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 693 max_bw_value); 694 max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 695 max_bw_units); 696 } 697 698 return 0; 699 } 700 EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit); 701 702 int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode) 703 { 704 u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)]; 705 u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)]; 706 707 memset(in, 0, sizeof(in)); 708 memset(out, 0, sizeof(out)); 709 710 MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL); 711 MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1); 712 MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode); 713 714 return mlx5_cmd_exec_check_status(mdev, in, sizeof(in), 715 out, sizeof(out)); 716 } 717 EXPORT_SYMBOL_GPL(mlx5_set_port_wol); 718 719 int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode) 720 { 721 u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)]; 722 u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)]; 723 int err; 724 725 memset(in, 0, sizeof(in)); 726 memset(out, 0, sizeof(out)); 727 728 MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL); 729 730 err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in), 731 out, sizeof(out)); 732 733 if (!err) 734 *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode); 735 736 return err; 737 } 738 EXPORT_SYMBOL_GPL(mlx5_query_port_wol); 739 740 static int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, 741 int outlen) 742 { 743 u32 in[MLX5_ST_SZ_DW(pcmr_reg)]; 744 745 memset(in, 0, sizeof(in)); 746 MLX5_SET(pcmr_reg, in, local_port, 1); 747 748 return mlx5_core_access_reg(mdev, in, sizeof(in), out, 749 outlen, MLX5_REG_PCMR, 0, 0); 750 } 751 752 static int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen) 753 { 754 u32 out[MLX5_ST_SZ_DW(pcmr_reg)]; 755 756 return mlx5_core_access_reg(mdev, in, inlen, out, 757 sizeof(out), MLX5_REG_PCMR, 0, 1); 758 } 759 760 int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable) 761 { 762 u32 in[MLX5_ST_SZ_DW(pcmr_reg)]; 763 764 memset(in, 0, sizeof(in)); 765 MLX5_SET(pcmr_reg, in, local_port, 1); 766 MLX5_SET(pcmr_reg, in, fcs_chk, enable); 767 768 return mlx5_set_ports_check(mdev, in, sizeof(in)); 769 } 770 771 void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported, 772 bool *enabled) 773 { 774 u32 out[MLX5_ST_SZ_DW(pcmr_reg)]; 775 /* Default values for FW which do not support MLX5_REG_PCMR */ 776 *supported = false; 777 *enabled = true; 778 779 if (!MLX5_CAP_GEN(mdev, ports_check)) 780 return; 781 782 if (mlx5_query_ports_check(mdev, out, sizeof(out))) 783 return; 784 785 *supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap)); 786 *enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk)); 787 } 788