1 /* 2 * Copyright (c) 2018, 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 "port.h" 34 35 /* speed in units of 1Mb */ 36 static const u32 mlx5e_link_speed[MLX5E_LINK_MODES_NUMBER] = { 37 [MLX5E_1000BASE_CX_SGMII] = 1000, 38 [MLX5E_1000BASE_KX] = 1000, 39 [MLX5E_10GBASE_CX4] = 10000, 40 [MLX5E_10GBASE_KX4] = 10000, 41 [MLX5E_10GBASE_KR] = 10000, 42 [MLX5E_20GBASE_KR2] = 20000, 43 [MLX5E_40GBASE_CR4] = 40000, 44 [MLX5E_40GBASE_KR4] = 40000, 45 [MLX5E_56GBASE_R4] = 56000, 46 [MLX5E_10GBASE_CR] = 10000, 47 [MLX5E_10GBASE_SR] = 10000, 48 [MLX5E_10GBASE_ER] = 10000, 49 [MLX5E_40GBASE_SR4] = 40000, 50 [MLX5E_40GBASE_LR4] = 40000, 51 [MLX5E_50GBASE_SR2] = 50000, 52 [MLX5E_100GBASE_CR4] = 100000, 53 [MLX5E_100GBASE_SR4] = 100000, 54 [MLX5E_100GBASE_KR4] = 100000, 55 [MLX5E_100GBASE_LR4] = 100000, 56 [MLX5E_100BASE_TX] = 100, 57 [MLX5E_1000BASE_T] = 1000, 58 [MLX5E_10GBASE_T] = 10000, 59 [MLX5E_25GBASE_CR] = 25000, 60 [MLX5E_25GBASE_KR] = 25000, 61 [MLX5E_25GBASE_SR] = 25000, 62 [MLX5E_50GBASE_CR2] = 50000, 63 [MLX5E_50GBASE_KR2] = 50000, 64 }; 65 66 static const u32 mlx5e_ext_link_speed[MLX5E_EXT_LINK_MODES_NUMBER] = { 67 [MLX5E_SGMII_100M] = 100, 68 [MLX5E_1000BASE_X_SGMII] = 1000, 69 [MLX5E_5GBASE_R] = 5000, 70 [MLX5E_10GBASE_XFI_XAUI_1] = 10000, 71 [MLX5E_40GBASE_XLAUI_4_XLPPI_4] = 40000, 72 [MLX5E_25GAUI_1_25GBASE_CR_KR] = 25000, 73 [MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2] = 50000, 74 [MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR] = 50000, 75 [MLX5E_CAUI_4_100GBASE_CR4_KR4] = 100000, 76 [MLX5E_100GAUI_2_100GBASE_CR2_KR2] = 100000, 77 [MLX5E_200GAUI_4_200GBASE_CR4_KR4] = 200000, 78 [MLX5E_400GAUI_8] = 400000, 79 }; 80 81 static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev, 82 const u32 **arr, u32 *size, 83 bool force_legacy) 84 { 85 bool ext = force_legacy ? false : MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); 86 87 *size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) : 88 ARRAY_SIZE(mlx5e_link_speed); 89 *arr = ext ? mlx5e_ext_link_speed : mlx5e_link_speed; 90 } 91 92 int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext, 93 struct mlx5e_port_eth_proto *eproto) 94 { 95 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 96 int err; 97 98 if (!eproto) 99 return -EINVAL; 100 101 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port); 102 if (err) 103 return err; 104 105 eproto->cap = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, 106 eth_proto_capability); 107 eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin); 108 eproto->oper = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper); 109 return 0; 110 } 111 112 void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status, 113 u8 *an_disable_cap, u8 *an_disable_admin) 114 { 115 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 116 117 *an_status = 0; 118 *an_disable_cap = 0; 119 *an_disable_admin = 0; 120 121 if (mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, 1)) 122 return; 123 124 *an_status = MLX5_GET(ptys_reg, out, an_status); 125 *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap); 126 *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); 127 } 128 129 int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable, 130 u32 proto_admin, bool ext) 131 { 132 u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 133 u32 in[MLX5_ST_SZ_DW(ptys_reg)]; 134 u8 an_disable_admin; 135 u8 an_disable_cap; 136 u8 an_status; 137 138 mlx5_port_query_eth_autoneg(dev, &an_status, &an_disable_cap, 139 &an_disable_admin); 140 if (!an_disable_cap && an_disable) 141 return -EPERM; 142 143 memset(in, 0, sizeof(in)); 144 145 MLX5_SET(ptys_reg, in, local_port, 1); 146 MLX5_SET(ptys_reg, in, an_disable_admin, an_disable); 147 MLX5_SET(ptys_reg, in, proto_mask, MLX5_PTYS_EN); 148 if (ext) 149 MLX5_SET(ptys_reg, in, ext_eth_proto_admin, proto_admin); 150 else 151 MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin); 152 153 return mlx5_core_access_reg(dev, in, sizeof(in), out, 154 sizeof(out), MLX5_REG_PTYS, 0, 1); 155 } 156 157 u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper, 158 bool force_legacy) 159 { 160 unsigned long temp = eth_proto_oper; 161 const u32 *table; 162 u32 speed = 0; 163 u32 max_size; 164 int i; 165 166 mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy); 167 i = find_first_bit(&temp, max_size); 168 if (i < max_size) 169 speed = table[i]; 170 return speed; 171 } 172 173 int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 174 { 175 struct mlx5e_port_eth_proto eproto; 176 bool force_legacy = false; 177 bool ext; 178 int err; 179 180 ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); 181 err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto); 182 if (err) 183 goto out; 184 if (ext && !eproto.admin) { 185 force_legacy = true; 186 err = mlx5_port_query_eth_proto(mdev, 1, false, &eproto); 187 if (err) 188 goto out; 189 } 190 *speed = mlx5e_port_ptys2speed(mdev, eproto.oper, force_legacy); 191 if (!(*speed)) 192 err = -EINVAL; 193 194 out: 195 return err; 196 } 197 198 int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 199 { 200 struct mlx5e_port_eth_proto eproto; 201 u32 max_speed = 0; 202 const u32 *table; 203 u32 max_size; 204 bool ext; 205 int err; 206 int i; 207 208 ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); 209 err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto); 210 if (err) 211 return err; 212 213 mlx5e_port_get_speed_arr(mdev, &table, &max_size, false); 214 for (i = 0; i < max_size; ++i) 215 if (eproto.cap & MLX5E_PROT_MASK(i)) 216 max_speed = max(max_speed, table[i]); 217 218 *speed = max_speed; 219 return 0; 220 } 221 222 u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed, 223 bool force_legacy) 224 { 225 u32 link_modes = 0; 226 const u32 *table; 227 u32 max_size; 228 int i; 229 230 mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy); 231 for (i = 0; i < max_size; ++i) { 232 if (table[i] == speed) 233 link_modes |= MLX5E_PROT_MASK(i); 234 } 235 return link_modes; 236 } 237 238 int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out) 239 { 240 int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 241 void *in; 242 int err; 243 244 in = kzalloc(sz, GFP_KERNEL); 245 if (!in) 246 return -ENOMEM; 247 248 MLX5_SET(pbmc_reg, in, local_port, 1); 249 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0); 250 251 kfree(in); 252 return err; 253 } 254 255 int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in) 256 { 257 int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 258 void *out; 259 int err; 260 261 out = kzalloc(sz, GFP_KERNEL); 262 if (!out) 263 return -ENOMEM; 264 265 MLX5_SET(pbmc_reg, in, local_port, 1); 266 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1); 267 268 kfree(out); 269 return err; 270 } 271 272 /* buffer[i]: buffer that priority i mapped to */ 273 int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 274 { 275 int sz = MLX5_ST_SZ_BYTES(pptb_reg); 276 u32 prio_x_buff; 277 void *out; 278 void *in; 279 int prio; 280 int err; 281 282 in = kzalloc(sz, GFP_KERNEL); 283 out = kzalloc(sz, GFP_KERNEL); 284 if (!in || !out) { 285 err = -ENOMEM; 286 goto out; 287 } 288 289 MLX5_SET(pptb_reg, in, local_port, 1); 290 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 291 if (err) 292 goto out; 293 294 prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff); 295 for (prio = 0; prio < 8; prio++) { 296 buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF; 297 mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]); 298 } 299 out: 300 kfree(in); 301 kfree(out); 302 return err; 303 } 304 305 int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 306 { 307 int sz = MLX5_ST_SZ_BYTES(pptb_reg); 308 u32 prio_x_buff; 309 void *out; 310 void *in; 311 int prio; 312 int err; 313 314 in = kzalloc(sz, GFP_KERNEL); 315 out = kzalloc(sz, GFP_KERNEL); 316 if (!in || !out) { 317 err = -ENOMEM; 318 goto out; 319 } 320 321 /* First query the pptb register */ 322 MLX5_SET(pptb_reg, in, local_port, 1); 323 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 324 if (err) 325 goto out; 326 327 memcpy(in, out, sz); 328 MLX5_SET(pptb_reg, in, local_port, 1); 329 330 /* Update the pm and prio_x_buff */ 331 MLX5_SET(pptb_reg, in, pm, 0xFF); 332 333 prio_x_buff = 0; 334 for (prio = 0; prio < 8; prio++) 335 prio_x_buff |= (buffer[prio] << (4 * prio)); 336 MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff); 337 338 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1); 339 340 out: 341 kfree(in); 342 kfree(out); 343 return err; 344 } 345 346 static u32 fec_supported_speeds[] = { 347 10000, 348 40000, 349 25000, 350 50000, 351 56000, 352 100000 353 }; 354 355 #define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds) 356 357 /* get/set FEC admin field for a given speed */ 358 static int mlx5e_fec_admin_field(u32 *pplm, 359 u8 *fec_policy, 360 bool write, 361 u32 speed) 362 { 363 switch (speed) { 364 case 10000: 365 case 40000: 366 if (!write) 367 *fec_policy = MLX5_GET(pplm_reg, pplm, 368 fec_override_admin_10g_40g); 369 else 370 MLX5_SET(pplm_reg, pplm, 371 fec_override_admin_10g_40g, *fec_policy); 372 break; 373 case 25000: 374 if (!write) 375 *fec_policy = MLX5_GET(pplm_reg, pplm, 376 fec_override_admin_25g); 377 else 378 MLX5_SET(pplm_reg, pplm, 379 fec_override_admin_25g, *fec_policy); 380 break; 381 case 50000: 382 if (!write) 383 *fec_policy = MLX5_GET(pplm_reg, pplm, 384 fec_override_admin_50g); 385 else 386 MLX5_SET(pplm_reg, pplm, 387 fec_override_admin_50g, *fec_policy); 388 break; 389 case 56000: 390 if (!write) 391 *fec_policy = MLX5_GET(pplm_reg, pplm, 392 fec_override_admin_56g); 393 else 394 MLX5_SET(pplm_reg, pplm, 395 fec_override_admin_56g, *fec_policy); 396 break; 397 case 100000: 398 if (!write) 399 *fec_policy = MLX5_GET(pplm_reg, pplm, 400 fec_override_admin_100g); 401 else 402 MLX5_SET(pplm_reg, pplm, 403 fec_override_admin_100g, *fec_policy); 404 break; 405 default: 406 return -EINVAL; 407 } 408 return 0; 409 } 410 411 /* returns FEC capabilities for a given speed */ 412 static int mlx5e_get_fec_cap_field(u32 *pplm, 413 u8 *fec_cap, 414 u32 speed) 415 { 416 switch (speed) { 417 case 10000: 418 case 40000: 419 *fec_cap = MLX5_GET(pplm_reg, pplm, 420 fec_override_cap_10g_40g); 421 break; 422 case 25000: 423 *fec_cap = MLX5_GET(pplm_reg, pplm, 424 fec_override_cap_25g); 425 break; 426 case 50000: 427 *fec_cap = MLX5_GET(pplm_reg, pplm, 428 fec_override_cap_50g); 429 break; 430 case 56000: 431 *fec_cap = MLX5_GET(pplm_reg, pplm, 432 fec_override_cap_56g); 433 break; 434 case 100000: 435 *fec_cap = MLX5_GET(pplm_reg, pplm, 436 fec_override_cap_100g); 437 break; 438 default: 439 return -EINVAL; 440 } 441 return 0; 442 } 443 444 bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy) 445 { 446 u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 447 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 448 int sz = MLX5_ST_SZ_BYTES(pplm_reg); 449 int err; 450 int i; 451 452 if (!MLX5_CAP_GEN(dev, pcam_reg)) 453 return -EOPNOTSUPP; 454 455 if (!MLX5_CAP_PCAM_REG(dev, pplm)) 456 return -EOPNOTSUPP; 457 458 MLX5_SET(pplm_reg, in, local_port, 1); 459 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 460 if (err) 461 return false; 462 463 for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS; i++) { 464 u8 fec_caps; 465 466 mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]); 467 if (fec_caps & fec_policy) 468 return true; 469 } 470 return false; 471 } 472 473 int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active, 474 u8 *fec_configured_mode) 475 { 476 u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 477 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 478 int sz = MLX5_ST_SZ_BYTES(pplm_reg); 479 u32 link_speed; 480 int err; 481 482 if (!MLX5_CAP_GEN(dev, pcam_reg)) 483 return -EOPNOTSUPP; 484 485 if (!MLX5_CAP_PCAM_REG(dev, pplm)) 486 return -EOPNOTSUPP; 487 488 MLX5_SET(pplm_reg, in, local_port, 1); 489 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 490 if (err) 491 return err; 492 493 *fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active); 494 495 if (!fec_configured_mode) 496 return 0; 497 498 err = mlx5e_port_linkspeed(dev, &link_speed); 499 if (err) 500 return err; 501 502 return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed); 503 } 504 505 int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy) 506 { 507 u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 508 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 509 int sz = MLX5_ST_SZ_BYTES(pplm_reg); 510 u8 fec_policy_auto = 0; 511 u8 fec_caps = 0; 512 int err; 513 int i; 514 515 if (!MLX5_CAP_GEN(dev, pcam_reg)) 516 return -EOPNOTSUPP; 517 518 if (!MLX5_CAP_PCAM_REG(dev, pplm)) 519 return -EOPNOTSUPP; 520 521 MLX5_SET(pplm_reg, in, local_port, 1); 522 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 523 if (err) 524 return err; 525 526 MLX5_SET(pplm_reg, out, local_port, 1); 527 528 for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS; i++) { 529 mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]); 530 /* policy supported for link speed */ 531 if (fec_caps & fec_policy) 532 mlx5e_fec_admin_field(out, &fec_policy, 1, 533 fec_supported_speeds[i]); 534 else 535 /* set FEC to auto*/ 536 mlx5e_fec_admin_field(out, &fec_policy_auto, 1, 537 fec_supported_speeds[i]); 538 } 539 540 return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1); 541 } 542