linux/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright(c) 2013 - 2021 Intel Corporation. */
   3
   4#ifdef CONFIG_I40E_DCB
   5#include "i40e.h"
   6#include <net/dcbnl.h>
   7
   8#define I40E_DCBNL_STATUS_SUCCESS       0
   9#define I40E_DCBNL_STATUS_ERROR         1
  10static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg,
  11                                struct i40e_dcb_app_priority_table *app);
  12/**
  13 * i40e_get_pfc_delay - retrieve PFC Link Delay
  14 * @hw: pointer to hardware struct
  15 * @delay: holds the PFC Link delay value
  16 *
  17 * Returns PFC Link Delay from the PRTDCB_GENC.PFCLDA
  18 **/
  19static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay)
  20{
  21        u32 val;
  22
  23        val = rd32(hw, I40E_PRTDCB_GENC);
  24        *delay = (u16)((val & I40E_PRTDCB_GENC_PFCLDA_MASK) >>
  25                       I40E_PRTDCB_GENC_PFCLDA_SHIFT);
  26}
  27
  28/**
  29 * i40e_dcbnl_ieee_getets - retrieve local IEEE ETS configuration
  30 * @dev: the corresponding netdev
  31 * @ets: structure to hold the ETS information
  32 *
  33 * Returns local IEEE ETS configuration
  34 **/
  35static int i40e_dcbnl_ieee_getets(struct net_device *dev,
  36                                  struct ieee_ets *ets)
  37{
  38        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
  39        struct i40e_dcbx_config *dcbxcfg;
  40
  41        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
  42                return -EINVAL;
  43
  44        dcbxcfg = &pf->hw.local_dcbx_config;
  45        ets->willing = dcbxcfg->etscfg.willing;
  46        ets->ets_cap = I40E_MAX_TRAFFIC_CLASS;
  47        ets->cbs = dcbxcfg->etscfg.cbs;
  48        memcpy(ets->tc_tx_bw, dcbxcfg->etscfg.tcbwtable,
  49                sizeof(ets->tc_tx_bw));
  50        memcpy(ets->tc_rx_bw, dcbxcfg->etscfg.tcbwtable,
  51                sizeof(ets->tc_rx_bw));
  52        memcpy(ets->tc_tsa, dcbxcfg->etscfg.tsatable,
  53                sizeof(ets->tc_tsa));
  54        memcpy(ets->prio_tc, dcbxcfg->etscfg.prioritytable,
  55                sizeof(ets->prio_tc));
  56        memcpy(ets->tc_reco_bw, dcbxcfg->etsrec.tcbwtable,
  57                sizeof(ets->tc_reco_bw));
  58        memcpy(ets->tc_reco_tsa, dcbxcfg->etsrec.tsatable,
  59                sizeof(ets->tc_reco_tsa));
  60        memcpy(ets->reco_prio_tc, dcbxcfg->etscfg.prioritytable,
  61                sizeof(ets->reco_prio_tc));
  62
  63        return 0;
  64}
  65
  66/**
  67 * i40e_dcbnl_ieee_getpfc - retrieve local IEEE PFC configuration
  68 * @dev: the corresponding netdev
  69 * @pfc: structure to hold the PFC information
  70 *
  71 * Returns local IEEE PFC configuration
  72 **/
  73static int i40e_dcbnl_ieee_getpfc(struct net_device *dev,
  74                                  struct ieee_pfc *pfc)
  75{
  76        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
  77        struct i40e_dcbx_config *dcbxcfg;
  78        struct i40e_hw *hw = &pf->hw;
  79        int i;
  80
  81        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
  82                return -EINVAL;
  83
  84        dcbxcfg = &hw->local_dcbx_config;
  85        pfc->pfc_cap = dcbxcfg->pfc.pfccap;
  86        pfc->pfc_en = dcbxcfg->pfc.pfcenable;
  87        pfc->mbc = dcbxcfg->pfc.mbc;
  88        i40e_get_pfc_delay(hw, &pfc->delay);
  89
  90        /* Get Requests/Indications */
  91        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
  92                pfc->requests[i] = pf->stats.priority_xoff_tx[i];
  93                pfc->indications[i] = pf->stats.priority_xoff_rx[i];
  94        }
  95
  96        return 0;
  97}
  98
  99/**
 100 * i40e_dcbnl_ieee_setets - set IEEE ETS configuration
 101 * @netdev: the corresponding netdev
 102 * @ets: structure to hold the ETS information
 103 *
 104 * Set IEEE ETS configuration
 105 **/
 106static int i40e_dcbnl_ieee_setets(struct net_device *netdev,
 107                                  struct ieee_ets *ets)
 108{
 109        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 110        struct i40e_dcbx_config *old_cfg;
 111        int i, ret;
 112
 113        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
 114            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 115                return -EINVAL;
 116
 117        old_cfg = &pf->hw.local_dcbx_config;
 118        /* Copy current config into temp */
 119        pf->tmp_cfg = *old_cfg;
 120
 121        /* Update the ETS configuration for temp */
 122        pf->tmp_cfg.etscfg.willing = ets->willing;
 123        pf->tmp_cfg.etscfg.maxtcs = I40E_MAX_TRAFFIC_CLASS;
 124        pf->tmp_cfg.etscfg.cbs = ets->cbs;
 125        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
 126                pf->tmp_cfg.etscfg.tcbwtable[i] = ets->tc_tx_bw[i];
 127                pf->tmp_cfg.etscfg.tsatable[i] = ets->tc_tsa[i];
 128                pf->tmp_cfg.etscfg.prioritytable[i] = ets->prio_tc[i];
 129                pf->tmp_cfg.etsrec.tcbwtable[i] = ets->tc_reco_bw[i];
 130                pf->tmp_cfg.etsrec.tsatable[i] = ets->tc_reco_tsa[i];
 131                pf->tmp_cfg.etsrec.prioritytable[i] = ets->reco_prio_tc[i];
 132        }
 133
 134        /* Commit changes to HW */
 135        ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);
 136        if (ret) {
 137                dev_info(&pf->pdev->dev,
 138                         "Failed setting DCB ETS configuration err %s aq_err %s\n",
 139                         i40e_stat_str(&pf->hw, ret),
 140                         i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
 141                return -EINVAL;
 142        }
 143
 144        return 0;
 145}
 146
 147/**
 148 * i40e_dcbnl_ieee_setpfc - set local IEEE PFC configuration
 149 * @netdev: the corresponding netdev
 150 * @pfc: structure to hold the PFC information
 151 *
 152 * Sets local IEEE PFC configuration
 153 **/
 154static int i40e_dcbnl_ieee_setpfc(struct net_device *netdev,
 155                                  struct ieee_pfc *pfc)
 156{
 157        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 158        struct i40e_dcbx_config *old_cfg;
 159        int ret;
 160
 161        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
 162            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 163                return -EINVAL;
 164
 165        old_cfg = &pf->hw.local_dcbx_config;
 166        /* Copy current config into temp */
 167        pf->tmp_cfg = *old_cfg;
 168        if (pfc->pfc_cap)
 169                pf->tmp_cfg.pfc.pfccap = pfc->pfc_cap;
 170        else
 171                pf->tmp_cfg.pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
 172        pf->tmp_cfg.pfc.pfcenable = pfc->pfc_en;
 173
 174        ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);
 175        if (ret) {
 176                dev_info(&pf->pdev->dev,
 177                         "Failed setting DCB PFC configuration err %s aq_err %s\n",
 178                         i40e_stat_str(&pf->hw, ret),
 179                         i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
 180                return -EINVAL;
 181        }
 182
 183        return 0;
 184}
 185
 186/**
 187 * i40e_dcbnl_ieee_setapp - set local IEEE App configuration
 188 * @netdev: the corresponding netdev
 189 * @app: structure to hold the Application information
 190 *
 191 * Sets local IEEE App configuration
 192 **/
 193static int i40e_dcbnl_ieee_setapp(struct net_device *netdev,
 194                                  struct dcb_app *app)
 195{
 196        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 197        struct i40e_dcb_app_priority_table new_app;
 198        struct i40e_dcbx_config *old_cfg;
 199        int ret;
 200
 201        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
 202            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 203                return -EINVAL;
 204
 205        old_cfg = &pf->hw.local_dcbx_config;
 206        if (old_cfg->numapps == I40E_DCBX_MAX_APPS)
 207                return -EINVAL;
 208
 209        ret = dcb_ieee_setapp(netdev, app);
 210        if (ret)
 211                return ret;
 212
 213        new_app.selector = app->selector;
 214        new_app.protocolid = app->protocol;
 215        new_app.priority = app->priority;
 216        /* Already internally available */
 217        if (i40e_dcbnl_find_app(old_cfg, &new_app))
 218                return 0;
 219
 220        /* Copy current config into temp */
 221        pf->tmp_cfg = *old_cfg;
 222        /* Add the app */
 223        pf->tmp_cfg.app[pf->tmp_cfg.numapps++] = new_app;
 224
 225        ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);
 226        if (ret) {
 227                dev_info(&pf->pdev->dev,
 228                         "Failed setting DCB configuration err %s aq_err %s\n",
 229                         i40e_stat_str(&pf->hw, ret),
 230                         i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
 231                return -EINVAL;
 232        }
 233
 234        return 0;
 235}
 236
 237/**
 238 * i40e_dcbnl_ieee_delapp - delete local IEEE App configuration
 239 * @netdev: the corresponding netdev
 240 * @app: structure to hold the Application information
 241 *
 242 * Deletes local IEEE App configuration other than the first application
 243 * required by firmware
 244 **/
 245static int i40e_dcbnl_ieee_delapp(struct net_device *netdev,
 246                                  struct dcb_app *app)
 247{
 248        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 249        struct i40e_dcbx_config *old_cfg;
 250        int i, j, ret;
 251
 252        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
 253            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 254                return -EINVAL;
 255
 256        ret = dcb_ieee_delapp(netdev, app);
 257        if (ret)
 258                return ret;
 259
 260        old_cfg = &pf->hw.local_dcbx_config;
 261        /* Need one app for FW so keep it */
 262        if (old_cfg->numapps == 1)
 263                return 0;
 264
 265        /* Copy current config into temp */
 266        pf->tmp_cfg = *old_cfg;
 267
 268        /* Find and reset the app */
 269        for (i = 1; i < pf->tmp_cfg.numapps; i++) {
 270                if (app->selector == pf->tmp_cfg.app[i].selector &&
 271                    app->protocol == pf->tmp_cfg.app[i].protocolid &&
 272                    app->priority == pf->tmp_cfg.app[i].priority) {
 273                        /* Reset the app data */
 274                        pf->tmp_cfg.app[i].selector = 0;
 275                        pf->tmp_cfg.app[i].protocolid = 0;
 276                        pf->tmp_cfg.app[i].priority = 0;
 277                        break;
 278                }
 279        }
 280
 281        /* If the specific DCB app not found */
 282        if (i == pf->tmp_cfg.numapps)
 283                return -EINVAL;
 284
 285        pf->tmp_cfg.numapps--;
 286        /* Overwrite the tmp_cfg app */
 287        for (j = i; j < pf->tmp_cfg.numapps; j++)
 288                pf->tmp_cfg.app[j] = old_cfg->app[j + 1];
 289
 290        ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);
 291        if (ret) {
 292                dev_info(&pf->pdev->dev,
 293                         "Failed setting DCB configuration err %s aq_err %s\n",
 294                         i40e_stat_str(&pf->hw, ret),
 295                         i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
 296                return -EINVAL;
 297        }
 298
 299        return 0;
 300}
 301
 302/**
 303 * i40e_dcbnl_getstate - Get DCB enabled state
 304 * @netdev: the corresponding netdev
 305 *
 306 * Get the current DCB enabled state
 307 **/
 308static u8 i40e_dcbnl_getstate(struct net_device *netdev)
 309{
 310        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 311
 312        dev_dbg(&pf->pdev->dev, "DCB state=%d\n",
 313                !!(pf->flags & I40E_FLAG_DCB_ENABLED));
 314        return !!(pf->flags & I40E_FLAG_DCB_ENABLED);
 315}
 316
 317/**
 318 * i40e_dcbnl_setstate - Set DCB state
 319 * @netdev: the corresponding netdev
 320 * @state: enable or disable
 321 *
 322 * Set the DCB state
 323 **/
 324static u8 i40e_dcbnl_setstate(struct net_device *netdev, u8 state)
 325{
 326        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 327        int ret = I40E_DCBNL_STATUS_SUCCESS;
 328
 329        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 330            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 331                return ret;
 332
 333        dev_dbg(&pf->pdev->dev, "new state=%d current state=%d\n",
 334                state, (pf->flags & I40E_FLAG_DCB_ENABLED) ? 1 : 0);
 335        /* Nothing to do */
 336        if (!state == !(pf->flags & I40E_FLAG_DCB_ENABLED))
 337                return ret;
 338
 339        if (i40e_is_sw_dcb(pf)) {
 340                if (state) {
 341                        pf->flags |= I40E_FLAG_DCB_ENABLED;
 342                        memcpy(&pf->hw.desired_dcbx_config,
 343                               &pf->hw.local_dcbx_config,
 344                               sizeof(struct i40e_dcbx_config));
 345                } else {
 346                        pf->flags &= ~I40E_FLAG_DCB_ENABLED;
 347                }
 348        } else {
 349                /* Cannot directly manipulate FW LLDP Agent */
 350                ret = I40E_DCBNL_STATUS_ERROR;
 351        }
 352        return ret;
 353}
 354
 355/**
 356 * i40e_dcbnl_set_pg_tc_cfg_tx - Set CEE PG Tx config
 357 * @netdev: the corresponding netdev
 358 * @tc: the corresponding traffic class
 359 * @prio_type: the traffic priority type
 360 * @bwg_id: the BW group id the traffic class belongs to
 361 * @bw_pct: the BW percentage for the corresponding BWG
 362 * @up_map: prio mapped to corresponding tc
 363 *
 364 * Set Tx PG settings for CEE mode
 365 **/
 366static void i40e_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc,
 367                                        u8 prio_type, u8 bwg_id, u8 bw_pct,
 368                                        u8 up_map)
 369{
 370        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 371        int i;
 372
 373        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 374            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 375                return;
 376
 377        /* LLTC not supported yet */
 378        if (tc >= I40E_MAX_TRAFFIC_CLASS)
 379                return;
 380
 381        /* prio_type, bwg_id and bw_pct per UP are not supported */
 382
 383        /* Use only up_map to map tc */
 384        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
 385                if (up_map & BIT(i))
 386                        pf->tmp_cfg.etscfg.prioritytable[i] = tc;
 387        }
 388        pf->tmp_cfg.etscfg.tsatable[tc] = I40E_IEEE_TSA_ETS;
 389        dev_dbg(&pf->pdev->dev,
 390                "Set PG config tc=%d bwg_id=%d prio_type=%d bw_pct=%d up_map=%d\n",
 391                tc, bwg_id, prio_type, bw_pct, up_map);
 392}
 393
 394/**
 395 * i40e_dcbnl_set_pg_bwg_cfg_tx - Set CEE PG Tx BW config
 396 * @netdev: the corresponding netdev
 397 * @pgid: the corresponding traffic class
 398 * @bw_pct: the BW percentage for the specified traffic class
 399 *
 400 * Set Tx BW settings for CEE mode
 401 **/
 402static void i40e_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,
 403                                         u8 bw_pct)
 404{
 405        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 406
 407        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 408            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 409                return;
 410
 411        /* LLTC not supported yet */
 412        if (pgid >= I40E_MAX_TRAFFIC_CLASS)
 413                return;
 414
 415        pf->tmp_cfg.etscfg.tcbwtable[pgid] = bw_pct;
 416        dev_dbg(&pf->pdev->dev, "Set PG BW config tc=%d bw_pct=%d\n",
 417                pgid, bw_pct);
 418}
 419
 420/**
 421 * i40e_dcbnl_set_pg_tc_cfg_rx - Set CEE PG Rx config
 422 * @netdev: the corresponding netdev
 423 * @prio: the corresponding traffic class
 424 * @prio_type: the traffic priority type
 425 * @pgid: the BW group id the traffic class belongs to
 426 * @bw_pct: the BW percentage for the corresponding BWG
 427 * @up_map: prio mapped to corresponding tc
 428 *
 429 * Set Rx BW settings for CEE mode. The hardware does not support this
 430 * so we won't allow setting of this parameter.
 431 **/
 432static void i40e_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev,
 433                                        int __always_unused prio,
 434                                        u8 __always_unused prio_type,
 435                                        u8 __always_unused pgid,
 436                                        u8 __always_unused bw_pct,
 437                                        u8 __always_unused up_map)
 438{
 439        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 440
 441        dev_dbg(&pf->pdev->dev, "Rx TC PG Config Not Supported.\n");
 442}
 443
 444/**
 445 * i40e_dcbnl_set_pg_bwg_cfg_rx - Set CEE PG Rx config
 446 * @netdev: the corresponding netdev
 447 * @pgid: the corresponding traffic class
 448 * @bw_pct: the BW percentage for the specified traffic class
 449 *
 450 * Set Rx BW settings for CEE mode. The hardware does not support this
 451 * so we won't allow setting of this parameter.
 452 **/
 453static void i40e_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int pgid,
 454                                         u8 bw_pct)
 455{
 456        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 457
 458        dev_dbg(&pf->pdev->dev, "Rx BWG PG Config Not Supported.\n");
 459}
 460
 461/**
 462 * i40e_dcbnl_get_pg_tc_cfg_tx - Get CEE PG Tx config
 463 * @netdev: the corresponding netdev
 464 * @prio: the corresponding user priority
 465 * @prio_type: traffic priority type
 466 * @pgid: the BW group ID the traffic class belongs to
 467 * @bw_pct: BW percentage for the corresponding BWG
 468 * @up_map: prio mapped to corresponding TC
 469 *
 470 * Get Tx PG settings for CEE mode
 471 **/
 472static void i40e_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int prio,
 473                                        u8 __always_unused *prio_type,
 474                                        u8 *pgid,
 475                                        u8 __always_unused *bw_pct,
 476                                        u8 __always_unused *up_map)
 477{
 478        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 479
 480        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 481            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 482                return;
 483
 484        if (prio >= I40E_MAX_USER_PRIORITY)
 485                return;
 486
 487        *pgid = pf->hw.local_dcbx_config.etscfg.prioritytable[prio];
 488        dev_dbg(&pf->pdev->dev, "Get PG config prio=%d tc=%d\n",
 489                prio, *pgid);
 490}
 491
 492/**
 493 * i40e_dcbnl_get_pg_bwg_cfg_tx - Get CEE PG BW config
 494 * @netdev: the corresponding netdev
 495 * @pgid: the corresponding traffic class
 496 * @bw_pct: the BW percentage for the corresponding TC
 497 *
 498 * Get Tx BW settings for given TC in CEE mode
 499 **/
 500static void i40e_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,
 501                                         u8 *bw_pct)
 502{
 503        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 504
 505        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 506            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 507                return;
 508
 509        if (pgid >= I40E_MAX_TRAFFIC_CLASS)
 510                return;
 511
 512        *bw_pct = pf->hw.local_dcbx_config.etscfg.tcbwtable[pgid];
 513        dev_dbg(&pf->pdev->dev, "Get PG BW config tc=%d bw_pct=%d\n",
 514                pgid, *bw_pct);
 515}
 516
 517/**
 518 * i40e_dcbnl_get_pg_tc_cfg_rx - Get CEE PG Rx config
 519 * @netdev: the corresponding netdev
 520 * @prio: the corresponding user priority
 521 * @prio_type: the traffic priority type
 522 * @pgid: the PG ID
 523 * @bw_pct: the BW percentage for the corresponding BWG
 524 * @up_map: prio mapped to corresponding TC
 525 *
 526 * Get Rx PG settings for CEE mode. The UP2TC map is applied in same
 527 * manner for Tx and Rx (symmetrical) so return the TC information for
 528 * given priority accordingly.
 529 **/
 530static void i40e_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int prio,
 531                                        u8 *prio_type, u8 *pgid, u8 *bw_pct,
 532                                        u8 *up_map)
 533{
 534        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 535
 536        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 537            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 538                return;
 539
 540        if (prio >= I40E_MAX_USER_PRIORITY)
 541                return;
 542
 543        *pgid = pf->hw.local_dcbx_config.etscfg.prioritytable[prio];
 544}
 545
 546/**
 547 * i40e_dcbnl_get_pg_bwg_cfg_rx - Get CEE PG BW Rx config
 548 * @netdev: the corresponding netdev
 549 * @pgid: the corresponding traffic class
 550 * @bw_pct: the BW percentage for the corresponding TC
 551 *
 552 * Get Rx BW settings for given TC in CEE mode
 553 * The adapter doesn't support Rx ETS and runs in strict priority
 554 * mode in Rx path and hence just return 0.
 555 **/
 556static void i40e_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int pgid,
 557                                         u8 *bw_pct)
 558{
 559        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 560
 561        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 562            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 563                return;
 564        *bw_pct = 0;
 565}
 566
 567/**
 568 * i40e_dcbnl_set_pfc_cfg - Set CEE PFC configuration
 569 * @netdev: the corresponding netdev
 570 * @prio: the corresponding user priority
 571 * @setting: the PFC setting for given priority
 572 *
 573 * Set the PFC enabled/disabled setting for given user priority
 574 **/
 575static void i40e_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio,
 576                                   u8 setting)
 577{
 578        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 579
 580        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 581            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 582                return;
 583
 584        if (prio >= I40E_MAX_USER_PRIORITY)
 585                return;
 586
 587        pf->tmp_cfg.pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
 588        if (setting)
 589                pf->tmp_cfg.pfc.pfcenable |= BIT(prio);
 590        else
 591                pf->tmp_cfg.pfc.pfcenable &= ~BIT(prio);
 592        dev_dbg(&pf->pdev->dev,
 593                "Set PFC Config up=%d setting=%d pfcenable=0x%x\n",
 594                prio, setting, pf->tmp_cfg.pfc.pfcenable);
 595}
 596
 597/**
 598 * i40e_dcbnl_get_pfc_cfg - Get CEE PFC configuration
 599 * @netdev: the corresponding netdev
 600 * @prio: the corresponding user priority
 601 * @setting: the PFC setting for given priority
 602 *
 603 * Get the PFC enabled/disabled setting for given user priority
 604 **/
 605static void i40e_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio,
 606                                   u8 *setting)
 607{
 608        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 609
 610        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 611            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 612                return;
 613
 614        if (prio >= I40E_MAX_USER_PRIORITY)
 615                return;
 616
 617        *setting = (pf->hw.local_dcbx_config.pfc.pfcenable >> prio) & 0x1;
 618        dev_dbg(&pf->pdev->dev,
 619                "Get PFC Config up=%d setting=%d pfcenable=0x%x\n",
 620                prio, *setting, pf->hw.local_dcbx_config.pfc.pfcenable);
 621}
 622
 623/**
 624 * i40e_dcbnl_cee_set_all - Commit CEE DCB settings to hardware
 625 * @netdev: the corresponding netdev
 626 *
 627 * Commit the current DCB configuration to hardware
 628 **/
 629static u8 i40e_dcbnl_cee_set_all(struct net_device *netdev)
 630{
 631        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 632        int err;
 633
 634        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 635            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 636                return I40E_DCBNL_STATUS_ERROR;
 637
 638        dev_dbg(&pf->pdev->dev, "Commit DCB Configuration to the hardware\n");
 639        err = i40e_hw_dcb_config(pf, &pf->tmp_cfg);
 640
 641        return err ? I40E_DCBNL_STATUS_ERROR : I40E_DCBNL_STATUS_SUCCESS;
 642}
 643
 644/**
 645 * i40e_dcbnl_get_cap - Get DCBX capabilities of adapter
 646 * @netdev: the corresponding netdev
 647 * @capid: the capability type
 648 * @cap: the capability value
 649 *
 650 * Return the capability value for a given capability type
 651 **/
 652static u8 i40e_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
 653{
 654        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 655
 656        if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
 657                return I40E_DCBNL_STATUS_ERROR;
 658
 659        switch (capid) {
 660        case DCB_CAP_ATTR_PG:
 661        case DCB_CAP_ATTR_PFC:
 662                *cap = true;
 663                break;
 664        case DCB_CAP_ATTR_PG_TCS:
 665        case DCB_CAP_ATTR_PFC_TCS:
 666                *cap = 0x80;
 667                break;
 668        case DCB_CAP_ATTR_DCBX:
 669                *cap = pf->dcbx_cap;
 670                break;
 671        case DCB_CAP_ATTR_UP2TC:
 672        case DCB_CAP_ATTR_GSP:
 673        case DCB_CAP_ATTR_BCN:
 674        default:
 675                *cap = false;
 676                break;
 677        }
 678
 679        dev_dbg(&pf->pdev->dev, "Get Capability cap=%d capval=0x%x\n",
 680                capid, *cap);
 681        return I40E_DCBNL_STATUS_SUCCESS;
 682}
 683
 684/**
 685 * i40e_dcbnl_getnumtcs - Get max number of traffic classes supported
 686 * @netdev: the corresponding netdev
 687 * @tcid: the TC id
 688 * @num: total number of TCs supported by the device
 689 *
 690 * Return the total number of TCs supported by the adapter
 691 **/
 692static int i40e_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
 693{
 694        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 695
 696        if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
 697                return -EINVAL;
 698
 699        *num = I40E_MAX_TRAFFIC_CLASS;
 700        return 0;
 701}
 702
 703/**
 704 * i40e_dcbnl_setnumtcs - Set CEE number of traffic classes
 705 * @netdev: the corresponding netdev
 706 * @tcid: the TC id
 707 * @num: total number of TCs
 708 *
 709 * Set the total number of TCs (Unsupported)
 710 **/
 711static int i40e_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num)
 712{
 713        return -EINVAL;
 714}
 715
 716/**
 717 * i40e_dcbnl_getpfcstate - Get CEE PFC mode
 718 * @netdev: the corresponding netdev
 719 *
 720 * Get the current PFC enabled state
 721 **/
 722static u8 i40e_dcbnl_getpfcstate(struct net_device *netdev)
 723{
 724        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 725
 726        /* Return enabled if any PFC enabled UP */
 727        if (pf->hw.local_dcbx_config.pfc.pfcenable)
 728                return 1;
 729        else
 730                return 0;
 731}
 732
 733/**
 734 * i40e_dcbnl_setpfcstate - Set CEE PFC mode
 735 * @netdev: the corresponding netdev
 736 * @state: required state
 737 *
 738 * The PFC state to be set; this is enabled/disabled based on the PFC
 739 * priority settings and not via this call for i40e driver
 740 **/
 741static void i40e_dcbnl_setpfcstate(struct net_device *netdev, u8 state)
 742{
 743        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 744
 745        dev_dbg(&pf->pdev->dev, "PFC State is modified via PFC config.\n");
 746}
 747
 748/**
 749 * i40e_dcbnl_getapp - Get CEE APP
 750 * @netdev: the corresponding netdev
 751 * @idtype: the App selector
 752 * @id: the App ethtype or port number
 753 *
 754 * Return the CEE mode app for the given idtype and id
 755 **/
 756static int i40e_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id)
 757{
 758        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 759        struct dcb_app app = {
 760                                .selector = idtype,
 761                                .protocol = id,
 762                             };
 763
 764        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
 765            (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
 766                return -EINVAL;
 767
 768        return dcb_getapp(netdev, &app);
 769}
 770
 771/**
 772 * i40e_dcbnl_setdcbx - set required DCBx capability
 773 * @netdev: the corresponding netdev
 774 * @mode: new DCB mode managed or CEE+IEEE
 775 *
 776 * Set DCBx capability features
 777 **/
 778static u8 i40e_dcbnl_setdcbx(struct net_device *netdev, u8 mode)
 779{
 780        struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
 781
 782        /* Do not allow to set mode if managed by Firmware */
 783        if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)
 784                return I40E_DCBNL_STATUS_ERROR;
 785
 786        /* No support for LLD_MANAGED modes or CEE+IEEE */
 787        if ((mode & DCB_CAP_DCBX_LLD_MANAGED) ||
 788            ((mode & DCB_CAP_DCBX_VER_IEEE) && (mode & DCB_CAP_DCBX_VER_CEE)) ||
 789            !(mode & DCB_CAP_DCBX_HOST))
 790                return I40E_DCBNL_STATUS_ERROR;
 791
 792        /* Already set to the given mode no change */
 793        if (mode == pf->dcbx_cap)
 794                return I40E_DCBNL_STATUS_SUCCESS;
 795
 796        pf->dcbx_cap = mode;
 797        if (mode & DCB_CAP_DCBX_VER_CEE)
 798                pf->hw.local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
 799        else
 800                pf->hw.local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
 801
 802        dev_dbg(&pf->pdev->dev, "mode=%d\n", mode);
 803        return I40E_DCBNL_STATUS_SUCCESS;
 804}
 805
 806/**
 807 * i40e_dcbnl_getdcbx - retrieve current DCBx capability
 808 * @dev: the corresponding netdev
 809 *
 810 * Returns DCBx capability features
 811 **/
 812static u8 i40e_dcbnl_getdcbx(struct net_device *dev)
 813{
 814        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
 815
 816        return pf->dcbx_cap;
 817}
 818
 819/**
 820 * i40e_dcbnl_get_perm_hw_addr - MAC address used by DCBx
 821 * @dev: the corresponding netdev
 822 * @perm_addr: buffer to store the MAC address
 823 *
 824 * Returns the SAN MAC address used for LLDP exchange
 825 **/
 826static void i40e_dcbnl_get_perm_hw_addr(struct net_device *dev,
 827                                        u8 *perm_addr)
 828{
 829        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
 830        int i, j;
 831
 832        memset(perm_addr, 0xff, MAX_ADDR_LEN);
 833
 834        for (i = 0; i < dev->addr_len; i++)
 835                perm_addr[i] = pf->hw.mac.perm_addr[i];
 836
 837        for (j = 0; j < dev->addr_len; j++, i++)
 838                perm_addr[i] = pf->hw.mac.san_addr[j];
 839}
 840
 841static const struct dcbnl_rtnl_ops dcbnl_ops = {
 842        .ieee_getets    = i40e_dcbnl_ieee_getets,
 843        .ieee_getpfc    = i40e_dcbnl_ieee_getpfc,
 844        .getdcbx        = i40e_dcbnl_getdcbx,
 845        .getpermhwaddr  = i40e_dcbnl_get_perm_hw_addr,
 846        .ieee_setets    = i40e_dcbnl_ieee_setets,
 847        .ieee_setpfc    = i40e_dcbnl_ieee_setpfc,
 848        .ieee_setapp    = i40e_dcbnl_ieee_setapp,
 849        .ieee_delapp    = i40e_dcbnl_ieee_delapp,
 850        .getstate       = i40e_dcbnl_getstate,
 851        .setstate       = i40e_dcbnl_setstate,
 852        .setpgtccfgtx   = i40e_dcbnl_set_pg_tc_cfg_tx,
 853        .setpgbwgcfgtx  = i40e_dcbnl_set_pg_bwg_cfg_tx,
 854        .setpgtccfgrx   = i40e_dcbnl_set_pg_tc_cfg_rx,
 855        .setpgbwgcfgrx  = i40e_dcbnl_set_pg_bwg_cfg_rx,
 856        .getpgtccfgtx   = i40e_dcbnl_get_pg_tc_cfg_tx,
 857        .getpgbwgcfgtx  = i40e_dcbnl_get_pg_bwg_cfg_tx,
 858        .getpgtccfgrx   = i40e_dcbnl_get_pg_tc_cfg_rx,
 859        .getpgbwgcfgrx  = i40e_dcbnl_get_pg_bwg_cfg_rx,
 860        .setpfccfg      = i40e_dcbnl_set_pfc_cfg,
 861        .getpfccfg      = i40e_dcbnl_get_pfc_cfg,
 862        .setall         = i40e_dcbnl_cee_set_all,
 863        .getcap         = i40e_dcbnl_get_cap,
 864        .getnumtcs      = i40e_dcbnl_getnumtcs,
 865        .setnumtcs      = i40e_dcbnl_setnumtcs,
 866        .getpfcstate    = i40e_dcbnl_getpfcstate,
 867        .setpfcstate    = i40e_dcbnl_setpfcstate,
 868        .getapp         = i40e_dcbnl_getapp,
 869        .setdcbx        = i40e_dcbnl_setdcbx,
 870};
 871
 872/**
 873 * i40e_dcbnl_set_all - set all the apps and ieee data from DCBx config
 874 * @vsi: the corresponding vsi
 875 *
 876 * Set up all the IEEE APPs in the DCBNL App Table and generate event for
 877 * other settings
 878 **/
 879void i40e_dcbnl_set_all(struct i40e_vsi *vsi)
 880{
 881        struct net_device *dev = vsi->netdev;
 882        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
 883        struct i40e_dcbx_config *dcbxcfg;
 884        struct i40e_hw *hw = &pf->hw;
 885        struct dcb_app sapp;
 886        u8 prio, tc_map;
 887        int i;
 888
 889        /* SW DCB taken care by DCBNL set calls */
 890        if (pf->dcbx_cap & DCB_CAP_DCBX_HOST)
 891                return;
 892
 893        /* DCB not enabled */
 894        if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
 895                return;
 896
 897        /* MFP mode but not an iSCSI PF so return */
 898        if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(hw->func_caps.iscsi))
 899                return;
 900
 901        dcbxcfg = &hw->local_dcbx_config;
 902
 903        /* Set up all the App TLVs if DCBx is negotiated */
 904        for (i = 0; i < dcbxcfg->numapps; i++) {
 905                prio = dcbxcfg->app[i].priority;
 906                tc_map = BIT(dcbxcfg->etscfg.prioritytable[prio]);
 907
 908                /* Add APP only if the TC is enabled for this VSI */
 909                if (tc_map & vsi->tc_config.enabled_tc) {
 910                        sapp.selector = dcbxcfg->app[i].selector;
 911                        sapp.protocol = dcbxcfg->app[i].protocolid;
 912                        sapp.priority = prio;
 913                        dcb_ieee_setapp(dev, &sapp);
 914                }
 915        }
 916
 917        /* Notify user-space of the changes */
 918        dcbnl_ieee_notify(dev, RTM_SETDCB, DCB_CMD_IEEE_SET, 0, 0);
 919}
 920
 921/**
 922 * i40e_dcbnl_vsi_del_app - Delete APP for given VSI
 923 * @vsi: the corresponding vsi
 924 * @app: APP to delete
 925 *
 926 * Delete given APP from the DCBNL APP table for given
 927 * VSI
 928 **/
 929static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi,
 930                                  struct i40e_dcb_app_priority_table *app)
 931{
 932        struct net_device *dev = vsi->netdev;
 933        struct dcb_app sapp;
 934
 935        if (!dev)
 936                return -EINVAL;
 937
 938        sapp.selector = app->selector;
 939        sapp.protocol = app->protocolid;
 940        sapp.priority = app->priority;
 941        return dcb_ieee_delapp(dev, &sapp);
 942}
 943
 944/**
 945 * i40e_dcbnl_del_app - Delete APP on all VSIs
 946 * @pf: the corresponding PF
 947 * @app: APP to delete
 948 *
 949 * Delete given APP from all the VSIs for given PF
 950 **/
 951static void i40e_dcbnl_del_app(struct i40e_pf *pf,
 952                               struct i40e_dcb_app_priority_table *app)
 953{
 954        int v, err;
 955
 956        for (v = 0; v < pf->num_alloc_vsi; v++) {
 957                if (pf->vsi[v] && pf->vsi[v]->netdev) {
 958                        err = i40e_dcbnl_vsi_del_app(pf->vsi[v], app);
 959                        dev_dbg(&pf->pdev->dev, "Deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n",
 960                                pf->vsi[v]->seid, err, app->selector,
 961                                app->protocolid, app->priority);
 962                }
 963        }
 964}
 965
 966/**
 967 * i40e_dcbnl_find_app - Search APP in given DCB config
 968 * @cfg: DCBX configuration data
 969 * @app: APP to search for
 970 *
 971 * Find given APP in the DCB configuration
 972 **/
 973static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg,
 974                                struct i40e_dcb_app_priority_table *app)
 975{
 976        int i;
 977
 978        for (i = 0; i < cfg->numapps; i++) {
 979                if (app->selector == cfg->app[i].selector &&
 980                    app->protocolid == cfg->app[i].protocolid &&
 981                    app->priority == cfg->app[i].priority)
 982                        return true;
 983        }
 984
 985        return false;
 986}
 987
 988/**
 989 * i40e_dcbnl_flush_apps - Delete all removed APPs
 990 * @pf: the corresponding PF
 991 * @old_cfg: old DCBX configuration data
 992 * @new_cfg: new DCBX configuration data
 993 *
 994 * Find and delete all APPs that are not present in the passed
 995 * DCB configuration
 996 **/
 997void i40e_dcbnl_flush_apps(struct i40e_pf *pf,
 998                           struct i40e_dcbx_config *old_cfg,
 999                           struct i40e_dcbx_config *new_cfg)
1000{
1001        struct i40e_dcb_app_priority_table app;
1002        int i;
1003
1004        /* MFP mode but not an iSCSI PF so return */
1005        if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi))
1006                return;
1007
1008        for (i = 0; i < old_cfg->numapps; i++) {
1009                app = old_cfg->app[i];
1010                /* The APP is not available anymore delete it */
1011                if (!i40e_dcbnl_find_app(new_cfg, &app))
1012                        i40e_dcbnl_del_app(pf, &app);
1013        }
1014}
1015
1016/**
1017 * i40e_dcbnl_setup - DCBNL setup
1018 * @vsi: the corresponding vsi
1019 *
1020 * Set up DCBNL ops and initial APP TLVs
1021 **/
1022void i40e_dcbnl_setup(struct i40e_vsi *vsi)
1023{
1024        struct net_device *dev = vsi->netdev;
1025        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
1026
1027        /* Not DCB capable */
1028        if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
1029                return;
1030
1031        dev->dcbnl_ops = &dcbnl_ops;
1032
1033        /* Set initial IEEE DCB settings */
1034        i40e_dcbnl_set_all(vsi);
1035}
1036#endif /* CONFIG_I40E_DCB */
1037