// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019, Intel Corporation. */
#include "ice.h"
#include "ice_dcb.h"
#include "ice_dcb_lib.h"
#include "ice_dcb_nl.h"
#include <net/dcbnl.h>
/**
* ice_dcbnl_devreset - perform enough of a ifdown/ifup to sync DCBNL info
* @netdev: device associated with interface that needs reset
*/
static void ice_dcbnl_devreset(struct net_device *netdev)
{
struct ice_pf *pf = ice_netdev_to_pf(netdev);
while (ice_is_reset_in_progress(pf->state))
usleep_range(1000, 2000);
dev_close(netdev);
netdev_state_change(netdev);
dev_open(netdev, NULL);
netdev_state_change(netdev);
}
/**
* ice_dcbnl_getets - retrieve local ETS configuration
* @netdev: the relevant netdev
* @ets: struct to hold ETS configuration
*/
static int ice_dcbnl_getets(struct net_device *netdev, struct ieee_ets *ets)
{
struct ice_dcbx_cfg *dcbxcfg;
struct ice_pf *pf;
pf = ice_netdev_to_pf(netdev);
dcbxcfg = &pf->hw.port_info->qos_cfg.local_dcbx_cfg;
ets->willing = dcbxcfg->etscfg.willing;
ets->ets_cap = dcbxcfg->etscfg.maxtcs;
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.prio_table, 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.prio_table,
sizeof(ets->reco_prio_tc));
return 0;
}
/**
* ice_dcbnl_setets - set IEEE ETS configuration
* @netdev: pointer to relevant netdev
* @ets: struct to hold ETS configuration
*/
static int ice_dcbnl_setets(struct net_device *netdev, struct ieee_ets *ets)
{
struct ice_pf *pf = ice_netdev_to_pf(netdev);
struct ice_dcbx_cfg *new_cfg;
int bwcfg = 0, bwrec = 0;
int err, i;
if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) ||
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
if (pf->lag && pf->lag->bonded) {
netdev_err(netdev, "DCB changes not allowed when in a bond\n");
return -EINVAL;
}
new_cfg = &pf->hw.port_info->qos_cfg.desired_dcbx_cfg;
mutex_lock(&pf->tc_mutex);
new_cfg->etscfg.willing = ets->willing;
new_cfg->etscfg.cbs = ets->cbs;
ice_for_each_traffic_class(i) {
new_cfg->etscfg.tcbwtable[i] = ets->tc_tx_bw[i];
bwcfg += ets->tc_tx_bw[i];
new_cfg->etscfg.tsatable[i] = ets->tc_tsa[i];
if (new_cfg->pfc_mode == ICE_QOS_MODE_VLAN) {
/* in DSCP mode up->tc mapping cannot change */
new_cfg->etscfg.prio_table[i] = ets->prio_tc[i];
new_cfg->etsrec.prio_table[i] = ets->reco_prio_tc[i];
}
new_cfg->etsrec.tcbwtable[i] = ets->tc_reco_bw[i];
bwrec += ets->tc_reco_bw[i];
new_cfg->etsrec.tsatable[i] = ets->tc_reco_tsa[i];
}
if (ice_dcb_bwchk(pf, new_cfg)) {
err = -EINVAL;
goto ets_out;
}
new_cfg->etscfg.maxtcs = pf->hw.func_caps.common_cap.maxtc;
if (!bwcfg)
new_cfg->etscfg.tcbwtable[0