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