linux/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright(c) 2013 - 2018 Intel Corporation. */
   3
   4#ifdef CONFIG_I40E_DCB
   5#include "i40e.h"
   6#include <net/dcbnl.h>
   7
   8/**
   9 * i40e_get_pfc_delay - retrieve PFC Link Delay
  10 * @hw: pointer to hardware struct
  11 * @delay: holds the PFC Link delay value
  12 *
  13 * Returns PFC Link Delay from the PRTDCB_GENC.PFCLDA
  14 **/
  15static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay)
  16{
  17        u32 val;
  18
  19        val = rd32(hw, I40E_PRTDCB_GENC);
  20        *delay = (u16)((val & I40E_PRTDCB_GENC_PFCLDA_MASK) >>
  21                       I40E_PRTDCB_GENC_PFCLDA_SHIFT);
  22}
  23
  24/**
  25 * i40e_dcbnl_ieee_getets - retrieve local IEEE ETS configuration
  26 * @dev: the corresponding netdev
  27 * @ets: structure to hold the ETS information
  28 *
  29 * Returns local IEEE ETS configuration
  30 **/
  31static int i40e_dcbnl_ieee_getets(struct net_device *dev,
  32                                  struct ieee_ets *ets)
  33{
  34        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
  35        struct i40e_dcbx_config *dcbxcfg;
  36        struct i40e_hw *hw = &pf->hw;
  37
  38        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
  39                return -EINVAL;
  40
  41        dcbxcfg = &hw->local_dcbx_config;
  42        ets->willing = dcbxcfg->etscfg.willing;
  43        ets->ets_cap = dcbxcfg->etscfg.maxtcs;
  44        ets->cbs = dcbxcfg->etscfg.cbs;
  45        memcpy(ets->tc_tx_bw, dcbxcfg->etscfg.tcbwtable,
  46                sizeof(ets->tc_tx_bw));
  47        memcpy(ets->tc_rx_bw, dcbxcfg->etscfg.tcbwtable,
  48                sizeof(ets->tc_rx_bw));
  49        memcpy(ets->tc_tsa, dcbxcfg->etscfg.tsatable,
  50                sizeof(ets->tc_tsa));
  51        memcpy(ets->prio_tc, dcbxcfg->etscfg.prioritytable,
  52                sizeof(ets->prio_tc));
  53        memcpy(ets->tc_reco_bw, dcbxcfg->etsrec.tcbwtable,
  54                sizeof(ets->tc_reco_bw));
  55        memcpy(ets->tc_reco_tsa, dcbxcfg->etsrec.tsatable,
  56                sizeof(ets->tc_reco_tsa));
  57        memcpy(ets->reco_prio_tc, dcbxcfg->etscfg.prioritytable,
  58                sizeof(ets->reco_prio_tc));
  59
  60        return 0;
  61}
  62
  63/**
  64 * i40e_dcbnl_ieee_getpfc - retrieve local IEEE PFC configuration
  65 * @dev: the corresponding netdev
  66 * @pfc: structure to hold the PFC information
  67 *
  68 * Returns local IEEE PFC configuration
  69 **/
  70static int i40e_dcbnl_ieee_getpfc(struct net_device *dev,
  71                                  struct ieee_pfc *pfc)
  72{
  73        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
  74        struct i40e_dcbx_config *dcbxcfg;
  75        struct i40e_hw *hw = &pf->hw;
  76        int i;
  77
  78        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
  79                return -EINVAL;
  80
  81        dcbxcfg = &hw->local_dcbx_config;
  82        pfc->pfc_cap = dcbxcfg->pfc.pfccap;
  83        pfc->pfc_en = dcbxcfg->pfc.pfcenable;
  84        pfc->mbc = dcbxcfg->pfc.mbc;
  85        i40e_get_pfc_delay(hw, &pfc->delay);
  86
  87        /* Get Requests/Indicatiosn */
  88        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
  89                pfc->requests[i] = pf->stats.priority_xoff_tx[i];
  90                pfc->indications[i] = pf->stats.priority_xoff_rx[i];
  91        }
  92
  93        return 0;
  94}
  95
  96/**
  97 * i40e_dcbnl_getdcbx - retrieve current DCBx capability
  98 * @dev: the corresponding netdev
  99 *
 100 * Returns DCBx capability features
 101 **/
 102static u8 i40e_dcbnl_getdcbx(struct net_device *dev)
 103{
 104        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
 105
 106        return pf->dcbx_cap;
 107}
 108
 109/**
 110 * i40e_dcbnl_get_perm_hw_addr - MAC address used by DCBx
 111 * @dev: the corresponding netdev
 112 * @perm_addr: buffer to store the MAC address
 113 *
 114 * Returns the SAN MAC address used for LLDP exchange
 115 **/
 116static void i40e_dcbnl_get_perm_hw_addr(struct net_device *dev,
 117                                        u8 *perm_addr)
 118{
 119        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
 120        int i, j;
 121
 122        memset(perm_addr, 0xff, MAX_ADDR_LEN);
 123
 124        for (i = 0; i < dev->addr_len; i++)
 125                perm_addr[i] = pf->hw.mac.perm_addr[i];
 126
 127        for (j = 0; j < dev->addr_len; j++, i++)
 128                perm_addr[i] = pf->hw.mac.san_addr[j];
 129}
 130
 131static const struct dcbnl_rtnl_ops dcbnl_ops = {
 132        .ieee_getets    = i40e_dcbnl_ieee_getets,
 133        .ieee_getpfc    = i40e_dcbnl_ieee_getpfc,
 134        .getdcbx        = i40e_dcbnl_getdcbx,
 135        .getpermhwaddr  = i40e_dcbnl_get_perm_hw_addr,
 136};
 137
 138/**
 139 * i40e_dcbnl_set_all - set all the apps and ieee data from DCBx config
 140 * @vsi: the corresponding vsi
 141 *
 142 * Set up all the IEEE APPs in the DCBNL App Table and generate event for
 143 * other settings
 144 **/
 145void i40e_dcbnl_set_all(struct i40e_vsi *vsi)
 146{
 147        struct net_device *dev = vsi->netdev;
 148        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
 149        struct i40e_dcbx_config *dcbxcfg;
 150        struct i40e_hw *hw = &pf->hw;
 151        struct dcb_app sapp;
 152        u8 prio, tc_map;
 153        int i;
 154
 155        /* DCB not enabled */
 156        if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
 157                return;
 158
 159        /* MFP mode but not an iSCSI PF so return */
 160        if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi))
 161                return;
 162
 163        dcbxcfg = &hw->local_dcbx_config;
 164
 165        /* Set up all the App TLVs if DCBx is negotiated */
 166        for (i = 0; i < dcbxcfg->numapps; i++) {
 167                prio = dcbxcfg->app[i].priority;
 168                tc_map = BIT(dcbxcfg->etscfg.prioritytable[prio]);
 169
 170                /* Add APP only if the TC is enabled for this VSI */
 171                if (tc_map & vsi->tc_config.enabled_tc) {
 172                        sapp.selector = dcbxcfg->app[i].selector;
 173                        sapp.protocol = dcbxcfg->app[i].protocolid;
 174                        sapp.priority = prio;
 175                        dcb_ieee_setapp(dev, &sapp);
 176                }
 177        }
 178
 179        /* Notify user-space of the changes */
 180        dcbnl_ieee_notify(dev, RTM_SETDCB, DCB_CMD_IEEE_SET, 0, 0);
 181}
 182
 183/**
 184 * i40e_dcbnl_vsi_del_app - Delete APP for given VSI
 185 * @vsi: the corresponding vsi
 186 * @app: APP to delete
 187 *
 188 * Delete given APP from the DCBNL APP table for given
 189 * VSI
 190 **/
 191static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi,
 192                                  struct i40e_dcb_app_priority_table *app)
 193{
 194        struct net_device *dev = vsi->netdev;
 195        struct dcb_app sapp;
 196
 197        if (!dev)
 198                return -EINVAL;
 199
 200        sapp.selector = app->selector;
 201        sapp.protocol = app->protocolid;
 202        sapp.priority = app->priority;
 203        return dcb_ieee_delapp(dev, &sapp);
 204}
 205
 206/**
 207 * i40e_dcbnl_del_app - Delete APP on all VSIs
 208 * @pf: the corresponding PF
 209 * @app: APP to delete
 210 *
 211 * Delete given APP from all the VSIs for given PF
 212 **/
 213static void i40e_dcbnl_del_app(struct i40e_pf *pf,
 214                               struct i40e_dcb_app_priority_table *app)
 215{
 216        int v, err;
 217
 218        for (v = 0; v < pf->num_alloc_vsi; v++) {
 219                if (pf->vsi[v] && pf->vsi[v]->netdev) {
 220                        err = i40e_dcbnl_vsi_del_app(pf->vsi[v], app);
 221                        dev_dbg(&pf->pdev->dev, "Deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n",
 222                                pf->vsi[v]->seid, err, app->selector,
 223                                app->protocolid, app->priority);
 224                }
 225        }
 226}
 227
 228/**
 229 * i40e_dcbnl_find_app - Search APP in given DCB config
 230 * @cfg: DCBX configuration data
 231 * @app: APP to search for
 232 *
 233 * Find given APP in the DCB configuration
 234 **/
 235static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg,
 236                                struct i40e_dcb_app_priority_table *app)
 237{
 238        int i;
 239
 240        for (i = 0; i < cfg->numapps; i++) {
 241                if (app->selector == cfg->app[i].selector &&
 242                    app->protocolid == cfg->app[i].protocolid &&
 243                    app->priority == cfg->app[i].priority)
 244                        return true;
 245        }
 246
 247        return false;
 248}
 249
 250/**
 251 * i40e_dcbnl_flush_apps - Delete all removed APPs
 252 * @pf: the corresponding PF
 253 * @old_cfg: old DCBX configuration data
 254 * @new_cfg: new DCBX configuration data
 255 *
 256 * Find and delete all APPs that are not present in the passed
 257 * DCB configuration
 258 **/
 259void i40e_dcbnl_flush_apps(struct i40e_pf *pf,
 260                           struct i40e_dcbx_config *old_cfg,
 261                           struct i40e_dcbx_config *new_cfg)
 262{
 263        struct i40e_dcb_app_priority_table app;
 264        int i;
 265
 266        /* MFP mode but not an iSCSI PF so return */
 267        if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi))
 268                return;
 269
 270        for (i = 0; i < old_cfg->numapps; i++) {
 271                app = old_cfg->app[i];
 272                /* The APP is not available anymore delete it */
 273                if (!i40e_dcbnl_find_app(new_cfg, &app))
 274                        i40e_dcbnl_del_app(pf, &app);
 275        }
 276}
 277
 278/**
 279 * i40e_dcbnl_setup - DCBNL setup
 280 * @vsi: the corresponding vsi
 281 *
 282 * Set up DCBNL ops and initial APP TLVs
 283 **/
 284void i40e_dcbnl_setup(struct i40e_vsi *vsi)
 285{
 286        struct net_device *dev = vsi->netdev;
 287        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
 288
 289        /* Not DCB capable */
 290        if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
 291                return;
 292
 293        dev->dcbnl_ops = &dcbnl_ops;
 294
 295        /* Set initial IEEE DCB settings */
 296        i40e_dcbnl_set_all(vsi);
 297}
 298#endif /* CONFIG_I40E_DCB */
 299