cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

i40e_dcb_nl.c (28383B)


      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 */