1033 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2013 - 2021 Intel Corporation. */3 4#ifdef CONFIG_I40E_DCB5#include <net/dcbnl.h>6#include "i40e.h"7 8#define I40E_DCBNL_STATUS_SUCCESS 09#define I40E_DCBNL_STATUS_ERROR 110static 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 Delay14 * @hw: pointer to hardware struct15 * @delay: holds the PFC Link delay value16 *17 * Returns PFC Link Delay from the PRTDCB_GENC.PFCLDA18 **/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 = FIELD_GET(I40E_PRTDCB_GENC_PFCLDA_MASK, val);25}26 27/**28 * i40e_dcbnl_ieee_getets - retrieve local IEEE ETS configuration29 * @dev: the corresponding netdev30 * @ets: structure to hold the ETS information31 *32 * Returns local IEEE ETS configuration33 **/34static int i40e_dcbnl_ieee_getets(struct net_device *dev,35 struct ieee_ets *ets)36{37 struct i40e_pf *pf = i40e_netdev_to_pf(dev);38 struct i40e_dcbx_config *dcbxcfg;39 40 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))41 return -EINVAL;42 43 dcbxcfg = &pf->hw.local_dcbx_config;44 ets->willing = dcbxcfg->etscfg.willing;45 ets->ets_cap = I40E_MAX_TRAFFIC_CLASS;46 ets->cbs = dcbxcfg->etscfg.cbs;47 memcpy(ets->tc_tx_bw, dcbxcfg->etscfg.tcbwtable,48 sizeof(ets->tc_tx_bw));49 memcpy(ets->tc_rx_bw, dcbxcfg->etscfg.tcbwtable,50 sizeof(ets->tc_rx_bw));51 memcpy(ets->tc_tsa, dcbxcfg->etscfg.tsatable,52 sizeof(ets->tc_tsa));53 memcpy(ets->prio_tc, dcbxcfg->etscfg.prioritytable,54 sizeof(ets->prio_tc));55 memcpy(ets->tc_reco_bw, dcbxcfg->etsrec.tcbwtable,56 sizeof(ets->tc_reco_bw));57 memcpy(ets->tc_reco_tsa, dcbxcfg->etsrec.tsatable,58 sizeof(ets->tc_reco_tsa));59 memcpy(ets->reco_prio_tc, dcbxcfg->etscfg.prioritytable,60 sizeof(ets->reco_prio_tc));61 62 return 0;63}64 65/**66 * i40e_dcbnl_ieee_getpfc - retrieve local IEEE PFC configuration67 * @dev: the corresponding netdev68 * @pfc: structure to hold the PFC information69 *70 * Returns local IEEE PFC configuration71 **/72static int i40e_dcbnl_ieee_getpfc(struct net_device *dev,73 struct ieee_pfc *pfc)74{75 struct i40e_pf *pf = i40e_netdev_to_pf(dev);76 struct i40e_dcbx_config *dcbxcfg;77 struct i40e_hw *hw = &pf->hw;78 int i;79 80 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))81 return -EINVAL;82 83 dcbxcfg = &hw->local_dcbx_config;84 pfc->pfc_cap = dcbxcfg->pfc.pfccap;85 pfc->pfc_en = dcbxcfg->pfc.pfcenable;86 pfc->mbc = dcbxcfg->pfc.mbc;87 i40e_get_pfc_delay(hw, &pfc->delay);88 89 /* Get Requests/Indications */90 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {91 pfc->requests[i] = pf->stats.priority_xoff_tx[i];92 pfc->indications[i] = pf->stats.priority_xoff_rx[i];93 }94 95 return 0;96}97 98/**99 * i40e_dcbnl_ieee_setets - set IEEE ETS configuration100 * @netdev: the corresponding netdev101 * @ets: structure to hold the ETS information102 *103 * Set IEEE ETS configuration104 **/105static int i40e_dcbnl_ieee_setets(struct net_device *netdev,106 struct ieee_ets *ets)107{108 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);109 struct i40e_dcbx_config *old_cfg;110 int i, ret;111 112 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||113 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))114 return -EINVAL;115 116 old_cfg = &pf->hw.local_dcbx_config;117 /* Copy current config into temp */118 pf->tmp_cfg = *old_cfg;119 120 /* Update the ETS configuration for temp */121 pf->tmp_cfg.etscfg.willing = ets->willing;122 pf->tmp_cfg.etscfg.maxtcs = I40E_MAX_TRAFFIC_CLASS;123 pf->tmp_cfg.etscfg.cbs = ets->cbs;124 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {125 pf->tmp_cfg.etscfg.tcbwtable[i] = ets->tc_tx_bw[i];126 pf->tmp_cfg.etscfg.tsatable[i] = ets->tc_tsa[i];127 pf->tmp_cfg.etscfg.prioritytable[i] = ets->prio_tc[i];128 pf->tmp_cfg.etsrec.tcbwtable[i] = ets->tc_reco_bw[i];129 pf->tmp_cfg.etsrec.tsatable[i] = ets->tc_reco_tsa[i];130 pf->tmp_cfg.etsrec.prioritytable[i] = ets->reco_prio_tc[i];131 }132 133 /* Commit changes to HW */134 ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);135 if (ret) {136 dev_info(&pf->pdev->dev,137 "Failed setting DCB ETS configuration err %pe aq_err %s\n",138 ERR_PTR(ret),139 i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));140 return -EINVAL;141 }142 143 return 0;144}145 146/**147 * i40e_dcbnl_ieee_setpfc - set local IEEE PFC configuration148 * @netdev: the corresponding netdev149 * @pfc: structure to hold the PFC information150 *151 * Sets local IEEE PFC configuration152 **/153static int i40e_dcbnl_ieee_setpfc(struct net_device *netdev,154 struct ieee_pfc *pfc)155{156 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);157 struct i40e_dcbx_config *old_cfg;158 int ret;159 160 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||161 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))162 return -EINVAL;163 164 old_cfg = &pf->hw.local_dcbx_config;165 /* Copy current config into temp */166 pf->tmp_cfg = *old_cfg;167 if (pfc->pfc_cap)168 pf->tmp_cfg.pfc.pfccap = pfc->pfc_cap;169 else170 pf->tmp_cfg.pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;171 pf->tmp_cfg.pfc.pfcenable = pfc->pfc_en;172 173 ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);174 if (ret) {175 dev_info(&pf->pdev->dev,176 "Failed setting DCB PFC configuration err %pe aq_err %s\n",177 ERR_PTR(ret),178 i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));179 return -EINVAL;180 }181 182 return 0;183}184 185/**186 * i40e_dcbnl_ieee_setapp - set local IEEE App configuration187 * @netdev: the corresponding netdev188 * @app: structure to hold the Application information189 *190 * Sets local IEEE App configuration191 **/192static int i40e_dcbnl_ieee_setapp(struct net_device *netdev,193 struct dcb_app *app)194{195 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);196 struct i40e_dcb_app_priority_table new_app;197 struct i40e_dcbx_config *old_cfg;198 int ret;199 200 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||201 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))202 return -EINVAL;203 204 old_cfg = &pf->hw.local_dcbx_config;205 if (old_cfg->numapps == I40E_DCBX_MAX_APPS)206 return -EINVAL;207 208 ret = dcb_ieee_setapp(netdev, app);209 if (ret)210 return ret;211 212 new_app.selector = app->selector;213 new_app.protocolid = app->protocol;214 new_app.priority = app->priority;215 /* Already internally available */216 if (i40e_dcbnl_find_app(old_cfg, &new_app))217 return 0;218 219 /* Copy current config into temp */220 pf->tmp_cfg = *old_cfg;221 /* Add the app */222 pf->tmp_cfg.app[pf->tmp_cfg.numapps++] = new_app;223 224 ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);225 if (ret) {226 dev_info(&pf->pdev->dev,227 "Failed setting DCB configuration err %pe aq_err %s\n",228 ERR_PTR(ret),229 i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));230 return -EINVAL;231 }232 233 return 0;234}235 236/**237 * i40e_dcbnl_ieee_delapp - delete local IEEE App configuration238 * @netdev: the corresponding netdev239 * @app: structure to hold the Application information240 *241 * Deletes local IEEE App configuration other than the first application242 * required by firmware243 **/244static int i40e_dcbnl_ieee_delapp(struct net_device *netdev,245 struct dcb_app *app)246{247 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);248 struct i40e_dcbx_config *old_cfg;249 int i, j, ret;250 251 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||252 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))253 return -EINVAL;254 255 ret = dcb_ieee_delapp(netdev, app);256 if (ret)257 return ret;258 259 old_cfg = &pf->hw.local_dcbx_config;260 /* Need one app for FW so keep it */261 if (old_cfg->numapps == 1)262 return 0;263 264 /* Copy current config into temp */265 pf->tmp_cfg = *old_cfg;266 267 /* Find and reset the app */268 for (i = 1; i < pf->tmp_cfg.numapps; i++) {269 if (app->selector == pf->tmp_cfg.app[i].selector &&270 app->protocol == pf->tmp_cfg.app[i].protocolid &&271 app->priority == pf->tmp_cfg.app[i].priority) {272 /* Reset the app data */273 pf->tmp_cfg.app[i].selector = 0;274 pf->tmp_cfg.app[i].protocolid = 0;275 pf->tmp_cfg.app[i].priority = 0;276 break;277 }278 }279 280 /* If the specific DCB app not found */281 if (i == pf->tmp_cfg.numapps)282 return -EINVAL;283 284 pf->tmp_cfg.numapps--;285 /* Overwrite the tmp_cfg app */286 for (j = i; j < pf->tmp_cfg.numapps; j++)287 pf->tmp_cfg.app[j] = old_cfg->app[j + 1];288 289 ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);290 if (ret) {291 dev_info(&pf->pdev->dev,292 "Failed setting DCB configuration err %pe aq_err %s\n",293 ERR_PTR(ret),294 i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));295 return -EINVAL;296 }297 298 return 0;299}300 301/**302 * i40e_dcbnl_getstate - Get DCB enabled state303 * @netdev: the corresponding netdev304 *305 * Get the current DCB enabled state306 **/307static u8 i40e_dcbnl_getstate(struct net_device *netdev)308{309 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);310 311 dev_dbg(&pf->pdev->dev, "DCB state=%d\n",312 test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0);313 return test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0;314}315 316/**317 * i40e_dcbnl_setstate - Set DCB state318 * @netdev: the corresponding netdev319 * @state: enable or disable320 *321 * Set the DCB state322 **/323static u8 i40e_dcbnl_setstate(struct net_device *netdev, u8 state)324{325 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);326 int ret = I40E_DCBNL_STATUS_SUCCESS;327 328 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||329 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))330 return ret;331 332 dev_dbg(&pf->pdev->dev, "new state=%d current state=%d\n",333 state, test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0);334 /* Nothing to do */335 if (!state == !test_bit(I40E_FLAG_DCB_ENA, pf->flags))336 return ret;337 338 if (i40e_is_sw_dcb(pf)) {339 if (state) {340 set_bit(I40E_FLAG_DCB_ENA, pf->flags);341 memcpy(&pf->hw.desired_dcbx_config,342 &pf->hw.local_dcbx_config,343 sizeof(struct i40e_dcbx_config));344 } else {345 clear_bit(I40E_FLAG_DCB_ENA, pf->flags);346 }347 } else {348 /* Cannot directly manipulate FW LLDP Agent */349 ret = I40E_DCBNL_STATUS_ERROR;350 }351 return ret;352}353 354/**355 * i40e_dcbnl_set_pg_tc_cfg_tx - Set CEE PG Tx config356 * @netdev: the corresponding netdev357 * @tc: the corresponding traffic class358 * @prio_type: the traffic priority type359 * @bwg_id: the BW group id the traffic class belongs to360 * @bw_pct: the BW percentage for the corresponding BWG361 * @up_map: prio mapped to corresponding tc362 *363 * Set Tx PG settings for CEE mode364 **/365static void i40e_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc,366 u8 prio_type, u8 bwg_id, u8 bw_pct,367 u8 up_map)368{369 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);370 int i;371 372 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||373 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))374 return;375 376 /* LLTC not supported yet */377 if (tc >= I40E_MAX_TRAFFIC_CLASS)378 return;379 380 /* prio_type, bwg_id and bw_pct per UP are not supported */381 382 /* Use only up_map to map tc */383 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {384 if (up_map & BIT(i))385 pf->tmp_cfg.etscfg.prioritytable[i] = tc;386 }387 pf->tmp_cfg.etscfg.tsatable[tc] = I40E_IEEE_TSA_ETS;388 dev_dbg(&pf->pdev->dev,389 "Set PG config tc=%d bwg_id=%d prio_type=%d bw_pct=%d up_map=%d\n",390 tc, bwg_id, prio_type, bw_pct, up_map);391}392 393/**394 * i40e_dcbnl_set_pg_bwg_cfg_tx - Set CEE PG Tx BW config395 * @netdev: the corresponding netdev396 * @pgid: the corresponding traffic class397 * @bw_pct: the BW percentage for the specified traffic class398 *399 * Set Tx BW settings for CEE mode400 **/401static void i40e_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,402 u8 bw_pct)403{404 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);405 406 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||407 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))408 return;409 410 /* LLTC not supported yet */411 if (pgid >= I40E_MAX_TRAFFIC_CLASS)412 return;413 414 pf->tmp_cfg.etscfg.tcbwtable[pgid] = bw_pct;415 dev_dbg(&pf->pdev->dev, "Set PG BW config tc=%d bw_pct=%d\n",416 pgid, bw_pct);417}418 419/**420 * i40e_dcbnl_set_pg_tc_cfg_rx - Set CEE PG Rx config421 * @netdev: the corresponding netdev422 * @prio: the corresponding traffic class423 * @prio_type: the traffic priority type424 * @pgid: the BW group id the traffic class belongs to425 * @bw_pct: the BW percentage for the corresponding BWG426 * @up_map: prio mapped to corresponding tc427 *428 * Set Rx BW settings for CEE mode. The hardware does not support this429 * so we won't allow setting of this parameter.430 **/431static void i40e_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev,432 int __always_unused prio,433 u8 __always_unused prio_type,434 u8 __always_unused pgid,435 u8 __always_unused bw_pct,436 u8 __always_unused up_map)437{438 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);439 440 dev_dbg(&pf->pdev->dev, "Rx TC PG Config Not Supported.\n");441}442 443/**444 * i40e_dcbnl_set_pg_bwg_cfg_rx - Set CEE PG Rx config445 * @netdev: the corresponding netdev446 * @pgid: the corresponding traffic class447 * @bw_pct: the BW percentage for the specified traffic class448 *449 * Set Rx BW settings for CEE mode. The hardware does not support this450 * so we won't allow setting of this parameter.451 **/452static void i40e_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int pgid,453 u8 bw_pct)454{455 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);456 457 dev_dbg(&pf->pdev->dev, "Rx BWG PG Config Not Supported.\n");458}459 460/**461 * i40e_dcbnl_get_pg_tc_cfg_tx - Get CEE PG Tx config462 * @netdev: the corresponding netdev463 * @prio: the corresponding user priority464 * @prio_type: traffic priority type465 * @pgid: the BW group ID the traffic class belongs to466 * @bw_pct: BW percentage for the corresponding BWG467 * @up_map: prio mapped to corresponding TC468 *469 * Get Tx PG settings for CEE mode470 **/471static void i40e_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int prio,472 u8 __always_unused *prio_type,473 u8 *pgid,474 u8 __always_unused *bw_pct,475 u8 __always_unused *up_map)476{477 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);478 479 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||480 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))481 return;482 483 if (prio >= I40E_MAX_USER_PRIORITY)484 return;485 486 *pgid = pf->hw.local_dcbx_config.etscfg.prioritytable[prio];487 dev_dbg(&pf->pdev->dev, "Get PG config prio=%d tc=%d\n",488 prio, *pgid);489}490 491/**492 * i40e_dcbnl_get_pg_bwg_cfg_tx - Get CEE PG BW config493 * @netdev: the corresponding netdev494 * @pgid: the corresponding traffic class495 * @bw_pct: the BW percentage for the corresponding TC496 *497 * Get Tx BW settings for given TC in CEE mode498 **/499static void i40e_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,500 u8 *bw_pct)501{502 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);503 504 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||505 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))506 return;507 508 if (pgid >= I40E_MAX_TRAFFIC_CLASS)509 return;510 511 *bw_pct = pf->hw.local_dcbx_config.etscfg.tcbwtable[pgid];512 dev_dbg(&pf->pdev->dev, "Get PG BW config tc=%d bw_pct=%d\n",513 pgid, *bw_pct);514}515 516/**517 * i40e_dcbnl_get_pg_tc_cfg_rx - Get CEE PG Rx config518 * @netdev: the corresponding netdev519 * @prio: the corresponding user priority520 * @prio_type: the traffic priority type521 * @pgid: the PG ID522 * @bw_pct: the BW percentage for the corresponding BWG523 * @up_map: prio mapped to corresponding TC524 *525 * Get Rx PG settings for CEE mode. The UP2TC map is applied in same526 * manner for Tx and Rx (symmetrical) so return the TC information for527 * given priority accordingly.528 **/529static void i40e_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int prio,530 u8 *prio_type, u8 *pgid, u8 *bw_pct,531 u8 *up_map)532{533 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);534 535 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||536 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))537 return;538 539 if (prio >= I40E_MAX_USER_PRIORITY)540 return;541 542 *pgid = pf->hw.local_dcbx_config.etscfg.prioritytable[prio];543}544 545/**546 * i40e_dcbnl_get_pg_bwg_cfg_rx - Get CEE PG BW Rx config547 * @netdev: the corresponding netdev548 * @pgid: the corresponding traffic class549 * @bw_pct: the BW percentage for the corresponding TC550 *551 * Get Rx BW settings for given TC in CEE mode552 * The adapter doesn't support Rx ETS and runs in strict priority553 * mode in Rx path and hence just return 0.554 **/555static void i40e_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int pgid,556 u8 *bw_pct)557{558 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);559 560 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||561 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))562 return;563 *bw_pct = 0;564}565 566/**567 * i40e_dcbnl_set_pfc_cfg - Set CEE PFC configuration568 * @netdev: the corresponding netdev569 * @prio: the corresponding user priority570 * @setting: the PFC setting for given priority571 *572 * Set the PFC enabled/disabled setting for given user priority573 **/574static void i40e_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio,575 u8 setting)576{577 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);578 579 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||580 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))581 return;582 583 if (prio >= I40E_MAX_USER_PRIORITY)584 return;585 586 pf->tmp_cfg.pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;587 if (setting)588 pf->tmp_cfg.pfc.pfcenable |= BIT(prio);589 else590 pf->tmp_cfg.pfc.pfcenable &= ~BIT(prio);591 dev_dbg(&pf->pdev->dev,592 "Set PFC Config up=%d setting=%d pfcenable=0x%x\n",593 prio, setting, pf->tmp_cfg.pfc.pfcenable);594}595 596/**597 * i40e_dcbnl_get_pfc_cfg - Get CEE PFC configuration598 * @netdev: the corresponding netdev599 * @prio: the corresponding user priority600 * @setting: the PFC setting for given priority601 *602 * Get the PFC enabled/disabled setting for given user priority603 **/604static void i40e_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio,605 u8 *setting)606{607 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);608 609 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||610 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))611 return;612 613 if (prio >= I40E_MAX_USER_PRIORITY)614 return;615 616 *setting = (pf->hw.local_dcbx_config.pfc.pfcenable >> prio) & 0x1;617 dev_dbg(&pf->pdev->dev,618 "Get PFC Config up=%d setting=%d pfcenable=0x%x\n",619 prio, *setting, pf->hw.local_dcbx_config.pfc.pfcenable);620}621 622/**623 * i40e_dcbnl_cee_set_all - Commit CEE DCB settings to hardware624 * @netdev: the corresponding netdev625 *626 * Commit the current DCB configuration to hardware627 **/628static u8 i40e_dcbnl_cee_set_all(struct net_device *netdev)629{630 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);631 int err;632 633 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||634 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))635 return I40E_DCBNL_STATUS_ERROR;636 637 dev_dbg(&pf->pdev->dev, "Commit DCB Configuration to the hardware\n");638 err = i40e_hw_dcb_config(pf, &pf->tmp_cfg);639 640 return err ? I40E_DCBNL_STATUS_ERROR : I40E_DCBNL_STATUS_SUCCESS;641}642 643/**644 * i40e_dcbnl_get_cap - Get DCBX capabilities of adapter645 * @netdev: the corresponding netdev646 * @capid: the capability type647 * @cap: the capability value648 *649 * Return the capability value for a given capability type650 **/651static u8 i40e_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)652{653 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);654 655 if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags))656 return I40E_DCBNL_STATUS_ERROR;657 658 switch (capid) {659 case DCB_CAP_ATTR_PG:660 case DCB_CAP_ATTR_PFC:661 *cap = true;662 break;663 case DCB_CAP_ATTR_PG_TCS:664 case DCB_CAP_ATTR_PFC_TCS:665 *cap = 0x80;666 break;667 case DCB_CAP_ATTR_DCBX:668 *cap = pf->dcbx_cap;669 break;670 case DCB_CAP_ATTR_UP2TC:671 case DCB_CAP_ATTR_GSP:672 case DCB_CAP_ATTR_BCN:673 default:674 *cap = false;675 break;676 }677 678 dev_dbg(&pf->pdev->dev, "Get Capability cap=%d capval=0x%x\n",679 capid, *cap);680 return I40E_DCBNL_STATUS_SUCCESS;681}682 683/**684 * i40e_dcbnl_getnumtcs - Get max number of traffic classes supported685 * @netdev: the corresponding netdev686 * @tcid: the TC id687 * @num: total number of TCs supported by the device688 *689 * Return the total number of TCs supported by the adapter690 **/691static int i40e_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)692{693 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);694 695 if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags))696 return -EINVAL;697 698 *num = I40E_MAX_TRAFFIC_CLASS;699 return 0;700}701 702/**703 * i40e_dcbnl_setnumtcs - Set CEE number of traffic classes704 * @netdev: the corresponding netdev705 * @tcid: the TC id706 * @num: total number of TCs707 *708 * Set the total number of TCs (Unsupported)709 **/710static int i40e_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num)711{712 return -EINVAL;713}714 715/**716 * i40e_dcbnl_getpfcstate - Get CEE PFC mode717 * @netdev: the corresponding netdev718 *719 * Get the current PFC enabled state720 **/721static u8 i40e_dcbnl_getpfcstate(struct net_device *netdev)722{723 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);724 725 /* Return enabled if any PFC enabled UP */726 if (pf->hw.local_dcbx_config.pfc.pfcenable)727 return 1;728 else729 return 0;730}731 732/**733 * i40e_dcbnl_setpfcstate - Set CEE PFC mode734 * @netdev: the corresponding netdev735 * @state: required state736 *737 * The PFC state to be set; this is enabled/disabled based on the PFC738 * priority settings and not via this call for i40e driver739 **/740static void i40e_dcbnl_setpfcstate(struct net_device *netdev, u8 state)741{742 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);743 744 dev_dbg(&pf->pdev->dev, "PFC State is modified via PFC config.\n");745}746 747/**748 * i40e_dcbnl_getapp - Get CEE APP749 * @netdev: the corresponding netdev750 * @idtype: the App selector751 * @id: the App ethtype or port number752 *753 * Return the CEE mode app for the given idtype and id754 **/755static int i40e_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id)756{757 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);758 struct dcb_app app = {759 .selector = idtype,760 .protocol = id,761 };762 763 if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||764 (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))765 return -EINVAL;766 767 return dcb_getapp(netdev, &app);768}769 770/**771 * i40e_dcbnl_setdcbx - set required DCBx capability772 * @netdev: the corresponding netdev773 * @mode: new DCB mode managed or CEE+IEEE774 *775 * Set DCBx capability features776 **/777static u8 i40e_dcbnl_setdcbx(struct net_device *netdev, u8 mode)778{779 struct i40e_pf *pf = i40e_netdev_to_pf(netdev);780 781 /* Do not allow to set mode if managed by Firmware */782 if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)783 return I40E_DCBNL_STATUS_ERROR;784 785 /* No support for LLD_MANAGED modes or CEE+IEEE */786 if ((mode & DCB_CAP_DCBX_LLD_MANAGED) ||787 ((mode & DCB_CAP_DCBX_VER_IEEE) && (mode & DCB_CAP_DCBX_VER_CEE)) ||788 !(mode & DCB_CAP_DCBX_HOST))789 return I40E_DCBNL_STATUS_ERROR;790 791 /* Already set to the given mode no change */792 if (mode == pf->dcbx_cap)793 return I40E_DCBNL_STATUS_SUCCESS;794 795 pf->dcbx_cap = mode;796 if (mode & DCB_CAP_DCBX_VER_CEE)797 pf->hw.local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;798 else799 pf->hw.local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;800 801 dev_dbg(&pf->pdev->dev, "mode=%d\n", mode);802 return I40E_DCBNL_STATUS_SUCCESS;803}804 805/**806 * i40e_dcbnl_getdcbx - retrieve current DCBx capability807 * @dev: the corresponding netdev808 *809 * Returns DCBx capability features810 **/811static u8 i40e_dcbnl_getdcbx(struct net_device *dev)812{813 struct i40e_pf *pf = i40e_netdev_to_pf(dev);814 815 return pf->dcbx_cap;816}817 818/**819 * i40e_dcbnl_get_perm_hw_addr - MAC address used by DCBx820 * @dev: the corresponding netdev821 * @perm_addr: buffer to store the MAC address822 *823 * Returns the SAN MAC address used for LLDP exchange824 **/825static void i40e_dcbnl_get_perm_hw_addr(struct net_device *dev,826 u8 *perm_addr)827{828 struct i40e_pf *pf = i40e_netdev_to_pf(dev);829 int i;830 831 memset(perm_addr, 0xff, MAX_ADDR_LEN);832 833 for (i = 0; i < dev->addr_len; i++)834 perm_addr[i] = pf->hw.mac.perm_addr[i];835}836 837static const struct dcbnl_rtnl_ops dcbnl_ops = {838 .ieee_getets = i40e_dcbnl_ieee_getets,839 .ieee_getpfc = i40e_dcbnl_ieee_getpfc,840 .getdcbx = i40e_dcbnl_getdcbx,841 .getpermhwaddr = i40e_dcbnl_get_perm_hw_addr,842 .ieee_setets = i40e_dcbnl_ieee_setets,843 .ieee_setpfc = i40e_dcbnl_ieee_setpfc,844 .ieee_setapp = i40e_dcbnl_ieee_setapp,845 .ieee_delapp = i40e_dcbnl_ieee_delapp,846 .getstate = i40e_dcbnl_getstate,847 .setstate = i40e_dcbnl_setstate,848 .setpgtccfgtx = i40e_dcbnl_set_pg_tc_cfg_tx,849 .setpgbwgcfgtx = i40e_dcbnl_set_pg_bwg_cfg_tx,850 .setpgtccfgrx = i40e_dcbnl_set_pg_tc_cfg_rx,851 .setpgbwgcfgrx = i40e_dcbnl_set_pg_bwg_cfg_rx,852 .getpgtccfgtx = i40e_dcbnl_get_pg_tc_cfg_tx,853 .getpgbwgcfgtx = i40e_dcbnl_get_pg_bwg_cfg_tx,854 .getpgtccfgrx = i40e_dcbnl_get_pg_tc_cfg_rx,855 .getpgbwgcfgrx = i40e_dcbnl_get_pg_bwg_cfg_rx,856 .setpfccfg = i40e_dcbnl_set_pfc_cfg,857 .getpfccfg = i40e_dcbnl_get_pfc_cfg,858 .setall = i40e_dcbnl_cee_set_all,859 .getcap = i40e_dcbnl_get_cap,860 .getnumtcs = i40e_dcbnl_getnumtcs,861 .setnumtcs = i40e_dcbnl_setnumtcs,862 .getpfcstate = i40e_dcbnl_getpfcstate,863 .setpfcstate = i40e_dcbnl_setpfcstate,864 .getapp = i40e_dcbnl_getapp,865 .setdcbx = i40e_dcbnl_setdcbx,866};867 868/**869 * i40e_dcbnl_set_all - set all the apps and ieee data from DCBx config870 * @vsi: the corresponding vsi871 *872 * Set up all the IEEE APPs in the DCBNL App Table and generate event for873 * other settings874 **/875void i40e_dcbnl_set_all(struct i40e_vsi *vsi)876{877 struct net_device *dev = vsi->netdev;878 struct i40e_pf *pf = i40e_netdev_to_pf(dev);879 struct i40e_dcbx_config *dcbxcfg;880 struct i40e_hw *hw = &pf->hw;881 struct dcb_app sapp;882 u8 prio, tc_map;883 int i;884 885 /* SW DCB taken care by DCBNL set calls */886 if (pf->dcbx_cap & DCB_CAP_DCBX_HOST)887 return;888 889 /* DCB not enabled */890 if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags))891 return;892 893 /* MFP mode but not an iSCSI PF so return */894 if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && !(hw->func_caps.iscsi))895 return;896 897 dcbxcfg = &hw->local_dcbx_config;898 899 /* Set up all the App TLVs if DCBx is negotiated */900 for (i = 0; i < dcbxcfg->numapps; i++) {901 prio = dcbxcfg->app[i].priority;902 tc_map = BIT(dcbxcfg->etscfg.prioritytable[prio]);903 904 /* Add APP only if the TC is enabled for this VSI */905 if (tc_map & vsi->tc_config.enabled_tc) {906 sapp.selector = dcbxcfg->app[i].selector;907 sapp.protocol = dcbxcfg->app[i].protocolid;908 sapp.priority = prio;909 dcb_ieee_setapp(dev, &sapp);910 }911 }912 913 /* Notify user-space of the changes */914 dcbnl_ieee_notify(dev, RTM_SETDCB, DCB_CMD_IEEE_SET, 0, 0);915}916 917/**918 * i40e_dcbnl_vsi_del_app - Delete APP for given VSI919 * @vsi: the corresponding vsi920 * @app: APP to delete921 *922 * Delete given APP from the DCBNL APP table for given923 * VSI924 **/925static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi,926 struct i40e_dcb_app_priority_table *app)927{928 struct net_device *dev = vsi->netdev;929 struct dcb_app sapp;930 931 if (!dev)932 return -EINVAL;933 934 sapp.selector = app->selector;935 sapp.protocol = app->protocolid;936 sapp.priority = app->priority;937 return dcb_ieee_delapp(dev, &sapp);938}939 940/**941 * i40e_dcbnl_del_app - Delete APP on all VSIs942 * @pf: the corresponding PF943 * @app: APP to delete944 *945 * Delete given APP from all the VSIs for given PF946 **/947static void i40e_dcbnl_del_app(struct i40e_pf *pf,948 struct i40e_dcb_app_priority_table *app)949{950 struct i40e_vsi *vsi;951 int v, err;952 953 i40e_pf_for_each_vsi(pf, v, vsi)954 if (vsi->netdev) {955 err = i40e_dcbnl_vsi_del_app(vsi, app);956 dev_dbg(&pf->pdev->dev, "Deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n",957 vsi->seid, err, app->selector,958 app->protocolid, app->priority);959 }960}961 962/**963 * i40e_dcbnl_find_app - Search APP in given DCB config964 * @cfg: DCBX configuration data965 * @app: APP to search for966 *967 * Find given APP in the DCB configuration968 **/969static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg,970 struct i40e_dcb_app_priority_table *app)971{972 int i;973 974 for (i = 0; i < cfg->numapps; i++) {975 if (app->selector == cfg->app[i].selector &&976 app->protocolid == cfg->app[i].protocolid &&977 app->priority == cfg->app[i].priority)978 return true;979 }980 981 return false;982}983 984/**985 * i40e_dcbnl_flush_apps - Delete all removed APPs986 * @pf: the corresponding PF987 * @old_cfg: old DCBX configuration data988 * @new_cfg: new DCBX configuration data989 *990 * Find and delete all APPs that are not present in the passed991 * DCB configuration992 **/993void i40e_dcbnl_flush_apps(struct i40e_pf *pf,994 struct i40e_dcbx_config *old_cfg,995 struct i40e_dcbx_config *new_cfg)996{997 struct i40e_dcb_app_priority_table app;998 int i;999 1000 /* MFP mode but not an iSCSI PF so return */1001 if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && !(pf->hw.func_caps.iscsi))1002 return;1003 1004 for (i = 0; i < old_cfg->numapps; i++) {1005 app = old_cfg->app[i];1006 /* The APP is not available anymore delete it */1007 if (!i40e_dcbnl_find_app(new_cfg, &app))1008 i40e_dcbnl_del_app(pf, &app);1009 }1010}1011 1012/**1013 * i40e_dcbnl_setup - DCBNL setup1014 * @vsi: the corresponding vsi1015 *1016 * Set up DCBNL ops and initial APP TLVs1017 **/1018void i40e_dcbnl_setup(struct i40e_vsi *vsi)1019{1020 struct net_device *dev = vsi->netdev;1021 struct i40e_pf *pf = i40e_netdev_to_pf(dev);1022 1023 /* Not DCB capable */1024 if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags))1025 return;1026 1027 dev->dcbnl_ops = &dcbnl_ops;1028 1029 /* Set initial IEEE DCB settings */1030 i40e_dcbnl_set_all(vsi);1031}1032#endif /* CONFIG_I40E_DCB */1033