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