// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2021 Intel Corporation. */
#ifdef CONFIG_I40E_DCB
#include <net/dcbnl.h>
#include "i40e.h"
#define I40E_DCBNL_STATUS_SUCCESS 0
#define I40E_DCBNL_STATUS_ERROR 1
static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg,
struct i40e_dcb_app_priority_table *app);
/**
* i40e_get_pfc_delay - retrieve PFC Link Delay
* @hw: pointer to hardware struct
* @delay: holds the PFC Link delay value
*
* Returns PFC Link Delay from the PRTDCB_GENC.PFCLDA
**/
static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay)
{
u32 val;
val = rd32(hw, I40E_PRTDCB_GENC);
*delay = FIELD_GET(I40E_PRTDCB_GENC_PFCLDA_MASK, val);
}
/**
* i40e_dcbnl_ieee_getets - retrieve local IEEE ETS configuration
* @dev: the corresponding netdev
* @ets: structure to hold the ETS information
*
* Returns local IEEE ETS configuration
**/
static int i40e_dcbnl_ieee_getets(struct net_device *dev,
struct ieee_ets *ets)
{
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
struct i40e_dcbx_config *dcbxcfg;
if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
dcbxcfg = &pf->hw.local_dcbx_config;
ets->willing = dcbxcfg->etscfg.willing;
ets->ets_cap = I40E_MAX_TRAFFIC_CLASS;
ets->cbs = dcbxcfg->etscfg.cbs;
memcpy(ets->tc_tx_bw, dcbxcfg->etscfg.tcbwtable,
sizeof(ets->tc_tx_bw));
memcpy(ets->tc_rx_bw, dcbxcfg->etscfg.tcbwtable,
sizeof(ets->tc_rx_bw));
memcpy(ets->tc_tsa, dcbxcfg->etscfg.tsatable,
sizeof(ets->tc_tsa));
memcpy(ets->prio_tc, dcbxcfg->etscfg.prioritytable,
sizeof(ets->prio_tc));
memcpy(ets->tc_reco_bw, dcbxcfg->etsrec.tcbwtable,
sizeof(ets->tc_reco_bw));
memcpy(ets->tc_reco_tsa, dcbxcfg->etsrec.tsatable,
sizeof(ets->tc_reco_tsa));
memcpy(ets->reco_prio_tc, dcbxcfg->etscfg.prioritytable,
sizeof(ets->reco_prio_tc));
return 0;
}
/**
* i40e_dcbnl_ieee_getpfc - retrieve local IEEE PFC configuration
* @dev: the corresponding netdev
* @pfc: structure to hold the PFC information
*
* Returns local IEEE PFC configuration
**/
static int i40e_dcbnl_ieee_getpfc(struct net_device *dev,
struct ieee_pfc *pfc)
{
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
struct i40e_dcbx_config *dcbxcfg;
struct i40e_hw *hw = &pf->hw;
int i;
if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
dcbxcfg = &hw->local_dcbx_config;
pfc->pfc_cap = dcbxcfg->pfc.pfccap;
pfc->pfc_en = dcbxcfg->pfc.pfcenable;
pfc->mbc = dcbxcfg->pfc.mbc;
i40e_get_pfc_delay(hw, &pfc->delay);
/* Get Requests/Indications */
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
pfc->requests[i] = pf->stats.priority_xoff_tx[i];
pfc->indications[i] = pf->stats.priority_xoff_rx[i];
}
return 0;
}
/**
* i40e_dcbnl_ieee_setets - set IEEE ETS configuration
* @netdev: the corresponding netdev
* @ets: structure to hold the ETS information
*
* Set IEEE ETS configuration
**/
static int i40e_dcbnl_ieee_setets(struct net_device *netdev,
struct ieee_ets *ets)
{
struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
struct i40e_dcbx_config *old_cfg;
int i, ret;
if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
(pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
return -EINVAL;
old_cfg = &pf->hw.local_dcbx_config;
/* Copy current config into temp */
pf->tmp_cfg = *old_cfg;
/* Update the ETS configuration for temp */
pf->tmp_cfg.etscfg.willing = ets->willing;
pf->tmp_cfg.etscfg.maxtcs = I40E_MAX_TRAFFIC_CLASS;
pf->tmp_cfg.etscfg.cbs = ets->cbs;
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
pf->tmp_cfg.etscfg.tcbwtable[i] = ets->tc_tx_bw[i];
pf->tmp_cfg.etscfg.tsatable[i] = ets->tc_tsa[i];
pf->tmp_cfg.etscfg.prioritytable[i] = ets->prio_tc[i];
pf->tmp_cfg.etsrec.tcbwtable[i] = ets->tc_reco_bw[i];
pf->tmp_cfg.etsrec.tsatable[i] = ets->tc_reco_tsa[i];
pf->tmp_cfg.etsrec.prioritytable[i] = ets->reco_prio_tc[i];
}
/* Commit changes to HW */
ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);
if (ret) {
dev_info(&pf->pdev->dev,
"Failed setting DCB ETS configuration err %pe aq_err %s\n",
ERR_PTR(ret),
i40e_aq_str(&pf->hw, pf