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 u32 mlx5e_port_ptys2speed(u32 eth_proto_oper) 67 { 68 unsigned long temp = eth_proto_oper; 69 u32 speed = 0; 70 int i; 71 72 i = find_first_bit(&temp, MLX5E_LINK_MODES_NUMBER); 73 if (i < MLX5E_LINK_MODES_NUMBER) 74 speed = mlx5e_link_speed[i]; 75 76 return speed; 77 } 78 79 int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 80 { 81 u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {}; 82 u32 eth_proto_oper; 83 int err; 84 85 err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1); 86 if (err) 87 return err; 88 89 eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); 90 *speed = mlx5e_port_ptys2speed(eth_proto_oper); 91 if (!(*speed)) { 92 mlx5_core_warn(mdev, "cannot get port speed\n"); 93 err = -EINVAL; 94 } 95 96 return err; 97 } 98 99 int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 100 { 101 u32 max_speed = 0; 102 u32 proto_cap; 103 int err; 104 int i; 105 106 err = mlx5_query_port_proto_cap(mdev, &proto_cap, MLX5_PTYS_EN); 107 if (err) 108 return err; 109 110 for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) 111 if (proto_cap & MLX5E_PROT_MASK(i)) 112 max_speed = max(max_speed, mlx5e_link_speed[i]); 113 114 *speed = max_speed; 115 return 0; 116 } 117 118 u32 mlx5e_port_speed2linkmodes(u32 speed) 119 { 120 u32 link_modes = 0; 121 int i; 122 123 for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { 124 if (mlx5e_link_speed[i] == speed) 125 link_modes |= MLX5E_PROT_MASK(i); 126 } 127 128 return link_modes; 129 } 130 131 int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out) 132 { 133 int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 134 void *in; 135 int err; 136 137 in = kzalloc(sz, GFP_KERNEL); 138 if (!in) 139 return -ENOMEM; 140 141 MLX5_SET(pbmc_reg, in, local_port, 1); 142 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0); 143 144 kfree(in); 145 return err; 146 } 147 148 int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in) 149 { 150 int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 151 void *out; 152 int err; 153 154 out = kzalloc(sz, GFP_KERNEL); 155 if (!out) 156 return -ENOMEM; 157 158 MLX5_SET(pbmc_reg, in, local_port, 1); 159 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1); 160 161 kfree(out); 162 return err; 163 } 164 165 /* buffer[i]: buffer that priority i mapped to */ 166 int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 167 { 168 int sz = MLX5_ST_SZ_BYTES(pptb_reg); 169 u32 prio_x_buff; 170 void *out; 171 void *in; 172 int prio; 173 int err; 174 175 in = kzalloc(sz, GFP_KERNEL); 176 out = kzalloc(sz, GFP_KERNEL); 177 if (!in || !out) { 178 err = -ENOMEM; 179 goto out; 180 } 181 182 MLX5_SET(pptb_reg, in, local_port, 1); 183 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 184 if (err) 185 goto out; 186 187 prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff); 188 for (prio = 0; prio < 8; prio++) { 189 buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF; 190 mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]); 191 } 192 out: 193 kfree(in); 194 kfree(out); 195 return err; 196 } 197 198 int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 199 { 200 int sz = MLX5_ST_SZ_BYTES(pptb_reg); 201 u32 prio_x_buff; 202 void *out; 203 void *in; 204 int prio; 205 int err; 206 207 in = kzalloc(sz, GFP_KERNEL); 208 out = kzalloc(sz, GFP_KERNEL); 209 if (!in || !out) { 210 err = -ENOMEM; 211 goto out; 212 } 213 214 /* First query the pptb register */ 215 MLX5_SET(pptb_reg, in, local_port, 1); 216 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 217 if (err) 218 goto out; 219 220 memcpy(in, out, sz); 221 MLX5_SET(pptb_reg, in, local_port, 1); 222 223 /* Update the pm and prio_x_buff */ 224 MLX5_SET(pptb_reg, in, pm, 0xFF); 225 226 prio_x_buff = 0; 227 for (prio = 0; prio < 8; prio++) 228 prio_x_buff |= (buffer[prio] << (4 * prio)); 229 MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff); 230 231 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1); 232 233 out: 234 kfree(in); 235 kfree(out); 236 return err; 237 } 238 239 static u32 fec_supported_speeds[] = { 240 10000, 241 40000, 242 25000, 243 50000, 244 56000, 245 100000 246 }; 247 248 #define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds) 249 250 /* get/set FEC admin field for a given speed */ 251 static int mlx5e_fec_admin_field(u32 *pplm, 252 u8 *fec_policy, 253 bool write, 254 u32 speed) 255 { 256 switch (speed) { 257 case 10000: 258 case 40000: 259 if (!write) 260 *fec_policy = MLX5_GET(pplm_reg, pplm, 261 fec_override_admin_10g_40g); 262 else 263 MLX5_SET(pplm_reg, pplm, 264 fec_override_admin_10g_40g, *fec_policy); 265 break; 266 case 25000: 267 if (!write) 268 *fec_policy = MLX5_GET(pplm_reg, pplm, 269 fec_override_admin_25g); 270 else 271 MLX5_SET(pplm_reg, pplm, 272 fec_override_admin_25g, *fec_policy); 273 break; 274 case 50000: 275 if (!write) 276 *fec_policy = MLX5_GET(pplm_reg, pplm, 277 fec_override_admin_50g); 278 else 279 MLX5_SET(pplm_reg, pplm, 280 fec_override_admin_50g, *fec_policy); 281 break; 282 case 56000: 283 if (!write) 284 *fec_policy = MLX5_GET(pplm_reg, pplm, 285 fec_override_admin_56g); 286 else 287 MLX5_SET(pplm_reg, pplm, 288 fec_override_admin_56g, *fec_policy); 289 break; 290 case 100000: 291 if (!write) 292 *fec_policy = MLX5_GET(pplm_reg, pplm, 293 fec_override_admin_100g); 294 else 295 MLX5_SET(pplm_reg, pplm, 296 fec_override_admin_100g, *fec_policy); 297 break; 298 default: 299 return -EINVAL; 300 } 301 return 0; 302 } 303 304 /* returns FEC capabilities for a given speed */ 305 static int mlx5e_get_fec_cap_field(u32 *pplm, 306 u8 *fec_cap, 307 u32 speed) 308 { 309 switch (speed) { 310 case 10000: 311 case 40000: 312 *fec_cap = MLX5_GET(pplm_reg, pplm, 313 fec_override_cap_10g_40g); 314 break; 315 case 25000: 316 *fec_cap = MLX5_GET(pplm_reg, pplm, 317 fec_override_cap_25g); 318 break; 319 case 50000: 320 *fec_cap = MLX5_GET(pplm_reg, pplm, 321 fec_override_cap_50g); 322 break; 323 case 56000: 324 *fec_cap = MLX5_GET(pplm_reg, pplm, 325 fec_override_cap_56g); 326 break; 327 case 100000: 328 *fec_cap = MLX5_GET(pplm_reg, pplm, 329 fec_override_cap_100g); 330 break; 331 default: 332 return -EINVAL; 333 } 334 return 0; 335 } 336 337 int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps) 338 { 339 u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 340 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 341 int sz = MLX5_ST_SZ_BYTES(pplm_reg); 342 u32 current_fec_speed; 343 int err; 344 345 if (!MLX5_CAP_GEN(dev, pcam_reg)) 346 return -EOPNOTSUPP; 347 348 if (!MLX5_CAP_PCAM_REG(dev, pplm)) 349 return -EOPNOTSUPP; 350 351 MLX5_SET(pplm_reg, in, local_port, 1); 352 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 353 if (err) 354 return err; 355 356 err = mlx5e_port_linkspeed(dev, ¤t_fec_speed); 357 if (err) 358 return err; 359 360 return mlx5e_get_fec_cap_field(out, fec_caps, current_fec_speed); 361 } 362 363 int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active, 364 u8 *fec_configured_mode) 365 { 366 u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 367 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 368 int sz = MLX5_ST_SZ_BYTES(pplm_reg); 369 u32 link_speed; 370 int err; 371 372 if (!MLX5_CAP_GEN(dev, pcam_reg)) 373 return -EOPNOTSUPP; 374 375 if (!MLX5_CAP_PCAM_REG(dev, pplm)) 376 return -EOPNOTSUPP; 377 378 MLX5_SET(pplm_reg, in, local_port, 1); 379 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 380 if (err) 381 return err; 382 383 *fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active); 384 385 if (!fec_configured_mode) 386 return 0; 387 388 err = mlx5e_port_linkspeed(dev, &link_speed); 389 if (err) 390 return err; 391 392 return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed); 393 } 394 395 int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy) 396 { 397 u8 fec_policy_nofec = BIT(MLX5E_FEC_NOFEC); 398 bool fec_mode_not_supp_in_speed = false; 399 u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 400 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 401 int sz = MLX5_ST_SZ_BYTES(pplm_reg); 402 u8 fec_policy_auto = 0; 403 u8 fec_caps = 0; 404 int err; 405 int i; 406 407 if (!MLX5_CAP_GEN(dev, pcam_reg)) 408 return -EOPNOTSUPP; 409 410 if (!MLX5_CAP_PCAM_REG(dev, pplm)) 411 return -EOPNOTSUPP; 412 413 MLX5_SET(pplm_reg, in, local_port, 1); 414 err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 415 if (err) 416 return err; 417 418 MLX5_SET(pplm_reg, out, local_port, 1); 419 420 for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS; i++) { 421 mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]); 422 /* policy supported for link speed, or policy is auto */ 423 if (fec_caps & fec_policy || fec_policy == fec_policy_auto) { 424 mlx5e_fec_admin_field(out, &fec_policy, 1, 425 fec_supported_speeds[i]); 426 } else { 427 /* turn off FEC if supported. Else, leave it the same */ 428 if (fec_caps & fec_policy_nofec) 429 mlx5e_fec_admin_field(out, &fec_policy_nofec, 1, 430 fec_supported_speeds[i]); 431 fec_mode_not_supp_in_speed = true; 432 } 433 } 434 435 if (fec_mode_not_supp_in_speed) 436 mlx5_core_dbg(dev, 437 "FEC policy 0x%x is not supported for some speeds", 438 fec_policy); 439 440 return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1); 441 } 442