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 int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, 357 u16 offset, u16 size, u8 *data) 358 { 359 int module_num, status, err, page_num = 0; 360 u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {}; 361 u32 out[MLX5_ST_SZ_DW(mcia_reg)]; 362 u16 i2c_addr = 0; 363 u8 module_id; 364 void *ptr; 365 366 err = mlx5_query_module_num(dev, &module_num); 367 if (err) 368 return err; 369 370 err = mlx5_query_module_id(dev, module_num, &module_id); 371 if (err) 372 return err; 373 374 switch (module_id) { 375 case MLX5_MODULE_ID_SFP: 376 mlx5_sfp_eeprom_params_set(&i2c_addr, &page_num, &offset); 377 break; 378 case MLX5_MODULE_ID_QSFP: 379 case MLX5_MODULE_ID_QSFP_PLUS: 380 case MLX5_MODULE_ID_QSFP28: 381 mlx5_qsfp_eeprom_params_set(&i2c_addr, &page_num, &offset); 382 break; 383 default: 384 mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id); 385 return -EINVAL; 386 } 387 388 if (offset + size > MLX5_EEPROM_PAGE_LENGTH) 389 /* Cross pages read, read until offset 256 in low page */ 390 size -= offset + size - MLX5_EEPROM_PAGE_LENGTH; 391 392 size = min_t(int, size, MLX5_EEPROM_MAX_BYTES); 393 394 MLX5_SET(mcia_reg, in, l, 0); 395 MLX5_SET(mcia_reg, in, module, module_num); 396 MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr); 397 MLX5_SET(mcia_reg, in, page_number, page_num); 398 MLX5_SET(mcia_reg, in, device_address, offset); 399 MLX5_SET(mcia_reg, in, size, size); 400 401 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 402 sizeof(out), MLX5_REG_MCIA, 0, 0); 403 if (err) 404 return err; 405 406 status = MLX5_GET(mcia_reg, out, status); 407 if (status) { 408 mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n", 409 status); 410 return -EIO; 411 } 412 413 ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0); 414 memcpy(data, ptr, size); 415 416 return size; 417 } 418 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom); 419 420 static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc, 421 int pvlc_size, u8 local_port) 422 { 423 u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0}; 424 425 MLX5_SET(pvlc_reg, in, local_port, local_port); 426 return mlx5_core_access_reg(dev, in, sizeof(in), pvlc, 427 pvlc_size, MLX5_REG_PVLC, 0, 0); 428 } 429 430 int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev, 431 u8 *vl_hw_cap, u8 local_port) 432 { 433 u32 out[MLX5_ST_SZ_DW(pvlc_reg)]; 434 int err; 435 436 err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port); 437 if (err) 438 return err; 439 440 *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap); 441 442 return 0; 443 } 444 EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap); 445 446 int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev, 447 u8 port_num, void *out, size_t sz) 448 { 449 u32 *in; 450 int err; 451 452 in = kvzalloc(sz, GFP_KERNEL); 453 if (!in) { 454 err = -ENOMEM; 455 return err; 456 } 457 458 MLX5_SET(ppcnt_reg, in, local_port, port_num); 459 460 MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP); 461 err = mlx5_core_access_reg(dev, in, sz, out, 462 sz, MLX5_REG_PPCNT, 0, 0); 463 464 kvfree(in); 465 return err; 466 } 467 EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt); 468 469 static int mlx5_query_pfcc_reg(struct mlx5_core_dev *dev, u32 *out, 470 u32 out_size) 471 { 472 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 473 474 MLX5_SET(pfcc_reg, in, local_port, 1); 475 476 return mlx5_core_access_reg(dev, in, sizeof(in), out, 477 out_size, MLX5_REG_PFCC, 0, 0); 478 } 479 480 int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause) 481 { 482 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 483 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 484 485 MLX5_SET(pfcc_reg, in, local_port, 1); 486 MLX5_SET(pfcc_reg, in, pptx, tx_pause); 487 MLX5_SET(pfcc_reg, in, pprx, rx_pause); 488 489 return mlx5_core_access_reg(dev, in, sizeof(in), out, 490 sizeof(out), MLX5_REG_PFCC, 0, 1); 491 } 492 EXPORT_SYMBOL_GPL(mlx5_set_port_pause); 493 494 int mlx5_query_port_pause(struct mlx5_core_dev *dev, 495 u32 *rx_pause, u32 *tx_pause) 496 { 497 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 498 int err; 499 500 err = mlx5_query_pfcc_reg(dev, out, sizeof(out)); 501 if (err) 502 return err; 503 504 if (rx_pause) 505 *rx_pause = MLX5_GET(pfcc_reg, out, pprx); 506 507 if (tx_pause) 508 *tx_pause = MLX5_GET(pfcc_reg, out, pptx); 509 510 return 0; 511 } 512 EXPORT_SYMBOL_GPL(mlx5_query_port_pause); 513 514 int mlx5_set_port_stall_watermark(struct mlx5_core_dev *dev, 515 u16 stall_critical_watermark, 516 u16 stall_minor_watermark) 517 { 518 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 519 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 520 521 MLX5_SET(pfcc_reg, in, local_port, 1); 522 MLX5_SET(pfcc_reg, in, pptx_mask_n, 1); 523 MLX5_SET(pfcc_reg, in, pprx_mask_n, 1); 524 MLX5_SET(pfcc_reg, in, ppan_mask_n, 1); 525 MLX5_SET(pfcc_reg, in, critical_stall_mask, 1); 526 MLX5_SET(pfcc_reg, in, minor_stall_mask, 1); 527 MLX5_SET(pfcc_reg, in, device_stall_critical_watermark, 528 stall_critical_watermark); 529 MLX5_SET(pfcc_reg, in, device_stall_minor_watermark, stall_minor_watermark); 530 531 return mlx5_core_access_reg(dev, in, sizeof(in), out, 532 sizeof(out), MLX5_REG_PFCC, 0, 1); 533 } 534 535 int mlx5_query_port_stall_watermark(struct mlx5_core_dev *dev, 536 u16 *stall_critical_watermark, 537 u16 *stall_minor_watermark) 538 { 539 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 540 int err; 541 542 err = mlx5_query_pfcc_reg(dev, out, sizeof(out)); 543 if (err) 544 return err; 545 546 if (stall_critical_watermark) 547 *stall_critical_watermark = MLX5_GET(pfcc_reg, out, 548 device_stall_critical_watermark); 549 550 if (stall_minor_watermark) 551 *stall_minor_watermark = MLX5_GET(pfcc_reg, out, 552 device_stall_minor_watermark); 553 554 return 0; 555 } 556 557 int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx) 558 { 559 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 560 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 561 562 MLX5_SET(pfcc_reg, in, local_port, 1); 563 MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx); 564 MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx); 565 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx); 566 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx); 567 568 return mlx5_core_access_reg(dev, in, sizeof(in), out, 569 sizeof(out), MLX5_REG_PFCC, 0, 1); 570 } 571 EXPORT_SYMBOL_GPL(mlx5_set_port_pfc); 572 573 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx) 574 { 575 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 576 int err; 577 578 err = mlx5_query_pfcc_reg(dev, out, sizeof(out)); 579 if (err) 580 return err; 581 582 if (pfc_en_tx) 583 *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx); 584 585 if (pfc_en_rx) 586 *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx); 587 588 return 0; 589 } 590 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc); 591 592 int mlx5_max_tc(struct mlx5_core_dev *mdev) 593 { 594 u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8; 595 596 return num_tc - 1; 597 } 598 599 int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out) 600 { 601 u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0}; 602 603 MLX5_SET(dcbx_param, in, port_number, 1); 604 605 return mlx5_core_access_reg(mdev, in, sizeof(in), out, 606 sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0); 607 } 608 609 int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in) 610 { 611 u32 out[MLX5_ST_SZ_DW(dcbx_param)]; 612 613 MLX5_SET(dcbx_param, in, port_number, 1); 614 615 return mlx5_core_access_reg(mdev, in, sizeof(out), out, 616 sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1); 617 } 618 619 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc) 620 { 621 u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0}; 622 u32 out[MLX5_ST_SZ_DW(qtct_reg)]; 623 int err; 624 int i; 625 626 for (i = 0; i < 8; i++) { 627 if (prio_tc[i] > mlx5_max_tc(mdev)) 628 return -EINVAL; 629 630 MLX5_SET(qtct_reg, in, prio, i); 631 MLX5_SET(qtct_reg, in, tclass, prio_tc[i]); 632 633 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 634 sizeof(out), MLX5_REG_QTCT, 0, 1); 635 if (err) 636 return err; 637 } 638 639 return 0; 640 } 641 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc); 642 643 int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev, 644 u8 prio, u8 *tc) 645 { 646 u32 in[MLX5_ST_SZ_DW(qtct_reg)]; 647 u32 out[MLX5_ST_SZ_DW(qtct_reg)]; 648 int err; 649 650 memset(in, 0, sizeof(in)); 651 memset(out, 0, sizeof(out)); 652 653 MLX5_SET(qtct_reg, in, port_number, 1); 654 MLX5_SET(qtct_reg, in, prio, prio); 655 656 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 657 sizeof(out), MLX5_REG_QTCT, 0, 0); 658 if (!err) 659 *tc = MLX5_GET(qtct_reg, out, tclass); 660 661 return err; 662 } 663 EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc); 664 665 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, 666 int inlen) 667 { 668 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 669 670 if (!MLX5_CAP_GEN(mdev, ets)) 671 return -EOPNOTSUPP; 672 673 return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out), 674 MLX5_REG_QETCR, 0, 1); 675 } 676 677 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out, 678 int outlen) 679 { 680 u32 in[MLX5_ST_SZ_DW(qetc_reg)]; 681 682 if (!MLX5_CAP_GEN(mdev, ets)) 683 return -EOPNOTSUPP; 684 685 memset(in, 0, sizeof(in)); 686 return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen, 687 MLX5_REG_QETCR, 0, 0); 688 } 689 690 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group) 691 { 692 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; 693 int i; 694 695 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 696 MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1); 697 MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]); 698 } 699 700 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 701 } 702 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group); 703 704 int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev, 705 u8 tc, u8 *tc_group) 706 { 707 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 708 void *ets_tcn_conf; 709 int err; 710 711 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 712 if (err) 713 return err; 714 715 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, 716 tc_configuration[tc]); 717 718 *tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 719 group); 720 721 return 0; 722 } 723 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group); 724 725 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw) 726 { 727 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; 728 int i; 729 730 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 731 MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1); 732 MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]); 733 } 734 735 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 736 } 737 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc); 738 739 int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev, 740 u8 tc, u8 *bw_pct) 741 { 742 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 743 void *ets_tcn_conf; 744 int err; 745 746 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 747 if (err) 748 return err; 749 750 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, 751 tc_configuration[tc]); 752 753 *bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 754 bw_allocation); 755 756 return 0; 757 } 758 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc); 759 760 int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev, 761 u8 *max_bw_value, 762 u8 *max_bw_units) 763 { 764 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; 765 void *ets_tcn_conf; 766 int i; 767 768 MLX5_SET(qetc_reg, in, port_number, 1); 769 770 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 771 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]); 772 773 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1); 774 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units, 775 max_bw_units[i]); 776 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value, 777 max_bw_value[i]); 778 } 779 780 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 781 } 782 EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit); 783 784 int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev, 785 u8 *max_bw_value, 786 u8 *max_bw_units) 787 { 788 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 789 void *ets_tcn_conf; 790 int err; 791 int i; 792 793 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 794 if (err) 795 return err; 796 797 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 798 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]); 799 800 max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 801 max_bw_value); 802 max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 803 max_bw_units); 804 } 805 806 return 0; 807 } 808 EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit); 809 810 int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode) 811 { 812 u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {}; 813 814 MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL); 815 MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1); 816 MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode); 817 return mlx5_cmd_exec_in(mdev, set_wol_rol, in); 818 } 819 EXPORT_SYMBOL_GPL(mlx5_set_port_wol); 820 821 int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode) 822 { 823 u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {}; 824 u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {}; 825 int err; 826 827 MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL); 828 err = mlx5_cmd_exec_inout(mdev, query_wol_rol, in, out); 829 if (!err) 830 *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode); 831 832 return err; 833 } 834 EXPORT_SYMBOL_GPL(mlx5_query_port_wol); 835 836 int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, int outlen) 837 { 838 u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0}; 839 840 MLX5_SET(pcmr_reg, in, local_port, 1); 841 return mlx5_core_access_reg(mdev, in, sizeof(in), out, 842 outlen, MLX5_REG_PCMR, 0, 0); 843 } 844 845 int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen) 846 { 847 u32 out[MLX5_ST_SZ_DW(pcmr_reg)]; 848 849 return mlx5_core_access_reg(mdev, in, inlen, out, 850 sizeof(out), MLX5_REG_PCMR, 0, 1); 851 } 852 853 int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable) 854 { 855 u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0}; 856 int err; 857 858 err = mlx5_query_ports_check(mdev, in, sizeof(in)); 859 if (err) 860 return err; 861 MLX5_SET(pcmr_reg, in, local_port, 1); 862 MLX5_SET(pcmr_reg, in, fcs_chk, enable); 863 return mlx5_set_ports_check(mdev, in, sizeof(in)); 864 } 865 866 void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported, 867 bool *enabled) 868 { 869 u32 out[MLX5_ST_SZ_DW(pcmr_reg)]; 870 /* Default values for FW which do not support MLX5_REG_PCMR */ 871 *supported = false; 872 *enabled = true; 873 874 if (!MLX5_CAP_GEN(mdev, ports_check)) 875 return; 876 877 if (mlx5_query_ports_check(mdev, out, sizeof(out))) 878 return; 879 880 *supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap)); 881 *enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk)); 882 } 883 884 int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size) 885 { 886 u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0}; 887 888 return mlx5_core_access_reg(mdev, in, sizeof(in), mtpps, 889 mtpps_size, MLX5_REG_MTPPS, 0, 0); 890 } 891 892 int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size) 893 { 894 u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0}; 895 896 return mlx5_core_access_reg(mdev, mtpps, mtpps_size, out, 897 sizeof(out), MLX5_REG_MTPPS, 0, 1); 898 } 899 900 int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode) 901 { 902 u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; 903 u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; 904 int err = 0; 905 906 MLX5_SET(mtppse_reg, in, pin, pin); 907 908 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 909 sizeof(out), MLX5_REG_MTPPSE, 0, 0); 910 if (err) 911 return err; 912 913 *arm = MLX5_GET(mtppse_reg, in, event_arm); 914 *mode = MLX5_GET(mtppse_reg, in, event_generation_mode); 915 916 return err; 917 } 918 919 int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode) 920 { 921 u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; 922 u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; 923 924 MLX5_SET(mtppse_reg, in, pin, pin); 925 MLX5_SET(mtppse_reg, in, event_arm, arm); 926 MLX5_SET(mtppse_reg, in, event_generation_mode, mode); 927 928 return mlx5_core_access_reg(mdev, in, sizeof(in), out, 929 sizeof(out), MLX5_REG_MTPPSE, 0, 1); 930 } 931 932 int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state) 933 { 934 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {}; 935 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {}; 936 int err; 937 938 MLX5_SET(qpts_reg, in, local_port, 1); 939 MLX5_SET(qpts_reg, in, trust_state, trust_state); 940 941 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 942 sizeof(out), MLX5_REG_QPTS, 0, 1); 943 return err; 944 } 945 946 int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state) 947 { 948 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {}; 949 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {}; 950 int err; 951 952 MLX5_SET(qpts_reg, in, local_port, 1); 953 954 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 955 sizeof(out), MLX5_REG_QPTS, 0, 0); 956 if (!err) 957 *trust_state = MLX5_GET(qpts_reg, out, trust_state); 958 959 return err; 960 } 961 962 int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, u8 dscp, u8 prio) 963 { 964 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg); 965 void *qpdpm_dscp; 966 void *out; 967 void *in; 968 int err; 969 970 in = kzalloc(sz, GFP_KERNEL); 971 out = kzalloc(sz, GFP_KERNEL); 972 if (!in || !out) { 973 err = -ENOMEM; 974 goto out; 975 } 976 977 MLX5_SET(qpdpm_reg, in, local_port, 1); 978 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0); 979 if (err) 980 goto out; 981 982 memcpy(in, out, sz); 983 MLX5_SET(qpdpm_reg, in, local_port, 1); 984 985 /* Update the corresponding dscp entry */ 986 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[dscp]); 987 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, prio); 988 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1); 989 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1); 990 991 out: 992 kfree(in); 993 kfree(out); 994 return err; 995 } 996 997 /* dscp2prio[i]: priority that dscp i mapped to */ 998 #define MLX5E_SUPPORTED_DSCP 64 999 int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio) 1000 { 1001 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg); 1002 void *qpdpm_dscp; 1003 void *out; 1004 void *in; 1005 int err; 1006 int i; 1007 1008 in = kzalloc(sz, GFP_KERNEL); 1009 out = kzalloc(sz, GFP_KERNEL); 1010 if (!in || !out) { 1011 err = -ENOMEM; 1012 goto out; 1013 } 1014 1015 MLX5_SET(qpdpm_reg, in, local_port, 1); 1016 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0); 1017 if (err) 1018 goto out; 1019 1020 for (i = 0; i < (MLX5E_SUPPORTED_DSCP); i++) { 1021 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]); 1022 dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio); 1023 } 1024 1025 out: 1026 kfree(in); 1027 kfree(out); 1028 return err; 1029 } 1030