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_port_link_width_oper(struct mlx5_core_dev *dev, 158 u8 *link_width_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, local_port); 164 if (err) 165 return err; 166 167 *link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper); 168 169 return 0; 170 } 171 EXPORT_SYMBOL_GPL(mlx5_query_port_link_width_oper); 172 173 int mlx5_query_port_ib_proto_oper(struct mlx5_core_dev *dev, 174 u8 *proto_oper, u8 local_port) 175 { 176 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 177 int err; 178 179 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB, 180 local_port); 181 if (err) 182 return err; 183 184 *proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper); 185 186 return 0; 187 } 188 EXPORT_SYMBOL(mlx5_query_port_ib_proto_oper); 189 190 /* This function should be used after setting a port register only */ 191 void mlx5_toggle_port_link(struct mlx5_core_dev *dev) 192 { 193 enum mlx5_port_status ps; 194 195 mlx5_query_port_admin_status(dev, &ps); 196 mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN); 197 if (ps == MLX5_PORT_UP) 198 mlx5_set_port_admin_status(dev, MLX5_PORT_UP); 199 } 200 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link); 201 202 int mlx5_set_port_admin_status(struct mlx5_core_dev *dev, 203 enum mlx5_port_status status) 204 { 205 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0}; 206 u32 out[MLX5_ST_SZ_DW(paos_reg)]; 207 208 MLX5_SET(paos_reg, in, local_port, 1); 209 MLX5_SET(paos_reg, in, admin_status, status); 210 MLX5_SET(paos_reg, in, ase, 1); 211 return mlx5_core_access_reg(dev, in, sizeof(in), out, 212 sizeof(out), MLX5_REG_PAOS, 0, 1); 213 } 214 EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status); 215 216 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev, 217 enum mlx5_port_status *status) 218 { 219 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0}; 220 u32 out[MLX5_ST_SZ_DW(paos_reg)]; 221 int err; 222 223 MLX5_SET(paos_reg, in, local_port, 1); 224 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 225 sizeof(out), MLX5_REG_PAOS, 0, 0); 226 if (err) 227 return err; 228 *status = MLX5_GET(paos_reg, out, admin_status); 229 return 0; 230 } 231 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status); 232 233 static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu, 234 u16 *max_mtu, u16 *oper_mtu, u8 port) 235 { 236 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; 237 u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; 238 239 MLX5_SET(pmtu_reg, in, local_port, port); 240 mlx5_core_access_reg(dev, in, sizeof(in), out, 241 sizeof(out), MLX5_REG_PMTU, 0, 0); 242 243 if (max_mtu) 244 *max_mtu = MLX5_GET(pmtu_reg, out, max_mtu); 245 if (oper_mtu) 246 *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu); 247 if (admin_mtu) 248 *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu); 249 } 250 251 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port) 252 { 253 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; 254 u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; 255 256 MLX5_SET(pmtu_reg, in, admin_mtu, mtu); 257 MLX5_SET(pmtu_reg, in, local_port, port); 258 return mlx5_core_access_reg(dev, in, sizeof(in), out, 259 sizeof(out), MLX5_REG_PMTU, 0, 1); 260 } 261 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu); 262 263 void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu, 264 u8 port) 265 { 266 mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port); 267 } 268 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu); 269 270 void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu, 271 u8 port) 272 { 273 mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port); 274 } 275 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu); 276 277 static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num) 278 { 279 u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0}; 280 u32 out[MLX5_ST_SZ_DW(pmlp_reg)]; 281 int module_mapping; 282 int err; 283 284 MLX5_SET(pmlp_reg, in, local_port, 1); 285 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), 286 MLX5_REG_PMLP, 0, 0); 287 if (err) 288 return err; 289 290 module_mapping = MLX5_GET(pmlp_reg, out, lane0_module_mapping); 291 *module_num = module_mapping & MLX5_EEPROM_IDENTIFIER_BYTE_MASK; 292 293 return 0; 294 } 295 296 static int mlx5_eeprom_page(int offset) 297 { 298 if (offset < MLX5_EEPROM_PAGE_LENGTH) 299 /* Addresses between 0-255 - page 00 */ 300 return 0; 301 302 /* Addresses between 256 - 639 belongs to pages 01, 02 and 03 303 * For example, offset = 400 belongs to page 02: 304 * 1 + ((400 - 256)/128) = 2 305 */ 306 return 1 + ((offset - MLX5_EEPROM_PAGE_LENGTH) / 307 MLX5_EEPROM_HIGH_PAGE_LENGTH); 308 } 309 310 static int mlx5_eeprom_high_page_offset(int page_num) 311 { 312 if (!page_num) /* Page 0 always start from low page */ 313 return 0; 314 315 /* High page */ 316 return page_num * MLX5_EEPROM_HIGH_PAGE_LENGTH; 317 } 318 319 int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, 320 u16 offset, u16 size, u8 *data) 321 { 322 int module_num, page_num, status, err; 323 u32 out[MLX5_ST_SZ_DW(mcia_reg)]; 324 u32 in[MLX5_ST_SZ_DW(mcia_reg)]; 325 u16 i2c_addr; 326 void *ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0); 327 328 err = mlx5_query_module_num(dev, &module_num); 329 if (err) 330 return err; 331 332 memset(in, 0, sizeof(in)); 333 size = min_t(int, size, MLX5_EEPROM_MAX_BYTES); 334 335 /* Get the page number related to the given offset */ 336 page_num = mlx5_eeprom_page(offset); 337 338 /* Set the right offset according to the page number, 339 * For page_num > 0, relative offset is always >= 128 (high page). 340 */ 341 offset -= mlx5_eeprom_high_page_offset(page_num); 342 343 if (offset + size > MLX5_EEPROM_PAGE_LENGTH) 344 /* Cross pages read, read until offset 256 in low page */ 345 size -= offset + size - MLX5_EEPROM_PAGE_LENGTH; 346 347 i2c_addr = MLX5_I2C_ADDR_LOW; 348 349 MLX5_SET(mcia_reg, in, l, 0); 350 MLX5_SET(mcia_reg, in, module, module_num); 351 MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr); 352 MLX5_SET(mcia_reg, in, page_number, page_num); 353 MLX5_SET(mcia_reg, in, device_address, offset); 354 MLX5_SET(mcia_reg, in, size, size); 355 356 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 357 sizeof(out), MLX5_REG_MCIA, 0, 0); 358 if (err) 359 return err; 360 361 status = MLX5_GET(mcia_reg, out, status); 362 if (status) { 363 mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n", 364 status); 365 return -EIO; 366 } 367 368 memcpy(data, ptr, size); 369 370 return size; 371 } 372 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom); 373 374 static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc, 375 int pvlc_size, u8 local_port) 376 { 377 u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0}; 378 379 MLX5_SET(pvlc_reg, in, local_port, local_port); 380 return mlx5_core_access_reg(dev, in, sizeof(in), pvlc, 381 pvlc_size, MLX5_REG_PVLC, 0, 0); 382 } 383 384 int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev, 385 u8 *vl_hw_cap, u8 local_port) 386 { 387 u32 out[MLX5_ST_SZ_DW(pvlc_reg)]; 388 int err; 389 390 err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port); 391 if (err) 392 return err; 393 394 *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap); 395 396 return 0; 397 } 398 EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap); 399 400 int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev, 401 u8 port_num, void *out, size_t sz) 402 { 403 u32 *in; 404 int err; 405 406 in = kvzalloc(sz, GFP_KERNEL); 407 if (!in) { 408 err = -ENOMEM; 409 return err; 410 } 411 412 MLX5_SET(ppcnt_reg, in, local_port, port_num); 413 414 MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP); 415 err = mlx5_core_access_reg(dev, in, sz, out, 416 sz, MLX5_REG_PPCNT, 0, 0); 417 418 kvfree(in); 419 return err; 420 } 421 EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt); 422 423 static int mlx5_query_pfcc_reg(struct mlx5_core_dev *dev, u32 *out, 424 u32 out_size) 425 { 426 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 427 428 MLX5_SET(pfcc_reg, in, local_port, 1); 429 430 return mlx5_core_access_reg(dev, in, sizeof(in), out, 431 out_size, MLX5_REG_PFCC, 0, 0); 432 } 433 434 int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause) 435 { 436 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 437 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 438 439 MLX5_SET(pfcc_reg, in, local_port, 1); 440 MLX5_SET(pfcc_reg, in, pptx, tx_pause); 441 MLX5_SET(pfcc_reg, in, pprx, rx_pause); 442 443 return mlx5_core_access_reg(dev, in, sizeof(in), out, 444 sizeof(out), MLX5_REG_PFCC, 0, 1); 445 } 446 EXPORT_SYMBOL_GPL(mlx5_set_port_pause); 447 448 int mlx5_query_port_pause(struct mlx5_core_dev *dev, 449 u32 *rx_pause, u32 *tx_pause) 450 { 451 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 452 int err; 453 454 err = mlx5_query_pfcc_reg(dev, out, sizeof(out)); 455 if (err) 456 return err; 457 458 if (rx_pause) 459 *rx_pause = MLX5_GET(pfcc_reg, out, pprx); 460 461 if (tx_pause) 462 *tx_pause = MLX5_GET(pfcc_reg, out, pptx); 463 464 return 0; 465 } 466 EXPORT_SYMBOL_GPL(mlx5_query_port_pause); 467 468 int mlx5_set_port_stall_watermark(struct mlx5_core_dev *dev, 469 u16 stall_critical_watermark, 470 u16 stall_minor_watermark) 471 { 472 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 473 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 474 475 MLX5_SET(pfcc_reg, in, local_port, 1); 476 MLX5_SET(pfcc_reg, in, pptx_mask_n, 1); 477 MLX5_SET(pfcc_reg, in, pprx_mask_n, 1); 478 MLX5_SET(pfcc_reg, in, ppan_mask_n, 1); 479 MLX5_SET(pfcc_reg, in, critical_stall_mask, 1); 480 MLX5_SET(pfcc_reg, in, minor_stall_mask, 1); 481 MLX5_SET(pfcc_reg, in, device_stall_critical_watermark, 482 stall_critical_watermark); 483 MLX5_SET(pfcc_reg, in, device_stall_minor_watermark, stall_minor_watermark); 484 485 return mlx5_core_access_reg(dev, in, sizeof(in), out, 486 sizeof(out), MLX5_REG_PFCC, 0, 1); 487 } 488 489 int mlx5_query_port_stall_watermark(struct mlx5_core_dev *dev, 490 u16 *stall_critical_watermark, 491 u16 *stall_minor_watermark) 492 { 493 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 494 int err; 495 496 err = mlx5_query_pfcc_reg(dev, out, sizeof(out)); 497 if (err) 498 return err; 499 500 if (stall_critical_watermark) 501 *stall_critical_watermark = MLX5_GET(pfcc_reg, out, 502 device_stall_critical_watermark); 503 504 if (stall_minor_watermark) 505 *stall_minor_watermark = MLX5_GET(pfcc_reg, out, 506 device_stall_minor_watermark); 507 508 return 0; 509 } 510 511 int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx) 512 { 513 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; 514 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 515 516 MLX5_SET(pfcc_reg, in, local_port, 1); 517 MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx); 518 MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx); 519 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx); 520 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx); 521 522 return mlx5_core_access_reg(dev, in, sizeof(in), out, 523 sizeof(out), MLX5_REG_PFCC, 0, 1); 524 } 525 EXPORT_SYMBOL_GPL(mlx5_set_port_pfc); 526 527 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx) 528 { 529 u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; 530 int err; 531 532 err = mlx5_query_pfcc_reg(dev, out, sizeof(out)); 533 if (err) 534 return err; 535 536 if (pfc_en_tx) 537 *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx); 538 539 if (pfc_en_rx) 540 *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx); 541 542 return 0; 543 } 544 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc); 545 546 int mlx5_max_tc(struct mlx5_core_dev *mdev) 547 { 548 u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8; 549 550 return num_tc - 1; 551 } 552 553 int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out) 554 { 555 u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0}; 556 557 MLX5_SET(dcbx_param, in, port_number, 1); 558 559 return mlx5_core_access_reg(mdev, in, sizeof(in), out, 560 sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0); 561 } 562 563 int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in) 564 { 565 u32 out[MLX5_ST_SZ_DW(dcbx_param)]; 566 567 MLX5_SET(dcbx_param, in, port_number, 1); 568 569 return mlx5_core_access_reg(mdev, in, sizeof(out), out, 570 sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1); 571 } 572 573 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc) 574 { 575 u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0}; 576 u32 out[MLX5_ST_SZ_DW(qtct_reg)]; 577 int err; 578 int i; 579 580 for (i = 0; i < 8; i++) { 581 if (prio_tc[i] > mlx5_max_tc(mdev)) 582 return -EINVAL; 583 584 MLX5_SET(qtct_reg, in, prio, i); 585 MLX5_SET(qtct_reg, in, tclass, prio_tc[i]); 586 587 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 588 sizeof(out), MLX5_REG_QTCT, 0, 1); 589 if (err) 590 return err; 591 } 592 593 return 0; 594 } 595 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc); 596 597 int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev, 598 u8 prio, u8 *tc) 599 { 600 u32 in[MLX5_ST_SZ_DW(qtct_reg)]; 601 u32 out[MLX5_ST_SZ_DW(qtct_reg)]; 602 int err; 603 604 memset(in, 0, sizeof(in)); 605 memset(out, 0, sizeof(out)); 606 607 MLX5_SET(qtct_reg, in, port_number, 1); 608 MLX5_SET(qtct_reg, in, prio, prio); 609 610 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 611 sizeof(out), MLX5_REG_QTCT, 0, 0); 612 if (!err) 613 *tc = MLX5_GET(qtct_reg, out, tclass); 614 615 return err; 616 } 617 EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc); 618 619 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, 620 int inlen) 621 { 622 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 623 624 if (!MLX5_CAP_GEN(mdev, ets)) 625 return -EOPNOTSUPP; 626 627 return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out), 628 MLX5_REG_QETCR, 0, 1); 629 } 630 631 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out, 632 int outlen) 633 { 634 u32 in[MLX5_ST_SZ_DW(qetc_reg)]; 635 636 if (!MLX5_CAP_GEN(mdev, ets)) 637 return -EOPNOTSUPP; 638 639 memset(in, 0, sizeof(in)); 640 return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen, 641 MLX5_REG_QETCR, 0, 0); 642 } 643 644 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group) 645 { 646 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; 647 int i; 648 649 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 650 MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1); 651 MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]); 652 } 653 654 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 655 } 656 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group); 657 658 int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev, 659 u8 tc, u8 *tc_group) 660 { 661 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 662 void *ets_tcn_conf; 663 int err; 664 665 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 666 if (err) 667 return err; 668 669 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, 670 tc_configuration[tc]); 671 672 *tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 673 group); 674 675 return 0; 676 } 677 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group); 678 679 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw) 680 { 681 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; 682 int i; 683 684 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 685 MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1); 686 MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]); 687 } 688 689 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 690 } 691 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc); 692 693 int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev, 694 u8 tc, u8 *bw_pct) 695 { 696 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 697 void *ets_tcn_conf; 698 int err; 699 700 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 701 if (err) 702 return err; 703 704 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, 705 tc_configuration[tc]); 706 707 *bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 708 bw_allocation); 709 710 return 0; 711 } 712 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc); 713 714 int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev, 715 u8 *max_bw_value, 716 u8 *max_bw_units) 717 { 718 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; 719 void *ets_tcn_conf; 720 int i; 721 722 MLX5_SET(qetc_reg, in, port_number, 1); 723 724 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 725 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]); 726 727 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1); 728 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units, 729 max_bw_units[i]); 730 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value, 731 max_bw_value[i]); 732 } 733 734 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); 735 } 736 EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit); 737 738 int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev, 739 u8 *max_bw_value, 740 u8 *max_bw_units) 741 { 742 u32 out[MLX5_ST_SZ_DW(qetc_reg)]; 743 void *ets_tcn_conf; 744 int err; 745 int i; 746 747 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); 748 if (err) 749 return err; 750 751 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 752 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]); 753 754 max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 755 max_bw_value); 756 max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, 757 max_bw_units); 758 } 759 760 return 0; 761 } 762 EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit); 763 764 int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode) 765 { 766 u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {0}; 767 u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)] = {0}; 768 769 MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL); 770 MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1); 771 MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode); 772 return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); 773 } 774 EXPORT_SYMBOL_GPL(mlx5_set_port_wol); 775 776 int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode) 777 { 778 u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {0}; 779 u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {0}; 780 int err; 781 782 MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL); 783 err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); 784 if (!err) 785 *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode); 786 787 return err; 788 } 789 EXPORT_SYMBOL_GPL(mlx5_query_port_wol); 790 791 int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, int outlen) 792 { 793 u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0}; 794 795 MLX5_SET(pcmr_reg, in, local_port, 1); 796 return mlx5_core_access_reg(mdev, in, sizeof(in), out, 797 outlen, MLX5_REG_PCMR, 0, 0); 798 } 799 800 int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen) 801 { 802 u32 out[MLX5_ST_SZ_DW(pcmr_reg)]; 803 804 return mlx5_core_access_reg(mdev, in, inlen, out, 805 sizeof(out), MLX5_REG_PCMR, 0, 1); 806 } 807 808 int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable) 809 { 810 u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0}; 811 int err; 812 813 err = mlx5_query_ports_check(mdev, in, sizeof(in)); 814 if (err) 815 return err; 816 MLX5_SET(pcmr_reg, in, local_port, 1); 817 MLX5_SET(pcmr_reg, in, fcs_chk, enable); 818 return mlx5_set_ports_check(mdev, in, sizeof(in)); 819 } 820 821 void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported, 822 bool *enabled) 823 { 824 u32 out[MLX5_ST_SZ_DW(pcmr_reg)]; 825 /* Default values for FW which do not support MLX5_REG_PCMR */ 826 *supported = false; 827 *enabled = true; 828 829 if (!MLX5_CAP_GEN(mdev, ports_check)) 830 return; 831 832 if (mlx5_query_ports_check(mdev, out, sizeof(out))) 833 return; 834 835 *supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap)); 836 *enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk)); 837 } 838 839 int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size) 840 { 841 u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0}; 842 843 return mlx5_core_access_reg(mdev, in, sizeof(in), mtpps, 844 mtpps_size, MLX5_REG_MTPPS, 0, 0); 845 } 846 847 int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size) 848 { 849 u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0}; 850 851 return mlx5_core_access_reg(mdev, mtpps, mtpps_size, out, 852 sizeof(out), MLX5_REG_MTPPS, 0, 1); 853 } 854 855 int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode) 856 { 857 u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; 858 u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; 859 int err = 0; 860 861 MLX5_SET(mtppse_reg, in, pin, pin); 862 863 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 864 sizeof(out), MLX5_REG_MTPPSE, 0, 0); 865 if (err) 866 return err; 867 868 *arm = MLX5_GET(mtppse_reg, in, event_arm); 869 *mode = MLX5_GET(mtppse_reg, in, event_generation_mode); 870 871 return err; 872 } 873 874 int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode) 875 { 876 u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; 877 u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; 878 879 MLX5_SET(mtppse_reg, in, pin, pin); 880 MLX5_SET(mtppse_reg, in, event_arm, arm); 881 MLX5_SET(mtppse_reg, in, event_generation_mode, mode); 882 883 return mlx5_core_access_reg(mdev, in, sizeof(in), out, 884 sizeof(out), MLX5_REG_MTPPSE, 0, 1); 885 } 886 887 int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state) 888 { 889 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {}; 890 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {}; 891 int err; 892 893 MLX5_SET(qpts_reg, in, local_port, 1); 894 MLX5_SET(qpts_reg, in, trust_state, trust_state); 895 896 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 897 sizeof(out), MLX5_REG_QPTS, 0, 1); 898 return err; 899 } 900 901 int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state) 902 { 903 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {}; 904 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {}; 905 int err; 906 907 MLX5_SET(qpts_reg, in, local_port, 1); 908 909 err = mlx5_core_access_reg(mdev, in, sizeof(in), out, 910 sizeof(out), MLX5_REG_QPTS, 0, 0); 911 if (!err) 912 *trust_state = MLX5_GET(qpts_reg, out, trust_state); 913 914 return err; 915 } 916 917 int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, u8 dscp, u8 prio) 918 { 919 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg); 920 void *qpdpm_dscp; 921 void *out; 922 void *in; 923 int err; 924 925 in = kzalloc(sz, GFP_KERNEL); 926 out = kzalloc(sz, GFP_KERNEL); 927 if (!in || !out) { 928 err = -ENOMEM; 929 goto out; 930 } 931 932 MLX5_SET(qpdpm_reg, in, local_port, 1); 933 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0); 934 if (err) 935 goto out; 936 937 memcpy(in, out, sz); 938 MLX5_SET(qpdpm_reg, in, local_port, 1); 939 940 /* Update the corresponding dscp entry */ 941 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[dscp]); 942 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, prio); 943 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1); 944 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1); 945 946 out: 947 kfree(in); 948 kfree(out); 949 return err; 950 } 951 952 /* dscp2prio[i]: priority that dscp i mapped to */ 953 #define MLX5E_SUPPORTED_DSCP 64 954 int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio) 955 { 956 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg); 957 void *qpdpm_dscp; 958 void *out; 959 void *in; 960 int err; 961 int i; 962 963 in = kzalloc(sz, GFP_KERNEL); 964 out = kzalloc(sz, GFP_KERNEL); 965 if (!in || !out) { 966 err = -ENOMEM; 967 goto out; 968 } 969 970 MLX5_SET(qpdpm_reg, in, local_port, 1); 971 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0); 972 if (err) 973 goto out; 974 975 for (i = 0; i < (MLX5E_SUPPORTED_DSCP); i++) { 976 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]); 977 dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio); 978 } 979 980 out: 981 kfree(in); 982 kfree(out); 983 return err; 984 } 985