net/ice/base: save user provided PHY config
[dpdk.git] / drivers / net / ice / base / ice_common.c
index 86d3be1..a0ab25a 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2001-2018
+ * Copyright(c) 2001-2019
  */
 
 #include "ice_common.h"
@@ -270,21 +270,23 @@ enum ice_status
 ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
                     struct ice_link_status *link, struct ice_sq_cd *cd)
 {
-       struct ice_link_status *hw_link_info_old, *hw_link_info;
        struct ice_aqc_get_link_status_data link_data = { 0 };
        struct ice_aqc_get_link_status *resp;
+       struct ice_link_status *li_old, *li;
        enum ice_media_type *hw_media_type;
        struct ice_fc_info *hw_fc_info;
        bool tx_pause, rx_pause;
        struct ice_aq_desc desc;
        enum ice_status status;
+       struct ice_hw *hw;
        u16 cmd_flags;
 
        if (!pi)
                return ICE_ERR_PARAM;
-       hw_link_info_old = &pi->phy.link_info_old;
+       hw = pi->hw;
+       li_old = &pi->phy.link_info_old;
        hw_media_type = &pi->phy.media_type;
-       hw_link_info = &pi->phy.link_info;
+       li = &pi->phy.link_info;
        hw_fc_info = &pi->fc;
 
        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_status);
@@ -293,27 +295,27 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
        resp->cmd_flags = CPU_TO_LE16(cmd_flags);
        resp->lport_num = pi->lport;
 
-       status = ice_aq_send_cmd(pi->hw, &desc, &link_data, sizeof(link_data),
-                                cd);
+       status = ice_aq_send_cmd(hw, &desc, &link_data, sizeof(link_data), cd);
 
        if (status != ICE_SUCCESS)
                return status;
 
        /* save off old link status information */
-       *hw_link_info_old = *hw_link_info;
+       *li_old = *li;
 
        /* update current link status information */
-       hw_link_info->link_speed = LE16_TO_CPU(link_data.link_speed);
-       hw_link_info->phy_type_low = LE64_TO_CPU(link_data.phy_type_low);
-       hw_link_info->phy_type_high = LE64_TO_CPU(link_data.phy_type_high);
+       li->link_speed = LE16_TO_CPU(link_data.link_speed);
+       li->phy_type_low = LE64_TO_CPU(link_data.phy_type_low);
+       li->phy_type_high = LE64_TO_CPU(link_data.phy_type_high);
        *hw_media_type = ice_get_media_type(pi);
-       hw_link_info->link_info = link_data.link_info;
-       hw_link_info->an_info = link_data.an_info;
-       hw_link_info->ext_info = link_data.ext_info;
-       hw_link_info->max_frame_size = LE16_TO_CPU(link_data.max_frame_size);
-       hw_link_info->fec_info = link_data.cfg & ICE_AQ_FEC_MASK;
-       hw_link_info->topo_media_conflict = link_data.topo_media_conflict;
-       hw_link_info->pacing = link_data.cfg & ICE_AQ_CFG_PACING_M;
+       li->link_info = link_data.link_info;
+       li->an_info = link_data.an_info;
+       li->ext_info = link_data.ext_info;
+       li->max_frame_size = LE16_TO_CPU(link_data.max_frame_size);
+       li->fec_info = link_data.cfg & ICE_AQ_FEC_MASK;
+       li->topo_media_conflict = link_data.topo_media_conflict;
+       li->pacing = link_data.cfg & (ICE_AQ_CFG_PACING_M |
+                                     ICE_AQ_CFG_PACING_TYPE_M);
 
        /* update fc info */
        tx_pause = !!(link_data.an_info & ICE_AQ_LINK_PAUSE_TX);
@@ -327,13 +329,24 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
        else
                hw_fc_info->current_mode = ICE_FC_NONE;
 
-       hw_link_info->lse_ena =
-               !!(resp->cmd_flags & CPU_TO_LE16(ICE_AQ_LSE_IS_ENABLED));
-
+       li->lse_ena = !!(resp->cmd_flags & CPU_TO_LE16(ICE_AQ_LSE_IS_ENABLED));
+
+       ice_debug(hw, ICE_DBG_LINK, "link_speed = 0x%x\n", li->link_speed);
+       ice_debug(hw, ICE_DBG_LINK, "phy_type_low = 0x%llx\n",
+                 (unsigned long long)li->phy_type_low);
+       ice_debug(hw, ICE_DBG_LINK, "phy_type_high = 0x%llx\n",
+                 (unsigned long long)li->phy_type_high);
+       ice_debug(hw, ICE_DBG_LINK, "media_type = 0x%x\n", *hw_media_type);
+       ice_debug(hw, ICE_DBG_LINK, "link_info = 0x%x\n", li->link_info);
+       ice_debug(hw, ICE_DBG_LINK, "an_info = 0x%x\n", li->an_info);
+       ice_debug(hw, ICE_DBG_LINK, "ext_info = 0x%x\n", li->ext_info);
+       ice_debug(hw, ICE_DBG_LINK, "lse_ena = 0x%x\n", li->lse_ena);
+       ice_debug(hw, ICE_DBG_LINK, "max_frame = 0x%x\n", li->max_frame_size);
+       ice_debug(hw, ICE_DBG_LINK, "pacing = 0x%x\n", li->pacing);
 
        /* save link status information */
        if (link)
-               *link = *hw_link_info;
+               *link = *li;
 
        /* flag cleared so calling functions don't call AQ again */
        pi->phy.get_link_info = false;
@@ -365,22 +378,22 @@ static void ice_init_flex_flags(struct ice_hw *hw, enum ice_rxdid prof_id)
         */
        case ICE_RXDID_FLEX_NIC:
        case ICE_RXDID_FLEX_NIC_2:
-               ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_PKT_FRG,
-                                  ICE_RXFLG_UDP_GRE, ICE_RXFLG_PKT_DSI,
-                                  ICE_RXFLG_FIN, idx++);
+               ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_FLG_PKT_FRG,
+                                  ICE_FLG_UDP_GRE, ICE_FLG_PKT_DSI,
+                                  ICE_FLG_FIN, idx++);
                /* flex flag 1 is not used for flexi-flag programming, skipping
                 * these four FLG64 bits.
                 */
-               ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_SYN, ICE_RXFLG_RST,
-                                  ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, idx++);
-               ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_PKT_DSI,
-                                  ICE_RXFLG_PKT_DSI, ICE_RXFLG_EVLAN_x8100,
-                                  ICE_RXFLG_EVLAN_x9100, idx++);
-               ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_VLAN_x8100,
-                                  ICE_RXFLG_TNL_VLAN, ICE_RXFLG_TNL_MAC,
-                                  ICE_RXFLG_TNL0, idx++);
-               ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_TNL1, ICE_RXFLG_TNL2,
-                                  ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, idx);
+               ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_FLG_SYN, ICE_FLG_RST,
+                                  ICE_FLG_PKT_DSI, ICE_FLG_PKT_DSI, idx++);
+               ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_FLG_PKT_DSI,
+                                  ICE_FLG_PKT_DSI, ICE_FLG_EVLAN_x8100,
+                                  ICE_FLG_EVLAN_x9100, idx++);
+               ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_FLG_VLAN_x8100,
+                                  ICE_FLG_TNL_VLAN, ICE_FLG_TNL_MAC,
+                                  ICE_FLG_TNL0, idx++);
+               ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_FLG_TNL1, ICE_FLG_TNL2,
+                                  ICE_FLG_PKT_DSI, ICE_FLG_PKT_DSI, idx);
                break;
 
        default:
@@ -399,17 +412,17 @@ static void ice_init_flex_flags(struct ice_hw *hw, enum ice_rxdid prof_id)
  */
 static void ice_init_flex_flds(struct ice_hw *hw, enum ice_rxdid prof_id)
 {
-       enum ice_flex_rx_mdid mdid;
+       enum ice_flex_mdid mdid;
 
        switch (prof_id) {
        case ICE_RXDID_FLEX_NIC:
        case ICE_RXDID_FLEX_NIC_2:
-               ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_RX_MDID_HASH_LOW, 0);
-               ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_RX_MDID_HASH_HIGH, 1);
-               ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_RX_MDID_FLOW_ID_LOWER, 2);
+               ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_MDID_RX_HASH_LOW, 0);
+               ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_MDID_RX_HASH_HIGH, 1);
+               ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_MDID_FLOW_ID_LOWER, 2);
 
                mdid = (prof_id == ICE_RXDID_FLEX_NIC_2) ?
-                       ICE_RX_MDID_SRC_VSI : ICE_RX_MDID_FLOW_ID_HIGH;
+                       ICE_MDID_SRC_VSI : ICE_MDID_FLOW_ID_HIGH;
 
                ICE_PROG_FLEX_ENTRY(hw, prof_id, mdid, 3);
 
@@ -741,7 +754,7 @@ void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf)
  * Determines the itr/intrl granularities based on the maximum aggregate
  * bandwidth according to the device's configuration during power-on.
  */
-static enum ice_status ice_get_itr_intrl_gran(struct ice_hw *hw)
+static void ice_get_itr_intrl_gran(struct ice_hw *hw)
 {
        u8 max_agg_bw = (rd32(hw, GL_PWR_MODE_CTL) &
                         GL_PWR_MODE_CTL_CAR_MAX_BW_M) >>
@@ -758,13 +771,7 @@ static enum ice_status ice_get_itr_intrl_gran(struct ice_hw *hw)
                hw->itr_gran = ICE_ITR_GRAN_MAX_25;
                hw->intrl_gran = ICE_INTRL_GRAN_MAX_25;
                break;
-       default:
-               ice_debug(hw, ICE_DBG_INIT,
-                         "Failed to determine itr/intrl granularity\n");
-               return ICE_ERR_CFG;
        }
-
-       return ICE_SUCCESS;
 }
 
 /**
@@ -795,9 +802,7 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
        if (status)
                return status;
 
-       status = ice_get_itr_intrl_gran(hw);
-       if (status)
-               return status;
+       ice_get_itr_intrl_gran(hw);
 
 
        status = ice_init_all_ctrlq(hw);
@@ -813,6 +818,9 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
        if (status)
                goto err_unroll_cqinit;
 
+       /* Set bit to enable Flow Director filters */
+       wr32(hw, PFQF_FD_ENA, PFQF_FD_ENA_FD_ENA_M);
+       INIT_LIST_HEAD(&hw->fdir_list_head);
 
        ice_clear_pxe_mode(hw);
 
@@ -909,6 +917,10 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
        ice_init_flex_flds(hw, ICE_RXDID_FLEX_NIC);
        ice_init_flex_flds(hw, ICE_RXDID_FLEX_NIC_2);
 
+       /* Obtain counter base index which would be used by flow director */
+       status = ice_alloc_fd_res_cntr(hw, &hw->fd_ctr_base);
+       if (status)
+               goto err_unroll_fltr_mgmt_struct;
 
        return ICE_SUCCESS;
 
@@ -934,10 +946,12 @@ err_unroll_cqinit:
  */
 void ice_deinit_hw(struct ice_hw *hw)
 {
+       ice_free_fd_res_cntr(hw, hw->fd_ctr_base);
        ice_cleanup_fltr_mgmt_struct(hw);
 
        ice_sched_cleanup_all(hw);
        ice_sched_clear_agg(hw);
+       ice_free_seg(hw);
 
        if (hw->port_info) {
                ice_free(hw, hw->port_info);
@@ -1511,6 +1525,42 @@ enum ice_status ice_aq_get_fw_ver(struct ice_hw *hw, struct ice_sq_cd *cd)
        return status;
 }
 
+/**
+ * ice_aq_send_driver_ver
+ * @hw: pointer to the HW struct
+ * @dv: driver's major, minor version
+ * @cd: pointer to command details structure or NULL
+ *
+ * Send the driver version (0x0002) to the firmware
+ */
+enum ice_status
+ice_aq_send_driver_ver(struct ice_hw *hw, struct ice_driver_ver *dv,
+                      struct ice_sq_cd *cd)
+{
+       struct ice_aqc_driver_ver *cmd;
+       struct ice_aq_desc desc;
+       u16 len;
+
+       cmd = &desc.params.driver_ver;
+
+       if (!dv)
+               return ICE_ERR_PARAM;
+
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_driver_ver);
+
+       desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
+       cmd->major_ver = dv->major_ver;
+       cmd->minor_ver = dv->minor_ver;
+       cmd->build_ver = dv->build_ver;
+       cmd->subbuild_ver = dv->subbuild_ver;
+
+       len = 0;
+       while (len < sizeof(dv->driver_string) &&
+              IS_ASCII(dv->driver_string[len]) && dv->driver_string[len])
+               len++;
+
+       return ice_aq_send_cmd(hw, &desc, dv->driver_string, len, cd);
+}
 
 /**
  * ice_aq_q_shutdown
@@ -1785,11 +1835,11 @@ ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,
  * @hw: pointer to the HW struct
  * @type: type of resource
  * @num: number of resources to allocate
- * @sh: shared if true, dedicated if false
+ * @btm: allocate from bottom
  * @res: pointer to array that will receive the resources
  */
 enum ice_status
-ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool sh, u16 *res)
+ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool btm, u16 *res)
 {
        struct ice_aqc_alloc_free_res_elem *buf;
        enum ice_status status;
@@ -1803,8 +1853,11 @@ ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool sh, u16 *res)
 
        /* Prepare buffer to allocate resource. */
        buf->num_elems = CPU_TO_LE16(num);
-       buf->res_type = CPU_TO_LE16(type | (sh ? ICE_AQC_RES_TYPE_FLAG_SHARED :
-               ICE_AQC_RES_TYPE_FLAG_DEDICATED));
+       buf->res_type = CPU_TO_LE16(type | ICE_AQC_RES_TYPE_FLAG_DEDICATED |
+                                   ICE_AQC_RES_TYPE_FLAG_IGNORE_INDEX);
+       if (btm)
+               buf->res_type |= CPU_TO_LE16(ICE_AQC_RES_TYPE_FLAG_SCAN_BOTTOM);
+
        status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
                                       ice_aqc_opc_alloc_res, NULL);
        if (status)
@@ -1937,6 +1990,18 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
                                          number);
                        }
                        break;
+               case ICE_AQC_CAPS_DCB:
+                       caps->dcb = (number == 1);
+                       caps->active_tc_bitmap = logical_id;
+                       caps->maxtc = phys_id;
+                       ice_debug(hw, ICE_DBG_INIT,
+                                 "HW caps: DCB = %d\n", caps->dcb);
+                       ice_debug(hw, ICE_DBG_INIT,
+                                 "HW caps: Active TC bitmap = %d\n",
+                                 caps->active_tc_bitmap);
+                       ice_debug(hw, ICE_DBG_INIT,
+                                 "HW caps: TC Max = %d\n", caps->maxtc);
+                       break;
                case ICE_AQC_CAPS_RSS:
                        caps->rss_table_size = number;
                        caps->rss_table_entry_width = logical_id;
@@ -1975,6 +2040,34 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
                                  "HW caps: MSIX first vector index = %d\n",
                                  caps->msix_vector_first_id);
                        break;
+               case ICE_AQC_CAPS_FD:
+               {
+                       u32 reg_val, val;
+
+                       if (dev_p) {
+                               dev_p->num_flow_director_fltr = number;
+                               ice_debug(hw, ICE_DBG_INIT,
+                                         "HW caps: Dev.fd_fltr =%d\n",
+                                         dev_p->num_flow_director_fltr);
+                       }
+                       if (func_p) {
+                               reg_val = rd32(hw, GLQF_FD_SIZE);
+                               val = (reg_val & GLQF_FD_SIZE_FD_GSIZE_M) >>
+                                     GLQF_FD_SIZE_FD_GSIZE_S;
+                               func_p->fd_fltr_guar =
+                                       ice_get_num_per_func(hw, val);
+                               val = (reg_val & GLQF_FD_SIZE_FD_BSIZE_M) >>
+                                     GLQF_FD_SIZE_FD_BSIZE_S;
+                               func_p->fd_fltr_best_effort = val;
+                               ice_debug(hw, ICE_DBG_INIT,
+                                         "HW:func.fd_fltr guar= %d\n",
+                                         func_p->fd_fltr_guar);
+                               ice_debug(hw, ICE_DBG_INIT,
+                                         "HW:func.fd_fltr best effort=%d\n",
+                                         func_p->fd_fltr_best_effort);
+                       }
+                       break;
+               }
                case ICE_AQC_CAPS_MAX_MTU:
                        caps->max_mtu = number;
                        if (dev_p)
@@ -2332,7 +2425,7 @@ ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high,
 /**
  * ice_aq_set_phy_cfg
  * @hw: pointer to the HW struct
- * @lport: logical port number
+ * @pi: port info structure of the interested logical port
  * @cfg: structure with PHY configuration data to be set
  * @cd: pointer to command details structure or NULL
  *
@@ -2342,19 +2435,45 @@ ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high,
  * parameters. This status will be indicated by the command response (0x0601).
  */
 enum ice_status
-ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport,
+ice_aq_set_phy_cfg(struct ice_hw *hw, struct ice_port_info *pi,
                   struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd)
 {
        struct ice_aq_desc desc;
+       enum ice_status status;
 
        if (!cfg)
                return ICE_ERR_PARAM;
 
+       /* Ensure that only valid bits of cfg->caps can be turned on. */
+       if (cfg->caps & ~ICE_AQ_PHY_ENA_VALID_MASK) {
+               ice_debug(hw, ICE_DBG_PHY,
+                         "Invalid bit is set in ice_aqc_set_phy_cfg_data->caps : 0x%x\n",
+                         cfg->caps);
+
+               cfg->caps &= ICE_AQ_PHY_ENA_VALID_MASK;
+       }
+
        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_phy_cfg);
-       desc.params.set_phy.lport_num = lport;
+       desc.params.set_phy.lport_num = pi->lport;
        desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
 
-       return ice_aq_send_cmd(hw, &desc, cfg, sizeof(*cfg), cd);
+       ice_debug(hw, ICE_DBG_LINK, "phy_type_low = 0x%llx\n",
+                 (unsigned long long)LE64_TO_CPU(cfg->phy_type_low));
+       ice_debug(hw, ICE_DBG_LINK, "phy_type_high = 0x%llx\n",
+                 (unsigned long long)LE64_TO_CPU(cfg->phy_type_high));
+       ice_debug(hw, ICE_DBG_LINK, "caps = 0x%x\n", cfg->caps);
+       ice_debug(hw, ICE_DBG_LINK, "low_power_ctrl = 0x%x\n",
+                 cfg->low_power_ctrl);
+       ice_debug(hw, ICE_DBG_LINK, "eee_cap = 0x%x\n", cfg->eee_cap);
+       ice_debug(hw, ICE_DBG_LINK, "eeer_value = 0x%x\n", cfg->eeer_value);
+       ice_debug(hw, ICE_DBG_LINK, "link_fec_opt = 0x%x\n", cfg->link_fec_opt);
+
+       status = ice_aq_send_cmd(hw, &desc, cfg, sizeof(*cfg), cd);
+
+       if (!status)
+               pi->phy.curr_user_phy_cfg = *cfg;
+
+       return status;
 }
 
 /**
@@ -2398,6 +2517,38 @@ out:
        return status;
 }
 
+/**
+ * ice_cache_phy_user_req
+ * @pi: port information structure
+ * @cache_data: PHY logging data
+ * @cache_mode: PHY logging mode
+ *
+ * Log the user request on (FC, FEC, SPEED) for later user.
+ */
+static void
+ice_cache_phy_user_req(struct ice_port_info *pi,
+                      struct ice_phy_cache_mode_data cache_data,
+                      enum ice_phy_cache_mode cache_mode)
+{
+       if (!pi)
+               return;
+
+       switch (cache_mode) {
+       case ICE_FC_MODE:
+               pi->phy.curr_user_fc_req = cache_data.data.curr_user_fc_req;
+               break;
+       case ICE_SPEED_MODE:
+               pi->phy.curr_user_speed_req =
+                       cache_data.data.curr_user_speed_req;
+               break;
+       case ICE_FEC_MODE:
+               pi->phy.curr_user_fec_req = cache_data.data.curr_user_fec_req;
+               break;
+       default:
+               break;
+       }
+}
+
 /**
  * ice_set_fc
  * @pi: port information structure
@@ -2410,6 +2561,7 @@ enum ice_status
 ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
 {
        struct ice_aqc_set_phy_cfg_data cfg = { 0 };
+       struct ice_phy_cache_mode_data cache_data;
        struct ice_aqc_get_phy_caps_data *pcaps;
        enum ice_status status;
        u8 pause_mask = 0x0;
@@ -2420,6 +2572,10 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
        hw = pi->hw;
        *aq_failures = ICE_SET_FC_AQ_FAIL_NONE;
 
+       /* Cache user FC request */
+       cache_data.data.curr_user_fc_req = pi->fc.req_mode;
+       ice_cache_phy_user_req(pi, cache_data, ICE_FC_MODE);
+
        switch (pi->fc.req_mode) {
        case ICE_FC_FULL:
                pause_mask |= ICE_AQC_PHY_EN_TX_LINK_PAUSE;
@@ -2451,8 +2607,10 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
        /* clear the old pause settings */
        cfg.caps = pcaps->caps & ~(ICE_AQC_PHY_EN_TX_LINK_PAUSE |
                                   ICE_AQC_PHY_EN_RX_LINK_PAUSE);
+
        /* set the new capabilities */
        cfg.caps |= pause_mask;
+
        /* If the capabilities have changed, then set the new config */
        if (cfg.caps != pcaps->caps) {
                int retry_count, retry_max = 10;
@@ -2468,7 +2626,7 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
                cfg.eeer_value = pcaps->eeer_value;
                cfg.link_fec_opt = pcaps->link_fec_options;
 
-               status = ice_aq_set_phy_cfg(hw, pi->lport, &cfg, NULL);
+               status = ice_aq_set_phy_cfg(hw, pi, &cfg, NULL);
                if (status) {
                        *aq_failures = ICE_SET_FC_AQ_FAIL_SET;
                        goto out;
@@ -2935,7 +3093,7 @@ ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_handle,
  * Association of Tx queue to Doorbell queue is not part of Add LAN Tx queue
  * flow.
  */
-static enum ice_status
+enum ice_status
 ice_aq_add_lan_txq(struct ice_hw *hw, u8 num_qgrps,
                   struct ice_aqc_add_tx_qgrp *qg_list, u16 buf_size,
                   struct ice_sq_cd *cd)
@@ -3510,11 +3668,36 @@ ice_get_ctx(u8 *src_ctx, u8 *dest_ctx, struct ice_ctx_ele *ce_info)
        return ICE_SUCCESS;
 }
 
+/**
+ * ice_get_lan_q_ctx - get the LAN queue context for the given VSI and TC
+ * @hw: pointer to the HW struct
+ * @vsi_handle: software VSI handle
+ * @tc: TC number
+ * @q_handle: software queue handle
+ */
+struct ice_q_ctx *
+ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle)
+{
+       struct ice_vsi_ctx *vsi;
+       struct ice_q_ctx *q_ctx;
+
+       vsi = ice_get_vsi_ctx(hw, vsi_handle);
+       if (!vsi)
+               return NULL;
+       if (q_handle >= vsi->num_lan_q_entries[tc])
+               return NULL;
+       if (!vsi->lan_q_ctx[tc])
+               return NULL;
+       q_ctx = vsi->lan_q_ctx[tc];
+       return &q_ctx[q_handle];
+}
+
 /**
  * ice_ena_vsi_txq
  * @pi: port information structure
  * @vsi_handle: software VSI handle
  * @tc: TC number
+ * @q_handle: software queue handle
  * @num_qgrps: Number of added queue groups
  * @buf: list of queue groups to be added
  * @buf_size: size of buffer for indirect command
@@ -3523,12 +3706,13 @@ ice_get_ctx(u8 *src_ctx, u8 *dest_ctx, struct ice_ctx_ele *ce_info)
  * This function adds one LAN queue
  */
 enum ice_status
-ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_qgrps,
-               struct ice_aqc_add_tx_qgrp *buf, u16 buf_size,
+ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 q_handle,
+               u8 num_qgrps, struct ice_aqc_add_tx_qgrp *buf, u16 buf_size,
                struct ice_sq_cd *cd)
 {
        struct ice_aqc_txsched_elem_data node = { 0 };
        struct ice_sched_node *parent;
+       struct ice_q_ctx *q_ctx;
        enum ice_status status;
        struct ice_hw *hw;
 
@@ -3545,6 +3729,14 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_qgrps,
 
        ice_acquire_lock(&pi->sched_lock);
 
+       q_ctx = ice_get_lan_q_ctx(hw, vsi_handle, tc, q_handle);
+       if (!q_ctx) {
+               ice_debug(hw, ICE_DBG_SCHED, "Enaq: invalid queue handle %d\n",
+                         q_handle);
+               status = ICE_ERR_PARAM;
+               goto ena_txq_exit;
+       }
+
        /* find a parent node */
        parent = ice_sched_get_free_qparent(pi, vsi_handle, tc,
                                            ICE_SCHED_NODE_OWNER_LAN);
@@ -3579,9 +3771,13 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_qgrps,
 
        node.node_teid = buf->txqs[0].q_teid;
        node.data.elem_type = ICE_AQC_ELEM_TYPE_LEAF;
+       q_ctx->q_handle = q_handle;
+       q_ctx->q_teid = LE32_TO_CPU(node.node_teid);
 
-       /* add a leaf node into schduler tree queue layer */
+       /* add a leaf node into scheduler tree queue layer */
        status = ice_sched_add_node(pi, hw->num_tx_sched_layers - 1, &node);
+       if (!status)
+               status = ice_sched_replay_q_bw(pi, q_ctx);
 
 ena_txq_exit:
        ice_release_lock(&pi->sched_lock);
@@ -3591,7 +3787,10 @@ ena_txq_exit:
 /**
  * ice_dis_vsi_txq
  * @pi: port information structure
+ * @vsi_handle: software VSI handle
+ * @tc: TC number
  * @num_queues: number of queues
+ * @q_handles: pointer to software queue handle array
  * @q_ids: pointer to the q_id array
  * @q_teids: pointer to queue node teids
  * @rst_src: if called due to reset, specifies the reset source
@@ -3601,25 +3800,30 @@ ena_txq_exit:
  * This function removes queues and their corresponding nodes in SW DB
  */
 enum ice_status
-ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,
-               u32 *q_teids, enum ice_disq_rst_src rst_src, u16 vmvf_num,
+ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
+               u16 *q_handles, u16 *q_ids, u32 *q_teids,
+               enum ice_disq_rst_src rst_src, u16 vmvf_num,
                struct ice_sq_cd *cd)
 {
        enum ice_status status = ICE_ERR_DOES_NOT_EXIST;
        struct ice_aqc_dis_txq_item qg_list;
+       struct ice_q_ctx *q_ctx;
        u16 i;
 
        if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
                return ICE_ERR_CFG;
 
-       /* if queue is disabled already yet the disable queue command has to be
-        * sent to complete the VF reset, then call ice_aq_dis_lan_txq without
-        * any queue information
-        */
 
-       if (!num_queues && rst_src)
-               return ice_aq_dis_lan_txq(pi->hw, 0, NULL, 0, rst_src, vmvf_num,
-                                         NULL);
+       if (!num_queues) {
+               /* if queue is disabled already yet the disable queue command
+                * has to be sent to complete the VF reset, then call
+                * ice_aq_dis_lan_txq without any queue information
+                */
+               if (rst_src)
+                       return ice_aq_dis_lan_txq(pi->hw, 0, NULL, 0, rst_src,
+                                                 vmvf_num, NULL);
+               return ICE_ERR_CFG;
+       }
 
        ice_acquire_lock(&pi->sched_lock);
 
@@ -3629,6 +3833,17 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,
                node = ice_sched_find_node_by_teid(pi->root, q_teids[i]);
                if (!node)
                        continue;
+               q_ctx = ice_get_lan_q_ctx(pi->hw, vsi_handle, tc, q_handles[i]);
+               if (!q_ctx) {
+                       ice_debug(pi->hw, ICE_DBG_SCHED, "invalid queue handle%d\n",
+                                 q_handles[i]);
+                       continue;
+               }
+               if (q_ctx->q_handle != q_handles[i]) {
+                       ice_debug(pi->hw, ICE_DBG_SCHED, "Err:handles %d %d\n",
+                                 q_ctx->q_handle, q_handles[i]);
+                       continue;
+               }
                qg_list.parent_teid = node->info.parent_teid;
                qg_list.num_qs = 1;
                qg_list.q_id[0] = CPU_TO_LE16(q_ids[i]);
@@ -3639,6 +3854,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,
                if (status != ICE_SUCCESS)
                        break;
                ice_free_sched_node(pi, node);
+               q_ctx->q_handle = ICE_INVAL_Q_HANDLE;
        }
        ice_release_lock(&pi->sched_lock);
        return status;
@@ -3749,7 +3965,10 @@ enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle)
                if (status)
                        return status;
        }
-
+       /* Replay per VSI all RSS configurations */
+       status = ice_replay_rss_cfg(hw, vsi_handle);
+       if (status)
+               return status;
        /* Replay per VSI all filters */
        status = ice_replay_vsi_all_fltr(hw, vsi_handle);
        if (!status)
@@ -3858,3 +4077,18 @@ ice_sched_query_elem(struct ice_hw *hw, u32 node_teid,
                ice_debug(hw, ICE_DBG_SCHED, "query element failed\n");
        return status;
 }
+
+/**
+ * ice_is_fw_in_rec_mode
+ * @hw: pointer to the HW struct
+ *
+ * This function returns true if fw is in recovery mode
+ */
+bool ice_is_fw_in_rec_mode(struct ice_hw *hw)
+{
+       u32 reg;
+
+       /* check the current FW mode */
+       reg = rd32(hw, GL_MNG_FWSM);
+       return (reg & GL_MNG_FWSM_FW_MODES_M) > ICE_FW_MODE_DBG;
+}