1 /* 2 * Copyright (c) 2016, Mellanox Technologies. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 #include <linux/device.h> 33 #include <linux/netdevice.h> 34 #include "en.h" 35 36 #define MLX5E_MAX_PRIORITY 8 37 38 #define MLX5E_100MB (100000) 39 #define MLX5E_1GB (1000000) 40 41 #define MLX5E_CEE_STATE_UP 1 42 #define MLX5E_CEE_STATE_DOWN 0 43 44 /* If dcbx mode is non-host set the dcbx mode to host. 45 */ 46 static int mlx5e_dcbnl_set_dcbx_mode(struct mlx5e_priv *priv, 47 enum mlx5_dcbx_oper_mode mode) 48 { 49 struct mlx5_core_dev *mdev = priv->mdev; 50 u32 param[MLX5_ST_SZ_DW(dcbx_param)]; 51 int err; 52 53 err = mlx5_query_port_dcbx_param(mdev, param); 54 if (err) 55 return err; 56 57 MLX5_SET(dcbx_param, param, version_admin, mode); 58 if (mode != MLX5E_DCBX_PARAM_VER_OPER_HOST) 59 MLX5_SET(dcbx_param, param, willing_admin, 1); 60 61 return mlx5_set_port_dcbx_param(mdev, param); 62 } 63 64 static int mlx5e_dcbnl_switch_to_host_mode(struct mlx5e_priv *priv) 65 { 66 struct mlx5e_dcbx *dcbx = &priv->dcbx; 67 int err; 68 69 if (!MLX5_CAP_GEN(priv->mdev, dcbx)) 70 return 0; 71 72 if (dcbx->mode == MLX5E_DCBX_PARAM_VER_OPER_HOST) 73 return 0; 74 75 err = mlx5e_dcbnl_set_dcbx_mode(priv, MLX5E_DCBX_PARAM_VER_OPER_HOST); 76 if (err) 77 return err; 78 79 dcbx->mode = MLX5E_DCBX_PARAM_VER_OPER_HOST; 80 return 0; 81 } 82 83 static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev, 84 struct ieee_ets *ets) 85 { 86 struct mlx5e_priv *priv = netdev_priv(netdev); 87 struct mlx5_core_dev *mdev = priv->mdev; 88 int err = 0; 89 int i; 90 91 if (!MLX5_CAP_GEN(priv->mdev, ets)) 92 return -EOPNOTSUPP; 93 94 ets->ets_cap = mlx5_max_tc(priv->mdev) + 1; 95 for (i = 0; i < ets->ets_cap; i++) { 96 err = mlx5_query_port_prio_tc(mdev, i, &ets->prio_tc[i]); 97 if (err) 98 return err; 99 } 100 101 for (i = 0; i < ets->ets_cap; i++) { 102 err = mlx5_query_port_tc_bw_alloc(mdev, i, &ets->tc_tx_bw[i]); 103 if (err) 104 return err; 105 if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC) 106 priv->dcbx.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS; 107 } 108 109 memcpy(ets->tc_tsa, priv->dcbx.tc_tsa, sizeof(ets->tc_tsa)); 110 111 return err; 112 } 113 114 enum { 115 MLX5E_VENDOR_TC_GROUP_NUM = 7, 116 MLX5E_ETS_TC_GROUP_NUM = 0, 117 }; 118 119 static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc) 120 { 121 bool any_tc_mapped_to_ets = false; 122 int strict_group; 123 int i; 124 125 for (i = 0; i <= max_tc; i++) 126 if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) 127 any_tc_mapped_to_ets = true; 128 129 strict_group = any_tc_mapped_to_ets ? 1 : 0; 130 131 for (i = 0; i <= max_tc; i++) { 132 switch (ets->tc_tsa[i]) { 133 case IEEE_8021QAZ_TSA_VENDOR: 134 tc_group[i] = MLX5E_VENDOR_TC_GROUP_NUM; 135 break; 136 case IEEE_8021QAZ_TSA_STRICT: 137 tc_group[i] = strict_group++; 138 break; 139 case IEEE_8021QAZ_TSA_ETS: 140 tc_group[i] = MLX5E_ETS_TC_GROUP_NUM; 141 break; 142 } 143 } 144 } 145 146 static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw, 147 u8 *tc_group, int max_tc) 148 { 149 int i; 150 151 for (i = 0; i <= max_tc; i++) { 152 switch (ets->tc_tsa[i]) { 153 case IEEE_8021QAZ_TSA_VENDOR: 154 tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; 155 break; 156 case IEEE_8021QAZ_TSA_STRICT: 157 tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; 158 break; 159 case IEEE_8021QAZ_TSA_ETS: 160 tc_tx_bw[i] = ets->tc_tx_bw[i]; 161 break; 162 } 163 } 164 } 165 166 int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets) 167 { 168 struct mlx5_core_dev *mdev = priv->mdev; 169 u8 tc_tx_bw[IEEE_8021QAZ_MAX_TCS]; 170 u8 tc_group[IEEE_8021QAZ_MAX_TCS]; 171 int max_tc = mlx5_max_tc(mdev); 172 int err; 173 174 mlx5e_build_tc_group(ets, tc_group, max_tc); 175 mlx5e_build_tc_tx_bw(ets, tc_tx_bw, tc_group, max_tc); 176 177 err = mlx5_set_port_prio_tc(mdev, ets->prio_tc); 178 if (err) 179 return err; 180 181 err = mlx5_set_port_tc_group(mdev, tc_group); 182 if (err) 183 return err; 184 185 err = mlx5_set_port_tc_bw_alloc(mdev, tc_tx_bw); 186 187 if (err) 188 return err; 189 190 memcpy(priv->dcbx.tc_tsa, ets->tc_tsa, sizeof(ets->tc_tsa)); 191 192 return err; 193 } 194 195 static int mlx5e_dbcnl_validate_ets(struct net_device *netdev, 196 struct ieee_ets *ets) 197 { 198 int bw_sum = 0; 199 int i; 200 201 /* Validate Priority */ 202 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 203 if (ets->prio_tc[i] >= MLX5E_MAX_PRIORITY) { 204 netdev_err(netdev, 205 "Failed to validate ETS: priority value greater than max(%d)\n", 206 MLX5E_MAX_PRIORITY); 207 return -EINVAL; 208 } 209 } 210 211 /* Validate Bandwidth Sum */ 212 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 213 if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) { 214 if (!ets->tc_tx_bw[i]) { 215 netdev_err(netdev, 216 "Failed to validate ETS: BW 0 is illegal\n"); 217 return -EINVAL; 218 } 219 220 bw_sum += ets->tc_tx_bw[i]; 221 } 222 } 223 224 if (bw_sum != 0 && bw_sum != 100) { 225 netdev_err(netdev, 226 "Failed to validate ETS: BW sum is illegal\n"); 227 return -EINVAL; 228 } 229 return 0; 230 } 231 232 static int mlx5e_dcbnl_ieee_setets(struct net_device *netdev, 233 struct ieee_ets *ets) 234 { 235 struct mlx5e_priv *priv = netdev_priv(netdev); 236 int err; 237 238 if (!MLX5_CAP_GEN(priv->mdev, ets)) 239 return -EOPNOTSUPP; 240 241 err = mlx5e_dbcnl_validate_ets(netdev, ets); 242 if (err) 243 return err; 244 245 err = mlx5e_dcbnl_ieee_setets_core(priv, ets); 246 if (err) 247 return err; 248 249 return 0; 250 } 251 252 static int mlx5e_dcbnl_ieee_getpfc(struct net_device *dev, 253 struct ieee_pfc *pfc) 254 { 255 struct mlx5e_priv *priv = netdev_priv(dev); 256 struct mlx5_core_dev *mdev = priv->mdev; 257 struct mlx5e_pport_stats *pstats = &priv->stats.pport; 258 int i; 259 260 pfc->pfc_cap = mlx5_max_tc(mdev) + 1; 261 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 262 pfc->requests[i] = PPORT_PER_PRIO_GET(pstats, i, tx_pause); 263 pfc->indications[i] = PPORT_PER_PRIO_GET(pstats, i, rx_pause); 264 } 265 266 return mlx5_query_port_pfc(mdev, &pfc->pfc_en, NULL); 267 } 268 269 static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev, 270 struct ieee_pfc *pfc) 271 { 272 struct mlx5e_priv *priv = netdev_priv(dev); 273 struct mlx5_core_dev *mdev = priv->mdev; 274 u8 curr_pfc_en; 275 int ret; 276 277 mlx5_query_port_pfc(mdev, &curr_pfc_en, NULL); 278 279 if (pfc->pfc_en == curr_pfc_en) 280 return 0; 281 282 ret = mlx5_set_port_pfc(mdev, pfc->pfc_en, pfc->pfc_en); 283 mlx5_toggle_port_link(mdev); 284 285 return ret; 286 } 287 288 static u8 mlx5e_dcbnl_getdcbx(struct net_device *dev) 289 { 290 struct mlx5e_priv *priv = netdev_priv(dev); 291 292 return priv->dcbx.cap; 293 } 294 295 static u8 mlx5e_dcbnl_setdcbx(struct net_device *dev, u8 mode) 296 { 297 struct mlx5e_priv *priv = netdev_priv(dev); 298 struct mlx5e_dcbx *dcbx = &priv->dcbx; 299 300 if (mode & DCB_CAP_DCBX_LLD_MANAGED) 301 return 1; 302 303 if ((!mode) && MLX5_CAP_GEN(priv->mdev, dcbx)) { 304 if (dcbx->mode == MLX5E_DCBX_PARAM_VER_OPER_AUTO) 305 return 0; 306 307 /* set dcbx to fw controlled */ 308 if (!mlx5e_dcbnl_set_dcbx_mode(priv, MLX5E_DCBX_PARAM_VER_OPER_AUTO)) { 309 dcbx->mode = MLX5E_DCBX_PARAM_VER_OPER_AUTO; 310 dcbx->cap &= ~DCB_CAP_DCBX_HOST; 311 return 0; 312 } 313 314 return 1; 315 } 316 317 if (!(mode & DCB_CAP_DCBX_HOST)) 318 return 1; 319 320 if (mlx5e_dcbnl_switch_to_host_mode(netdev_priv(dev))) 321 return 1; 322 323 dcbx->cap = mode; 324 325 return 0; 326 } 327 328 static int mlx5e_dcbnl_ieee_getmaxrate(struct net_device *netdev, 329 struct ieee_maxrate *maxrate) 330 { 331 struct mlx5e_priv *priv = netdev_priv(netdev); 332 struct mlx5_core_dev *mdev = priv->mdev; 333 u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; 334 u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; 335 int err; 336 int i; 337 338 err = mlx5_query_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit); 339 if (err) 340 return err; 341 342 memset(maxrate->tc_maxrate, 0, sizeof(maxrate->tc_maxrate)); 343 344 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 345 switch (max_bw_unit[i]) { 346 case MLX5_100_MBPS_UNIT: 347 maxrate->tc_maxrate[i] = max_bw_value[i] * MLX5E_100MB; 348 break; 349 case MLX5_GBPS_UNIT: 350 maxrate->tc_maxrate[i] = max_bw_value[i] * MLX5E_1GB; 351 break; 352 case MLX5_BW_NO_LIMIT: 353 break; 354 default: 355 WARN(true, "non-supported BW unit"); 356 break; 357 } 358 } 359 360 return 0; 361 } 362 363 static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device *netdev, 364 struct ieee_maxrate *maxrate) 365 { 366 struct mlx5e_priv *priv = netdev_priv(netdev); 367 struct mlx5_core_dev *mdev = priv->mdev; 368 u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; 369 u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; 370 __u64 upper_limit_mbps = roundup(255 * MLX5E_100MB, MLX5E_1GB); 371 int i; 372 373 memset(max_bw_value, 0, sizeof(max_bw_value)); 374 memset(max_bw_unit, 0, sizeof(max_bw_unit)); 375 376 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 377 if (!maxrate->tc_maxrate[i]) { 378 max_bw_unit[i] = MLX5_BW_NO_LIMIT; 379 continue; 380 } 381 if (maxrate->tc_maxrate[i] < upper_limit_mbps) { 382 max_bw_value[i] = div_u64(maxrate->tc_maxrate[i], 383 MLX5E_100MB); 384 max_bw_value[i] = max_bw_value[i] ? max_bw_value[i] : 1; 385 max_bw_unit[i] = MLX5_100_MBPS_UNIT; 386 } else { 387 max_bw_value[i] = div_u64(maxrate->tc_maxrate[i], 388 MLX5E_1GB); 389 max_bw_unit[i] = MLX5_GBPS_UNIT; 390 } 391 } 392 393 return mlx5_modify_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit); 394 } 395 396 static u8 mlx5e_dcbnl_setall(struct net_device *netdev) 397 { 398 struct mlx5e_priv *priv = netdev_priv(netdev); 399 struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; 400 struct mlx5_core_dev *mdev = priv->mdev; 401 struct ieee_ets ets; 402 struct ieee_pfc pfc; 403 int err = -EOPNOTSUPP; 404 int i; 405 406 if (!MLX5_CAP_GEN(mdev, ets)) 407 goto out; 408 409 memset(&ets, 0, sizeof(ets)); 410 memset(&pfc, 0, sizeof(pfc)); 411 412 ets.ets_cap = IEEE_8021QAZ_MAX_TCS; 413 for (i = 0; i < CEE_DCBX_MAX_PGS; i++) { 414 ets.tc_tx_bw[i] = cee_cfg->pg_bw_pct[i]; 415 ets.tc_rx_bw[i] = cee_cfg->pg_bw_pct[i]; 416 ets.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS; 417 ets.prio_tc[i] = cee_cfg->prio_to_pg_map[i]; 418 } 419 420 err = mlx5e_dbcnl_validate_ets(netdev, &ets); 421 if (err) { 422 netdev_err(netdev, 423 "%s, Failed to validate ETS: %d\n", __func__, err); 424 goto out; 425 } 426 427 err = mlx5e_dcbnl_ieee_setets_core(priv, &ets); 428 if (err) { 429 netdev_err(netdev, 430 "%s, Failed to set ETS: %d\n", __func__, err); 431 goto out; 432 } 433 434 /* Set PFC */ 435 pfc.pfc_cap = mlx5_max_tc(mdev) + 1; 436 if (!cee_cfg->pfc_enable) 437 pfc.pfc_en = 0; 438 else 439 for (i = 0; i < CEE_DCBX_MAX_PRIO; i++) 440 pfc.pfc_en |= cee_cfg->pfc_setting[i] << i; 441 442 err = mlx5e_dcbnl_ieee_setpfc(netdev, &pfc); 443 if (err) { 444 netdev_err(netdev, 445 "%s, Failed to set PFC: %d\n", __func__, err); 446 goto out; 447 } 448 out: 449 return err ? MLX5_DCB_NO_CHG : MLX5_DCB_CHG_RESET; 450 } 451 452 static u8 mlx5e_dcbnl_getstate(struct net_device *netdev) 453 { 454 return MLX5E_CEE_STATE_UP; 455 } 456 457 static void mlx5e_dcbnl_getpermhwaddr(struct net_device *netdev, 458 u8 *perm_addr) 459 { 460 struct mlx5e_priv *priv = netdev_priv(netdev); 461 462 if (!perm_addr) 463 return; 464 465 memset(perm_addr, 0xff, MAX_ADDR_LEN); 466 467 mlx5_query_nic_vport_mac_address(priv->mdev, 0, perm_addr); 468 } 469 470 static void mlx5e_dcbnl_setpgtccfgtx(struct net_device *netdev, 471 int priority, u8 prio_type, 472 u8 pgid, u8 bw_pct, u8 up_map) 473 { 474 struct mlx5e_priv *priv = netdev_priv(netdev); 475 struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; 476 477 if (priority >= CEE_DCBX_MAX_PRIO) { 478 netdev_err(netdev, 479 "%s, priority is out of range\n", __func__); 480 return; 481 } 482 483 if (pgid >= CEE_DCBX_MAX_PGS) { 484 netdev_err(netdev, 485 "%s, priority group is out of range\n", __func__); 486 return; 487 } 488 489 cee_cfg->prio_to_pg_map[priority] = pgid; 490 } 491 492 static void mlx5e_dcbnl_setpgbwgcfgtx(struct net_device *netdev, 493 int pgid, u8 bw_pct) 494 { 495 struct mlx5e_priv *priv = netdev_priv(netdev); 496 struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; 497 498 if (pgid >= CEE_DCBX_MAX_PGS) { 499 netdev_err(netdev, 500 "%s, priority group is out of range\n", __func__); 501 return; 502 } 503 504 cee_cfg->pg_bw_pct[pgid] = bw_pct; 505 } 506 507 static void mlx5e_dcbnl_getpgtccfgtx(struct net_device *netdev, 508 int priority, u8 *prio_type, 509 u8 *pgid, u8 *bw_pct, u8 *up_map) 510 { 511 struct mlx5e_priv *priv = netdev_priv(netdev); 512 struct mlx5_core_dev *mdev = priv->mdev; 513 514 if (!MLX5_CAP_GEN(priv->mdev, ets)) { 515 netdev_err(netdev, "%s, ets is not supported\n", __func__); 516 return; 517 } 518 519 if (priority >= CEE_DCBX_MAX_PRIO) { 520 netdev_err(netdev, 521 "%s, priority is out of range\n", __func__); 522 return; 523 } 524 525 *prio_type = 0; 526 *bw_pct = 0; 527 *up_map = 0; 528 529 if (mlx5_query_port_prio_tc(mdev, priority, pgid)) 530 *pgid = 0; 531 } 532 533 static void mlx5e_dcbnl_getpgbwgcfgtx(struct net_device *netdev, 534 int pgid, u8 *bw_pct) 535 { 536 struct mlx5e_priv *priv = netdev_priv(netdev); 537 struct mlx5_core_dev *mdev = priv->mdev; 538 539 if (pgid >= CEE_DCBX_MAX_PGS) { 540 netdev_err(netdev, 541 "%s, priority group is out of range\n", __func__); 542 return; 543 } 544 545 if (mlx5_query_port_tc_bw_alloc(mdev, pgid, bw_pct)) 546 *bw_pct = 0; 547 } 548 549 static void mlx5e_dcbnl_setpfccfg(struct net_device *netdev, 550 int priority, u8 setting) 551 { 552 struct mlx5e_priv *priv = netdev_priv(netdev); 553 struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; 554 555 if (priority >= CEE_DCBX_MAX_PRIO) { 556 netdev_err(netdev, 557 "%s, priority is out of range\n", __func__); 558 return; 559 } 560 561 if (setting > 1) 562 return; 563 564 cee_cfg->pfc_setting[priority] = setting; 565 } 566 567 static int 568 mlx5e_dcbnl_get_priority_pfc(struct net_device *netdev, 569 int priority, u8 *setting) 570 { 571 struct ieee_pfc pfc; 572 int err; 573 574 err = mlx5e_dcbnl_ieee_getpfc(netdev, &pfc); 575 576 if (err) 577 *setting = 0; 578 else 579 *setting = (pfc.pfc_en >> priority) & 0x01; 580 581 return err; 582 } 583 584 static void mlx5e_dcbnl_getpfccfg(struct net_device *netdev, 585 int priority, u8 *setting) 586 { 587 if (priority >= CEE_DCBX_MAX_PRIO) { 588 netdev_err(netdev, 589 "%s, priority is out of range\n", __func__); 590 return; 591 } 592 593 if (!setting) 594 return; 595 596 mlx5e_dcbnl_get_priority_pfc(netdev, priority, setting); 597 } 598 599 static u8 mlx5e_dcbnl_getcap(struct net_device *netdev, 600 int capid, u8 *cap) 601 { 602 struct mlx5e_priv *priv = netdev_priv(netdev); 603 struct mlx5_core_dev *mdev = priv->mdev; 604 u8 rval = 0; 605 606 switch (capid) { 607 case DCB_CAP_ATTR_PG: 608 *cap = true; 609 break; 610 case DCB_CAP_ATTR_PFC: 611 *cap = true; 612 break; 613 case DCB_CAP_ATTR_UP2TC: 614 *cap = false; 615 break; 616 case DCB_CAP_ATTR_PG_TCS: 617 *cap = 1 << mlx5_max_tc(mdev); 618 break; 619 case DCB_CAP_ATTR_PFC_TCS: 620 *cap = 1 << mlx5_max_tc(mdev); 621 break; 622 case DCB_CAP_ATTR_GSP: 623 *cap = false; 624 break; 625 case DCB_CAP_ATTR_BCN: 626 *cap = false; 627 break; 628 case DCB_CAP_ATTR_DCBX: 629 *cap = priv->dcbx.cap | 630 DCB_CAP_DCBX_VER_CEE | 631 DCB_CAP_DCBX_VER_IEEE; 632 break; 633 default: 634 *cap = 0; 635 rval = 1; 636 break; 637 } 638 639 return rval; 640 } 641 642 static int mlx5e_dcbnl_getnumtcs(struct net_device *netdev, 643 int tcs_id, u8 *num) 644 { 645 struct mlx5e_priv *priv = netdev_priv(netdev); 646 struct mlx5_core_dev *mdev = priv->mdev; 647 648 switch (tcs_id) { 649 case DCB_NUMTCS_ATTR_PG: 650 case DCB_NUMTCS_ATTR_PFC: 651 *num = mlx5_max_tc(mdev) + 1; 652 break; 653 default: 654 return -EINVAL; 655 } 656 657 return 0; 658 } 659 660 static u8 mlx5e_dcbnl_getpfcstate(struct net_device *netdev) 661 { 662 struct ieee_pfc pfc; 663 664 if (mlx5e_dcbnl_ieee_getpfc(netdev, &pfc)) 665 return MLX5E_CEE_STATE_DOWN; 666 667 return pfc.pfc_en ? MLX5E_CEE_STATE_UP : MLX5E_CEE_STATE_DOWN; 668 } 669 670 static void mlx5e_dcbnl_setpfcstate(struct net_device *netdev, u8 state) 671 { 672 struct mlx5e_priv *priv = netdev_priv(netdev); 673 struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg; 674 675 if ((state != MLX5E_CEE_STATE_UP) && (state != MLX5E_CEE_STATE_DOWN)) 676 return; 677 678 cee_cfg->pfc_enable = state; 679 } 680 681 const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = { 682 .ieee_getets = mlx5e_dcbnl_ieee_getets, 683 .ieee_setets = mlx5e_dcbnl_ieee_setets, 684 .ieee_getmaxrate = mlx5e_dcbnl_ieee_getmaxrate, 685 .ieee_setmaxrate = mlx5e_dcbnl_ieee_setmaxrate, 686 .ieee_getpfc = mlx5e_dcbnl_ieee_getpfc, 687 .ieee_setpfc = mlx5e_dcbnl_ieee_setpfc, 688 .getdcbx = mlx5e_dcbnl_getdcbx, 689 .setdcbx = mlx5e_dcbnl_setdcbx, 690 691 /* CEE interfaces */ 692 .setall = mlx5e_dcbnl_setall, 693 .getstate = mlx5e_dcbnl_getstate, 694 .getpermhwaddr = mlx5e_dcbnl_getpermhwaddr, 695 696 .setpgtccfgtx = mlx5e_dcbnl_setpgtccfgtx, 697 .setpgbwgcfgtx = mlx5e_dcbnl_setpgbwgcfgtx, 698 .getpgtccfgtx = mlx5e_dcbnl_getpgtccfgtx, 699 .getpgbwgcfgtx = mlx5e_dcbnl_getpgbwgcfgtx, 700 701 .setpfccfg = mlx5e_dcbnl_setpfccfg, 702 .getpfccfg = mlx5e_dcbnl_getpfccfg, 703 .getcap = mlx5e_dcbnl_getcap, 704 .getnumtcs = mlx5e_dcbnl_getnumtcs, 705 .getpfcstate = mlx5e_dcbnl_getpfcstate, 706 .setpfcstate = mlx5e_dcbnl_setpfcstate, 707 }; 708 709 static void mlx5e_dcbnl_query_dcbx_mode(struct mlx5e_priv *priv, 710 enum mlx5_dcbx_oper_mode *mode) 711 { 712 u32 out[MLX5_ST_SZ_DW(dcbx_param)]; 713 714 *mode = MLX5E_DCBX_PARAM_VER_OPER_HOST; 715 716 if (!mlx5_query_port_dcbx_param(priv->mdev, out)) 717 *mode = MLX5_GET(dcbx_param, out, version_oper); 718 719 /* From driver's point of view, we only care if the mode 720 * is host (HOST) or non-host (AUTO) 721 */ 722 if (*mode != MLX5E_DCBX_PARAM_VER_OPER_HOST) 723 *mode = MLX5E_DCBX_PARAM_VER_OPER_AUTO; 724 } 725 726 static void mlx5e_ets_init(struct mlx5e_priv *priv) 727 { 728 int i; 729 struct ieee_ets ets; 730 731 if (!MLX5_CAP_GEN(priv->mdev, ets)) 732 return; 733 734 memset(&ets, 0, sizeof(ets)); 735 ets.ets_cap = mlx5_max_tc(priv->mdev) + 1; 736 for (i = 0; i < ets.ets_cap; i++) { 737 ets.tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; 738 ets.tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR; 739 ets.prio_tc[i] = i; 740 } 741 742 memcpy(priv->dcbx.tc_tsa, ets.tc_tsa, sizeof(ets.tc_tsa)); 743 744 /* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */ 745 ets.prio_tc[0] = 1; 746 ets.prio_tc[1] = 0; 747 748 mlx5e_dcbnl_ieee_setets_core(priv, &ets); 749 } 750 751 void mlx5e_dcbnl_initialize(struct mlx5e_priv *priv) 752 { 753 struct mlx5e_dcbx *dcbx = &priv->dcbx; 754 755 if (!MLX5_CAP_GEN(priv->mdev, qos)) 756 return; 757 758 if (MLX5_CAP_GEN(priv->mdev, dcbx)) 759 mlx5e_dcbnl_query_dcbx_mode(priv, &dcbx->mode); 760 761 priv->dcbx.cap = DCB_CAP_DCBX_VER_CEE | 762 DCB_CAP_DCBX_VER_IEEE; 763 if (priv->dcbx.mode == MLX5E_DCBX_PARAM_VER_OPER_HOST) 764 priv->dcbx.cap |= DCB_CAP_DCBX_HOST; 765 766 mlx5e_ets_init(priv); 767 } 768