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