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