1 /*- 2 * Copyright (c) 2015-2021 Mellanox Technologies. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 * $FreeBSD$ 26 */ 27 28 #include "en.h" 29 #include "port_buffer.h" 30 31 void 32 mlx5e_create_stats(struct sysctl_ctx_list *ctx, 33 struct sysctl_oid_list *parent, const char *buffer, 34 const char **desc, unsigned num, u64 * arg) 35 { 36 struct sysctl_oid *node; 37 unsigned x; 38 39 sysctl_ctx_init(ctx); 40 41 node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, 42 buffer, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Statistics"); 43 if (node == NULL) 44 return; 45 for (x = 0; x != num; x++) { 46 SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 47 desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]); 48 } 49 } 50 51 void 52 mlx5e_create_counter_stats(struct sysctl_ctx_list *ctx, 53 struct sysctl_oid_list *parent, const char *buffer, 54 const char **desc, unsigned num, counter_u64_t *arg) 55 { 56 struct sysctl_oid *node; 57 unsigned x; 58 59 sysctl_ctx_init(ctx); 60 61 node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, 62 buffer, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Statistics"); 63 if (node == NULL) 64 return; 65 for (x = 0; x != num; x++) { 66 SYSCTL_ADD_COUNTER_U64(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 67 desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]); 68 } 69 } 70 71 static void 72 mlx5e_ethtool_sync_tx_completion_fact(struct mlx5e_priv *priv) 73 { 74 /* 75 * Limit the maximum distance between completion events to 76 * half of the currently set TX queue size. 77 * 78 * The maximum number of queue entries a single IP packet can 79 * consume is given by MLX5_SEND_WQE_MAX_WQEBBS. 80 * 81 * The worst case max value is then given as below: 82 */ 83 uint64_t max = priv->params_ethtool.tx_queue_size / 84 (2 * MLX5_SEND_WQE_MAX_WQEBBS); 85 86 /* 87 * Update the maximum completion factor value in case the 88 * tx_queue_size field changed. Ensure we don't overflow 89 * 16-bits. 90 */ 91 if (max < 1) 92 max = 1; 93 else if (max > 65535) 94 max = 65535; 95 priv->params_ethtool.tx_completion_fact_max = max; 96 97 /* 98 * Verify that the current TX completion factor is within the 99 * given limits: 100 */ 101 if (priv->params_ethtool.tx_completion_fact < 1) 102 priv->params_ethtool.tx_completion_fact = 1; 103 else if (priv->params_ethtool.tx_completion_fact > max) 104 priv->params_ethtool.tx_completion_fact = max; 105 } 106 107 static int 108 mlx5e_getmaxrate(struct mlx5e_priv *priv) 109 { 110 struct mlx5_core_dev *mdev = priv->mdev; 111 u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; 112 u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; 113 int err; 114 int i; 115 116 PRIV_LOCK(priv); 117 err = -mlx5_query_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit); 118 if (err) 119 goto done; 120 121 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 122 switch (max_bw_unit[i]) { 123 case MLX5_100_MBPS_UNIT: 124 priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_100MB; 125 break; 126 case MLX5_GBPS_UNIT: 127 priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_1GB; 128 break; 129 case MLX5_BW_NO_LIMIT: 130 priv->params_ethtool.max_bw_value[i] = 0; 131 break; 132 default: 133 priv->params_ethtool.max_bw_value[i] = -1; 134 WARN_ONCE(true, "non-supported BW unit"); 135 break; 136 } 137 } 138 done: 139 PRIV_UNLOCK(priv); 140 return (err); 141 } 142 143 static int 144 mlx5e_get_max_alloc(struct mlx5e_priv *priv) 145 { 146 struct mlx5_core_dev *mdev = priv->mdev; 147 int err; 148 int x; 149 150 PRIV_LOCK(priv); 151 err = -mlx5_query_port_tc_bw_alloc(mdev, priv->params_ethtool.max_bw_share); 152 if (err == 0) { 153 /* set default value */ 154 for (x = 0; x != IEEE_8021QAZ_MAX_TCS; x++) { 155 priv->params_ethtool.max_bw_share[x] = 156 100 / IEEE_8021QAZ_MAX_TCS; 157 } 158 err = -mlx5_set_port_tc_bw_alloc(mdev, 159 priv->params_ethtool.max_bw_share); 160 } 161 PRIV_UNLOCK(priv); 162 163 return (err); 164 } 165 166 static int 167 mlx5e_get_dscp(struct mlx5e_priv *priv) 168 { 169 struct mlx5_core_dev *mdev = priv->mdev; 170 int err; 171 172 if (MLX5_CAP_GEN(mdev, qcam_reg) == 0 || 173 MLX5_CAP_QCAM_REG(mdev, qpts) == 0 || 174 MLX5_CAP_QCAM_REG(mdev, qpdpm) == 0) 175 return (EOPNOTSUPP); 176 177 PRIV_LOCK(priv); 178 err = -mlx5_query_dscp2prio(mdev, priv->params_ethtool.dscp2prio); 179 if (err) 180 goto done; 181 182 err = -mlx5_query_trust_state(mdev, &priv->params_ethtool.trust_state); 183 if (err) 184 goto done; 185 done: 186 PRIV_UNLOCK(priv); 187 return (err); 188 } 189 190 static void 191 mlx5e_tc_get_parameters(struct mlx5e_priv *priv, 192 u64 *new_bw_value, u8 *max_bw_value, u8 *max_bw_unit) 193 { 194 const u64 upper_limit_mbps = 255 * MLX5E_100MB; 195 const u64 upper_limit_gbps = 255 * MLX5E_1GB; 196 u64 temp; 197 int i; 198 199 memset(max_bw_value, 0, IEEE_8021QAZ_MAX_TCS); 200 memset(max_bw_unit, 0, IEEE_8021QAZ_MAX_TCS); 201 202 for (i = 0; i <= mlx5_max_tc(priv->mdev); i++) { 203 temp = (new_bw_value != NULL) ? 204 new_bw_value[i] : priv->params_ethtool.max_bw_value[i]; 205 206 if (!temp) { 207 max_bw_unit[i] = MLX5_BW_NO_LIMIT; 208 } else if (temp > upper_limit_gbps) { 209 max_bw_unit[i] = MLX5_BW_NO_LIMIT; 210 } else if (temp <= upper_limit_mbps) { 211 max_bw_value[i] = howmany(temp, MLX5E_100MB); 212 max_bw_unit[i] = MLX5_100_MBPS_UNIT; 213 } else { 214 max_bw_value[i] = howmany(temp, MLX5E_1GB); 215 max_bw_unit[i] = MLX5_GBPS_UNIT; 216 } 217 } 218 } 219 220 static int 221 mlx5e_tc_maxrate_handler(SYSCTL_HANDLER_ARGS) 222 { 223 struct mlx5e_priv *priv = arg1; 224 struct mlx5_core_dev *mdev = priv->mdev; 225 u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; 226 u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; 227 u64 new_bw_value[IEEE_8021QAZ_MAX_TCS]; 228 u8 max_rates = mlx5_max_tc(mdev) + 1; 229 u8 x; 230 int err; 231 232 PRIV_LOCK(priv); 233 err = SYSCTL_OUT(req, priv->params_ethtool.max_bw_value, 234 sizeof(priv->params_ethtool.max_bw_value[0]) * max_rates); 235 if (err || !req->newptr) 236 goto done; 237 err = SYSCTL_IN(req, new_bw_value, 238 sizeof(new_bw_value[0]) * max_rates); 239 if (err) 240 goto done; 241 242 /* range check input value */ 243 for (x = 0; x != max_rates; x++) { 244 if (new_bw_value[x] % MLX5E_100MB) { 245 err = ERANGE; 246 goto done; 247 } 248 } 249 250 mlx5e_tc_get_parameters(priv, new_bw_value, max_bw_value, max_bw_unit); 251 252 err = -mlx5_modify_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit); 253 if (err) 254 goto done; 255 256 memcpy(priv->params_ethtool.max_bw_value, new_bw_value, 257 sizeof(priv->params_ethtool.max_bw_value)); 258 done: 259 PRIV_UNLOCK(priv); 260 return (err); 261 } 262 263 static int 264 mlx5e_tc_rate_share_handler(SYSCTL_HANDLER_ARGS) 265 { 266 struct mlx5e_priv *priv = arg1; 267 struct mlx5_core_dev *mdev = priv->mdev; 268 u8 max_bw_share[IEEE_8021QAZ_MAX_TCS]; 269 u8 max_rates = mlx5_max_tc(mdev) + 1; 270 int i; 271 int err; 272 int sum; 273 274 PRIV_LOCK(priv); 275 err = SYSCTL_OUT(req, priv->params_ethtool.max_bw_share, max_rates); 276 if (err || !req->newptr) 277 goto done; 278 err = SYSCTL_IN(req, max_bw_share, max_rates); 279 if (err) 280 goto done; 281 282 /* range check input value */ 283 for (sum = i = 0; i != max_rates; i++) { 284 if (max_bw_share[i] < 1 || max_bw_share[i] > 100) { 285 err = ERANGE; 286 goto done; 287 } 288 sum += max_bw_share[i]; 289 } 290 291 /* sum of values should be as close to 100 as possible */ 292 if (sum < (100 - max_rates + 1) || sum > 100) { 293 err = ERANGE; 294 goto done; 295 } 296 297 err = -mlx5_set_port_tc_bw_alloc(mdev, max_bw_share); 298 if (err) 299 goto done; 300 301 memcpy(priv->params_ethtool.max_bw_share, max_bw_share, 302 sizeof(priv->params_ethtool.max_bw_share)); 303 done: 304 PRIV_UNLOCK(priv); 305 return (err); 306 } 307 308 static int 309 mlx5e_get_prio_tc(struct mlx5e_priv *priv) 310 { 311 struct mlx5_core_dev *mdev = priv->mdev; 312 int err = 0; 313 int i; 314 315 PRIV_LOCK(priv); 316 if (!MLX5_CAP_GEN(priv->mdev, ets)) { 317 PRIV_UNLOCK(priv); 318 return (EOPNOTSUPP); 319 } 320 321 for (i = 0; i != MLX5E_MAX_PRIORITY; i++) { 322 err = -mlx5_query_port_prio_tc(mdev, i, priv->params_ethtool.prio_tc + i); 323 if (err) 324 break; 325 } 326 PRIV_UNLOCK(priv); 327 return (err); 328 } 329 330 static int 331 mlx5e_prio_to_tc_handler(SYSCTL_HANDLER_ARGS) 332 { 333 struct mlx5e_priv *priv = arg1; 334 struct mlx5_core_dev *mdev = priv->mdev; 335 uint8_t temp[MLX5E_MAX_PRIORITY]; 336 int err; 337 int i; 338 339 PRIV_LOCK(priv); 340 err = SYSCTL_OUT(req, priv->params_ethtool.prio_tc, MLX5E_MAX_PRIORITY); 341 if (err || !req->newptr) 342 goto done; 343 err = SYSCTL_IN(req, temp, MLX5E_MAX_PRIORITY); 344 if (err) 345 goto done; 346 347 for (i = 0; i != MLX5E_MAX_PRIORITY; i++) { 348 if (temp[i] > mlx5_max_tc(mdev)) { 349 err = ERANGE; 350 goto done; 351 } 352 } 353 354 for (i = 0; i != MLX5E_MAX_PRIORITY; i++) { 355 if (temp[i] == priv->params_ethtool.prio_tc[i]) 356 continue; 357 err = -mlx5_set_port_prio_tc(mdev, i, temp[i]); 358 if (err) 359 goto done; 360 /* update cached value */ 361 priv->params_ethtool.prio_tc[i] = temp[i]; 362 } 363 done: 364 PRIV_UNLOCK(priv); 365 return (err); 366 } 367 368 int 369 mlx5e_fec_update(struct mlx5e_priv *priv) 370 { 371 struct mlx5_core_dev *mdev = priv->mdev; 372 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 373 const int sz = MLX5_ST_SZ_BYTES(pplm_reg); 374 int err; 375 376 if (!MLX5_CAP_GEN(mdev, pcam_reg)) 377 return (EOPNOTSUPP); 378 379 if (!MLX5_CAP_PCAM_REG(mdev, pplm)) 380 return (EOPNOTSUPP); 381 382 MLX5_SET(pplm_reg, in, local_port, 1); 383 384 err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0); 385 if (err) 386 return (err); 387 388 /* get 10x..25x mask */ 389 priv->params_ethtool.fec_mask_10x_25x[0] = 390 MLX5_GET(pplm_reg, in, fec_override_admin_10g_40g); 391 priv->params_ethtool.fec_mask_10x_25x[1] = 392 MLX5_GET(pplm_reg, in, fec_override_admin_25g) & 393 MLX5_GET(pplm_reg, in, fec_override_admin_50g); 394 priv->params_ethtool.fec_mask_10x_25x[2] = 395 MLX5_GET(pplm_reg, in, fec_override_admin_56g); 396 priv->params_ethtool.fec_mask_10x_25x[3] = 397 MLX5_GET(pplm_reg, in, fec_override_admin_100g); 398 399 /* get 10x..25x available bits */ 400 priv->params_ethtool.fec_avail_10x_25x[0] = 401 MLX5_GET(pplm_reg, in, fec_override_cap_10g_40g); 402 priv->params_ethtool.fec_avail_10x_25x[1] = 403 MLX5_GET(pplm_reg, in, fec_override_cap_25g) & 404 MLX5_GET(pplm_reg, in, fec_override_cap_50g); 405 priv->params_ethtool.fec_avail_10x_25x[2] = 406 MLX5_GET(pplm_reg, in, fec_override_cap_56g); 407 priv->params_ethtool.fec_avail_10x_25x[3] = 408 MLX5_GET(pplm_reg, in, fec_override_cap_100g); 409 410 /* get 50x mask */ 411 priv->params_ethtool.fec_mask_50x[0] = 412 MLX5_GET(pplm_reg, in, fec_override_admin_50g_1x); 413 priv->params_ethtool.fec_mask_50x[1] = 414 MLX5_GET(pplm_reg, in, fec_override_admin_100g_2x); 415 priv->params_ethtool.fec_mask_50x[2] = 416 MLX5_GET(pplm_reg, in, fec_override_admin_200g_4x); 417 priv->params_ethtool.fec_mask_50x[3] = 418 MLX5_GET(pplm_reg, in, fec_override_admin_400g_8x); 419 420 /* get 50x available bits */ 421 priv->params_ethtool.fec_avail_50x[0] = 422 MLX5_GET(pplm_reg, in, fec_override_cap_50g_1x); 423 priv->params_ethtool.fec_avail_50x[1] = 424 MLX5_GET(pplm_reg, in, fec_override_cap_100g_2x); 425 priv->params_ethtool.fec_avail_50x[2] = 426 MLX5_GET(pplm_reg, in, fec_override_cap_200g_4x); 427 priv->params_ethtool.fec_avail_50x[3] = 428 MLX5_GET(pplm_reg, in, fec_override_cap_400g_8x); 429 430 /* get current FEC mask */ 431 priv->params_ethtool.fec_mode_active = 432 MLX5_GET(pplm_reg, in, fec_mode_active); 433 434 return (0); 435 } 436 437 static int 438 mlx5e_fec_mask_10x_25x_handler(SYSCTL_HANDLER_ARGS) 439 { 440 struct mlx5e_priv *priv = arg1; 441 struct mlx5_core_dev *mdev = priv->mdev; 442 u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 443 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 444 const int sz = MLX5_ST_SZ_BYTES(pplm_reg); 445 u8 fec_mask_10x_25x[MLX5E_MAX_FEC_10X_25X]; 446 u8 fec_cap_changed = 0; 447 u8 x; 448 int err; 449 450 PRIV_LOCK(priv); 451 err = SYSCTL_OUT(req, priv->params_ethtool.fec_mask_10x_25x, 452 sizeof(priv->params_ethtool.fec_mask_10x_25x)); 453 if (err || !req->newptr) 454 goto done; 455 456 err = SYSCTL_IN(req, fec_mask_10x_25x, 457 sizeof(fec_mask_10x_25x)); 458 if (err) 459 goto done; 460 461 if (!MLX5_CAP_GEN(mdev, pcam_reg)) { 462 err = EOPNOTSUPP; 463 goto done; 464 } 465 466 if (!MLX5_CAP_PCAM_REG(mdev, pplm)) { 467 err = EOPNOTSUPP; 468 goto done; 469 } 470 471 MLX5_SET(pplm_reg, in, local_port, 1); 472 473 err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0); 474 if (err) 475 goto done; 476 477 /* range check input value */ 478 for (x = 0; x != MLX5E_MAX_FEC_10X_25X; x++) { 479 /* check only one bit is set, if any */ 480 if (fec_mask_10x_25x[x] & (fec_mask_10x_25x[x] - 1)) { 481 err = ERANGE; 482 goto done; 483 } 484 /* check a supported bit is set, if any */ 485 if (fec_mask_10x_25x[x] & 486 ~priv->params_ethtool.fec_avail_10x_25x[x]) { 487 err = ERANGE; 488 goto done; 489 } 490 fec_cap_changed |= (fec_mask_10x_25x[x] ^ 491 priv->params_ethtool.fec_mask_10x_25x[x]); 492 } 493 494 /* check for no changes */ 495 if (fec_cap_changed == 0) 496 goto done; 497 498 memset(in, 0, sizeof(in)); 499 500 MLX5_SET(pplm_reg, in, local_port, 1); 501 502 /* set new values */ 503 MLX5_SET(pplm_reg, in, fec_override_admin_10g_40g, fec_mask_10x_25x[0]); 504 MLX5_SET(pplm_reg, in, fec_override_admin_25g, fec_mask_10x_25x[1]); 505 MLX5_SET(pplm_reg, in, fec_override_admin_50g, fec_mask_10x_25x[1]); 506 MLX5_SET(pplm_reg, in, fec_override_admin_56g, fec_mask_10x_25x[2]); 507 MLX5_SET(pplm_reg, in, fec_override_admin_100g, fec_mask_10x_25x[3]); 508 509 /* preserve other values */ 510 MLX5_SET(pplm_reg, in, fec_override_admin_50g_1x, priv->params_ethtool.fec_mask_50x[0]); 511 MLX5_SET(pplm_reg, in, fec_override_admin_100g_2x, priv->params_ethtool.fec_mask_50x[1]); 512 MLX5_SET(pplm_reg, in, fec_override_admin_200g_4x, priv->params_ethtool.fec_mask_50x[2]); 513 MLX5_SET(pplm_reg, in, fec_override_admin_400g_8x, priv->params_ethtool.fec_mask_50x[3]); 514 515 /* send new value to the firmware */ 516 err = -mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1); 517 if (err) 518 goto done; 519 520 memcpy(priv->params_ethtool.fec_mask_10x_25x, fec_mask_10x_25x, 521 sizeof(priv->params_ethtool.fec_mask_10x_25x)); 522 523 mlx5_toggle_port_link(priv->mdev); 524 done: 525 PRIV_UNLOCK(priv); 526 return (err); 527 } 528 529 static int 530 mlx5e_fec_avail_10x_25x_handler(SYSCTL_HANDLER_ARGS) 531 { 532 struct mlx5e_priv *priv = arg1; 533 int err; 534 535 PRIV_LOCK(priv); 536 err = SYSCTL_OUT(req, priv->params_ethtool.fec_avail_10x_25x, 537 sizeof(priv->params_ethtool.fec_avail_10x_25x)); 538 PRIV_UNLOCK(priv); 539 return (err); 540 } 541 542 static int 543 mlx5e_fec_mask_50x_handler(SYSCTL_HANDLER_ARGS) 544 { 545 struct mlx5e_priv *priv = arg1; 546 struct mlx5_core_dev *mdev = priv->mdev; 547 u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 548 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 549 const int sz = MLX5_ST_SZ_BYTES(pplm_reg); 550 u16 fec_mask_50x[MLX5E_MAX_FEC_50X]; 551 u16 fec_cap_changed = 0; 552 u8 x; 553 int err; 554 555 PRIV_LOCK(priv); 556 err = SYSCTL_OUT(req, priv->params_ethtool.fec_mask_50x, 557 sizeof(priv->params_ethtool.fec_mask_50x)); 558 if (err || !req->newptr) 559 goto done; 560 561 err = SYSCTL_IN(req, fec_mask_50x, 562 sizeof(fec_mask_50x)); 563 if (err) 564 goto done; 565 566 if (!MLX5_CAP_GEN(mdev, pcam_reg)) { 567 err = EOPNOTSUPP; 568 goto done; 569 } 570 571 if (!MLX5_CAP_PCAM_REG(mdev, pplm)) { 572 err = EOPNOTSUPP; 573 goto done; 574 } 575 576 MLX5_SET(pplm_reg, in, local_port, 1); 577 578 err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0); 579 if (err) 580 goto done; 581 582 /* range check input value */ 583 for (x = 0; x != MLX5E_MAX_FEC_50X; x++) { 584 /* check only one bit is set, if any */ 585 if (fec_mask_50x[x] & (fec_mask_50x[x] - 1)) { 586 err = ERANGE; 587 goto done; 588 } 589 /* check a supported bit is set, if any */ 590 if (fec_mask_50x[x] & 591 ~priv->params_ethtool.fec_avail_50x[x]) { 592 err = ERANGE; 593 goto done; 594 } 595 fec_cap_changed |= (fec_mask_50x[x] ^ 596 priv->params_ethtool.fec_mask_50x[x]); 597 } 598 599 /* check for no changes */ 600 if (fec_cap_changed == 0) 601 goto done; 602 603 memset(in, 0, sizeof(in)); 604 605 MLX5_SET(pplm_reg, in, local_port, 1); 606 607 /* set new values */ 608 MLX5_SET(pplm_reg, in, fec_override_admin_50g_1x, fec_mask_50x[0]); 609 MLX5_SET(pplm_reg, in, fec_override_admin_100g_2x, fec_mask_50x[1]); 610 MLX5_SET(pplm_reg, in, fec_override_admin_200g_4x, fec_mask_50x[2]); 611 MLX5_SET(pplm_reg, in, fec_override_admin_400g_8x, fec_mask_50x[3]); 612 613 /* preserve other values */ 614 MLX5_SET(pplm_reg, in, fec_override_admin_10g_40g, priv->params_ethtool.fec_mask_10x_25x[0]); 615 MLX5_SET(pplm_reg, in, fec_override_admin_25g, priv->params_ethtool.fec_mask_10x_25x[1]); 616 MLX5_SET(pplm_reg, in, fec_override_admin_50g, priv->params_ethtool.fec_mask_10x_25x[1]); 617 MLX5_SET(pplm_reg, in, fec_override_admin_56g, priv->params_ethtool.fec_mask_10x_25x[2]); 618 MLX5_SET(pplm_reg, in, fec_override_admin_100g, priv->params_ethtool.fec_mask_10x_25x[3]); 619 620 /* send new value to the firmware */ 621 err = -mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1); 622 if (err) 623 goto done; 624 625 memcpy(priv->params_ethtool.fec_mask_50x, fec_mask_50x, 626 sizeof(priv->params_ethtool.fec_mask_50x)); 627 628 mlx5_toggle_port_link(priv->mdev); 629 done: 630 PRIV_UNLOCK(priv); 631 return (err); 632 } 633 634 static int 635 mlx5e_fec_avail_50x_handler(SYSCTL_HANDLER_ARGS) 636 { 637 struct mlx5e_priv *priv = arg1; 638 int err; 639 640 PRIV_LOCK(priv); 641 err = SYSCTL_OUT(req, priv->params_ethtool.fec_avail_50x, 642 sizeof(priv->params_ethtool.fec_avail_50x)); 643 PRIV_UNLOCK(priv); 644 return (err); 645 } 646 647 static int 648 mlx5e_trust_state_handler(SYSCTL_HANDLER_ARGS) 649 { 650 struct mlx5e_priv *priv = arg1; 651 struct mlx5_core_dev *mdev = priv->mdev; 652 int err; 653 u8 result; 654 655 PRIV_LOCK(priv); 656 result = priv->params_ethtool.trust_state; 657 err = sysctl_handle_8(oidp, &result, 0, req); 658 if (err || !req->newptr || 659 result == priv->params_ethtool.trust_state) 660 goto done; 661 662 switch (result) { 663 case MLX5_QPTS_TRUST_PCP: 664 case MLX5_QPTS_TRUST_DSCP: 665 break; 666 case MLX5_QPTS_TRUST_BOTH: 667 if (!MLX5_CAP_QCAM_FEATURE(mdev, qpts_trust_both)) { 668 err = EOPNOTSUPP; 669 goto done; 670 } 671 break; 672 default: 673 err = ERANGE; 674 goto done; 675 } 676 677 err = -mlx5_set_trust_state(mdev, result); 678 if (err) 679 goto done; 680 681 priv->params_ethtool.trust_state = result; 682 683 /* update inline mode */ 684 mlx5e_refresh_sq_inline(priv); 685 #ifdef RATELIMIT 686 mlx5e_rl_refresh_sq_inline(&priv->rl); 687 #endif 688 done: 689 PRIV_UNLOCK(priv); 690 return (err); 691 } 692 693 static int 694 mlx5e_dscp_prio_handler(SYSCTL_HANDLER_ARGS) 695 { 696 struct mlx5e_priv *priv = arg1; 697 int prio_index = arg2; 698 struct mlx5_core_dev *mdev = priv->mdev; 699 uint8_t dscp2prio[MLX5_MAX_SUPPORTED_DSCP]; 700 uint8_t x; 701 int err; 702 703 PRIV_LOCK(priv); 704 err = SYSCTL_OUT(req, priv->params_ethtool.dscp2prio + prio_index, 705 sizeof(priv->params_ethtool.dscp2prio) / 8); 706 if (err || !req->newptr) 707 goto done; 708 709 memcpy(dscp2prio, priv->params_ethtool.dscp2prio, sizeof(dscp2prio)); 710 err = SYSCTL_IN(req, dscp2prio + prio_index, sizeof(dscp2prio) / 8); 711 if (err) 712 goto done; 713 for (x = 0; x != MLX5_MAX_SUPPORTED_DSCP; x++) { 714 if (dscp2prio[x] > 7) { 715 err = ERANGE; 716 goto done; 717 } 718 } 719 err = -mlx5_set_dscp2prio(mdev, dscp2prio); 720 if (err) 721 goto done; 722 723 /* update local array */ 724 memcpy(priv->params_ethtool.dscp2prio, dscp2prio, 725 sizeof(priv->params_ethtool.dscp2prio)); 726 done: 727 PRIV_UNLOCK(priv); 728 return (err); 729 } 730 731 int 732 mlx5e_update_buf_lossy(struct mlx5e_priv *priv) 733 { 734 struct ieee_pfc pfc; 735 736 PRIV_ASSERT_LOCKED(priv); 737 bzero(&pfc, sizeof(pfc)); 738 pfc.pfc_en = priv->params.rx_priority_flow_control; 739 return (-mlx5e_port_manual_buffer_config(priv, MLX5E_PORT_BUFFER_PFC, 740 priv->params_ethtool.hw_mtu, &pfc, NULL, NULL)); 741 } 742 743 static int 744 mlx5e_buf_size_handler(SYSCTL_HANDLER_ARGS) 745 { 746 struct mlx5e_priv *priv; 747 u32 buf_size[MLX5E_MAX_BUFFER]; 748 struct mlx5e_port_buffer port_buffer; 749 int error, i; 750 751 priv = arg1; 752 PRIV_LOCK(priv); 753 error = -mlx5e_port_query_buffer(priv, &port_buffer); 754 if (error != 0) 755 goto done; 756 for (i = 0; i < nitems(buf_size); i++) 757 buf_size[i] = port_buffer.buffer[i].size; 758 error = SYSCTL_OUT(req, buf_size, sizeof(buf_size)); 759 if (error != 0 || req->newptr == NULL) 760 goto done; 761 error = SYSCTL_IN(req, buf_size, sizeof(buf_size)); 762 if (error != 0) 763 goto done; 764 error = -mlx5e_port_manual_buffer_config(priv, MLX5E_PORT_BUFFER_SIZE, 765 priv->params_ethtool.hw_mtu, NULL, buf_size, NULL); 766 done: 767 PRIV_UNLOCK(priv); 768 return (error); 769 } 770 771 static int 772 mlx5e_buf_prio_handler(SYSCTL_HANDLER_ARGS) 773 { 774 struct mlx5e_priv *priv; 775 struct mlx5_core_dev *mdev; 776 u8 buffer[MLX5E_MAX_BUFFER]; 777 int error; 778 779 priv = arg1; 780 mdev = priv->mdev; 781 PRIV_LOCK(priv); 782 error = -mlx5e_port_query_priority2buffer(mdev, buffer); 783 if (error != 0) 784 goto done; 785 error = SYSCTL_OUT(req, buffer, MLX5E_MAX_BUFFER); 786 if (error != 0 || req->newptr == NULL) 787 goto done; 788 error = SYSCTL_IN(req, buffer, MLX5E_MAX_BUFFER); 789 if (error != 0) 790 goto done; 791 error = -mlx5e_port_manual_buffer_config(priv, 792 MLX5E_PORT_BUFFER_PRIO2BUFFER, 793 priv->params_ethtool.hw_mtu, NULL, NULL, buffer); 794 if (error == 0) 795 error = mlx5e_update_buf_lossy(priv); 796 done: 797 PRIV_UNLOCK(priv); 798 return (error); 799 } 800 801 static int 802 mlx5e_cable_length_handler(SYSCTL_HANDLER_ARGS) 803 { 804 struct mlx5e_priv *priv; 805 u_int cable_len; 806 int error; 807 808 priv = arg1; 809 PRIV_LOCK(priv); 810 cable_len = priv->dcbx.cable_len; 811 error = sysctl_handle_int(oidp, &cable_len, 0, req); 812 if (error == 0 && req->newptr != NULL && 813 cable_len != priv->dcbx.cable_len) { 814 error = -mlx5e_port_manual_buffer_config(priv, 815 MLX5E_PORT_BUFFER_CABLE_LEN, priv->params_ethtool.hw_mtu, 816 NULL, NULL, NULL); 817 if (error == 0) 818 priv->dcbx.cable_len = cable_len; 819 } 820 PRIV_UNLOCK(priv); 821 return (error); 822 } 823 824 static int 825 mlx5e_hw_temperature_handler(SYSCTL_HANDLER_ARGS) 826 { 827 struct mlx5e_priv *priv = arg1; 828 int err; 829 830 PRIV_LOCK(priv); 831 err = SYSCTL_OUT(req, priv->params_ethtool.hw_val_temp, 832 sizeof(priv->params_ethtool.hw_val_temp[0]) * 833 priv->params_ethtool.hw_num_temp); 834 if (err == 0 && req->newptr != NULL) 835 err = EOPNOTSUPP; 836 PRIV_UNLOCK(priv); 837 return (err); 838 } 839 840 int 841 mlx5e_hw_temperature_update(struct mlx5e_priv *priv) 842 { 843 int err; 844 u32 x; 845 846 if (priv->params_ethtool.hw_num_temp == 0) { 847 u32 out_cap[MLX5_ST_SZ_DW(mtcap)] = {}; 848 const int sz_cap = MLX5_ST_SZ_BYTES(mtcap); 849 u32 value; 850 851 err = -mlx5_core_access_reg(priv->mdev, NULL, 0, out_cap, sz_cap, 852 MLX5_ACCESS_REG_SUMMARY_CTRL_ID_MTCAP, 0, 0); 853 if (err) 854 goto done; 855 value = MLX5_GET(mtcap, out_cap, sensor_count); 856 if (value == 0) 857 return (0); 858 if (value > MLX5_MAX_TEMPERATURE) 859 value = MLX5_MAX_TEMPERATURE; 860 /* update number of temperature sensors */ 861 priv->params_ethtool.hw_num_temp = value; 862 } 863 864 for (x = 0; x != priv->params_ethtool.hw_num_temp; x++) { 865 u32 out_sensor[MLX5_ST_SZ_DW(mtmp_reg)] = {}; 866 const int sz_sensor = MLX5_ST_SZ_BYTES(mtmp_reg); 867 868 MLX5_SET(mtmp_reg, out_sensor, sensor_index, x); 869 870 err = -mlx5_core_access_reg(priv->mdev, out_sensor, sz_sensor, 871 out_sensor, sz_sensor, 872 MLX5_ACCESS_REG_SUMMARY_CTRL_ID_MTMP, 0, 0); 873 if (err) 874 goto done; 875 /* convert from 0.125 celsius to millicelsius */ 876 priv->params_ethtool.hw_val_temp[x] = 877 (s16)MLX5_GET(mtmp_reg, out_sensor, temperature) * 125; 878 } 879 done: 880 return (err); 881 } 882 883 #define MLX5_PARAM_OFFSET(n) \ 884 __offsetof(struct mlx5e_priv, params_ethtool.n) 885 886 static int 887 mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS) 888 { 889 struct mlx5e_priv *priv = arg1; 890 uint64_t value; 891 int mode_modify; 892 int was_opened; 893 int error; 894 895 PRIV_LOCK(priv); 896 value = priv->params_ethtool.arg[arg2]; 897 if (req != NULL) { 898 error = sysctl_handle_64(oidp, &value, 0, req); 899 if (error || req->newptr == NULL || 900 value == priv->params_ethtool.arg[arg2]) 901 goto done; 902 903 /* assign new value */ 904 priv->params_ethtool.arg[arg2] = value; 905 } else { 906 error = 0; 907 } 908 /* check if device is gone */ 909 if (priv->gone) { 910 error = ENXIO; 911 goto done; 912 } 913 was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); 914 mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify); 915 916 switch (MLX5_PARAM_OFFSET(arg[arg2])) { 917 case MLX5_PARAM_OFFSET(rx_coalesce_usecs): 918 /* import RX coal time */ 919 if (priv->params_ethtool.rx_coalesce_usecs < 1) 920 priv->params_ethtool.rx_coalesce_usecs = 0; 921 else if (priv->params_ethtool.rx_coalesce_usecs > 922 MLX5E_FLD_MAX(cqc, cq_period)) { 923 priv->params_ethtool.rx_coalesce_usecs = 924 MLX5E_FLD_MAX(cqc, cq_period); 925 } 926 priv->params.rx_cq_moderation_usec = 927 priv->params_ethtool.rx_coalesce_usecs; 928 929 /* check to avoid down and up the network interface */ 930 if (was_opened) 931 error = mlx5e_refresh_channel_params(priv); 932 break; 933 934 case MLX5_PARAM_OFFSET(rx_coalesce_pkts): 935 /* import RX coal pkts */ 936 if (priv->params_ethtool.rx_coalesce_pkts < 1) 937 priv->params_ethtool.rx_coalesce_pkts = 0; 938 else if (priv->params_ethtool.rx_coalesce_pkts > 939 MLX5E_FLD_MAX(cqc, cq_max_count)) { 940 priv->params_ethtool.rx_coalesce_pkts = 941 MLX5E_FLD_MAX(cqc, cq_max_count); 942 } 943 priv->params.rx_cq_moderation_pkts = 944 priv->params_ethtool.rx_coalesce_pkts; 945 946 /* check to avoid down and up the network interface */ 947 if (was_opened) 948 error = mlx5e_refresh_channel_params(priv); 949 break; 950 951 case MLX5_PARAM_OFFSET(tx_coalesce_usecs): 952 /* import TX coal time */ 953 if (priv->params_ethtool.tx_coalesce_usecs < 1) 954 priv->params_ethtool.tx_coalesce_usecs = 0; 955 else if (priv->params_ethtool.tx_coalesce_usecs > 956 MLX5E_FLD_MAX(cqc, cq_period)) { 957 priv->params_ethtool.tx_coalesce_usecs = 958 MLX5E_FLD_MAX(cqc, cq_period); 959 } 960 priv->params.tx_cq_moderation_usec = 961 priv->params_ethtool.tx_coalesce_usecs; 962 963 /* check to avoid down and up the network interface */ 964 if (was_opened) 965 error = mlx5e_refresh_channel_params(priv); 966 break; 967 968 case MLX5_PARAM_OFFSET(tx_coalesce_pkts): 969 /* import TX coal pkts */ 970 if (priv->params_ethtool.tx_coalesce_pkts < 1) 971 priv->params_ethtool.tx_coalesce_pkts = 0; 972 else if (priv->params_ethtool.tx_coalesce_pkts > 973 MLX5E_FLD_MAX(cqc, cq_max_count)) { 974 priv->params_ethtool.tx_coalesce_pkts = 975 MLX5E_FLD_MAX(cqc, cq_max_count); 976 } 977 priv->params.tx_cq_moderation_pkts = 978 priv->params_ethtool.tx_coalesce_pkts; 979 980 /* check to avoid down and up the network interface */ 981 if (was_opened) 982 error = mlx5e_refresh_channel_params(priv); 983 break; 984 985 case MLX5_PARAM_OFFSET(tx_queue_size): 986 /* network interface must be down */ 987 if (was_opened) 988 mlx5e_close_locked(priv->ifp); 989 990 /* import TX queue size */ 991 if (priv->params_ethtool.tx_queue_size < 992 (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) { 993 priv->params_ethtool.tx_queue_size = 994 (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE); 995 } else if (priv->params_ethtool.tx_queue_size > 996 priv->params_ethtool.tx_queue_size_max) { 997 priv->params_ethtool.tx_queue_size = 998 priv->params_ethtool.tx_queue_size_max; 999 } 1000 /* store actual TX queue size */ 1001 priv->params.log_sq_size = 1002 order_base_2(priv->params_ethtool.tx_queue_size); 1003 priv->params_ethtool.tx_queue_size = 1004 1 << priv->params.log_sq_size; 1005 1006 /* verify TX completion factor */ 1007 mlx5e_ethtool_sync_tx_completion_fact(priv); 1008 1009 /* restart network interface, if any */ 1010 if (was_opened) 1011 mlx5e_open_locked(priv->ifp); 1012 break; 1013 1014 case MLX5_PARAM_OFFSET(rx_queue_size): 1015 /* network interface must be down */ 1016 if (was_opened) 1017 mlx5e_close_locked(priv->ifp); 1018 1019 /* import RX queue size */ 1020 if (priv->params_ethtool.rx_queue_size < 1021 (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) { 1022 priv->params_ethtool.rx_queue_size = 1023 (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE); 1024 } else if (priv->params_ethtool.rx_queue_size > 1025 priv->params_ethtool.rx_queue_size_max) { 1026 priv->params_ethtool.rx_queue_size = 1027 priv->params_ethtool.rx_queue_size_max; 1028 } 1029 /* store actual RX queue size */ 1030 priv->params.log_rq_size = 1031 order_base_2(priv->params_ethtool.rx_queue_size); 1032 priv->params_ethtool.rx_queue_size = 1033 1 << priv->params.log_rq_size; 1034 1035 /* update least number of RX WQEs */ 1036 priv->params.min_rx_wqes = min( 1037 priv->params_ethtool.rx_queue_size - 1, 1038 MLX5E_PARAMS_DEFAULT_MIN_RX_WQES); 1039 1040 /* restart network interface, if any */ 1041 if (was_opened) 1042 mlx5e_open_locked(priv->ifp); 1043 break; 1044 1045 case MLX5_PARAM_OFFSET(channels_rsss): 1046 /* network interface must be down */ 1047 if (was_opened) 1048 mlx5e_close_locked(priv->ifp); 1049 1050 /* import number of channels */ 1051 if (priv->params_ethtool.channels_rsss < 1) 1052 priv->params_ethtool.channels_rsss = 1; 1053 else if (priv->params_ethtool.channels_rsss > 128) 1054 priv->params_ethtool.channels_rsss = 128; 1055 1056 priv->params.channels_rsss = priv->params_ethtool.channels_rsss; 1057 1058 /* restart network interface, if any */ 1059 if (was_opened) 1060 mlx5e_open_locked(priv->ifp); 1061 break; 1062 1063 case MLX5_PARAM_OFFSET(channels): 1064 /* network interface must be down */ 1065 if (was_opened) 1066 mlx5e_close_locked(priv->ifp); 1067 1068 /* import number of channels */ 1069 if (priv->params_ethtool.channels < 1) 1070 priv->params_ethtool.channels = 1; 1071 else if (priv->params_ethtool.channels > 1072 (u64) priv->mdev->priv.eq_table.num_comp_vectors) { 1073 priv->params_ethtool.channels = 1074 (u64) priv->mdev->priv.eq_table.num_comp_vectors; 1075 } 1076 priv->params.num_channels = priv->params_ethtool.channels; 1077 1078 /* restart network interface, if any */ 1079 if (was_opened) 1080 mlx5e_open_locked(priv->ifp); 1081 break; 1082 1083 case MLX5_PARAM_OFFSET(rx_coalesce_mode): 1084 /* network interface must be down */ 1085 if (was_opened != 0 && mode_modify == 0) 1086 mlx5e_close_locked(priv->ifp); 1087 1088 /* import RX coalesce mode */ 1089 if (priv->params_ethtool.rx_coalesce_mode > 3) 1090 priv->params_ethtool.rx_coalesce_mode = 3; 1091 priv->params.rx_cq_moderation_mode = 1092 priv->params_ethtool.rx_coalesce_mode; 1093 1094 /* restart network interface, if any */ 1095 if (was_opened != 0) { 1096 if (mode_modify == 0) 1097 mlx5e_open_locked(priv->ifp); 1098 else 1099 error = mlx5e_refresh_channel_params(priv); 1100 } 1101 break; 1102 1103 case MLX5_PARAM_OFFSET(tx_coalesce_mode): 1104 /* network interface must be down */ 1105 if (was_opened != 0 && mode_modify == 0) 1106 mlx5e_close_locked(priv->ifp); 1107 1108 /* import TX coalesce mode */ 1109 if (priv->params_ethtool.tx_coalesce_mode != 0) 1110 priv->params_ethtool.tx_coalesce_mode = 1; 1111 priv->params.tx_cq_moderation_mode = 1112 priv->params_ethtool.tx_coalesce_mode; 1113 1114 /* restart network interface, if any */ 1115 if (was_opened != 0) { 1116 if (mode_modify == 0) 1117 mlx5e_open_locked(priv->ifp); 1118 else 1119 error = mlx5e_refresh_channel_params(priv); 1120 } 1121 break; 1122 1123 case MLX5_PARAM_OFFSET(hw_lro): 1124 /* network interface must be down */ 1125 if (was_opened) 1126 mlx5e_close_locked(priv->ifp); 1127 1128 /* import HW LRO mode */ 1129 if (priv->params_ethtool.hw_lro != 0 && 1130 MLX5_CAP_ETH(priv->mdev, lro_cap)) { 1131 priv->params_ethtool.hw_lro = 1; 1132 /* check if feature should actually be enabled */ 1133 if (priv->ifp->if_capenable & IFCAP_LRO) { 1134 priv->params.hw_lro_en = true; 1135 } else { 1136 priv->params.hw_lro_en = false; 1137 1138 mlx5_en_warn(priv->ifp, "To enable HW LRO " 1139 "please also enable LRO via ifconfig(8).\n"); 1140 } 1141 } else { 1142 /* return an error if HW does not support this feature */ 1143 if (priv->params_ethtool.hw_lro != 0) 1144 error = EINVAL; 1145 priv->params.hw_lro_en = false; 1146 priv->params_ethtool.hw_lro = 0; 1147 } 1148 /* restart network interface, if any */ 1149 if (was_opened) 1150 mlx5e_open_locked(priv->ifp); 1151 break; 1152 1153 case MLX5_PARAM_OFFSET(cqe_zipping): 1154 /* network interface must be down */ 1155 if (was_opened) 1156 mlx5e_close_locked(priv->ifp); 1157 1158 /* import CQE zipping mode */ 1159 if (priv->params_ethtool.cqe_zipping && 1160 MLX5_CAP_GEN(priv->mdev, cqe_compression)) { 1161 priv->params.cqe_zipping_en = true; 1162 priv->params_ethtool.cqe_zipping = 1; 1163 } else { 1164 priv->params.cqe_zipping_en = false; 1165 priv->params_ethtool.cqe_zipping = 0; 1166 } 1167 /* restart network interface, if any */ 1168 if (was_opened) 1169 mlx5e_open_locked(priv->ifp); 1170 break; 1171 1172 case MLX5_PARAM_OFFSET(tx_completion_fact): 1173 /* network interface must be down */ 1174 if (was_opened) 1175 mlx5e_close_locked(priv->ifp); 1176 1177 /* verify parameter */ 1178 mlx5e_ethtool_sync_tx_completion_fact(priv); 1179 1180 /* restart network interface, if any */ 1181 if (was_opened) 1182 mlx5e_open_locked(priv->ifp); 1183 break; 1184 1185 case MLX5_PARAM_OFFSET(modify_tx_dma): 1186 /* check if network interface is opened */ 1187 if (was_opened) { 1188 priv->params_ethtool.modify_tx_dma = 1189 priv->params_ethtool.modify_tx_dma ? 1 : 0; 1190 /* modify tx according to value */ 1191 mlx5e_modify_tx_dma(priv, value != 0); 1192 } else { 1193 /* if closed force enable tx */ 1194 priv->params_ethtool.modify_tx_dma = 0; 1195 } 1196 break; 1197 1198 case MLX5_PARAM_OFFSET(modify_rx_dma): 1199 /* check if network interface is opened */ 1200 if (was_opened) { 1201 priv->params_ethtool.modify_rx_dma = 1202 priv->params_ethtool.modify_rx_dma ? 1 : 0; 1203 /* modify rx according to value */ 1204 mlx5e_modify_rx_dma(priv, value != 0); 1205 } else { 1206 /* if closed force enable rx */ 1207 priv->params_ethtool.modify_rx_dma = 0; 1208 } 1209 break; 1210 1211 case MLX5_PARAM_OFFSET(diag_pci_enable): 1212 priv->params_ethtool.diag_pci_enable = 1213 priv->params_ethtool.diag_pci_enable ? 1 : 0; 1214 1215 error = -mlx5_core_set_diagnostics_full(priv->mdev, 1216 priv->params_ethtool.diag_pci_enable, 1217 priv->params_ethtool.diag_general_enable); 1218 break; 1219 1220 case MLX5_PARAM_OFFSET(diag_general_enable): 1221 priv->params_ethtool.diag_general_enable = 1222 priv->params_ethtool.diag_general_enable ? 1 : 0; 1223 1224 error = -mlx5_core_set_diagnostics_full(priv->mdev, 1225 priv->params_ethtool.diag_pci_enable, 1226 priv->params_ethtool.diag_general_enable); 1227 break; 1228 1229 case MLX5_PARAM_OFFSET(mc_local_lb): 1230 priv->params_ethtool.mc_local_lb = 1231 priv->params_ethtool.mc_local_lb ? 1 : 0; 1232 1233 if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { 1234 error = mlx5_nic_vport_modify_local_lb(priv->mdev, 1235 MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb); 1236 } else { 1237 error = EOPNOTSUPP; 1238 } 1239 break; 1240 1241 case MLX5_PARAM_OFFSET(uc_local_lb): 1242 priv->params_ethtool.uc_local_lb = 1243 priv->params_ethtool.uc_local_lb ? 1 : 0; 1244 1245 if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { 1246 error = mlx5_nic_vport_modify_local_lb(priv->mdev, 1247 MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb); 1248 } else { 1249 error = EOPNOTSUPP; 1250 } 1251 break; 1252 1253 case MLX5_PARAM_OFFSET(irq_cpu_base): 1254 case MLX5_PARAM_OFFSET(irq_cpu_stride): 1255 if (was_opened) { 1256 /* network interface must toggled */ 1257 mlx5e_close_locked(priv->ifp); 1258 mlx5e_open_locked(priv->ifp); 1259 } 1260 break; 1261 1262 default: 1263 break; 1264 } 1265 done: 1266 PRIV_UNLOCK(priv); 1267 return (error); 1268 } 1269 1270 static const char *mlx5e_params_desc[] = { 1271 MLX5E_PARAMS(MLX5E_STATS_DESC) 1272 }; 1273 1274 static const char *mlx5e_port_stats_debug_desc[] = { 1275 MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC) 1276 }; 1277 1278 static int 1279 mlx5e_ethtool_debug_channel_info(SYSCTL_HANDLER_ARGS) 1280 { 1281 struct mlx5e_priv *priv; 1282 struct sbuf sb; 1283 struct mlx5e_channel *c; 1284 struct mlx5e_sq *sq; 1285 struct mlx5e_rq *rq; 1286 int error, i, tc; 1287 bool opened; 1288 1289 priv = arg1; 1290 error = sysctl_wire_old_buffer(req, 0); 1291 if (error != 0) 1292 return (error); 1293 if (sbuf_new_for_sysctl(&sb, NULL, 1024, req) == NULL) 1294 return (ENOMEM); 1295 sbuf_clear_flags(&sb, SBUF_INCLUDENUL); 1296 1297 PRIV_LOCK(priv); 1298 opened = test_bit(MLX5E_STATE_OPENED, &priv->state); 1299 1300 sbuf_printf(&sb, "pages irq %d\n", 1301 priv->mdev->priv.msix_arr[MLX5_EQ_VEC_PAGES].vector); 1302 sbuf_printf(&sb, "command irq %d\n", 1303 priv->mdev->priv.msix_arr[MLX5_EQ_VEC_CMD].vector); 1304 sbuf_printf(&sb, "async irq %d\n", 1305 priv->mdev->priv.msix_arr[MLX5_EQ_VEC_ASYNC].vector); 1306 1307 for (i = 0; i != priv->params.num_channels; i++) { 1308 int eqn_not_used = -1; 1309 int irqn = MLX5_EQ_VEC_COMP_BASE; 1310 1311 if (mlx5_vector2eqn(priv->mdev, i, &eqn_not_used, &irqn) != 0) 1312 continue; 1313 1314 c = opened ? &priv->channel[i] : NULL; 1315 rq = opened ? &c->rq : NULL; 1316 sbuf_printf(&sb, "channel %d rq %d cq %d irq %d\n", i, 1317 opened ? rq->rqn : -1, 1318 opened ? rq->cq.mcq.cqn : -1, 1319 priv->mdev->priv.msix_arr[irqn].vector); 1320 1321 for (tc = 0; tc != priv->num_tc; tc++) { 1322 sq = opened ? &c->sq[tc] : NULL; 1323 sbuf_printf(&sb, "channel %d tc %d sq %d cq %d irq %d\n", 1324 i, tc, 1325 opened ? sq->sqn : -1, 1326 opened ? sq->cq.mcq.cqn : -1, 1327 priv->mdev->priv.msix_arr[irqn].vector); 1328 } 1329 } 1330 PRIV_UNLOCK(priv); 1331 error = sbuf_finish(&sb); 1332 sbuf_delete(&sb); 1333 return (error); 1334 } 1335 1336 static int 1337 mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS) 1338 { 1339 struct mlx5e_priv *priv = arg1; 1340 int sys_debug; 1341 int error; 1342 1343 PRIV_LOCK(priv); 1344 if (priv->gone != 0) { 1345 error = ENODEV; 1346 goto done; 1347 } 1348 sys_debug = priv->sysctl_debug; 1349 error = sysctl_handle_int(oidp, &sys_debug, 0, req); 1350 if (error != 0 || !req->newptr) 1351 goto done; 1352 sys_debug = sys_debug ? 1 : 0; 1353 if (sys_debug == priv->sysctl_debug) 1354 goto done; 1355 1356 if ((priv->sysctl_debug = sys_debug)) { 1357 mlx5e_create_stats(&priv->stats.port_stats_debug.ctx, 1358 SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats", 1359 mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM, 1360 priv->stats.port_stats_debug.arg); 1361 SYSCTL_ADD_PROC(&priv->stats.port_stats_debug.ctx, 1362 SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO, 1363 "hw_ctx_debug", 1364 CTLFLAG_RD | CTLFLAG_MPSAFE | CTLTYPE_STRING, priv, 0, 1365 mlx5e_ethtool_debug_channel_info, "S", ""); 1366 } else { 1367 sysctl_ctx_free(&priv->stats.port_stats_debug.ctx); 1368 } 1369 done: 1370 PRIV_UNLOCK(priv); 1371 return (error); 1372 } 1373 1374 static void 1375 mlx5e_create_diagnostics(struct mlx5e_priv *priv) 1376 { 1377 struct mlx5_core_diagnostics_entry entry; 1378 struct sysctl_ctx_list *ctx; 1379 struct sysctl_oid *node; 1380 int x; 1381 1382 /* sysctl context we are using */ 1383 ctx = &priv->sysctl_ctx; 1384 1385 /* create root node */ 1386 node = SYSCTL_ADD_NODE(ctx, 1387 SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO, 1388 "diagnostics", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Diagnostics"); 1389 if (node == NULL) 1390 return; 1391 1392 /* create PCI diagnostics */ 1393 for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) { 1394 entry = mlx5_core_pci_diagnostics_table[x]; 1395 if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0) 1396 continue; 1397 SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 1398 entry.desc, CTLFLAG_RD, priv->params_pci.array + x, 1399 "PCI diagnostics counter"); 1400 } 1401 1402 /* create general diagnostics */ 1403 for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) { 1404 entry = mlx5_core_general_diagnostics_table[x]; 1405 if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0) 1406 continue; 1407 SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 1408 entry.desc, CTLFLAG_RD, priv->params_general.array + x, 1409 "General diagnostics counter"); 1410 } 1411 } 1412 1413 void 1414 mlx5e_create_ethtool(struct mlx5e_priv *priv) 1415 { 1416 struct sysctl_oid *fec_node; 1417 struct sysctl_oid *qos_node; 1418 struct sysctl_oid *node; 1419 const char *pnameunit; 1420 struct mlx5e_port_buffer port_buffer; 1421 unsigned x; 1422 int i; 1423 1424 /* set some defaults */ 1425 priv->params_ethtool.irq_cpu_base = -1; /* disabled */ 1426 priv->params_ethtool.irq_cpu_stride = 1; 1427 priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE; 1428 priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE; 1429 priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size; 1430 priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size; 1431 priv->params_ethtool.channels = priv->params.num_channels; 1432 priv->params_ethtool.channels_rsss = priv->params.channels_rsss; 1433 priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count); 1434 priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period); 1435 priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode; 1436 priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec; 1437 priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts; 1438 priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode; 1439 priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec; 1440 priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts; 1441 priv->params_ethtool.hw_lro = priv->params.hw_lro_en; 1442 priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en; 1443 mlx5e_ethtool_sync_tx_completion_fact(priv); 1444 1445 /* get default values for local loopback, if any */ 1446 if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { 1447 int err; 1448 u8 val; 1449 1450 err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val); 1451 if (err == 0) 1452 priv->params_ethtool.mc_local_lb = val; 1453 1454 err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val); 1455 if (err == 0) 1456 priv->params_ethtool.uc_local_lb = val; 1457 } 1458 1459 /* create root node */ 1460 node = SYSCTL_ADD_NODE(&priv->sysctl_ctx, 1461 SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO, 1462 "conf", CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, "Configuration"); 1463 if (node == NULL) 1464 return; 1465 for (x = 0; x != MLX5E_PARAMS_NUM; x++) { 1466 /* check for read-only parameter */ 1467 if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL || 1468 strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) { 1469 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 1470 mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD | 1471 CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU", 1472 mlx5e_params_desc[2 * x + 1]); 1473 } else { 1474 #if (__FreeBSD_version < 1100000) 1475 char path[64]; 1476 #endif 1477 /* 1478 * NOTE: In FreeBSD-11 and newer the 1479 * CTLFLAG_RWTUN flag will take care of 1480 * loading default sysctl value from the 1481 * kernel environment, if any: 1482 */ 1483 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 1484 mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN | 1485 CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU", 1486 mlx5e_params_desc[2 * x + 1]); 1487 1488 #if (__FreeBSD_version < 1100000) 1489 /* compute path for sysctl */ 1490 snprintf(path, sizeof(path), "dev.mce.%d.conf.%s", 1491 device_get_unit(priv->mdev->pdev->dev.bsddev), 1492 mlx5e_params_desc[2 * x]); 1493 1494 /* try to fetch tunable, if any */ 1495 if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x])) 1496 mlx5e_ethtool_handler(NULL, priv, x, NULL); 1497 #endif 1498 } 1499 } 1500 1501 /* create fec node */ 1502 fec_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx, 1503 SYSCTL_CHILDREN(node), OID_AUTO, 1504 "fec", CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 1505 "Forward Error Correction"); 1506 if (fec_node == NULL) 1507 return; 1508 1509 if (mlx5e_fec_update(priv) == 0) { 1510 SYSCTL_ADD_U32(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO, 1511 "mode_active", CTLFLAG_RD | CTLFLAG_MPSAFE, 1512 &priv->params_ethtool.fec_mode_active, 0, 1513 "Current FEC mode bit, if any."); 1514 1515 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO, 1516 "mask_10x_25x", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1517 priv, 0, &mlx5e_fec_mask_10x_25x_handler, "CU", 1518 "Set FEC masks for 10G_40G, 25G_50G, 56G, 100G respectivly. " 1519 "0:Auto " 1520 "1:NOFEC " 1521 "2:FIRECODE " 1522 "4:RS"); 1523 1524 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO, 1525 "avail_10x_25x", CTLTYPE_U8 | CTLFLAG_RD | CTLFLAG_MPSAFE, 1526 priv, 0, &mlx5e_fec_avail_10x_25x_handler, "CU", 1527 "Get available FEC bits for 10G_40G, 25G_50G, 56G, 100G respectivly. " 1528 "0:Auto " 1529 "1:NOFEC " 1530 "2:FIRECODE " 1531 "4:RS"); 1532 1533 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO, 1534 "mask_50x", CTLTYPE_U16 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1535 priv, 0, &mlx5e_fec_mask_50x_handler, "SU", 1536 "Set FEC masks for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. " 1537 "0:Auto " 1538 "128:RS " 1539 "512:LL RS"); 1540 1541 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO, 1542 "avail_50x", CTLTYPE_U16 | CTLFLAG_RD | CTLFLAG_MPSAFE, 1543 priv, 0, &mlx5e_fec_avail_50x_handler, "SU", 1544 "Get available FEC bits for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. " 1545 "0:Auto " 1546 "128:RS " 1547 "512:LL RS"); 1548 } 1549 1550 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 1551 "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 1552 0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics"); 1553 1554 pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev); 1555 1556 SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), 1557 OID_AUTO, "device_name", CTLFLAG_RD, 1558 __DECONST(void *, pnameunit), 0, 1559 "PCI device name"); 1560 1561 /* Diagnostics support */ 1562 mlx5e_create_diagnostics(priv); 1563 1564 /* create qos node */ 1565 qos_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx, 1566 SYSCTL_CHILDREN(node), OID_AUTO, 1567 "qos", CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 1568 "Quality Of Service configuration"); 1569 if (qos_node == NULL) 1570 return; 1571 1572 /* Priority rate limit support */ 1573 if (mlx5e_getmaxrate(priv) == 0) { 1574 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1575 OID_AUTO, "tc_max_rate", CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1576 priv, 0, mlx5e_tc_maxrate_handler, "QU", 1577 "Max rate for priority, specified in kilobits, where kilo=1000, " 1578 "max_rate must be divisible by 100000"); 1579 } 1580 1581 /* Bandwidth limiting by ratio */ 1582 if (mlx5e_get_max_alloc(priv) == 0) { 1583 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1584 OID_AUTO, "tc_rate_share", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1585 priv, 0, mlx5e_tc_rate_share_handler, "QU", 1586 "Specify bandwidth ratio from 1 to 100 " 1587 "for the available traffic classes"); 1588 } 1589 1590 /* Priority to traffic class mapping */ 1591 if (mlx5e_get_prio_tc(priv) == 0) { 1592 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1593 OID_AUTO, "prio_0_7_tc", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1594 priv, 0, mlx5e_prio_to_tc_handler, "CU", 1595 "Set traffic class 0 to 7 for priority 0 to 7 inclusivly"); 1596 } 1597 1598 /* DSCP support */ 1599 if (mlx5e_get_dscp(priv) == 0) { 1600 for (i = 0; i != MLX5_MAX_SUPPORTED_DSCP; i += 8) { 1601 char name[32]; 1602 snprintf(name, sizeof(name), "dscp_%d_%d_prio", i, i + 7); 1603 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1604 OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1605 priv, i, mlx5e_dscp_prio_handler, "CU", 1606 "Set DSCP to priority mapping, 0..7"); 1607 } 1608 #define A "Set trust state, 1:PCP 2:DSCP" 1609 #define B " 3:BOTH" 1610 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1611 OID_AUTO, "trust_state", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1612 priv, 0, mlx5e_trust_state_handler, "CU", 1613 MLX5_CAP_QCAM_FEATURE(priv->mdev, qpts_trust_both) ? 1614 A B : A); 1615 #undef B 1616 #undef A 1617 } 1618 1619 if (mlx5e_port_query_buffer(priv, &port_buffer) == 0) { 1620 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1621 OID_AUTO, "buffers_size", 1622 CTLTYPE_U32 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1623 priv, 0, mlx5e_buf_size_handler, "IU", 1624 "Set buffers sizes"); 1625 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1626 OID_AUTO, "buffers_prio", 1627 CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1628 priv, 0, mlx5e_buf_prio_handler, "CU", 1629 "Set prio to buffers mapping"); 1630 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1631 OID_AUTO, "cable_length", 1632 CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1633 priv, 0, mlx5e_cable_length_handler, "IU", 1634 "Set cable length in meters for xoff threshold calculation"); 1635 } 1636 1637 if (mlx5e_hw_temperature_update(priv) == 0) { 1638 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(priv->sysctl_ifnet), 1639 OID_AUTO, "hw_temperature", 1640 CTLTYPE_S32 | CTLFLAG_RD | CTLFLAG_MPSAFE, 1641 priv, 0, mlx5e_hw_temperature_handler, "I", 1642 "HW temperature in millicelsius"); 1643 } 1644 } 1645