// SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
+/* Copyright(c) 2013 - 2021 Intel Corporation. */
 
 #ifdef CONFIG_I40E_DCB
 #include "i40e.h"
 #include <net/dcbnl.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
 {
        struct i40e_pf *pf = i40e_netdev_to_pf(dev);
        struct i40e_dcbx_config *dcbxcfg;
-       struct i40e_hw *hw = &pf->hw;
 
        if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
                return -EINVAL;
 
-       dcbxcfg = &hw->local_dcbx_config;
+       dcbxcfg = &pf->hw.local_dcbx_config;
        ets->willing = dcbxcfg->etscfg.willing;
-       ets->ets_cap = dcbxcfg->etscfg.maxtcs;
+       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));
        pfc->mbc = dcbxcfg->pfc.mbc;
        i40e_get_pfc_delay(hw, &pfc->delay);
 
-       /* Get Requests/Indicatiosn */
+       /* 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 %s aq_err %s\n",
+                        i40e_stat_str(&pf->hw, ret),
+                        i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_dcbnl_ieee_setpfc - set local IEEE PFC configuration
+ * @netdev: the corresponding netdev
+ * @pfc: structure to hold the PFC information
+ *
+ * Sets local IEEE PFC configuration
+ **/
+static int i40e_dcbnl_ieee_setpfc(struct net_device *netdev,
+                                 struct ieee_pfc *pfc)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+       struct i40e_dcbx_config *old_cfg;
+       int 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;
+       if (pfc->pfc_cap)
+               pf->tmp_cfg.pfc.pfccap = pfc->pfc_cap;
+       else
+               pf->tmp_cfg.pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
+       pf->tmp_cfg.pfc.pfcenable = pfc->pfc_en;
+
+       ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "Failed setting DCB PFC configuration err %s aq_err %s\n",
+                        i40e_stat_str(&pf->hw, ret),
+                        i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_dcbnl_ieee_setapp - set local IEEE App configuration
+ * @netdev: the corresponding netdev
+ * @app: structure to hold the Application information
+ *
+ * Sets local IEEE App configuration
+ **/
+static int i40e_dcbnl_ieee_setapp(struct net_device *netdev,
+                                 struct dcb_app *app)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+       struct i40e_dcb_app_priority_table new_app;
+       struct i40e_dcbx_config *old_cfg;
+       int 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;
+       if (old_cfg->numapps == I40E_DCBX_MAX_APPS)
+               return -EINVAL;
+
+       ret = dcb_ieee_setapp(netdev, app);
+       if (ret)
+               return ret;
+
+       new_app.selector = app->selector;
+       new_app.protocolid = app->protocol;
+       new_app.priority = app->priority;
+       /* Already internally available */
+       if (i40e_dcbnl_find_app(old_cfg, &new_app))
+               return 0;
+
+       /* Copy current config into temp */
+       pf->tmp_cfg = *old_cfg;
+       /* Add the app */
+       pf->tmp_cfg.app[pf->tmp_cfg.numapps++] = new_app;
+
+       ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "Failed setting DCB configuration err %s aq_err %s\n",
+                        i40e_stat_str(&pf->hw, ret),
+                        i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_dcbnl_ieee_delapp - delete local IEEE App configuration
+ * @netdev: the corresponding netdev
+ * @app: structure to hold the Application information
+ *
+ * Deletes local IEEE App configuration other than the first application
+ * required by firmware
+ **/
+static int i40e_dcbnl_ieee_delapp(struct net_device *netdev,
+                                 struct dcb_app *app)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+       struct i40e_dcbx_config *old_cfg;
+       int i, j, ret;
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return -EINVAL;
+
+       ret = dcb_ieee_delapp(netdev, app);
+       if (ret)
+               return ret;
+
+       old_cfg = &pf->hw.local_dcbx_config;
+       /* Need one app for FW so keep it */
+       if (old_cfg->numapps == 1)
+               return 0;
+
+       /* Copy current config into temp */
+       pf->tmp_cfg = *old_cfg;
+
+       /* Find and reset the app */
+       for (i = 1; i < pf->tmp_cfg.numapps; i++) {
+               if (app->selector == pf->tmp_cfg.app[i].selector &&
+                   app->protocol == pf->tmp_cfg.app[i].protocolid &&
+                   app->priority == pf->tmp_cfg.app[i].priority) {
+                       /* Reset the app data */
+                       pf->tmp_cfg.app[i].selector = 0;
+                       pf->tmp_cfg.app[i].protocolid = 0;
+                       pf->tmp_cfg.app[i].priority = 0;
+                       break;
+               }
+       }
+
+       /* If the specific DCB app not found */
+       if (i == pf->tmp_cfg.numapps)
+               return -EINVAL;
+
+       pf->tmp_cfg.numapps--;
+       /* Overwrite the tmp_cfg app */
+       for (j = i; j < pf->tmp_cfg.numapps; j++)
+               pf->tmp_cfg.app[j] = old_cfg->app[j + 1];
+
+       ret = i40e_hw_dcb_config(pf, &pf->tmp_cfg);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "Failed setting DCB configuration err %s aq_err %s\n",
+                        i40e_stat_str(&pf->hw, ret),
+                        i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_dcbnl_getstate - Get DCB enabled state
+ * @netdev: the corresponding netdev
+ *
+ * Get the current DCB enabled state
+ **/
+static u8 i40e_dcbnl_getstate(struct net_device *netdev)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       dev_dbg(&pf->pdev->dev, "DCB state=%d\n",
+               !!(pf->flags & I40E_FLAG_DCB_ENABLED));
+       return !!(pf->flags & I40E_FLAG_DCB_ENABLED);
+}
+
+/**
+ * i40e_dcbnl_setstate - Set DCB state
+ * @netdev: the corresponding netdev
+ * @state: enable or disable
+ *
+ * Set the DCB state
+ **/
+static u8 i40e_dcbnl_setstate(struct net_device *netdev, u8 state)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+       int ret = I40E_DCBNL_STATUS_SUCCESS;
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return ret;
+
+       dev_dbg(&pf->pdev->dev, "new state=%d current state=%d\n",
+               state, (pf->flags & I40E_FLAG_DCB_ENABLED) ? 1 : 0);
+       /* Nothing to do */
+       if (!state == !(pf->flags & I40E_FLAG_DCB_ENABLED))
+               return ret;
+
+       if (i40e_is_sw_dcb(pf)) {
+               if (state) {
+                       pf->flags |= I40E_FLAG_DCB_ENABLED;
+                       memcpy(&pf->hw.desired_dcbx_config,
+                              &pf->hw.local_dcbx_config,
+                              sizeof(struct i40e_dcbx_config));
+               } else {
+                       pf->flags &= ~I40E_FLAG_DCB_ENABLED;
+               }
+       } else {
+               /* Cannot directly manipulate FW LLDP Agent */
+               ret = I40E_DCBNL_STATUS_ERROR;
+       }
+       return ret;
+}
+
+/**
+ * i40e_dcbnl_set_pg_tc_cfg_tx - Set CEE PG Tx config
+ * @netdev: the corresponding netdev
+ * @tc: the corresponding traffic class
+ * @prio_type: the traffic priority type
+ * @bwg_id: the BW group id the traffic class belongs to
+ * @bw_pct: the BW percentage for the corresponding BWG
+ * @up_map: prio mapped to corresponding tc
+ *
+ * Set Tx PG settings for CEE mode
+ **/
+static void i40e_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc,
+                                       u8 prio_type, u8 bwg_id, u8 bw_pct,
+                                       u8 up_map)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+       int i;
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return;
+
+       /* LLTC not supported yet */
+       if (tc >= I40E_MAX_TRAFFIC_CLASS)
+               return;
+
+       /* prio_type, bwg_id and bw_pct per UP are not supported */
+
+       /* Use only up_map to map tc */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               if (up_map & BIT(i))
+                       pf->tmp_cfg.etscfg.prioritytable[i] = tc;
+       }
+       pf->tmp_cfg.etscfg.tsatable[tc] = I40E_IEEE_TSA_ETS;
+       dev_dbg(&pf->pdev->dev,
+               "Set PG config tc=%d bwg_id=%d prio_type=%d bw_pct=%d up_map=%d\n",
+               tc, bwg_id, prio_type, bw_pct, up_map);
+}
+
+/**
+ * i40e_dcbnl_set_pg_tc_cfg_tx - Set CEE PG Tx BW config
+ * @netdev: the corresponding netdev
+ * @pgid: the corresponding traffic class
+ * @bw_pct: the BW percentage for the specified traffic class
+ *
+ * Set Tx BW settings for CEE mode
+ **/
+static void i40e_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,
+                                        u8 bw_pct)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return;
+
+       /* LLTC not supported yet */
+       if (pgid >= I40E_MAX_TRAFFIC_CLASS)
+               return;
+
+       pf->tmp_cfg.etscfg.tcbwtable[pgid] = bw_pct;
+       dev_dbg(&pf->pdev->dev, "Set PG BW config tc=%d bw_pct=%d\n",
+               pgid, bw_pct);
+}
+
+/**
+ * i40e_dcbnl_set_pg_tc_cfg_rx - Set CEE PG Rx config
+ * @netdev: the corresponding netdev
+ * @prio: the corresponding traffic class
+ * @prio_type: the traffic priority type
+ * @pgid: the BW group id the traffic class belongs to
+ * @bw_pct: the BW percentage for the corresponding BWG
+ * @up_map: prio mapped to corresponding tc
+ *
+ * Set Rx BW settings for CEE mode. The hardware does not support this
+ * so we won't allow setting of this parameter.
+ **/
+static void i40e_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev,
+                                       int __always_unused prio,
+                                       u8 __always_unused prio_type,
+                                       u8 __always_unused pgid,
+                                       u8 __always_unused bw_pct,
+                                       u8 __always_unused up_map)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       dev_dbg(&pf->pdev->dev, "Rx TC PG Config Not Supported.\n");
+}
+
+/**
+ * i40e_dcbnl_set_pg_bwg_cfg_rx - Set CEE PG Rx config
+ * @netdev: the corresponding netdev
+ * @pgid: the corresponding traffic class
+ * @bw_pct: the BW percentage for the specified traffic class
+ *
+ * Set Rx BW settings for CEE mode. The hardware does not support this
+ * so we won't allow setting of this parameter.
+ **/
+static void i40e_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int pgid,
+                                        u8 bw_pct)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       dev_dbg(&pf->pdev->dev, "Rx BWG PG Config Not Supported.\n");
+}
+
+/**
+ * i40e_dcbnl_get_pg_tc_cfg_tx - Get CEE PG Tx config
+ * @netdev: the corresponding netdev
+ * @prio: the corresponding user priority
+ * @prio_type: traffic priority type
+ * @pgid: the BW group ID the traffic class belongs to
+ * @bw_pct: BW percentage for the corresponding BWG
+ * @up_map: prio mapped to corresponding TC
+ *
+ * Get Tx PG settings for CEE mode
+ **/
+static void i40e_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int prio,
+                                       u8 __always_unused *prio_type,
+                                       u8 *pgid,
+                                       u8 __always_unused *bw_pct,
+                                       u8 __always_unused *up_map)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return;
+
+       if (prio >= I40E_MAX_USER_PRIORITY)
+               return;
+
+       *pgid = pf->hw.local_dcbx_config.etscfg.prioritytable[prio];
+       dev_dbg(&pf->pdev->dev, "Get PG config prio=%d tc=%d\n",
+               prio, *pgid);
+}
+
+/**
+ * i40e_dcbnl_get_pg_bwg_cfg_tx - Get CEE PG BW config
+ * @netdev: the corresponding netdev
+ * @pgid: the corresponding traffic class
+ * @bw_pct: the BW percentage for the corresponding TC
+ *
+ * Get Tx BW settings for given TC in CEE mode
+ **/
+static void i40e_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,
+                                        u8 *bw_pct)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return;
+
+       if (pgid >= I40E_MAX_TRAFFIC_CLASS)
+               return;
+
+       *bw_pct = pf->hw.local_dcbx_config.etscfg.tcbwtable[pgid];
+       dev_dbg(&pf->pdev->dev, "Get PG BW config tc=%d bw_pct=%d\n",
+               pgid, *bw_pct);
+}
+
+/**
+ * i40e_dcbnl_get_pg_tc_cfg_rx - Get CEE PG Rx config
+ * @netdev: the corresponding netdev
+ * @prio: the corresponding user priority
+ * @prio_type: the traffic priority type
+ * @pgid: the PG ID
+ * @bw_pct: the BW percentage for the corresponding BWG
+ * @up_map: prio mapped to corresponding TC
+ *
+ * Get Rx PG settings for CEE mode. The UP2TC map is applied in same
+ * manner for Tx and Rx (symmetrical) so return the TC information for
+ * given priority accordingly.
+ **/
+static void i40e_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int prio,
+                                       u8 *prio_type, u8 *pgid, u8 *bw_pct,
+                                       u8 *up_map)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return;
+
+       if (prio >= I40E_MAX_USER_PRIORITY)
+               return;
+
+       *pgid = pf->hw.local_dcbx_config.etscfg.prioritytable[prio];
+}
+
+/**
+ * i40e_dcbnl_get_pg_bwg_cfg_rx - Get CEE PG BW Rx config
+ * @netdev: the corresponding netdev
+ * @pgid: the corresponding traffic class
+ * @bw_pct: the BW percentage for the corresponding TC
+ *
+ * Get Rx BW settings for given TC in CEE mode
+ * The adapter doesn't support Rx ETS and runs in strict priority
+ * mode in Rx path and hence just return 0.
+ **/
+static void i40e_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int pgid,
+                                        u8 *bw_pct)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return;
+       *bw_pct = 0;
+}
+
+/**
+ * i40e_dcbnl_set_pfc_cfg - Set CEE PFC configuration
+ * @netdev: the corresponding netdev
+ * @prio: the corresponding user priority
+ * @setting: the PFC setting for given priority
+ *
+ * Set the PFC enabled/disabled setting for given user priority
+ **/
+static void i40e_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio,
+                                  u8 setting)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return;
+
+       if (prio >= I40E_MAX_USER_PRIORITY)
+               return;
+
+       pf->tmp_cfg.pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
+       if (setting)
+               pf->tmp_cfg.pfc.pfcenable |= BIT(prio);
+       else
+               pf->tmp_cfg.pfc.pfcenable &= ~BIT(prio);
+       dev_dbg(&pf->pdev->dev,
+               "Set PFC Config up=%d setting=%d pfcenable=0x%x\n",
+               prio, setting, pf->tmp_cfg.pfc.pfcenable);
+}
+
+/**
+ * i40e_dcbnl_get_pfc_cfg - Get CEE PFC configuration
+ * @netdev: the corresponding netdev
+ * @prio: the corresponding user priority
+ * @setting: the PFC setting for given priority
+ *
+ * Get the PFC enabled/disabled setting for given user priority
+ **/
+static void i40e_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio,
+                                  u8 *setting)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return;
+
+       if (prio >= I40E_MAX_USER_PRIORITY)
+               return;
+
+       *setting = (pf->hw.local_dcbx_config.pfc.pfcenable >> prio) & 0x1;
+       dev_dbg(&pf->pdev->dev,
+               "Get PFC Config up=%d setting=%d pfcenable=0x%x\n",
+               prio, *setting, pf->hw.local_dcbx_config.pfc.pfcenable);
+}
+
+/**
+ * i40e_dcbnl_cee_set_all - Commit CEE DCB settings to hardware
+ * @netdev: the corresponding netdev
+ *
+ * Commit the current DCB configuration to hardware
+ **/
+static u8 i40e_dcbnl_cee_set_all(struct net_device *netdev)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+       int err;
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return I40E_DCBNL_STATUS_ERROR;
+
+       dev_dbg(&pf->pdev->dev, "Commit DCB Configuration to the hardware\n");
+       err = i40e_hw_dcb_config(pf, &pf->tmp_cfg);
+
+       return err ? I40E_DCBNL_STATUS_ERROR : I40E_DCBNL_STATUS_SUCCESS;
+}
+
+/**
+ * i40e_dcbnl_get_cap - Get DCBX capabilities of adapter
+ * @netdev: the corresponding netdev
+ * @capid: the capability type
+ * @cap: the capability value
+ *
+ * Return the capability value for a given capability type
+ **/
+static u8 i40e_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
+               return I40E_DCBNL_STATUS_ERROR;
+
+       switch (capid) {
+       case DCB_CAP_ATTR_PG:
+       case DCB_CAP_ATTR_PFC:
+               *cap = true;
+               break;
+       case DCB_CAP_ATTR_PG_TCS:
+       case DCB_CAP_ATTR_PFC_TCS:
+               *cap = 0x80;
+               break;
+       case DCB_CAP_ATTR_DCBX:
+               *cap = pf->dcbx_cap;
+               break;
+       case DCB_CAP_ATTR_UP2TC:
+       case DCB_CAP_ATTR_GSP:
+       case DCB_CAP_ATTR_BCN:
+       default:
+               *cap = false;
+               break;
+       }
+
+       dev_dbg(&pf->pdev->dev, "Get Capability cap=%d capval=0x%x\n",
+               capid, *cap);
+       return I40E_DCBNL_STATUS_SUCCESS;
+}
+
+/**
+ * i40e_dcbnl_getnumtcs - Get max number of traffic classes supported
+ * @netdev: the corresponding netdev
+ * @tcid: the TC id
+ * @num: total number of TCs supported by the device
+ *
+ * Return the total number of TCs supported by the adapter
+ **/
+static int i40e_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
+               return -EINVAL;
+
+       *num = I40E_MAX_TRAFFIC_CLASS;
+       return 0;
+}
+
+/**
+ * i40e_dcbnl_setnumtcs - Set CEE number of traffic classes
+ * @netdev: the corresponding netdev
+ * @tcid: the TC id
+ * @num: total number of TCs
+ *
+ * Set the total number of TCs (Unsupported)
+ **/
+static int i40e_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num)
+{
+       return -EINVAL;
+}
+
+/**
+ * i40e_dcbnl_getpfcstate - Get CEE PFC mode
+ * @netdev: the corresponding netdev
+ *
+ * Get the current PFC enabled state
+ **/
+static u8 i40e_dcbnl_getpfcstate(struct net_device *netdev)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       /* Return enabled if any PFC enabled UP */
+       if (pf->hw.local_dcbx_config.pfc.pfcenable)
+               return 1;
+       else
+               return 0;
+}
+
+/**
+ * i40e_dcbnl_setpfcstate - Set CEE PFC mode
+ * @netdev: the corresponding netdev
+ * @state: required state
+ *
+ * The PFC state to be set; this is enabled/disabled based on the PFC
+ * priority settings and not via this call for i40e driver
+ **/
+static void i40e_dcbnl_setpfcstate(struct net_device *netdev, u8 state)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       dev_dbg(&pf->pdev->dev, "PFC State is modified via PFC config.\n");
+}
+
+/**
+ * i40e_dcbnl_getapp - Get CEE APP
+ * @netdev: the corresponding netdev
+ * @idtype: the App selector
+ * @id: the App ethtype or port number
+ *
+ * Return the CEE mode app for the given idtype and id
+ **/
+static int i40e_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+       struct dcb_app app = {
+                               .selector = idtype,
+                               .protocol = id,
+                            };
+
+       if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE) ||
+           (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED))
+               return -EINVAL;
+
+       return dcb_getapp(netdev, &app);
+}
+
+/**
+ * i40e_dcbnl_setdcbx - set required DCBx capability
+ * @netdev: the corresponding netdev
+ * @mode: new DCB mode managed or CEE+IEEE
+ *
+ * Set DCBx capability features
+ **/
+static u8 i40e_dcbnl_setdcbx(struct net_device *netdev, u8 mode)
+{
+       struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
+
+       /* Do not allow to set mode if managed by Firmware */
+       if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)
+               return I40E_DCBNL_STATUS_ERROR;
+
+       /* No support for LLD_MANAGED modes or CEE+IEEE */
+       if ((mode & DCB_CAP_DCBX_LLD_MANAGED) ||
+           ((mode & DCB_CAP_DCBX_VER_IEEE) && (mode & DCB_CAP_DCBX_VER_CEE)) ||
+           !(mode & DCB_CAP_DCBX_HOST))
+               return I40E_DCBNL_STATUS_ERROR;
+
+       /* Already set to the given mode no change */
+       if (mode == pf->dcbx_cap)
+               return I40E_DCBNL_STATUS_SUCCESS;
+
+       pf->dcbx_cap = mode;
+       if (mode & DCB_CAP_DCBX_VER_CEE)
+               pf->hw.local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
+       else
+               pf->hw.local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
+
+       dev_dbg(&pf->pdev->dev, "mode=%d\n", mode);
+       return I40E_DCBNL_STATUS_SUCCESS;
+}
+
 /**
  * i40e_dcbnl_getdcbx - retrieve current DCBx capability
  * @dev: the corresponding netdev
        .ieee_getets    = i40e_dcbnl_ieee_getets,
        .ieee_getpfc    = i40e_dcbnl_ieee_getpfc,
        .getdcbx        = i40e_dcbnl_getdcbx,
-       .getpermhwaddr  = i40e_dcbnl_get_perm_hw_addr,
+       .getpermhwaddr  = i40e_dcbnl_get_perm_hw_addr,
+       .ieee_setets    = i40e_dcbnl_ieee_setets,
+       .ieee_setpfc    = i40e_dcbnl_ieee_setpfc,
+       .ieee_setapp    = i40e_dcbnl_ieee_setapp,
+       .ieee_delapp    = i40e_dcbnl_ieee_delapp,
+       .getstate       = i40e_dcbnl_getstate,
+       .setstate       = i40e_dcbnl_setstate,
+       .setpgtccfgtx   = i40e_dcbnl_set_pg_tc_cfg_tx,
+       .setpgbwgcfgtx  = i40e_dcbnl_set_pg_bwg_cfg_tx,
+       .setpgtccfgrx   = i40e_dcbnl_set_pg_tc_cfg_rx,
+       .setpgbwgcfgrx  = i40e_dcbnl_set_pg_bwg_cfg_rx,
+       .getpgtccfgtx   = i40e_dcbnl_get_pg_tc_cfg_tx,
+       .getpgbwgcfgtx  = i40e_dcbnl_get_pg_bwg_cfg_tx,
+       .getpgtccfgrx   = i40e_dcbnl_get_pg_tc_cfg_rx,
+       .getpgbwgcfgrx  = i40e_dcbnl_get_pg_bwg_cfg_rx,
+       .setpfccfg      = i40e_dcbnl_set_pfc_cfg,
+       .getpfccfg      = i40e_dcbnl_get_pfc_cfg,
+       .setall         = i40e_dcbnl_cee_set_all,
+       .getcap         = i40e_dcbnl_get_cap,
+       .getnumtcs      = i40e_dcbnl_getnumtcs,
+       .setnumtcs      = i40e_dcbnl_setnumtcs,
+       .getpfcstate    = i40e_dcbnl_getpfcstate,
+       .setpfcstate    = i40e_dcbnl_setpfcstate,
+       .getapp         = i40e_dcbnl_getapp,
+       .setdcbx        = i40e_dcbnl_setdcbx,
 };
 
 /**
        u8 prio, tc_map;
        int i;
 
+       /* SW DCB taken care by DCBNL set calls */
+       if (pf->dcbx_cap & DCB_CAP_DCBX_HOST)
+               return;
+
        /* DCB not enabled */
        if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
                return;
 
        /* MFP mode but not an iSCSI PF so return */
-       if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi))
+       if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(hw->func_caps.iscsi))
                return;
 
        dcbxcfg = &hw->local_dcbx_config;