net/ice/base: remove duplicated AQ command flag setting
[dpdk.git] / drivers / net / ice / base / ice_common.c
index df66ba8..2a9185f 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2001-2019
+ * Copyright(c) 2001-2020 Intel Corporation
  */
 
 #include "ice_common.h"
@@ -9,27 +9,7 @@
 #include "ice_flow.h"
 #include "ice_switch.h"
 
-#define ICE_PF_RESET_WAIT_COUNT        200
-
-#define ICE_PROG_FLEX_ENTRY(hw, rxdid, mdid, idx) \
-       wr32((hw), GLFLXP_RXDID_FLX_WRD_##idx(rxdid), \
-            ((ICE_RX_OPC_MDID << \
-              GLFLXP_RXDID_FLX_WRD_##idx##_RXDID_OPCODE_S) & \
-             GLFLXP_RXDID_FLX_WRD_##idx##_RXDID_OPCODE_M) | \
-            (((mdid) << GLFLXP_RXDID_FLX_WRD_##idx##_PROT_MDID_S) & \
-             GLFLXP_RXDID_FLX_WRD_##idx##_PROT_MDID_M))
-
-#define ICE_PROG_FLG_ENTRY(hw, rxdid, flg_0, flg_1, flg_2, flg_3, idx) \
-       wr32((hw), GLFLXP_RXDID_FLAGS(rxdid, idx), \
-            (((flg_0) << GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S) & \
-             GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M) | \
-            (((flg_1) << GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_S) & \
-             GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_M) | \
-            (((flg_2) << GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_2_S) & \
-             GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_2_M) | \
-            (((flg_3) << GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_3_S) & \
-             GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_3_M))
-
+#define ICE_PF_RESET_WAIT_COUNT        300
 
 /**
  * ice_set_mac_type - Sets MAC type
  */
 static enum ice_status ice_set_mac_type(struct ice_hw *hw)
 {
-       enum ice_status status = ICE_SUCCESS;
-
        ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
 
-       if (hw->vendor_id == ICE_INTEL_VENDOR_ID) {
-               switch (hw->device_id) {
-               default:
-                       hw->mac_type = ICE_MAC_GENERIC;
-                       break;
-               }
-       } else {
-               status = ICE_ERR_DEVICE_NOT_SUPPORTED;
+       if (hw->vendor_id != ICE_INTEL_VENDOR_ID)
+               return ICE_ERR_DEVICE_NOT_SUPPORTED;
+
+       switch (hw->device_id) {
+       case ICE_DEV_ID_E810C_BACKPLANE:
+       case ICE_DEV_ID_E810C_QSFP:
+       case ICE_DEV_ID_E810C_SFP:
+       case ICE_DEV_ID_E810_XXV_BACKPLANE:
+       case ICE_DEV_ID_E810_XXV_QSFP:
+       case ICE_DEV_ID_E810_XXV_SFP:
+               hw->mac_type = ICE_MAC_E810;
+               break;
+       case ICE_DEV_ID_E822C_10G_BASE_T:
+       case ICE_DEV_ID_E822C_BACKPLANE:
+       case ICE_DEV_ID_E822C_QSFP:
+       case ICE_DEV_ID_E822C_SFP:
+       case ICE_DEV_ID_E822C_SGMII:
+       case ICE_DEV_ID_E822L_10G_BASE_T:
+       case ICE_DEV_ID_E822L_BACKPLANE:
+       case ICE_DEV_ID_E822L_SFP:
+       case ICE_DEV_ID_E822L_SGMII:
+       case ICE_DEV_ID_E823L_10G_BASE_T:
+       case ICE_DEV_ID_E823L_1GBE:
+       case ICE_DEV_ID_E823L_BACKPLANE:
+       case ICE_DEV_ID_E823L_QSFP:
+       case ICE_DEV_ID_E823L_SFP:
+               hw->mac_type = ICE_MAC_GENERIC;
+               break;
+       default:
+               hw->mac_type = ICE_MAC_UNKNOWN;
+               break;
        }
 
-       ice_debug(hw, ICE_DBG_INIT, "found mac_type: %d, status: %d\n",
-                 hw->mac_type, status);
-
-       return status;
+       ice_debug(hw, ICE_DBG_INIT, "mac_type: %d\n", hw->mac_type);
+       return ICE_SUCCESS;
 }
 
-
 /**
  * ice_clear_pf_cfg - Clear PF configuration
  * @hw: pointer to the hardware structure
@@ -89,7 +87,8 @@ enum ice_status ice_clear_pf_cfg(struct ice_hw *hw)
  * is returned in user specified buffer. Please interpret user specified
  * buffer as "manage_mac_read" response.
  * Response such as various MAC addresses are stored in HW struct (port.mac)
- * ice_aq_discover_caps is expected to be called before this function is called.
+ * ice_discover_dev_caps is expected to be called before this function is
+ * called.
  */
 static enum ice_status
 ice_aq_manage_mac_read(struct ice_hw *hw, void *buf, u16 buf_size,
@@ -132,7 +131,6 @@ ice_aq_manage_mac_read(struct ice_hw *hw, void *buf, u16 buf_size,
                                   ETH_ALEN, ICE_DMA_TO_NONDMA);
                        break;
                }
-
        return ICE_SUCCESS;
 }
 
@@ -155,11 +153,13 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
        u16 pcaps_size = sizeof(*pcaps);
        struct ice_aq_desc desc;
        enum ice_status status;
+       struct ice_hw *hw;
 
        cmd = &desc.params.get_phy;
 
        if (!pcaps || (report_mode & ~ICE_AQC_REPORT_MODE_M) || !pi)
                return ICE_ERR_PARAM;
+       hw = pi->hw;
 
        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_phy_caps);
 
@@ -167,16 +167,94 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
                cmd->param0 |= CPU_TO_LE16(ICE_AQC_GET_PHY_RQM);
 
        cmd->param0 |= CPU_TO_LE16(report_mode);
-       status = ice_aq_send_cmd(pi->hw, &desc, pcaps, pcaps_size, cd);
+       status = ice_aq_send_cmd(hw, &desc, pcaps, pcaps_size, cd);
+
+       ice_debug(hw, ICE_DBG_LINK, "get phy caps - report_mode = 0x%x\n",
+                 report_mode);
+       ice_debug(hw, ICE_DBG_LINK, "   phy_type_low = 0x%llx\n",
+                 (unsigned long long)LE64_TO_CPU(pcaps->phy_type_low));
+       ice_debug(hw, ICE_DBG_LINK, "   phy_type_high = 0x%llx\n",
+                 (unsigned long long)LE64_TO_CPU(pcaps->phy_type_high));
+       ice_debug(hw, ICE_DBG_LINK, "   caps = 0x%x\n", pcaps->caps);
+       ice_debug(hw, ICE_DBG_LINK, "   low_power_ctrl_an = 0x%x\n",
+                 pcaps->low_power_ctrl_an);
+       ice_debug(hw, ICE_DBG_LINK, "   eee_cap = 0x%x\n", pcaps->eee_cap);
+       ice_debug(hw, ICE_DBG_LINK, "   eeer_value = 0x%x\n",
+                 pcaps->eeer_value);
+       ice_debug(hw, ICE_DBG_LINK, "   link_fec_options = 0x%x\n",
+                 pcaps->link_fec_options);
+       ice_debug(hw, ICE_DBG_LINK, "   module_compliance_enforcement = 0x%x\n",
+                 pcaps->module_compliance_enforcement);
+       ice_debug(hw, ICE_DBG_LINK, "   extended_compliance_code = 0x%x\n",
+                 pcaps->extended_compliance_code);
+       ice_debug(hw, ICE_DBG_LINK, "   module_type[0] = 0x%x\n",
+                 pcaps->module_type[0]);
+       ice_debug(hw, ICE_DBG_LINK, "   module_type[1] = 0x%x\n",
+                 pcaps->module_type[1]);
+       ice_debug(hw, ICE_DBG_LINK, "   module_type[2] = 0x%x\n",
+                 pcaps->module_type[2]);
 
        if (status == ICE_SUCCESS && report_mode == ICE_AQC_REPORT_TOPO_CAP) {
                pi->phy.phy_type_low = LE64_TO_CPU(pcaps->phy_type_low);
                pi->phy.phy_type_high = LE64_TO_CPU(pcaps->phy_type_high);
+               ice_memcpy(pi->phy.link_info.module_type, &pcaps->module_type,
+                          sizeof(pi->phy.link_info.module_type),
+                          ICE_NONDMA_TO_NONDMA);
        }
 
        return status;
 }
 
+/**
+ * ice_aq_get_link_topo_handle - get link topology node return status
+ * @pi: port information structure
+ * @node_type: requested node type
+ * @cd: pointer to command details structure or NULL
+ *
+ * Get link topology node return status for specified node type (0x06E0)
+ *
+ * Node type cage can be used to determine if cage is present. If AQC
+ * returns error (ENOENT), then no cage present. If no cage present, then
+ * connection type is backplane or BASE-T.
+ */
+static enum ice_status
+ice_aq_get_link_topo_handle(struct ice_port_info *pi, u8 node_type,
+                           struct ice_sq_cd *cd)
+{
+       struct ice_aqc_get_link_topo *cmd;
+       struct ice_aq_desc desc;
+
+       cmd = &desc.params.get_link_topo;
+
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
+
+       cmd->addr.node_type_ctx = (ICE_AQC_LINK_TOPO_NODE_CTX_PORT <<
+                                  ICE_AQC_LINK_TOPO_NODE_CTX_S);
+
+       /* set node type */
+       cmd->addr.node_type_ctx |= (ICE_AQC_LINK_TOPO_NODE_TYPE_M & node_type);
+
+       return ice_aq_send_cmd(pi->hw, &desc, NULL, 0, cd);
+}
+
+/**
+ * ice_is_media_cage_present
+ * @pi: port information structure
+ *
+ * Returns true if media cage is present, else false. If no cage, then
+ * media type is backplane or BASE-T.
+ */
+static bool ice_is_media_cage_present(struct ice_port_info *pi)
+{
+       /* Node type cage can be used to determine if cage is present. If AQC
+        * returns error (ENOENT), then no cage present. If no cage present then
+        * connection type is backplane or BASE-T.
+        */
+       return !ice_aq_get_link_topo_handle(pi,
+                                           ICE_AQC_LINK_TOPO_NODE_TYPE_CAGE,
+                                           NULL);
+}
+
 /**
  * ice_get_media_type - Gets media type
  * @pi: port information structure
@@ -194,6 +272,18 @@ static enum ice_media_type ice_get_media_type(struct ice_port_info *pi)
                return ICE_MEDIA_UNKNOWN;
 
        if (hw_link_info->phy_type_low) {
+               /* 1G SGMII is a special case where some DA cable PHYs
+                * may show this as an option when it really shouldn't
+                * be since SGMII is meant to be between a MAC and a PHY
+                * in a backplane. Try to detect this case and handle it
+                */
+               if (hw_link_info->phy_type_low == ICE_PHY_TYPE_LOW_1G_SGMII &&
+                   (hw_link_info->module_type[ICE_AQC_MOD_TYPE_IDENT] ==
+                   ICE_AQC_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE ||
+                   hw_link_info->module_type[ICE_AQC_MOD_TYPE_IDENT] ==
+                   ICE_AQC_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE))
+                       return ICE_MEDIA_DA;
+
                switch (hw_link_info->phy_type_low) {
                case ICE_PHY_TYPE_LOW_1000BASE_SX:
                case ICE_PHY_TYPE_LOW_1000BASE_LX:
@@ -202,7 +292,6 @@ static enum ice_media_type ice_get_media_type(struct ice_port_info *pi)
                case ICE_PHY_TYPE_LOW_10G_SFI_C2C:
                case ICE_PHY_TYPE_LOW_25GBASE_SR:
                case ICE_PHY_TYPE_LOW_25GBASE_LR:
-               case ICE_PHY_TYPE_LOW_25G_AUI_C2C:
                case ICE_PHY_TYPE_LOW_40GBASE_SR4:
                case ICE_PHY_TYPE_LOW_40GBASE_LR4:
                case ICE_PHY_TYPE_LOW_50GBASE_SR2:
@@ -215,6 +304,15 @@ static enum ice_media_type ice_get_media_type(struct ice_port_info *pi)
                case ICE_PHY_TYPE_LOW_100GBASE_SR2:
                case ICE_PHY_TYPE_LOW_100GBASE_DR:
                        return ICE_MEDIA_FIBER;
+               case ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
+               case ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
+               case ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC:
+               case ICE_PHY_TYPE_LOW_50G_LAUI2_AOC_ACC:
+               case ICE_PHY_TYPE_LOW_50G_AUI2_AOC_ACC:
+               case ICE_PHY_TYPE_LOW_50G_AUI1_AOC_ACC:
+               case ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC:
+               case ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC:
+                       return ICE_MEDIA_FIBER;
                case ICE_PHY_TYPE_LOW_100BASE_TX:
                case ICE_PHY_TYPE_LOW_1000BASE_T:
                case ICE_PHY_TYPE_LOW_2500BASE_T:
@@ -233,6 +331,16 @@ static enum ice_media_type ice_get_media_type(struct ice_port_info *pi)
                case ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4:
                case ICE_PHY_TYPE_LOW_100GBASE_CP2:
                        return ICE_MEDIA_DA;
+               case ICE_PHY_TYPE_LOW_25G_AUI_C2C:
+               case ICE_PHY_TYPE_LOW_40G_XLAUI:
+               case ICE_PHY_TYPE_LOW_50G_LAUI2:
+               case ICE_PHY_TYPE_LOW_50G_AUI2:
+               case ICE_PHY_TYPE_LOW_50G_AUI1:
+               case ICE_PHY_TYPE_LOW_100G_AUI4:
+               case ICE_PHY_TYPE_LOW_100G_CAUI4:
+                       if (ice_is_media_cage_present(pi))
+                               return ICE_MEDIA_AUI;
+                       /* fall-through */
                case ICE_PHY_TYPE_LOW_1000BASE_KX:
                case ICE_PHY_TYPE_LOW_2500BASE_KX:
                case ICE_PHY_TYPE_LOW_2500BASE_X:
@@ -250,8 +358,16 @@ static enum ice_media_type ice_get_media_type(struct ice_port_info *pi)
                }
        } else {
                switch (hw_link_info->phy_type_high) {
+               case ICE_PHY_TYPE_HIGH_100G_AUI2:
+               case ICE_PHY_TYPE_HIGH_100G_CAUI2:
+                       if (ice_is_media_cage_present(pi))
+                               return ICE_MEDIA_AUI;
+                       /* fall-through */
                case ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4:
                        return ICE_MEDIA_BACKPLANE;
+               case ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC:
+               case ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC:
+                       return ICE_MEDIA_FIBER;
                }
        }
        return ICE_MEDIA_UNKNOWN;
@@ -331,18 +447,21 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
 
        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",
+       ice_debug(hw, ICE_DBG_LINK, "get link info\n");
+       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",
+       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);
+       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, "   fec_info = 0x%x\n", li->fec_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)
@@ -355,85 +474,40 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
 }
 
 /**
- * ice_init_flex_flags
- * @hw: pointer to the hardware structure
- * @prof_id: Rx Descriptor Builder profile ID
+ * ice_fill_tx_timer_and_fc_thresh
+ * @hw: pointer to the HW struct
+ * @cmd: pointer to MAC cfg structure
  *
- * Function to initialize Rx flex flags
+ * Add Tx timer and FC refresh threshold info to Set MAC Config AQ command
+ * descriptor
  */
-static void ice_init_flex_flags(struct ice_hw *hw, enum ice_rxdid prof_id)
+static void
+ice_fill_tx_timer_and_fc_thresh(struct ice_hw *hw,
+                               struct ice_aqc_set_mac_cfg *cmd)
 {
-       u8 idx = 0;
+       u16 fc_thres_val, tx_timer_val;
+       u32 val;
 
-       /* Flex-flag fields (0-2) are programmed with FLG64 bits with layout:
-        * flexiflags0[5:0] - TCP flags, is_packet_fragmented, is_packet_UDP_GRE
-        * flexiflags1[3:0] - Not used for flag programming
-        * flexiflags2[7:0] - Tunnel and VLAN types
-        * 2 invalid fields in last index
-        */
-       switch (prof_id) {
-       /* Rx flex flags are currently programmed for the NIC profiles only.
-        * Different flag bit programming configurations can be added per
-        * profile as needed.
+       /* We read back the transmit timer and fc threshold value of
+        * LFC. Thus, we will use index =
+        * PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_MAX_INDEX.
+        *
+        * Also, because we are opearating on transmit timer and fc
+        * threshold of LFC, we don't turn on any bit in tx_tmr_priority
         */
-       case ICE_RXDID_FLEX_NIC:
-       case ICE_RXDID_FLEX_NIC_2:
-               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_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:
-               ice_debug(hw, ICE_DBG_INIT,
-                         "Flag programming for profile ID %d not supported\n",
-                         prof_id);
-       }
-}
-
-/**
- * ice_init_flex_flds
- * @hw: pointer to the hardware structure
- * @prof_id: Rx Descriptor Builder profile ID
- *
- * Function to initialize flex descriptors
- */
-static void ice_init_flex_flds(struct ice_hw *hw, enum ice_rxdid prof_id)
-{
-       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_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_MDID_SRC_VSI : ICE_MDID_FLOW_ID_HIGH;
+#define IDX_OF_LFC PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_MAX_INDEX
 
-               ICE_PROG_FLEX_ENTRY(hw, prof_id, mdid, 3);
+       /* Retrieve the transmit timer */
+       val = rd32(hw, PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(IDX_OF_LFC));
+       tx_timer_val = val &
+               PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_M;
+       cmd->tx_tmr_value = CPU_TO_LE16(tx_timer_val);
 
-               ice_init_flex_flags(hw, prof_id);
-               break;
+       /* Retrieve the fc threshold */
+       val = rd32(hw, PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(IDX_OF_LFC));
+       fc_thres_val = val & PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_M;
 
-       default:
-               ice_debug(hw, ICE_DBG_INIT,
-                         "Field init for profile ID %d not supported\n",
-                         prof_id);
-       }
+       cmd->fc_refresh_threshold = CPU_TO_LE16(fc_thres_val);
 }
 
 /**
@@ -447,10 +521,8 @@ static void ice_init_flex_flds(struct ice_hw *hw, enum ice_rxdid prof_id)
 enum ice_status
 ice_aq_set_mac_cfg(struct ice_hw *hw, u16 max_frame_size, struct ice_sq_cd *cd)
 {
-       u16 fc_threshold_val, tx_timer_val;
        struct ice_aqc_set_mac_cfg *cmd;
        struct ice_aq_desc desc;
-       u32 reg_val;
 
        cmd = &desc.params.set_mac_cfg;
 
@@ -461,27 +533,7 @@ ice_aq_set_mac_cfg(struct ice_hw *hw, u16 max_frame_size, struct ice_sq_cd *cd)
 
        cmd->max_frame_size = CPU_TO_LE16(max_frame_size);
 
-       /* We read back the transmit timer and fc threshold value of
-        * LFC. Thus, we will use index =
-        * PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_MAX_INDEX.
-        *
-        * Also, because we are opearating on transmit timer and fc
-        * threshold of LFC, we don't turn on any bit in tx_tmr_priority
-        */
-#define IDX_OF_LFC PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_MAX_INDEX
-
-       /* Retrieve the transmit timer */
-       reg_val = rd32(hw,
-                      PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(IDX_OF_LFC));
-       tx_timer_val = reg_val &
-               PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_M;
-       cmd->tx_tmr_value = CPU_TO_LE16(tx_timer_val);
-
-       /* Retrieve the fc threshold */
-       reg_val = rd32(hw,
-                      PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(IDX_OF_LFC));
-       fc_threshold_val = reg_val & MAKEMASK(0xFFFF, 0);
-       cmd->fc_refresh_threshold = CPU_TO_LE16(fc_threshold_val);
+       ice_fill_tx_timer_and_fc_thresh(hw, cmd);
 
        return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
 }
@@ -490,40 +542,52 @@ ice_aq_set_mac_cfg(struct ice_hw *hw, u16 max_frame_size, struct ice_sq_cd *cd)
  * ice_init_fltr_mgmt_struct - initializes filter management list and locks
  * @hw: pointer to the HW struct
  */
-static enum ice_status ice_init_fltr_mgmt_struct(struct ice_hw *hw)
+enum ice_status ice_init_fltr_mgmt_struct(struct ice_hw *hw)
 {
        struct ice_switch_info *sw;
+       enum ice_status status;
 
        hw->switch_info = (struct ice_switch_info *)
                          ice_malloc(hw, sizeof(*hw->switch_info));
+
        sw = hw->switch_info;
 
        if (!sw)
                return ICE_ERR_NO_MEMORY;
 
        INIT_LIST_HEAD(&sw->vsi_list_map_head);
+       sw->prof_res_bm_init = 0;
 
-       return ice_init_def_sw_recp(hw);
+       status = ice_init_def_sw_recp(hw, &hw->switch_info->recp_list);
+       if (status) {
+               ice_free(hw, hw->switch_info);
+               return status;
+       }
+       return ICE_SUCCESS;
 }
 
 /**
- * ice_cleanup_fltr_mgmt_struct - cleanup filter management list and locks
+ * ice_cleanup_fltr_mgmt_single - clears single filter mngt struct
  * @hw: pointer to the HW struct
+ * @sw: pointer to switch info struct for which function clears filters
  */
-static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw)
+static void
+ice_cleanup_fltr_mgmt_single(struct ice_hw *hw, struct ice_switch_info *sw)
 {
-       struct ice_switch_info *sw = hw->switch_info;
        struct ice_vsi_list_map_info *v_pos_map;
        struct ice_vsi_list_map_info *v_tmp_map;
        struct ice_sw_recipe *recps;
        u8 i;
 
+       if (!sw)
+               return;
+
        LIST_FOR_EACH_ENTRY_SAFE(v_pos_map, v_tmp_map, &sw->vsi_list_map_head,
                                 ice_vsi_list_map_info, list_entry) {
                LIST_DEL(&v_pos_map->list_entry);
                ice_free(hw, v_pos_map);
        }
-       recps = hw->switch_info->recp_list;
+       recps = sw->recp_list;
        for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
                struct ice_recp_grp_entry *rg_entry, *tmprg_entry;
 
@@ -563,234 +627,25 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw)
                if (recps[i].root_buf)
                        ice_free(hw, recps[i].root_buf);
        }
-       ice_rm_all_sw_replay_rule_info(hw);
+       ice_rm_sw_replay_rule_info(hw, sw);
        ice_free(hw, sw->recp_list);
        ice_free(hw, sw);
 }
 
-#define ICE_FW_LOG_DESC_SIZE(n)        (sizeof(struct ice_aqc_fw_logging_data) + \
-       (((n) - 1) * sizeof(((struct ice_aqc_fw_logging_data *)0)->entry)))
-#define ICE_FW_LOG_DESC_SIZE_MAX       \
-       ICE_FW_LOG_DESC_SIZE(ICE_AQC_FW_LOG_ID_MAX)
-
-/**
- * ice_get_fw_log_cfg - get FW logging configuration
- * @hw: pointer to the HW struct
- */
-static enum ice_status ice_get_fw_log_cfg(struct ice_hw *hw)
-{
-       struct ice_aqc_fw_logging_data *config;
-       struct ice_aq_desc desc;
-       enum ice_status status;
-       u16 size;
-
-       size = ICE_FW_LOG_DESC_SIZE_MAX;
-       config = (struct ice_aqc_fw_logging_data *)ice_malloc(hw, size);
-       if (!config)
-               return ICE_ERR_NO_MEMORY;
-
-       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logging_info);
-
-       desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_BUF);
-       desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
-
-       status = ice_aq_send_cmd(hw, &desc, config, size, NULL);
-       if (!status) {
-               u16 i;
-
-               /* Save fw logging information into the HW structure */
-               for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {
-                       u16 v, m, flgs;
-
-                       v = LE16_TO_CPU(config->entry[i]);
-                       m = (v & ICE_AQC_FW_LOG_ID_M) >> ICE_AQC_FW_LOG_ID_S;
-                       flgs = (v & ICE_AQC_FW_LOG_EN_M) >> ICE_AQC_FW_LOG_EN_S;
-
-                       if (m < ICE_AQC_FW_LOG_ID_MAX)
-                               hw->fw_log.evnts[m].cur = flgs;
-               }
-       }
-
-       ice_free(hw, config);
-
-       return status;
-}
-
-/**
- * ice_cfg_fw_log - configure FW logging
- * @hw: pointer to the HW struct
- * @enable: enable certain FW logging events if true, disable all if false
- *
- * This function enables/disables the FW logging via Rx CQ events and a UART
- * port based on predetermined configurations. FW logging via the Rx CQ can be
- * enabled/disabled for individual PF's. However, FW logging via the UART can
- * only be enabled/disabled for all PFs on the same device.
- *
- * To enable overall FW logging, the "cq_en" and "uart_en" enable bits in
- * hw->fw_log need to be set accordingly, e.g. based on user-provided input,
- * before initializing the device.
- *
- * When re/configuring FW logging, callers need to update the "cfg" elements of
- * the hw->fw_log.evnts array with the desired logging event configurations for
- * modules of interest. When disabling FW logging completely, the callers can
- * just pass false in the "enable" parameter. On completion, the function will
- * update the "cur" element of the hw->fw_log.evnts array with the resulting
- * logging event configurations of the modules that are being re/configured. FW
- * logging modules that are not part of a reconfiguration operation retain their
- * previous states.
- *
- * Before resetting the device, it is recommended that the driver disables FW
- * logging before shutting down the control queue. When disabling FW logging
- * ("enable" = false), the latest configurations of FW logging events stored in
- * hw->fw_log.evnts[] are not overridden to allow them to be reconfigured after
- * a device reset.
- *
- * When enabling FW logging to emit log messages via the Rx CQ during the
- * device's initialization phase, a mechanism alternative to interrupt handlers
- * needs to be used to extract FW log messages from the Rx CQ periodically and
- * to prevent the Rx CQ from being full and stalling other types of control
- * messages from FW to SW. Interrupts are typically disabled during the device's
- * initialization phase.
- */
-static enum ice_status ice_cfg_fw_log(struct ice_hw *hw, bool enable)
-{
-       struct ice_aqc_fw_logging_data *data = NULL;
-       struct ice_aqc_fw_logging *cmd;
-       enum ice_status status = ICE_SUCCESS;
-       u16 i, chgs = 0, len = 0;
-       struct ice_aq_desc desc;
-       u8 actv_evnts = 0;
-       void *buf = NULL;
-
-       if (!hw->fw_log.cq_en && !hw->fw_log.uart_en)
-               return ICE_SUCCESS;
-
-       /* Disable FW logging only when the control queue is still responsive */
-       if (!enable &&
-           (!hw->fw_log.actv_evnts || !ice_check_sq_alive(hw, &hw->adminq)))
-               return ICE_SUCCESS;
-
-       /* Get current FW log settings */
-       status = ice_get_fw_log_cfg(hw);
-       if (status)
-               return status;
-
-       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logging);
-       cmd = &desc.params.fw_logging;
-
-       /* Indicate which controls are valid */
-       if (hw->fw_log.cq_en)
-               cmd->log_ctrl_valid |= ICE_AQC_FW_LOG_AQ_VALID;
-
-       if (hw->fw_log.uart_en)
-               cmd->log_ctrl_valid |= ICE_AQC_FW_LOG_UART_VALID;
-
-       if (enable) {
-               /* Fill in an array of entries with FW logging modules and
-                * logging events being reconfigured.
-                */
-               for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {
-                       u16 val;
-
-                       /* Keep track of enabled event types */
-                       actv_evnts |= hw->fw_log.evnts[i].cfg;
-
-                       if (hw->fw_log.evnts[i].cfg == hw->fw_log.evnts[i].cur)
-                               continue;
-
-                       if (!data) {
-                               data = (struct ice_aqc_fw_logging_data *)
-                                       ice_malloc(hw,
-                                                  ICE_FW_LOG_DESC_SIZE_MAX);
-                               if (!data)
-                                       return ICE_ERR_NO_MEMORY;
-                       }
-
-                       val = i << ICE_AQC_FW_LOG_ID_S;
-                       val |= hw->fw_log.evnts[i].cfg << ICE_AQC_FW_LOG_EN_S;
-                       data->entry[chgs++] = CPU_TO_LE16(val);
-               }
-
-               /* Only enable FW logging if at least one module is specified.
-                * If FW logging is currently enabled but all modules are not
-                * enabled to emit log messages, disable FW logging altogether.
-                */
-               if (actv_evnts) {
-                       /* Leave if there is effectively no change */
-                       if (!chgs)
-                               goto out;
-
-                       if (hw->fw_log.cq_en)
-                               cmd->log_ctrl |= ICE_AQC_FW_LOG_AQ_EN;
-
-                       if (hw->fw_log.uart_en)
-                               cmd->log_ctrl |= ICE_AQC_FW_LOG_UART_EN;
-
-                       buf = data;
-                       len = ICE_FW_LOG_DESC_SIZE(chgs);
-                       desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
-               }
-       }
-
-       status = ice_aq_send_cmd(hw, &desc, buf, len, NULL);
-       if (!status) {
-               /* Update the current configuration to reflect events enabled.
-                * hw->fw_log.cq_en and hw->fw_log.uart_en indicate if the FW
-                * logging mode is enabled for the device. They do not reflect
-                * actual modules being enabled to emit log messages. So, their
-                * values remain unchanged even when all modules are disabled.
-                */
-               u16 cnt = enable ? chgs : (u16)ICE_AQC_FW_LOG_ID_MAX;
-
-               hw->fw_log.actv_evnts = actv_evnts;
-               for (i = 0; i < cnt; i++) {
-                       u16 v, m;
-
-                       if (!enable) {
-                               /* When disabling all FW logging events as part
-                                * of device's de-initialization, the original
-                                * configurations are retained, and can be used
-                                * to reconfigure FW logging later if the device
-                                * is re-initialized.
-                                */
-                               hw->fw_log.evnts[i].cur = 0;
-                               continue;
-                       }
-
-                       v = LE16_TO_CPU(data->entry[i]);
-                       m = (v & ICE_AQC_FW_LOG_ID_M) >> ICE_AQC_FW_LOG_ID_S;
-                       hw->fw_log.evnts[m].cur = hw->fw_log.evnts[m].cfg;
-               }
-       }
-
-out:
-       if (data)
-               ice_free(hw, data);
-
-       return status;
-}
-
 /**
- * ice_output_fw_log
+ * ice_cleanup_all_fltr_mgmt - cleanup filter management list and locks
  * @hw: pointer to the HW struct
- * @desc: pointer to the AQ message descriptor
- * @buf: pointer to the buffer accompanying the AQ message
- *
- * Formats a FW Log message and outputs it via the standard driver logs.
  */
-void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf)
+void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw)
 {
-       ice_debug(hw, ICE_DBG_FW_LOG, "[ FW Log Msg Start ]\n");
-       ice_debug_array(hw, ICE_DBG_FW_LOG, 16, 1, (u8 *)buf,
-                       LE16_TO_CPU(desc->datalen));
-       ice_debug(hw, ICE_DBG_FW_LOG, "[ FW Log Msg End ]\n");
+       ice_cleanup_fltr_mgmt_single(hw, hw->switch_info);
 }
 
 /**
- * ice_get_itr_intrl_gran - determine int/intrl granularity
+ * ice_get_itr_intrl_gran
  * @hw: pointer to the HW struct
  *
- * Determines the itr/intrl granularities based on the maximum aggregate
+ * Determines the ITR/INTRL granularities based on the maximum aggregate
  * bandwidth according to the device's configuration during power-on.
  */
 static void ice_get_itr_intrl_gran(struct ice_hw *hw)
@@ -813,6 +668,27 @@ static void ice_get_itr_intrl_gran(struct ice_hw *hw)
        }
 }
 
+/**
+ * ice_print_rollback_msg - print FW rollback message
+ * @hw: pointer to the hardware structure
+ */
+void ice_print_rollback_msg(struct ice_hw *hw)
+{
+       char nvm_str[ICE_NVM_VER_LEN] = { 0 };
+       struct ice_orom_info *orom;
+       struct ice_nvm_info *nvm;
+
+       orom = &hw->flash.orom;
+       nvm = &hw->flash.nvm;
+
+       SNPRINTF(nvm_str, sizeof(nvm_str), "%x.%02x 0x%x %d.%d.%d",
+                nvm->major, nvm->minor, nvm->eetrack, orom->major,
+                orom->build, orom->patch);
+       ice_warn(hw,
+                "Firmware rollback mode detected. Current version is NVM: %s, FW: %d.%d. Device may exhibit limited functionality. Refer to the Intel(R) Ethernet Adapters and Devices User Guide for details on firmware rollback mode\n",
+                nvm_str, hw->fw_maj_ver, hw->fw_min_ver);
+}
+
 /**
  * ice_init_hw - main hardware initialization routine
  * @hw: pointer to the hardware structure
@@ -826,7 +702,6 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
 
        ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
 
-
        /* Set MAC type based on DeviceID */
        status = ice_set_mac_type(hw);
        if (status)
@@ -836,22 +711,22 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
                         PF_FUNC_RID_FUNCTION_NUMBER_M) >>
                PF_FUNC_RID_FUNCTION_NUMBER_S;
 
-
        status = ice_reset(hw, ICE_RESET_PFR);
        if (status)
                return status;
 
        ice_get_itr_intrl_gran(hw);
 
-
        status = ice_create_all_ctrlq(hw);
        if (status)
                goto err_unroll_cqinit;
 
-       /* Enable FW logging. Not fatal if this fails. */
-       status = ice_cfg_fw_log(hw, true);
+       status = ice_init_nvm(hw);
        if (status)
-               ice_debug(hw, ICE_DBG_INIT, "Failed to enable FW logging.\n");
+               goto err_unroll_cqinit;
+
+       if (ice_get_fw_mode(hw) == ICE_FW_MODE_ROLLBACK)
+               ice_print_rollback_msg(hw);
 
        status = ice_clear_pf_cfg(hw);
        if (status)
@@ -863,10 +738,6 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
 
        ice_clear_pxe_mode(hw);
 
-       status = ice_init_nvm(hw);
-       if (status)
-               goto err_unroll_cqinit;
-
        status = ice_get_caps(hw);
        if (status)
                goto err_unroll_cqinit;
@@ -887,21 +758,18 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
                goto err_unroll_alloc;
 
        hw->evb_veb = true;
-
        /* Query the allocated resources for Tx scheduler */
        status = ice_sched_query_res_alloc(hw);
        if (status) {
-               ice_debug(hw, ICE_DBG_SCHED,
-                         "Failed to get scheduler allocated resources\n");
+               ice_debug(hw, ICE_DBG_SCHED, "Failed to get scheduler allocated resources\n");
                goto err_unroll_alloc;
        }
-
+       ice_sched_get_psm_clk_freq(hw);
 
        /* Initialize port_info struct with scheduler data */
        status = ice_sched_init_port(hw->port_info);
        if (status)
                goto err_unroll_sched;
-
        pcaps = (struct ice_aqc_get_phy_caps_data *)
                ice_malloc(hw, sizeof(*pcaps));
        if (!pcaps) {
@@ -914,7 +782,7 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
                                     ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
        ice_free(hw, pcaps);
        if (status)
-               goto err_unroll_sched;
+               ice_debug(hw, ICE_DBG_PHY, "Get PHY capabilities failed, continuing anyway\n");
 
        /* Initialize port_info struct with link information */
        status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
@@ -930,12 +798,10 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
        /* Initialize max burst size */
        if (!hw->max_burst_size)
                ice_cfg_rl_burst_size(hw, ICE_SCHED_DFLT_BURST_SIZE);
-
        status = ice_init_fltr_mgmt_struct(hw);
        if (status)
                goto err_unroll_sched;
 
-
        /* Get MAC information */
        /* A single port can report up to two (LAN and WoL) addresses */
        mac_buf = ice_calloc(hw, 2,
@@ -952,9 +818,10 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
 
        if (status)
                goto err_unroll_fltr_mgmt_struct;
-
-       ice_init_flex_flds(hw, ICE_RXDID_FLEX_NIC);
-       ice_init_flex_flds(hw, ICE_RXDID_FLEX_NIC_2);
+       /* enable jumbo frame support at MAC level */
+       status = ice_aq_set_mac_cfg(hw, ICE_AQ_SET_MAC_FRAME_SIZE_MAX, NULL);
+       if (status)
+               goto err_unroll_fltr_mgmt_struct;
        /* Obtain counter base index which would be used by flow director */
        status = ice_alloc_fd_res_cntr(hw, &hw->fd_ctr_base);
        if (status)
@@ -962,6 +829,7 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
        status = ice_init_hw_tbls(hw);
        if (status)
                goto err_unroll_fltr_mgmt_struct;
+       ice_init_lock(&hw->tnl_lock);
        return ICE_SUCCESS;
 
 err_unroll_fltr_mgmt_struct:
@@ -993,14 +861,13 @@ void ice_deinit_hw(struct ice_hw *hw)
        ice_sched_clear_agg(hw);
        ice_free_seg(hw);
        ice_free_hw_tbls(hw);
+       ice_destroy_lock(&hw->tnl_lock);
 
        if (hw->port_info) {
                ice_free(hw, hw->port_info);
                hw->port_info = NULL;
        }
 
-       /* Attempt to disable FW logging before shutting down control queues */
-       ice_cfg_fw_log(hw, false);
        ice_destroy_all_ctrlq(hw);
 
        /* Clear VSI contexts if not already cleared */
@@ -1013,48 +880,49 @@ void ice_deinit_hw(struct ice_hw *hw)
  */
 enum ice_status ice_check_reset(struct ice_hw *hw)
 {
-       u32 cnt, reg = 0, grst_delay;
+       u32 cnt, reg = 0, grst_timeout, uld_mask;
 
        /* Poll for Device Active state in case a recent CORER, GLOBR,
         * or EMPR has occurred. The grst delay value is in 100ms units.
         * Add 1sec for outstanding AQ commands that can take a long time.
         */
-#define GLGEN_RSTCTL           0x000B8180 /* Reset Source: POR */
-#define GLGEN_RSTCTL_GRSTDEL_S 0
-#define GLGEN_RSTCTL_GRSTDEL_M MAKEMASK(0x3F, GLGEN_RSTCTL_GRSTDEL_S)
-       grst_delay = ((rd32(hw, GLGEN_RSTCTL) & GLGEN_RSTCTL_GRSTDEL_M) >>
-                     GLGEN_RSTCTL_GRSTDEL_S) + 10;
+       grst_timeout = ((rd32(hw, GLGEN_RSTCTL) & GLGEN_RSTCTL_GRSTDEL_M) >>
+                       GLGEN_RSTCTL_GRSTDEL_S) + 10;
 
-       for (cnt = 0; cnt < grst_delay; cnt++) {
+       for (cnt = 0; cnt < grst_timeout; cnt++) {
                ice_msec_delay(100, true);
                reg = rd32(hw, GLGEN_RSTAT);
                if (!(reg & GLGEN_RSTAT_DEVSTATE_M))
                        break;
        }
 
-       if (cnt == grst_delay) {
-               ice_debug(hw, ICE_DBG_INIT,
-                         "Global reset polling failed to complete.\n");
+       if (cnt == grst_timeout) {
+               ice_debug(hw, ICE_DBG_INIT, "Global reset polling failed to complete.\n");
                return ICE_ERR_RESET_FAILED;
        }
 
-#define ICE_RESET_DONE_MASK    (GLNVM_ULD_CORER_DONE_M | \
-                                GLNVM_ULD_GLOBR_DONE_M)
+#define ICE_RESET_DONE_MASK    (GLNVM_ULD_PCIER_DONE_M |\
+                                GLNVM_ULD_PCIER_DONE_1_M |\
+                                GLNVM_ULD_CORER_DONE_M |\
+                                GLNVM_ULD_GLOBR_DONE_M |\
+                                GLNVM_ULD_POR_DONE_M |\
+                                GLNVM_ULD_POR_DONE_1_M |\
+                                GLNVM_ULD_PCIER_DONE_2_M)
+
+       uld_mask = ICE_RESET_DONE_MASK;
 
        /* Device is Active; check Global Reset processes are done */
        for (cnt = 0; cnt < ICE_PF_RESET_WAIT_COUNT; cnt++) {
-               reg = rd32(hw, GLNVM_ULD) & ICE_RESET_DONE_MASK;
-               if (reg == ICE_RESET_DONE_MASK) {
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "Global reset processes done. %d\n", cnt);
+               reg = rd32(hw, GLNVM_ULD) & uld_mask;
+               if (reg == uld_mask) {
+                       ice_debug(hw, ICE_DBG_INIT, "Global reset processes done. %d\n", cnt);
                        break;
                }
                ice_msec_delay(10, true);
        }
 
        if (cnt == ICE_PF_RESET_WAIT_COUNT) {
-               ice_debug(hw, ICE_DBG_INIT,
-                         "Wait for Reset Done timed out. GLNVM_ULD = 0x%x\n",
+               ice_debug(hw, ICE_DBG_INIT, "Wait for Reset Done timed out. GLNVM_ULD = 0x%x\n",
                          reg);
                return ICE_ERR_RESET_FAILED;
        }
@@ -1092,7 +960,12 @@ static enum ice_status ice_pf_reset(struct ice_hw *hw)
 
        wr32(hw, PFGEN_CTRL, (reg | PFGEN_CTRL_PFSWR_M));
 
-       for (cnt = 0; cnt < ICE_PF_RESET_WAIT_COUNT; cnt++) {
+       /* Wait for the PFR to complete. The wait time is the global config lock
+        * timeout plus the PFR timeout which will account for a possible reset
+        * that is occurring during a download package operation.
+        */
+       for (cnt = 0; cnt < ICE_GLOBAL_CFG_LOCK_TIMEOUT +
+            ICE_PF_RESET_WAIT_COUNT; cnt++) {
                reg = rd32(hw, PFGEN_CTRL);
                if (!(reg & PFGEN_CTRL_PFSWR_M))
                        break;
@@ -1101,8 +974,7 @@ static enum ice_status ice_pf_reset(struct ice_hw *hw)
        }
 
        if (cnt == ICE_PF_RESET_WAIT_COUNT) {
-               ice_debug(hw, ICE_DBG_INIT,
-                         "PF reset polling failed to complete.\n");
+               ice_debug(hw, ICE_DBG_INIT, "PF reset polling failed to complete.\n");
                return ICE_ERR_RESET_FAILED;
        }
 
@@ -1144,13 +1016,10 @@ enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req)
        wr32(hw, GLGEN_RTRIG, val);
        ice_flush(hw);
 
-
        /* wait for the FW to be ready */
        return ice_check_reset(hw);
 }
 
-
-
 /**
  * ice_copy_rxq_ctx_to_hw
  * @hw: pointer to the hardware structure
@@ -1229,11 +1098,10 @@ ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
 
        rlan_ctx->prefena = 1;
 
-       ice_set_ctx((u8 *)rlan_ctx, ctx_buf, ice_rlan_ctx_info);
+       ice_set_ctx(hw, (u8 *)rlan_ctx, ctx_buf, ice_rlan_ctx_info);
        return ice_copy_rxq_ctx_to_hw(hw, ctx_buf, rxq_index);
 }
 
-#if !defined(NO_UNUSED_CTX_CODE) || defined(AE_DRIVER)
 /**
  * ice_clear_rxq_ctx
  * @hw: pointer to the hardware structure
@@ -1254,7 +1122,6 @@ enum ice_status ice_clear_rxq_ctx(struct ice_hw *hw, u32 rxq_index)
 
        return ICE_SUCCESS;
 }
-#endif /* !NO_UNUSED_CTX_CODE || AE_DRIVER */
 
 /* LAN Tx Queue Context */
 const struct ice_ctx_ele ice_tlan_ctx_info[] = {
@@ -1290,7 +1157,6 @@ const struct ice_ctx_ele ice_tlan_ctx_info[] = {
        { 0 }
 };
 
-#if !defined(NO_UNUSED_CTX_CODE) || defined(AE_DRIVER)
 /**
  * ice_copy_tx_cmpltnq_ctx_to_hw
  * @hw: pointer to the hardware structure
@@ -1355,7 +1221,7 @@ ice_write_tx_cmpltnq_ctx(struct ice_hw *hw,
 {
        u8 ctx_buf[ICE_TX_CMPLTNQ_CTX_SIZE_DWORDS * sizeof(u32)] = { 0 };
 
-       ice_set_ctx((u8 *)tx_cmpltnq_ctx, ctx_buf, ice_tx_cmpltnq_ctx_info);
+       ice_set_ctx(hw, (u8 *)tx_cmpltnq_ctx, ctx_buf, ice_tx_cmpltnq_ctx_info);
        return ice_copy_tx_cmpltnq_ctx_to_hw(hw, ctx_buf, tx_cmpltnq_index);
 }
 
@@ -1446,7 +1312,8 @@ ice_write_tx_drbell_q_ctx(struct ice_hw *hw,
 {
        u8 ctx_buf[ICE_TX_DRBELL_Q_CTX_SIZE_DWORDS * sizeof(u32)] = { 0 };
 
-       ice_set_ctx((u8 *)tx_drbell_q_ctx, ctx_buf, ice_tx_drbell_q_ctx_info);
+       ice_set_ctx(hw, (u8 *)tx_drbell_q_ctx, ctx_buf,
+                   ice_tx_drbell_q_ctx_info);
        return ice_copy_tx_drbell_q_ctx_to_hw(hw, ctx_buf, tx_drbell_q_index);
 }
 
@@ -1471,8 +1338,6 @@ ice_clear_tx_drbell_q_ctx(struct ice_hw *hw, u32 tx_drbell_q_index)
 
        return ICE_SUCCESS;
 }
-#endif /* !NO_UNUSED_CTX_CODE || AE_DRIVER */
-
 
 /* FW Admin Queue command wrappers */
 
@@ -1490,6 +1355,28 @@ enum ice_status
 ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf,
                u16 buf_size, struct ice_sq_cd *cd)
 {
+       if (hw->aq_send_cmd_fn) {
+               enum ice_status status = ICE_ERR_NOT_READY;
+               u16 retval = ICE_AQ_RC_OK;
+
+               ice_acquire_lock(&hw->adminq.sq_lock);
+               if (!hw->aq_send_cmd_fn(hw->aq_send_cmd_param, desc,
+                                       buf, buf_size)) {
+                       retval = LE16_TO_CPU(desc->retval);
+                       /* strip off FW internal code */
+                       if (retval)
+                               retval &= 0xff;
+                       if (retval == ICE_AQ_RC_OK)
+                               status = ICE_SUCCESS;
+                       else
+                               status = ICE_ERR_AQ_ERROR;
+               }
+
+               hw->adminq.sq_last_status = (enum ice_aq_err)retval;
+               ice_release_lock(&hw->adminq.sq_lock);
+
+               return status;
+       }
        return ice_sq_send_cmd(hw, &hw->adminq, desc, buf, buf_size, cd);
 }
 
@@ -1734,8 +1621,7 @@ ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
                goto ice_acquire_res_exit;
 
        if (status)
-               ice_debug(hw, ICE_DBG_RES,
-                         "resource %d acquire type %d failed.\n", res, access);
+               ice_debug(hw, ICE_DBG_RES, "resource %d acquire type %d failed.\n", res, access);
 
        /* If necessary, poll until the current lock owner timeouts */
        timeout = time_left;
@@ -1758,11 +1644,9 @@ ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
 ice_acquire_res_exit:
        if (status == ICE_ERR_AQ_NO_WORK) {
                if (access == ICE_RES_WRITE)
-                       ice_debug(hw, ICE_DBG_RES,
-                                 "resource indicates no work to do.\n");
+                       ice_debug(hw, ICE_DBG_RES, "resource indicates no work to do.\n");
                else
-                       ice_debug(hw, ICE_DBG_RES,
-                                 "Warning: ICE_ERR_AQ_NO_WORK not expected\n");
+                       ice_debug(hw, ICE_DBG_RES, "Warning: ICE_ERR_AQ_NO_WORK not expected\n");
        }
        return status;
 }
@@ -1847,9 +1731,8 @@ ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool btm, u16 *res)
        enum ice_status status;
        u16 buf_len;
 
-       buf_len = sizeof(*buf) + sizeof(buf->elem) * (num - 1);
-       buf = (struct ice_aqc_alloc_free_res_elem *)
-               ice_malloc(hw, buf_len);
+       buf_len = ice_struct_size(buf, elem, num);
+       buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len);
        if (!buf)
                return ICE_ERR_NO_MEMORY;
 
@@ -1865,7 +1748,7 @@ ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool btm, u16 *res)
        if (status)
                goto ice_alloc_res_exit;
 
-       ice_memcpy(res, buf->elem, sizeof(buf->elem) * num,
+       ice_memcpy(res, buf->elem, sizeof(*buf->elem) * num,
                   ICE_NONDMA_TO_NONDMA);
 
 ice_alloc_res_exit:
@@ -1880,14 +1763,13 @@ ice_alloc_res_exit:
  * @num: number of resources
  * @res: pointer to array that contains the resources to free
  */
-enum ice_status
-ice_free_hw_res(struct ice_hw *hw, u16 type, u16 num, u16 *res)
+enum ice_status ice_free_hw_res(struct ice_hw *hw, u16 type, u16 num, u16 *res)
 {
        struct ice_aqc_alloc_free_res_elem *buf;
        enum ice_status status;
        u16 buf_len;
 
-       buf_len = sizeof(*buf) + sizeof(buf->elem) * (num - 1);
+       buf_len = ice_struct_size(buf, elem, num);
        buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len);
        if (!buf)
                return ICE_ERR_NO_MEMORY;
@@ -1895,7 +1777,7 @@ ice_free_hw_res(struct ice_hw *hw, u16 type, u16 num, u16 *res)
        /* Prepare buffer to free resource. */
        buf->num_elems = CPU_TO_LE16(num);
        buf->res_type = CPU_TO_LE16(type);
-       ice_memcpy(buf->elem, res, sizeof(buf->elem) * num,
+       ice_memcpy(buf->elem, res, sizeof(*buf->elem) * num,
                   ICE_NONDMA_TO_NONDMA);
 
        status = ice_aq_alloc_free_res(hw, num, buf, buf_len,
@@ -1931,195 +1813,343 @@ static u32 ice_get_num_per_func(struct ice_hw *hw, u32 max)
 }
 
 /**
- * ice_parse_caps - parse function/device capabilities
+ * ice_parse_common_caps - parse common device/function capabilities
  * @hw: pointer to the HW struct
- * @buf: pointer to a buffer containing function/device capability records
- * @cap_count: number of capability records in the list
- * @opc: type of capabilities list to parse
+ * @caps: pointer to common capabilities structure
+ * @elem: the capability element to parse
+ * @prefix: message prefix for tracing capabilities
+ *
+ * Given a capability element, extract relevant details into the common
+ * capability structure.
  *
- * Helper function to parse function(0x000a)/device(0x000b) capabilities list.
+ * Returns: true if the capability matches one of the common capability ids,
+ * false otherwise.
  */
-static void
-ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
-              enum ice_adminq_opc opc)
+static bool
+ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps,
+                     struct ice_aqc_list_caps_elem *elem, const char *prefix)
 {
-       struct ice_aqc_list_caps_elem *cap_resp;
-       struct ice_hw_func_caps *func_p = NULL;
-       struct ice_hw_dev_caps *dev_p = NULL;
-       struct ice_hw_common_caps *caps;
-       char const *prefix;
-       u32 i;
-
-       if (!buf)
-               return;
+       u32 logical_id = LE32_TO_CPU(elem->logical_id);
+       u32 phys_id = LE32_TO_CPU(elem->phys_id);
+       u32 number = LE32_TO_CPU(elem->number);
+       u16 cap = LE16_TO_CPU(elem->cap);
+       bool found = true;
+
+       switch (cap) {
+       case ICE_AQC_CAPS_VALID_FUNCTIONS:
+               caps->valid_functions = number;
+               ice_debug(hw, ICE_DBG_INIT, "%s: valid_functions (bitmap) = %d\n", prefix,
+                         caps->valid_functions);
+               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, "%s: dcb = %d\n", prefix, caps->dcb);
+               ice_debug(hw, ICE_DBG_INIT, "%s: active_tc_bitmap = %d\n", prefix,
+                         caps->active_tc_bitmap);
+               ice_debug(hw, ICE_DBG_INIT, "%s: maxtc = %d\n", prefix, caps->maxtc);
+               break;
+       case ICE_AQC_CAPS_RSS:
+               caps->rss_table_size = number;
+               caps->rss_table_entry_width = logical_id;
+               ice_debug(hw, ICE_DBG_INIT, "%s: rss_table_size = %d\n", prefix,
+                         caps->rss_table_size);
+               ice_debug(hw, ICE_DBG_INIT, "%s: rss_table_entry_width = %d\n", prefix,
+                         caps->rss_table_entry_width);
+               break;
+       case ICE_AQC_CAPS_RXQS:
+               caps->num_rxq = number;
+               caps->rxq_first_id = phys_id;
+               ice_debug(hw, ICE_DBG_INIT, "%s: num_rxq = %d\n", prefix,
+                         caps->num_rxq);
+               ice_debug(hw, ICE_DBG_INIT, "%s: rxq_first_id = %d\n", prefix,
+                         caps->rxq_first_id);
+               break;
+       case ICE_AQC_CAPS_TXQS:
+               caps->num_txq = number;
+               caps->txq_first_id = phys_id;
+               ice_debug(hw, ICE_DBG_INIT, "%s: num_txq = %d\n", prefix,
+                         caps->num_txq);
+               ice_debug(hw, ICE_DBG_INIT, "%s: txq_first_id = %d\n", prefix,
+                         caps->txq_first_id);
+               break;
+       case ICE_AQC_CAPS_MSIX:
+               caps->num_msix_vectors = number;
+               caps->msix_vector_first_id = phys_id;
+               ice_debug(hw, ICE_DBG_INIT, "%s: num_msix_vectors = %d\n", prefix,
+                         caps->num_msix_vectors);
+               ice_debug(hw, ICE_DBG_INIT, "%s: msix_vector_first_id = %d\n", prefix,
+                         caps->msix_vector_first_id);
+               break;
+       case ICE_AQC_CAPS_MAX_MTU:
+               caps->max_mtu = number;
+               ice_debug(hw, ICE_DBG_INIT, "%s: max_mtu = %d\n",
+                         prefix, caps->max_mtu);
+               break;
+       default:
+               /* Not one of the recognized common capabilities */
+               found = false;
+       }
 
-       cap_resp = (struct ice_aqc_list_caps_elem *)buf;
+       return found;
+}
 
-       if (opc == ice_aqc_opc_list_dev_caps) {
-               dev_p = &hw->dev_caps;
-               caps = &dev_p->common_cap;
-               prefix = "dev cap";
-       } else if (opc == ice_aqc_opc_list_func_caps) {
-               func_p = &hw->func_caps;
-               caps = &func_p->common_cap;
-               prefix = "func cap";
-       } else {
-               ice_debug(hw, ICE_DBG_INIT, "wrong opcode\n");
-               return;
+/**
+ * ice_recalc_port_limited_caps - Recalculate port limited capabilities
+ * @hw: pointer to the HW structure
+ * @caps: pointer to capabilities structure to fix
+ *
+ * Re-calculate the capabilities that are dependent on the number of physical
+ * ports; i.e. some features are not supported or function differently on
+ * devices with more than 4 ports.
+ */
+static void
+ice_recalc_port_limited_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps)
+{
+       /* This assumes device capabilities are always scanned before function
+        * capabilities during the initialization flow.
+        */
+       if (hw->dev_caps.num_funcs > 4) {
+               /* Max 4 TCs per port */
+               caps->maxtc = 4;
+               ice_debug(hw, ICE_DBG_INIT, "reducing maxtc to %d (based on #ports)\n",
+                         caps->maxtc);
        }
+}
 
-       for (i = 0; caps && i < cap_count; i++, cap_resp++) {
-               u32 logical_id = LE32_TO_CPU(cap_resp->logical_id);
-               u32 phys_id = LE32_TO_CPU(cap_resp->phys_id);
-               u32 number = LE32_TO_CPU(cap_resp->number);
-               u16 cap = LE16_TO_CPU(cap_resp->cap);
-
-               switch (cap) {
-               case ICE_AQC_CAPS_VALID_FUNCTIONS:
-                       caps->valid_functions = number;
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: valid functions = %d\n", prefix,
-                                 caps->valid_functions);
-                       break;
+/**
+ * ice_parse_vsi_func_caps - Parse ICE_AQC_CAPS_VSI function caps
+ * @hw: pointer to the HW struct
+ * @func_p: pointer to function capabilities structure
+ * @cap: pointer to the capability element to parse
+ *
+ * Extract function capabilities for ICE_AQC_CAPS_VSI.
+ */
+static void
+ice_parse_vsi_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p,
+                       struct ice_aqc_list_caps_elem *cap)
+{
+       func_p->guar_num_vsi = ice_get_num_per_func(hw, ICE_MAX_VSI);
+       ice_debug(hw, ICE_DBG_INIT, "func caps: guar_num_vsi (fw) = %d\n",
+                 LE32_TO_CPU(cap->number));
+       ice_debug(hw, ICE_DBG_INIT, "func caps: guar_num_vsi = %d\n",
+                 func_p->guar_num_vsi);
+}
+
+/**
+ * ice_parse_fdir_func_caps - Parse ICE_AQC_CAPS_FD function caps
+ * @hw: pointer to the HW struct
+ * @func_p: pointer to function capabilities structure
+ *
+ * Extract function capabilities for ICE_AQC_CAPS_FD.
+ */
+static void
+ice_parse_fdir_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p)
+{
+       u32 reg_val, val;
+
+       if (hw->dcf_enabled)
+               return;
+       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, "func caps: fd_fltr_guar = %d\n",
+                 func_p->fd_fltr_guar);
+       ice_debug(hw, ICE_DBG_INIT, "func caps: fd_fltr_best_effort = %d\n",
+                 func_p->fd_fltr_best_effort);
+}
+
+/**
+ * ice_parse_func_caps - Parse function capabilities
+ * @hw: pointer to the HW struct
+ * @func_p: pointer to function capabilities structure
+ * @buf: buffer containing the function capability records
+ * @cap_count: the number of capabilities
+ *
+ * Helper function to parse function (0x000A) capabilities list. For
+ * capabilities shared between device and function, this relies on
+ * ice_parse_common_caps.
+ *
+ * Loop through the list of provided capabilities and extract the relevant
+ * data into the function capabilities structured.
+ */
+static void
+ice_parse_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p,
+                   void *buf, u32 cap_count)
+{
+       struct ice_aqc_list_caps_elem *cap_resp;
+       u32 i;
+
+       cap_resp = (struct ice_aqc_list_caps_elem *)buf;
+
+       ice_memset(func_p, 0, sizeof(*func_p), ICE_NONDMA_MEM);
+
+       for (i = 0; i < cap_count; i++) {
+               u16 cap = LE16_TO_CPU(cap_resp[i].cap);
+               bool found;
+
+               found = ice_parse_common_caps(hw, &func_p->common_cap,
+                                             &cap_resp[i], "func caps");
+
+               switch (cap) {
                case ICE_AQC_CAPS_VSI:
-                       if (dev_p) {
-                               dev_p->num_vsi_allocd_to_host = number;
-                               ice_debug(hw, ICE_DBG_INIT,
-                                         "%s: num VSI alloc to host = %d\n",
-                                         prefix,
-                                         dev_p->num_vsi_allocd_to_host);
-                       } else if (func_p) {
-                               func_p->guar_num_vsi =
-                                       ice_get_num_per_func(hw, ICE_MAX_VSI);
-                               ice_debug(hw, ICE_DBG_INIT,
-                                         "%s: num guaranteed VSI (fw) = %d\n",
-                                         prefix, number);
-                               ice_debug(hw, ICE_DBG_INIT,
-                                         "%s: num guaranteed VSI = %d\n",
-                                         prefix, func_p->guar_num_vsi);
-                       }
+                       ice_parse_vsi_func_caps(hw, func_p, &cap_resp[i]);
                        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,
-                                 "%s: DCB = %d\n", prefix, caps->dcb);
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: active TC bitmap = %d\n", prefix,
-                                 caps->active_tc_bitmap);
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: TC max = %d\n", prefix, caps->maxtc);
-                       break;
-               case ICE_AQC_CAPS_RSS:
-                       caps->rss_table_size = number;
-                       caps->rss_table_entry_width = logical_id;
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: RSS table size = %d\n", prefix,
-                                 caps->rss_table_size);
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: RSS table width = %d\n", prefix,
-                                 caps->rss_table_entry_width);
-                       break;
-               case ICE_AQC_CAPS_RXQS:
-                       caps->num_rxq = number;
-                       caps->rxq_first_id = phys_id;
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: num Rx queues = %d\n", prefix,
-                                 caps->num_rxq);
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: Rx first queue ID = %d\n", prefix,
-                                 caps->rxq_first_id);
+               case ICE_AQC_CAPS_FD:
+                       ice_parse_fdir_func_caps(hw, func_p);
                        break;
-               case ICE_AQC_CAPS_TXQS:
-                       caps->num_txq = number;
-                       caps->txq_first_id = phys_id;
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: num Tx queues = %d\n", prefix,
-                                 caps->num_txq);
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: Tx first queue ID = %d\n", prefix,
-                                 caps->txq_first_id);
+               default:
+                       /* Don't list common capabilities as unknown */
+                       if (!found)
+                               ice_debug(hw, ICE_DBG_INIT, "func caps: unknown capability[%d]: 0x%x\n",
+                                         i, cap);
                        break;
-               case ICE_AQC_CAPS_MSIX:
-                       caps->num_msix_vectors = number;
-                       caps->msix_vector_first_id = phys_id;
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: MSIX vector count = %d\n", prefix,
-                                 caps->num_msix_vectors);
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: MSIX first vector index = %d\n", prefix,
-                                 caps->msix_vector_first_id);
+               }
+       }
+
+       ice_recalc_port_limited_caps(hw, &func_p->common_cap);
+}
+
+/**
+ * ice_parse_valid_functions_cap - Parse ICE_AQC_CAPS_VALID_FUNCTIONS caps
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @cap: capability element to parse
+ *
+ * Parse ICE_AQC_CAPS_VALID_FUNCTIONS for device capabilities.
+ */
+static void
+ice_parse_valid_functions_cap(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
+                             struct ice_aqc_list_caps_elem *cap)
+{
+       u32 number = LE32_TO_CPU(cap->number);
+
+       dev_p->num_funcs = ice_hweight32(number);
+       ice_debug(hw, ICE_DBG_INIT, "dev caps: num_funcs = %d\n",
+                 dev_p->num_funcs);
+}
+
+/**
+ * ice_parse_vsi_dev_caps - Parse ICE_AQC_CAPS_VSI device caps
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @cap: capability element to parse
+ *
+ * Parse ICE_AQC_CAPS_VSI for device capabilities.
+ */
+static void
+ice_parse_vsi_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
+                      struct ice_aqc_list_caps_elem *cap)
+{
+       u32 number = LE32_TO_CPU(cap->number);
+
+       dev_p->num_vsi_allocd_to_host = number;
+       ice_debug(hw, ICE_DBG_INIT, "dev caps: num_vsi_allocd_to_host = %d\n",
+                 dev_p->num_vsi_allocd_to_host);
+}
+
+/**
+ * ice_parse_fdir_dev_caps - Parse ICE_AQC_CAPS_FD device caps
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @cap: capability element to parse
+ *
+ * Parse ICE_AQC_CAPS_FD for device capabilities.
+ */
+static void
+ice_parse_fdir_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
+                       struct ice_aqc_list_caps_elem *cap)
+{
+       u32 number = LE32_TO_CPU(cap->number);
+
+       dev_p->num_flow_director_fltr = number;
+       ice_debug(hw, ICE_DBG_INIT, "dev caps: num_flow_director_fltr = %d\n",
+                 dev_p->num_flow_director_fltr);
+}
+
+/**
+ * ice_parse_dev_caps - Parse device capabilities
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @buf: buffer containing the device capability records
+ * @cap_count: the number of capabilities
+ *
+ * Helper device to parse device (0x000B) capabilities list. For
+ * capabilities shared between device and function, this relies on
+ * ice_parse_common_caps.
+ *
+ * Loop through the list of provided capabilities and extract the relevant
+ * data into the device capabilities structured.
+ */
+static void
+ice_parse_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
+                  void *buf, u32 cap_count)
+{
+       struct ice_aqc_list_caps_elem *cap_resp;
+       u32 i;
+
+       cap_resp = (struct ice_aqc_list_caps_elem *)buf;
+
+       ice_memset(dev_p, 0, sizeof(*dev_p), ICE_NONDMA_MEM);
+
+       for (i = 0; i < cap_count; i++) {
+               u16 cap = LE16_TO_CPU(cap_resp[i].cap);
+               bool found;
+
+               found = ice_parse_common_caps(hw, &dev_p->common_cap,
+                                             &cap_resp[i], "dev caps");
+
+               switch (cap) {
+               case ICE_AQC_CAPS_VALID_FUNCTIONS:
+                       ice_parse_valid_functions_cap(hw, dev_p, &cap_resp[i]);
                        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,
-                                         "%s: num FD filters = %d\n", prefix,
-                                         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,
-                                         "%s: num guaranteed FD filters = %d\n",
-                                         prefix, func_p->fd_fltr_guar);
-                               ice_debug(hw, ICE_DBG_INIT,
-                                         "%s: num best effort FD filters = %d\n",
-                                         prefix, func_p->fd_fltr_best_effort);
-                       }
+               case ICE_AQC_CAPS_VSI:
+                       ice_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]);
                        break;
-               }
-               case ICE_AQC_CAPS_MAX_MTU:
-                       caps->max_mtu = number;
-                       ice_debug(hw, ICE_DBG_INIT, "%s: max MTU = %d\n",
-                                 prefix, caps->max_mtu);
+               case  ICE_AQC_CAPS_FD:
+                       ice_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]);
                        break;
                default:
-                       ice_debug(hw, ICE_DBG_INIT,
-                                 "%s: unknown capability[%d]: 0x%x\n", prefix,
-                                 i, cap);
+                       /* Don't list common capabilities as unknown */
+                       if (!found)
+                               ice_debug(hw, ICE_DBG_INIT, "dev caps: unknown capability[%d]: 0x%x\n",
+                                         i, cap);
                        break;
                }
        }
 
-       /* Re-calculate capabilities that are dependent on the number of
-        * physical ports; i.e. some features are not supported or function
-        * differently on devices with more than 4 ports.
-        */
-       if (caps && (ice_hweight32(caps->valid_functions) > 4)) {
-               /* Max 4 TCs per port */
-               caps->maxtc = 4;
-               ice_debug(hw, ICE_DBG_INIT,
-                         "%s: TC max = %d (based on #ports)\n", prefix,
-                         caps->maxtc);
-       }
+       ice_recalc_port_limited_caps(hw, &dev_p->common_cap);
 }
 
 /**
- * ice_aq_discover_caps - query function/device capabilities
+ * ice_aq_list_caps - query function/device capabilities
  * @hw: pointer to the HW struct
- * @buf: a virtual buffer to hold the capabilities
- * @buf_size: Size of the virtual buffer
- * @cap_count: cap count needed if AQ err==ENOMEM
- * @opc: capabilities type to discover - pass in the command opcode
+ * @buf: a buffer to hold the capabilities
+ * @buf_size: size of the buffer
+ * @cap_count: if not NULL, set to the number of capabilities reported
+ * @opc: capabilities type to discover, device or function
  * @cd: pointer to command details structure or NULL
  *
- * Get the function(0x000a)/device(0x000b) capabilities description from
- * the firmware.
+ * Get the function (0x000A) or device (0x000B) capabilities description from
+ * firmware and store it in the buffer.
+ *
+ * If the cap_count pointer is not NULL, then it is set to the number of
+ * capabilities firmware will report. Note that if the buffer size is too
+ * small, it is possible the command will return ICE_AQ_ERR_ENOMEM. The
+ * cap_count will still be updated in this case. It is recommended that the
+ * buffer size be set to ICE_AQ_MAX_BUF_LEN (the largest possible buffer that
+ * firmware could return) to avoid this.
  */
 static enum ice_status
-ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count,
-                    enum ice_adminq_opc opc, struct ice_sq_cd *cd)
+ice_aq_list_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count,
+                enum ice_adminq_opc opc, struct ice_sq_cd *cd)
 {
        struct ice_aqc_list_caps *cmd;
        struct ice_aq_desc desc;
@@ -2132,63 +2162,145 @@ ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count,
                return ICE_ERR_PARAM;
 
        ice_fill_dflt_direct_cmd_desc(&desc, opc);
-
        status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
-       if (!status)
-               ice_parse_caps(hw, buf, LE32_TO_CPU(cmd->count), opc);
-       else if (hw->adminq.sq_last_status == ICE_AQ_RC_ENOMEM)
+
+       if (cap_count)
                *cap_count = LE32_TO_CPU(cmd->count);
+
        return status;
 }
 
 /**
- * ice_discover_caps - get info about the HW
+ * ice_discover_dev_caps - Read and extract device capabilities
  * @hw: pointer to the hardware structure
- * @opc: capabilities type to discover - pass in the command opcode
+ * @dev_caps: pointer to device capabilities structure
+ *
+ * Read the device capabilities and extract them into the dev_caps structure
+ * for later use.
  */
 static enum ice_status
-ice_discover_caps(struct ice_hw *hw, enum ice_adminq_opc opc)
+ice_discover_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_caps)
 {
        enum ice_status status;
-       u32 cap_count;
-       u16 cbuf_len;
-       u8 retries;
-
-       /* The driver doesn't know how many capabilities the device will return
-        * so the buffer size required isn't known ahead of time. The driver
-        * starts with cbuf_len and if this turns out to be insufficient, the
-        * device returns ICE_AQ_RC_ENOMEM and also the cap_count it needs.
-        * The driver then allocates the buffer based on the count and retries
-        * the operation. So it follows that the retry count is 2.
+       u32 cap_count = 0;
+       void *cbuf;
+
+       cbuf = ice_malloc(hw, ICE_AQ_MAX_BUF_LEN);
+       if (!cbuf)
+               return ICE_ERR_NO_MEMORY;
+
+       /* Although the driver doesn't know the number of capabilities the
+        * device will return, we can simply send a 4KB buffer, the maximum
+        * possible size that firmware can return.
         */
-#define ICE_GET_CAP_BUF_COUNT  40
-#define ICE_GET_CAP_RETRY_COUNT        2
+       cap_count = ICE_AQ_MAX_BUF_LEN / sizeof(struct ice_aqc_list_caps_elem);
 
-       cap_count = ICE_GET_CAP_BUF_COUNT;
-       retries = ICE_GET_CAP_RETRY_COUNT;
+       status = ice_aq_list_caps(hw, cbuf, ICE_AQ_MAX_BUF_LEN, &cap_count,
+                                 ice_aqc_opc_list_dev_caps, NULL);
+       if (!status)
+               ice_parse_dev_caps(hw, dev_caps, cbuf, cap_count);
+       ice_free(hw, cbuf);
 
-       do {
-               void *cbuf;
+       return status;
+}
 
-               cbuf_len = (u16)(cap_count *
-                                sizeof(struct ice_aqc_list_caps_elem));
-               cbuf = ice_malloc(hw, cbuf_len);
-               if (!cbuf)
-                       return ICE_ERR_NO_MEMORY;
+/**
+ * ice_discover_func_caps - Read and extract function capabilities
+ * @hw: pointer to the hardware structure
+ * @func_caps: pointer to function capabilities structure
+ *
+ * Read the function capabilities and extract them into the func_caps structure
+ * for later use.
+ */
+static enum ice_status
+ice_discover_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_caps)
+{
+       enum ice_status status;
+       u32 cap_count = 0;
+       void *cbuf;
 
-               status = ice_aq_discover_caps(hw, cbuf, cbuf_len, &cap_count,
-                                             opc, NULL);
-               ice_free(hw, cbuf);
+       cbuf = ice_malloc(hw, ICE_AQ_MAX_BUF_LEN);
+       if (!cbuf)
+               return ICE_ERR_NO_MEMORY;
 
-               if (!status || hw->adminq.sq_last_status != ICE_AQ_RC_ENOMEM)
-                       break;
+       /* Although the driver doesn't know the number of capabilities the
+        * device will return, we can simply send a 4KB buffer, the maximum
+        * possible size that firmware can return.
+        */
+       cap_count = ICE_AQ_MAX_BUF_LEN / sizeof(struct ice_aqc_list_caps_elem);
 
-               /* If ENOMEM is returned, try again with bigger buffer */
-       } while (--retries);
+       status = ice_aq_list_caps(hw, cbuf, ICE_AQ_MAX_BUF_LEN, &cap_count,
+                                 ice_aqc_opc_list_func_caps, NULL);
+       if (!status)
+               ice_parse_func_caps(hw, func_caps, cbuf, cap_count);
+       ice_free(hw, cbuf);
 
        return status;
 }
 
+/**
+ * ice_set_safe_mode_caps - Override dev/func capabilities when in safe mode
+ * @hw: pointer to the hardware structure
+ */
+void ice_set_safe_mode_caps(struct ice_hw *hw)
+{
+       struct ice_hw_func_caps *func_caps = &hw->func_caps;
+       struct ice_hw_dev_caps *dev_caps = &hw->dev_caps;
+       struct ice_hw_common_caps cached_caps;
+       u32 num_funcs;
+
+       /* cache some func_caps values that should be restored after memset */
+       cached_caps = func_caps->common_cap;
+
+       /* unset func capabilities */
+       memset(func_caps, 0, sizeof(*func_caps));
+
+#define ICE_RESTORE_FUNC_CAP(name) \
+       func_caps->common_cap.name = cached_caps.name
+
+       /* restore cached values */
+       ICE_RESTORE_FUNC_CAP(valid_functions);
+       ICE_RESTORE_FUNC_CAP(txq_first_id);
+       ICE_RESTORE_FUNC_CAP(rxq_first_id);
+       ICE_RESTORE_FUNC_CAP(msix_vector_first_id);
+       ICE_RESTORE_FUNC_CAP(max_mtu);
+       ICE_RESTORE_FUNC_CAP(nvm_unified_update);
+
+       /* one Tx and one Rx queue in safe mode */
+       func_caps->common_cap.num_rxq = 1;
+       func_caps->common_cap.num_txq = 1;
+
+       /* two MSIX vectors, one for traffic and one for misc causes */
+       func_caps->common_cap.num_msix_vectors = 2;
+       func_caps->guar_num_vsi = 1;
+
+       /* cache some dev_caps values that should be restored after memset */
+       cached_caps = dev_caps->common_cap;
+       num_funcs = dev_caps->num_funcs;
+
+       /* unset dev capabilities */
+       memset(dev_caps, 0, sizeof(*dev_caps));
+
+#define ICE_RESTORE_DEV_CAP(name) \
+       dev_caps->common_cap.name = cached_caps.name
+
+       /* restore cached values */
+       ICE_RESTORE_DEV_CAP(valid_functions);
+       ICE_RESTORE_DEV_CAP(txq_first_id);
+       ICE_RESTORE_DEV_CAP(rxq_first_id);
+       ICE_RESTORE_DEV_CAP(msix_vector_first_id);
+       ICE_RESTORE_DEV_CAP(max_mtu);
+       ICE_RESTORE_DEV_CAP(nvm_unified_update);
+       dev_caps->num_funcs = num_funcs;
+
+       /* one Tx and one Rx queue per function in safe mode */
+       dev_caps->common_cap.num_rxq = num_funcs;
+       dev_caps->common_cap.num_txq = num_funcs;
+
+       /* two MSIX vectors per function */
+       dev_caps->common_cap.num_msix_vectors = 2 * num_funcs;
+}
+
 /**
  * ice_get_caps - get info about the HW
  * @hw: pointer to the hardware structure
@@ -2197,11 +2309,11 @@ enum ice_status ice_get_caps(struct ice_hw *hw)
 {
        enum ice_status status;
 
-       status = ice_discover_caps(hw, ice_aqc_opc_list_dev_caps);
-       if (!status)
-               status = ice_discover_caps(hw, ice_aqc_opc_list_func_caps);
+       status = ice_discover_dev_caps(hw, &hw->dev_caps);
+       if (status)
+               return status;
 
-       return status;
+       return ice_discover_func_caps(hw, &hw->func_caps);
 }
 
 /**
@@ -2224,11 +2336,7 @@ ice_aq_manage_mac_write(struct ice_hw *hw, const u8 *mac_addr, u8 flags,
        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_manage_mac_write);
 
        cmd->flags = flags;
-
-
-       /* Prep values for flags, sah, sal */
-       cmd->sah = HTONS(*((const u16 *)mac_addr));
-       cmd->sal = HTONL(*((const u32 *)(mac_addr + 2)));
+       ice_memcpy(cmd->mac_addr, mac_addr, ETH_ALEN, ICE_NONDMA_TO_DMA);
 
        return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
 }
@@ -2262,7 +2370,6 @@ void ice_clear_pxe_mode(struct ice_hw *hw)
                ice_aq_clear_pxe_mode(hw);
 }
 
-
 /**
  * ice_get_link_speed_based_on_phy_type - returns link speed
  * @phy_type_low: lower part of phy_type
@@ -2463,8 +2570,7 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, struct ice_port_info *pi,
 
        /* 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",
+               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;
@@ -2474,19 +2580,24 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, struct ice_port_info *pi,
        desc.params.set_phy.lport_num = pi->lport;
        desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
 
-       ice_debug(hw, ICE_DBG_LINK, "phy_type_low = 0x%llx\n",
+       ice_debug(hw, ICE_DBG_LINK, "set phy cfg\n");
+       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",
+       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);
+       ice_debug(hw, ICE_DBG_LINK, "   caps = 0x%x\n", cfg->caps);
+       ice_debug(hw, ICE_DBG_LINK, "   low_power_ctrl_an = 0x%x\n",
+                 cfg->low_power_ctrl_an);
+       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 (hw->adminq.sq_last_status == ICE_AQ_RC_EMODE)
+               status = ICE_SUCCESS;
+
        if (!status)
                pi->phy.curr_user_phy_cfg = *cfg;
 
@@ -2523,10 +2634,6 @@ enum ice_status ice_update_link_info(struct ice_port_info *pi)
 
                status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP,
                                             pcaps, NULL);
-               if (status == ICE_SUCCESS)
-                       ice_memcpy(li->module_type, &pcaps->module_type,
-                                  sizeof(li->module_type),
-                                  ICE_NONDMA_TO_NONDMA);
 
                ice_free(hw, pcaps);
        }
@@ -2567,33 +2674,95 @@ ice_cache_phy_user_req(struct ice_port_info *pi,
 }
 
 /**
- * ice_set_fc
- * @pi: port information structure
- * @aq_failures: pointer to status code, specific to ice_set_fc routine
- * @ena_auto_link_update: enable automatic link update
+ * ice_caps_to_fc_mode
+ * @caps: PHY capabilities
  *
- * Set the requested flow control mode.
+ * Convert PHY FC capabilities to ice FC mode
  */
-enum ice_status
-ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
+enum ice_fc_mode ice_caps_to_fc_mode(u8 caps)
+{
+       if (caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE &&
+           caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE)
+               return ICE_FC_FULL;
+
+       if (caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE)
+               return ICE_FC_TX_PAUSE;
+
+       if (caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE)
+               return ICE_FC_RX_PAUSE;
+
+       return ICE_FC_NONE;
+}
+
+/**
+ * ice_caps_to_fec_mode
+ * @caps: PHY capabilities
+ * @fec_options: Link FEC options
+ *
+ * Convert PHY FEC capabilities to ice FEC mode
+ */
+enum ice_fec_mode ice_caps_to_fec_mode(u8 caps, u8 fec_options)
+{
+       if (caps & ICE_AQC_PHY_EN_AUTO_FEC)
+               return ICE_FEC_AUTO;
+
+       if (fec_options & (ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN |
+                          ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ |
+                          ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN |
+                          ICE_AQC_PHY_FEC_25G_KR_REQ))
+               return ICE_FEC_BASER;
+
+       if (fec_options & (ICE_AQC_PHY_FEC_25G_RS_528_REQ |
+                          ICE_AQC_PHY_FEC_25G_RS_544_REQ |
+                          ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN))
+               return ICE_FEC_RS;
+
+       return ICE_FEC_NONE;
+}
+
+/**
+ * ice_cfg_phy_fc - Configure PHY FC data based on FC mode
+ * @pi: port information structure
+ * @cfg: PHY configuration data to set FC mode
+ * @req_mode: FC mode to configure
+ */
+static enum ice_status
+ice_cfg_phy_fc(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
+              enum ice_fc_mode req_mode)
 {
-       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;
-       struct ice_hw *hw;
 
-       if (!pi)
-               return ICE_ERR_PARAM;
-       hw = pi->hw;
-       *aq_failures = ICE_SET_FC_AQ_FAIL_NONE;
+       if (!pi || !cfg)
+               return ICE_ERR_BAD_PTR;
 
-       /* 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 (req_mode) {
+       case ICE_FC_AUTO:
+       {
+               struct ice_aqc_get_phy_caps_data *pcaps;
+               enum ice_status status;
+
+               pcaps = (struct ice_aqc_get_phy_caps_data *)
+                       ice_malloc(pi->hw, sizeof(*pcaps));
+               if (!pcaps)
+                       return ICE_ERR_NO_MEMORY;
 
-       switch (pi->fc.req_mode) {
+               /* Query the value of FC that both the NIC and attached media
+                * can do.
+                */
+               status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP,
+                                            pcaps, NULL);
+               if (status) {
+                       ice_free(pi->hw, pcaps);
+                       return status;
+               }
+
+               pause_mask |= pcaps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE;
+               pause_mask |= pcaps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE;
+
+               ice_free(pi->hw, pcaps);
+               break;
+       }
        case ICE_FC_FULL:
                pause_mask |= ICE_AQC_PHY_EN_TX_LINK_PAUSE;
                pause_mask |= ICE_AQC_PHY_EN_RX_LINK_PAUSE;
@@ -2608,6 +2777,42 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
                break;
        }
 
+       /* clear the old pause settings */
+       cfg->caps &= ~(ICE_AQC_PHY_EN_TX_LINK_PAUSE |
+               ICE_AQC_PHY_EN_RX_LINK_PAUSE);
+
+       /* set the new capabilities */
+       cfg->caps |= pause_mask;
+
+       /* Cache user FC request */
+       cache_data.data.curr_user_fc_req = req_mode;
+       ice_cache_phy_user_req(pi, cache_data, ICE_FC_MODE);
+
+       return ICE_SUCCESS;
+}
+
+/**
+ * ice_set_fc
+ * @pi: port information structure
+ * @aq_failures: pointer to status code, specific to ice_set_fc routine
+ * @ena_auto_link_update: enable automatic link update
+ *
+ * Set the requested flow control mode.
+ */
+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_aqc_get_phy_caps_data *pcaps;
+       enum ice_status status;
+       struct ice_hw *hw;
+
+       if (!pi || !aq_failures)
+               return ICE_ERR_BAD_PTR;
+
+       *aq_failures = 0;
+       hw = pi->hw;
+
        pcaps = (struct ice_aqc_get_phy_caps_data *)
                ice_malloc(hw, sizeof(*pcaps));
        if (!pcaps)
@@ -2621,12 +2826,16 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
                goto out;
        }
 
-       /* clear the old pause settings */
-       cfg.caps = pcaps->caps & ~(ICE_AQC_PHY_EN_TX_LINK_PAUSE |
-                                  ICE_AQC_PHY_EN_RX_LINK_PAUSE);
+       ice_copy_phy_caps_to_cfg(pi, pcaps, &cfg);
 
-       /* set the new capabilities */
-       cfg.caps |= pause_mask;
+       /* Configure the set PHY data */
+       status = ice_cfg_phy_fc(pi, &cfg, pi->fc.req_mode);
+       if (status) {
+               if (status != ICE_ERR_BAD_PTR)
+                       *aq_failures = ICE_SET_FC_AQ_FAIL_GET;
+
+               goto out;
+       }
 
        /* If the capabilities have changed, then set the new config */
        if (cfg.caps != pcaps->caps) {
@@ -2635,13 +2844,6 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
                /* Auto restart link so settings take effect */
                if (ena_auto_link_update)
                        cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
-               /* Copy over all the old settings */
-               cfg.phy_type_high = pcaps->phy_type_high;
-               cfg.phy_type_low = pcaps->phy_type_low;
-               cfg.low_power_ctrl = pcaps->low_power_ctrl;
-               cfg.eee_cap = pcaps->eee_cap;
-               cfg.eeer_value = pcaps->eeer_value;
-               cfg.link_fec_opt = pcaps->link_fec_options;
 
                status = ice_aq_set_phy_cfg(hw, pi, &cfg, NULL);
                if (status) {
@@ -2672,8 +2874,45 @@ out:
        return status;
 }
 
+/**
+ * ice_phy_caps_equals_cfg
+ * @phy_caps: PHY capabilities
+ * @phy_cfg: PHY configuration
+ *
+ * Helper function to determine if PHY capabilities matches PHY
+ * configuration
+ */
+bool
+ice_phy_caps_equals_cfg(struct ice_aqc_get_phy_caps_data *phy_caps,
+                       struct ice_aqc_set_phy_cfg_data *phy_cfg)
+{
+       u8 caps_mask, cfg_mask;
+
+       if (!phy_caps || !phy_cfg)
+               return false;
+
+       /* These bits are not common between capabilities and configuration.
+        * Do not use them to determine equality.
+        */
+       caps_mask = ICE_AQC_PHY_CAPS_MASK & ~(ICE_AQC_PHY_AN_MODE |
+                                             ICE_AQC_PHY_EN_MOD_QUAL);
+       cfg_mask = ICE_AQ_PHY_ENA_VALID_MASK & ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+
+       if (phy_caps->phy_type_low != phy_cfg->phy_type_low ||
+           phy_caps->phy_type_high != phy_cfg->phy_type_high ||
+           ((phy_caps->caps & caps_mask) != (phy_cfg->caps & cfg_mask)) ||
+           phy_caps->low_power_ctrl_an != phy_cfg->low_power_ctrl_an ||
+           phy_caps->eee_cap != phy_cfg->eee_cap ||
+           phy_caps->eeer_value != phy_cfg->eeer_value ||
+           phy_caps->link_fec_options != phy_cfg->link_fec_opt)
+               return false;
+
+       return true;
+}
+
 /**
  * ice_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data
+ * @pi: port information structure
  * @caps: PHY ability structure to copy date from
  * @cfg: PHY configuration structure to copy data to
  *
@@ -2681,42 +2920,77 @@ out:
  * data structure
  */
 void
-ice_copy_phy_caps_to_cfg(struct ice_aqc_get_phy_caps_data *caps,
+ice_copy_phy_caps_to_cfg(struct ice_port_info *pi,
+                        struct ice_aqc_get_phy_caps_data *caps,
                         struct ice_aqc_set_phy_cfg_data *cfg)
 {
-       if (!caps || !cfg)
+       if (!pi || !caps || !cfg)
                return;
 
+       ice_memset(cfg, 0, sizeof(*cfg), ICE_NONDMA_MEM);
        cfg->phy_type_low = caps->phy_type_low;
        cfg->phy_type_high = caps->phy_type_high;
        cfg->caps = caps->caps;
-       cfg->low_power_ctrl = caps->low_power_ctrl;
+       cfg->low_power_ctrl_an = caps->low_power_ctrl_an;
        cfg->eee_cap = caps->eee_cap;
        cfg->eeer_value = caps->eeer_value;
        cfg->link_fec_opt = caps->link_fec_options;
+       cfg->module_compliance_enforcement =
+               caps->module_compliance_enforcement;
+
+       if (ice_fw_supports_link_override(pi->hw)) {
+               struct ice_link_default_override_tlv tlv;
+
+               if (ice_get_link_default_override(&tlv, pi))
+                       return;
+
+               if (tlv.options & ICE_LINK_OVERRIDE_STRICT_MODE)
+                       cfg->module_compliance_enforcement |=
+                               ICE_LINK_OVERRIDE_STRICT_MODE;
+       }
 }
 
 /**
  * ice_cfg_phy_fec - Configure PHY FEC data based on FEC mode
+ * @pi: port information structure
  * @cfg: PHY configuration data to set FEC mode
  * @fec: FEC mode to configure
- *
- * Caller should copy ice_aqc_get_phy_caps_data.caps ICE_AQC_PHY_EN_AUTO_FEC
- * (bit 7) and ice_aqc_get_phy_caps_data.link_fec_options to cfg.caps
- * ICE_AQ_PHY_ENA_AUTO_FEC (bit 7) and cfg.link_fec_options before calling.
  */
-void
-ice_cfg_phy_fec(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fec_mode fec)
+enum ice_status
+ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
+               enum ice_fec_mode fec)
 {
+       struct ice_aqc_get_phy_caps_data *pcaps;
+       enum ice_status status = ICE_SUCCESS;
+       struct ice_hw *hw;
+
+       if (!pi || !cfg)
+               return ICE_ERR_BAD_PTR;
+
+       hw = pi->hw;
+
+       pcaps = (struct ice_aqc_get_phy_caps_data *)
+               ice_malloc(hw, sizeof(*pcaps));
+       if (!pcaps)
+               return ICE_ERR_NO_MEMORY;
+
+       status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP, pcaps,
+                                    NULL);
+       if (status)
+               goto out;
+
+       cfg->caps |= (pcaps->caps & ICE_AQC_PHY_EN_AUTO_FEC);
+       cfg->link_fec_opt = pcaps->link_fec_options;
+
        switch (fec) {
        case ICE_FEC_BASER:
                /* Clear RS bits, and AND BASE-R ability
                 * bits and OR request bits.
                 */
                cfg->link_fec_opt &= ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN |
-                                    ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN;
+                       ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN;
                cfg->link_fec_opt |= ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ |
-                                    ICE_AQC_PHY_FEC_25G_KR_REQ;
+                       ICE_AQC_PHY_FEC_25G_KR_REQ;
                break;
        case ICE_FEC_RS:
                /* Clear BASE-R bits, and AND RS ability
@@ -2724,7 +2998,7 @@ ice_cfg_phy_fec(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fec_mode fec)
                 */
                cfg->link_fec_opt &= ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN;
                cfg->link_fec_opt |= ICE_AQC_PHY_FEC_25G_RS_528_REQ |
-                                    ICE_AQC_PHY_FEC_25G_RS_544_REQ;
+                       ICE_AQC_PHY_FEC_25G_RS_544_REQ;
                break;
        case ICE_FEC_NONE:
                /* Clear all FEC option bits. */
@@ -2733,8 +3007,28 @@ ice_cfg_phy_fec(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fec_mode fec)
        case ICE_FEC_AUTO:
                /* AND auto FEC bit, and all caps bits. */
                cfg->caps &= ICE_AQC_PHY_CAPS_MASK;
+               cfg->link_fec_opt |= pcaps->link_fec_options;
+               break;
+       default:
+               status = ICE_ERR_PARAM;
                break;
        }
+
+       if (fec == ICE_FEC_AUTO && ice_fw_supports_link_override(pi->hw)) {
+               struct ice_link_default_override_tlv tlv;
+
+               if (ice_get_link_default_override(&tlv, pi))
+                       goto out;
+
+               if (!(tlv.options & ICE_LINK_OVERRIDE_STRICT_MODE) &&
+                   (tlv.options & ICE_LINK_OVERRIDE_EN))
+                       cfg->link_fec_opt = tlv.fec_options;
+       }
+
+out:
+       ice_free(hw, pcaps);
+
+       return status;
 }
 
 /**
@@ -2760,8 +3054,7 @@ enum ice_status ice_get_link_status(struct ice_port_info *pi, bool *link_up)
                status = ice_update_link_info(pi);
 
                if (status)
-                       ice_debug(pi->hw, ICE_DBG_LINK,
-                                 "get link status error, status = %d\n",
+                       ice_debug(pi->hw, ICE_DBG_LINK, "get link status error, status = %d\n",
                                  status);
        }
 
@@ -2848,7 +3141,6 @@ ice_aq_set_mac_loopback(struct ice_hw *hw, bool ena_lpbk, struct ice_sq_cd *cd)
        return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
 }
 
-
 /**
  * ice_aq_set_port_id_led
  * @pi: pointer to the port information
@@ -2869,7 +3161,6 @@ ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode,
 
        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_port_id_led);
 
-
        if (is_orig_mode)
                cmd->ident_mode = ICE_AQC_PORT_IDENT_LED_ORIG;
        else
@@ -2878,6 +3169,52 @@ ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode,
        return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
 }
 
+/**
+ * ice_aq_sff_eeprom
+ * @hw: pointer to the HW struct
+ * @lport: bits [7:0] = logical port, bit [8] = logical port valid
+ * @bus_addr: I2C bus address of the eeprom (typically 0xA0, 0=topo default)
+ * @mem_addr: I2C offset. lower 8 bits for address, 8 upper bits zero padding.
+ * @page: QSFP page
+ * @set_page: set or ignore the page
+ * @data: pointer to data buffer to be read/written to the I2C device.
+ * @length: 1-16 for read, 1 for write.
+ * @write: 0 read, 1 for write.
+ * @cd: pointer to command details structure or NULL
+ *
+ * Read/Write SFF EEPROM (0x06EE)
+ */
+enum ice_status
+ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr,
+                 u16 mem_addr, u8 page, u8 set_page, u8 *data, u8 length,
+                 bool write, struct ice_sq_cd *cd)
+{
+       struct ice_aqc_sff_eeprom *cmd;
+       struct ice_aq_desc desc;
+       enum ice_status status;
+
+       if (!data || (mem_addr & 0xff00))
+               return ICE_ERR_PARAM;
+
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_sff_eeprom);
+       cmd = &desc.params.read_write_sff_param;
+       desc.flags = CPU_TO_LE16(ICE_AQ_FLAG_RD);
+       cmd->lport_num = (u8)(lport & 0xff);
+       cmd->lport_num_valid = (u8)((lport >> 8) & 0x01);
+       cmd->i2c_bus_addr = CPU_TO_LE16(((bus_addr >> 1) &
+                                        ICE_AQC_SFF_I2CBUS_7BIT_M) |
+                                       ((set_page <<
+                                         ICE_AQC_SFF_SET_EEPROM_PAGE_S) &
+                                        ICE_AQC_SFF_SET_EEPROM_PAGE_M));
+       cmd->i2c_mem_addr = CPU_TO_LE16(mem_addr & 0xff);
+       cmd->eeprom_page = CPU_TO_LE16((u16)page << ICE_AQC_SFF_EEPROM_PAGE_S);
+       if (write)
+               cmd->i2c_bus_addr |= CPU_TO_LE16(ICE_AQC_SFF_IS_WRITE);
+
+       status = ice_aq_send_cmd(hw, &desc, data, length, cd);
+       return status;
+}
+
 /**
  * __ice_aq_get_set_rss_lut
  * @hw: pointer to the hardware structure
@@ -3112,10 +3449,10 @@ 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)
 {
-       u16 i, sum_header_size, sum_q_size = 0;
        struct ice_aqc_add_tx_qgrp *list;
        struct ice_aqc_add_txqs *cmd;
        struct ice_aq_desc desc;
+       u16 i, sum_size = 0;
 
        ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
 
@@ -3129,18 +3466,13 @@ ice_aq_add_lan_txq(struct ice_hw *hw, u8 num_qgrps,
        if (num_qgrps > ICE_LAN_TXQ_MAX_QGRPS)
                return ICE_ERR_PARAM;
 
-       sum_header_size = num_qgrps *
-               (sizeof(*qg_list) - sizeof(*qg_list->txqs));
-
-       list = qg_list;
-       for (i = 0; i < num_qgrps; i++) {
-               struct ice_aqc_add_txqs_perq *q = list->txqs;
-
-               sum_q_size += list->num_txqs * sizeof(*q);
-               list = (struct ice_aqc_add_tx_qgrp *)(q + list->num_txqs);
+       for (i = 0, list = qg_list; i < num_qgrps; i++) {
+               sum_size += ice_struct_size(list, txqs, list->num_txqs);
+               list = (struct ice_aqc_add_tx_qgrp *)(list->txqs +
+                                                     list->num_txqs);
        }
 
-       if (buf_size != (sum_header_size + sum_q_size))
+       if (buf_size != sum_size)
                return ICE_ERR_PARAM;
 
        desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
@@ -3168,6 +3500,7 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps,
                   enum ice_disq_rst_src rst_src, u16 vmvf_num,
                   struct ice_sq_cd *cd)
 {
+       struct ice_aqc_dis_txq_item *item;
        struct ice_aqc_dis_txqs *cmd;
        struct ice_aq_desc desc;
        enum ice_status status;
@@ -3211,16 +3544,16 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps,
         */
        desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
 
-       for (i = 0; i < num_qgrps; ++i) {
-               /* Calculate the size taken up by the queue IDs in this group */
-               sz += qg_list[i].num_qs * sizeof(qg_list[i].q_id);
-
-               /* Add the size of the group header */
-               sz += sizeof(qg_list[i]) - sizeof(qg_list[i].q_id);
+       for (i = 0, item = qg_list; i < num_qgrps; i++) {
+               u16 item_size = ice_struct_size(item, q_id, item->num_qs);
 
                /* If the num of queues is even, add 2 bytes of padding */
-               if ((qg_list[i].num_qs % 2) == 0)
-                       sz += 2;
+               if ((item->num_qs % 2) == 0)
+                       item_size += 2;
+
+               sz += item_size;
+
+               item = (struct ice_aqc_dis_txq_item *)((u8 *)item + item_size);
        }
 
        if (buf_size != sz)
@@ -3240,6 +3573,76 @@ do_aq:
        return status;
 }
 
+/**
+ * ice_aq_move_recfg_lan_txq
+ * @hw: pointer to the hardware structure
+ * @num_qs: number of queues to move/reconfigure
+ * @is_move: true if this operation involves node movement
+ * @is_tc_change: true if this operation involves a TC change
+ * @subseq_call: true if this operation is a subsequent call
+ * @flush_pipe: on timeout, true to flush pipe, false to return EAGAIN
+ * @timeout: timeout in units of 100 usec (valid values 0-50)
+ * @blocked_cgds: out param, bitmap of CGDs that timed out if returning EAGAIN
+ * @buf: struct containing src/dest TEID and per-queue info
+ * @buf_size: size of buffer for indirect command
+ * @txqs_moved: out param, number of queues successfully moved
+ * @cd: pointer to command details structure or NULL
+ *
+ * Move / Reconfigure Tx LAN queues (0x0C32)
+ */
+enum ice_status
+ice_aq_move_recfg_lan_txq(struct ice_hw *hw, u8 num_qs, bool is_move,
+                         bool is_tc_change, bool subseq_call, bool flush_pipe,
+                         u8 timeout, u32 *blocked_cgds,
+                         struct ice_aqc_move_txqs_data *buf, u16 buf_size,
+                         u8 *txqs_moved, struct ice_sq_cd *cd)
+{
+       struct ice_aqc_move_txqs *cmd;
+       struct ice_aq_desc desc;
+       enum ice_status status;
+
+       cmd = &desc.params.move_txqs;
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_move_recfg_txqs);
+
+#define ICE_LAN_TXQ_MOVE_TIMEOUT_MAX 50
+       if (timeout > ICE_LAN_TXQ_MOVE_TIMEOUT_MAX)
+               return ICE_ERR_PARAM;
+
+       if (is_tc_change && !flush_pipe && !blocked_cgds)
+               return ICE_ERR_PARAM;
+
+       if (!is_move && !is_tc_change)
+               return ICE_ERR_PARAM;
+
+       desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
+
+       if (is_move)
+               cmd->cmd_type |= ICE_AQC_Q_CMD_TYPE_MOVE;
+
+       if (is_tc_change)
+               cmd->cmd_type |= ICE_AQC_Q_CMD_TYPE_TC_CHANGE;
+
+       if (subseq_call)
+               cmd->cmd_type |= ICE_AQC_Q_CMD_SUBSEQ_CALL;
+
+       if (flush_pipe)
+               cmd->cmd_type |= ICE_AQC_Q_CMD_FLUSH_PIPE;
+
+       cmd->num_qs = num_qs;
+       cmd->timeout = ((timeout << ICE_AQC_Q_CMD_TIMEOUT_S) &
+                       ICE_AQC_Q_CMD_TIMEOUT_M);
+
+       status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
+
+       if (!status && txqs_moved)
+               *txqs_moved = cmd->num_qs;
+
+       if (hw->adminq.sq_last_status == ICE_AQ_RC_EAGAIN &&
+           is_tc_change && !flush_pipe)
+               *blocked_cgds = LE32_TO_CPU(cmd->blocked_cgds);
+
+       return status;
+}
 
 /* End of FW Admin Queue command wrappers */
 
@@ -3429,12 +3832,14 @@ ice_write_qword(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
 
 /**
  * ice_set_ctx - set context bits in packed structure
+ * @hw: pointer to the hardware structure
  * @src_ctx:  pointer to a generic non-packed context structure
  * @dest_ctx: pointer to memory for the packed structure
  * @ce_info:  a description of the structure to be transformed
  */
 enum ice_status
-ice_set_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
+ice_set_ctx(struct ice_hw *hw, u8 *src_ctx, u8 *dest_ctx,
+           const struct ice_ctx_ele *ce_info)
 {
        int f;
 
@@ -3443,6 +3848,11 @@ ice_set_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
                 * using the correct size so that we are correct regardless
                 * of the endianness of the machine.
                 */
+               if (ce_info[f].width > (ce_info[f].size_of * BITS_PER_BYTE)) {
+                       ice_debug(hw, ICE_DBG_QCTX, "Field %d width of %d bits larger than size of %d byte(s) ... skipping write\n",
+                                 f, ce_info[f].width, ce_info[f].size_of);
+                       continue;
+               }
                switch (ce_info[f].size_of) {
                case sizeof(u8):
                        ice_write_byte(src_ctx, dest_ctx, &ce_info[f]);
@@ -3464,9 +3874,6 @@ ice_set_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
        return ICE_SUCCESS;
 }
 
-
-
-
 /**
  * ice_read_byte - read context byte into struct
  * @src_ctx:  the context structure to read from
@@ -3772,7 +4179,18 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 q_handle,
         * Without setting the generic section as valid in valid_sections, the
         * Admin queue command will fail with error code ICE_AQ_RC_EINVAL.
         */
-       buf->txqs[0].info.valid_sections = ICE_AQC_ELEM_VALID_GENERIC;
+       buf->txqs[0].info.valid_sections =
+               ICE_AQC_ELEM_VALID_GENERIC | ICE_AQC_ELEM_VALID_CIR |
+               ICE_AQC_ELEM_VALID_EIR;
+       buf->txqs[0].info.generic = 0;
+       buf->txqs[0].info.cir_bw.bw_profile_idx =
+               CPU_TO_LE16(ICE_SCHED_DFLT_RL_PROF_ID);
+       buf->txqs[0].info.cir_bw.bw_alloc =
+               CPU_TO_LE16(ICE_SCHED_DFLT_BW_WT);
+       buf->txqs[0].info.eir_bw.bw_profile_idx =
+               CPU_TO_LE16(ICE_SCHED_DFLT_RL_PROF_ID);
+       buf->txqs[0].info.eir_bw.bw_alloc =
+               CPU_TO_LE16(ICE_SCHED_DFLT_BW_WT);
 
        /* add the LAN queue */
        status = ice_aq_add_lan_txq(hw, num_qgrps, buf, buf_size, cd);
@@ -3820,24 +4238,32 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
                struct ice_sq_cd *cd)
 {
        enum ice_status status = ICE_ERR_DOES_NOT_EXIST;
-       struct ice_aqc_dis_txq_item qg_list;
+       struct ice_aqc_dis_txq_item *qg_list;
        struct ice_q_ctx *q_ctx;
-       u16 i;
+       struct ice_hw *hw;
+       u16 i, buf_size;
 
        if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
                return ICE_ERR_CFG;
 
+       hw = pi->hw;
+
        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,
+                       return ice_aq_dis_lan_txq(hw, 0, NULL, 0, rst_src,
                                                  vmvf_num, NULL);
                return ICE_ERR_CFG;
        }
 
+       buf_size = ice_struct_size(qg_list, q_id, 1);
+       qg_list = (struct ice_aqc_dis_txq_item *)ice_malloc(hw, buf_size);
+       if (!qg_list)
+               return ICE_ERR_NO_MEMORY;
+
        ice_acquire_lock(&pi->sched_lock);
 
        for (i = 0; i < num_queues; i++) {
@@ -3846,23 +4272,22 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
                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]);
+               q_ctx = ice_get_lan_q_ctx(hw, vsi_handle, tc, q_handles[i]);
                if (!q_ctx) {
-                       ice_debug(pi->hw, ICE_DBG_SCHED, "invalid queue handle%d\n",
+                       ice_debug(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",
+                       ice_debug(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]);
-               status = ice_aq_dis_lan_txq(pi->hw, 1, &qg_list,
-                                           sizeof(qg_list), rst_src, vmvf_num,
-                                           cd);
+               qg_list->parent_teid = node->info.parent_teid;
+               qg_list->num_qs = 1;
+               qg_list->q_id[0] = CPU_TO_LE16(q_ids[i]);
+               status = ice_aq_dis_lan_txq(hw, 1, qg_list, buf_size, rst_src,
+                                           vmvf_num, cd);
 
                if (status != ICE_SUCCESS)
                        break;
@@ -3870,6 +4295,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
                q_ctx->q_handle = ICE_INVAL_Q_HANDLE;
        }
        ice_release_lock(&pi->sched_lock);
+       ice_free(hw, qg_list);
        return status;
 }
 
@@ -3884,7 +4310,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
  * This function adds/updates the VSI queues per TC.
  */
 static enum ice_status
-ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap,
+ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_handle, u16 tc_bitmap,
               u16 *maxqs, u8 owner)
 {
        enum ice_status status = ICE_SUCCESS;
@@ -3923,28 +4349,41 @@ ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap,
  * This function adds/updates the VSI LAN queues per TC.
  */
 enum ice_status
-ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap,
+ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u16 tc_bitmap,
                u16 *max_lanqs)
 {
        return ice_cfg_vsi_qs(pi, vsi_handle, tc_bitmap, max_lanqs,
                              ICE_SCHED_NODE_OWNER_LAN);
 }
 
-
+/**
+ * ice_is_main_vsi - checks whether the VSI is main VSI
+ * @hw: pointer to the HW struct
+ * @vsi_handle: VSI handle
+ *
+ * Checks whether the VSI is the main VSI (the first PF VSI created on
+ * given PF).
+ */
+static bool ice_is_main_vsi(struct ice_hw *hw, u16 vsi_handle)
+{
+       return vsi_handle == ICE_MAIN_VSI_HANDLE && hw->vsi_ctx[vsi_handle];
+}
 
 /**
  * ice_replay_pre_init - replay pre initialization
  * @hw: pointer to the HW struct
+ * @sw: pointer to switch info struct for which function initializes filters
  *
  * Initializes required config data for VSI, FD, ACL, and RSS before replay.
  */
-static enum ice_status ice_replay_pre_init(struct ice_hw *hw)
+static enum ice_status
+ice_replay_pre_init(struct ice_hw *hw, struct ice_switch_info *sw)
 {
-       struct ice_switch_info *sw = hw->switch_info;
+       enum ice_status status;
        u8 i;
 
        /* Delete old entries from replay filter list head if there is any */
-       ice_rm_all_sw_replay_rule_info(hw);
+       ice_rm_sw_replay_rule_info(hw, sw);
        /* In start of replay, move entries into replay_rules list, it
         * will allow adding rules entries back to filt_rules list,
         * which is operational list.
@@ -3954,7 +4393,11 @@ static enum ice_status ice_replay_pre_init(struct ice_hw *hw)
                                  &sw->recp_list[i].filt_replay_rules);
        ice_sched_replay_agg_vsi_preinit(hw);
 
-       return ice_sched_replay_tc_node_bw(hw);
+       status = ice_sched_replay_root_node_bw(hw->port_info);
+       if (status)
+               return status;
+
+       return ice_sched_replay_tc_node_bw(hw->port_info);
 }
 
 /**
@@ -3967,14 +4410,16 @@ static enum ice_status ice_replay_pre_init(struct ice_hw *hw)
  */
 enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle)
 {
+       struct ice_switch_info *sw = hw->switch_info;
+       struct ice_port_info *pi = hw->port_info;
        enum ice_status status;
 
        if (!ice_is_vsi_valid(hw, vsi_handle))
                return ICE_ERR_PARAM;
 
        /* Replay pre-initialization if there is any */
-       if (vsi_handle == ICE_MAIN_VSI_HANDLE) {
-               status = ice_replay_pre_init(hw);
+       if (ice_is_main_vsi(hw, vsi_handle)) {
+               status = ice_replay_pre_init(hw, sw);
                if (status)
                        return status;
        }
@@ -3983,7 +4428,7 @@ enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle)
        if (status)
                return status;
        /* Replay per VSI all filters */
-       status = ice_replay_vsi_all_fltr(hw, vsi_handle);
+       status = ice_replay_vsi_all_fltr(hw, pi, vsi_handle);
        if (!status)
                status = ice_replay_vsi_agg(hw, vsi_handle);
        return status;
@@ -4078,6 +4523,56 @@ ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
        *prev_stat = new_data;
 }
 
+/**
+ * ice_stat_update_repc - read GLV_REPC stats from chip and update stat values
+ * @hw: ptr to the hardware info
+ * @vsi_handle: VSI handle
+ * @prev_stat_loaded: bool to specify if the previous stat values are loaded
+ * @cur_stats: ptr to current stats structure
+ *
+ * The GLV_REPC statistic register actually tracks two 16bit statistics, and
+ * thus cannot be read using the normal ice_stat_update32 function.
+ *
+ * Read the GLV_REPC register associated with the given VSI, and update the
+ * rx_no_desc and rx_error values in the ice_eth_stats structure.
+ *
+ * Because the statistics in GLV_REPC stick at 0xFFFF, the register must be
+ * cleared each time it's read.
+ *
+ * Note that the GLV_RDPC register also counts the causes that would trigger
+ * GLV_REPC. However, it does not give the finer grained detail about why the
+ * packets are being dropped. The GLV_REPC values can be used to distinguish
+ * whether Rx packets are dropped due to errors or due to no available
+ * descriptors.
+ */
+void
+ice_stat_update_repc(struct ice_hw *hw, u16 vsi_handle, bool prev_stat_loaded,
+                    struct ice_eth_stats *cur_stats)
+{
+       u16 vsi_num, no_desc, error_cnt;
+       u32 repc;
+
+       if (!ice_is_vsi_valid(hw, vsi_handle))
+               return;
+
+       vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
+
+       /* If we haven't loaded stats yet, just clear the current value */
+       if (!prev_stat_loaded) {
+               wr32(hw, GLV_REPC(vsi_num), 0);
+               return;
+       }
+
+       repc = rd32(hw, GLV_REPC(vsi_num));
+       no_desc = (repc & GLV_REPC_NO_DESC_CNT_M) >> GLV_REPC_NO_DESC_CNT_S;
+       error_cnt = (repc & GLV_REPC_ERROR_CNT_M) >> GLV_REPC_ERROR_CNT_S;
+
+       /* Clear the count by writing to the stats register */
+       wr32(hw, GLV_REPC(vsi_num), 0);
+
+       cur_stats->rx_no_desc += no_desc;
+       cur_stats->rx_errors += error_cnt;
+}
 
 /**
  * ice_sched_query_elem - query element information from HW
@@ -4089,14 +4584,14 @@ ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
  */
 enum ice_status
 ice_sched_query_elem(struct ice_hw *hw, u32 node_teid,
-                    struct ice_aqc_get_elem *buf)
+                    struct ice_aqc_txsched_elem_data *buf)
 {
        u16 buf_size, num_elem_ret = 0;
        enum ice_status status;
 
        buf_size = sizeof(*buf);
        ice_memset(buf, 0, buf_size, ICE_NONDMA_MEM);
-       buf->generic[0].node_teid = CPU_TO_LE32(node_teid);
+       buf->node_teid = CPU_TO_LE32(node_teid);
        status = ice_aq_query_sched_elems(hw, 1, buf, buf_size, &num_elem_ret,
                                          NULL);
        if (status != ICE_SUCCESS || num_elem_ret != 1)
@@ -4105,16 +4600,214 @@ ice_sched_query_elem(struct ice_hw *hw, u32 node_teid,
 }
 
 /**
- * ice_is_fw_in_rec_mode
+ * ice_get_fw_mode - returns FW 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)
+enum ice_fw_modes ice_get_fw_mode(struct ice_hw *hw)
 {
-       u32 reg;
+#define ICE_FW_MODE_DBG_M BIT(0)
+#define ICE_FW_MODE_REC_M BIT(1)
+#define ICE_FW_MODE_ROLLBACK_M BIT(2)
+       u32 fw_mode;
 
        /* check the current FW mode */
-       reg = rd32(hw, GL_MNG_FWSM);
-       return (reg & GL_MNG_FWSM_FW_MODES_M) > ICE_FW_MODE_DBG;
+       fw_mode = rd32(hw, GL_MNG_FWSM) & GL_MNG_FWSM_FW_MODES_M;
+
+       if (fw_mode & ICE_FW_MODE_DBG_M)
+               return ICE_FW_MODE_DBG;
+       else if (fw_mode & ICE_FW_MODE_REC_M)
+               return ICE_FW_MODE_REC;
+       else if (fw_mode & ICE_FW_MODE_ROLLBACK_M)
+               return ICE_FW_MODE_ROLLBACK;
+       else
+               return ICE_FW_MODE_NORMAL;
+}
+
+/**
+ * ice_fw_supports_link_override
+ * @hw: pointer to the hardware structure
+ *
+ * Checks if the firmware supports link override
+ */
+bool ice_fw_supports_link_override(struct ice_hw *hw)
+{
+       if (hw->api_maj_ver == ICE_FW_API_LINK_OVERRIDE_MAJ) {
+               if (hw->api_min_ver > ICE_FW_API_LINK_OVERRIDE_MIN)
+                       return true;
+               if (hw->api_min_ver == ICE_FW_API_LINK_OVERRIDE_MIN &&
+                   hw->api_patch >= ICE_FW_API_LINK_OVERRIDE_PATCH)
+                       return true;
+       } else if (hw->api_maj_ver > ICE_FW_API_LINK_OVERRIDE_MAJ) {
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * ice_get_link_default_override
+ * @ldo: pointer to the link default override struct
+ * @pi: pointer to the port info struct
+ *
+ * Gets the link default override for a port
+ */
+enum ice_status
+ice_get_link_default_override(struct ice_link_default_override_tlv *ldo,
+                             struct ice_port_info *pi)
+{
+       u16 i, tlv, tlv_len, tlv_start, buf, offset;
+       struct ice_hw *hw = pi->hw;
+       enum ice_status status;
+
+       status = ice_get_pfa_module_tlv(hw, &tlv, &tlv_len,
+                                       ICE_SR_LINK_DEFAULT_OVERRIDE_PTR);
+       if (status) {
+               ice_debug(hw, ICE_DBG_INIT, "Failed to read link override TLV.\n");
+               return status;
+       }
+
+       /* Each port has its own config; calculate for our port */
+       tlv_start = tlv + pi->lport * ICE_SR_PFA_LINK_OVERRIDE_WORDS +
+               ICE_SR_PFA_LINK_OVERRIDE_OFFSET;
+
+       /* link options first */
+       status = ice_read_sr_word(hw, tlv_start, &buf);
+       if (status) {
+               ice_debug(hw, ICE_DBG_INIT, "Failed to read override link options.\n");
+               return status;
+       }
+       ldo->options = buf & ICE_LINK_OVERRIDE_OPT_M;
+       ldo->phy_config = (buf & ICE_LINK_OVERRIDE_PHY_CFG_M) >>
+               ICE_LINK_OVERRIDE_PHY_CFG_S;
+
+       /* link PHY config */
+       offset = tlv_start + ICE_SR_PFA_LINK_OVERRIDE_FEC_OFFSET;
+       status = ice_read_sr_word(hw, offset, &buf);
+       if (status) {
+               ice_debug(hw, ICE_DBG_INIT, "Failed to read override phy config.\n");
+               return status;
+       }
+       ldo->fec_options = buf & ICE_LINK_OVERRIDE_FEC_OPT_M;
+
+       /* PHY types low */
+       offset = tlv_start + ICE_SR_PFA_LINK_OVERRIDE_PHY_OFFSET;
+       for (i = 0; i < ICE_SR_PFA_LINK_OVERRIDE_PHY_WORDS; i++) {
+               status = ice_read_sr_word(hw, (offset + i), &buf);
+               if (status) {
+                       ice_debug(hw, ICE_DBG_INIT, "Failed to read override link options.\n");
+                       return status;
+               }
+               /* shift 16 bits at a time to fill 64 bits */
+               ldo->phy_type_low |= ((u64)buf << (i * 16));
+       }
+
+       /* PHY types high */
+       offset = tlv_start + ICE_SR_PFA_LINK_OVERRIDE_PHY_OFFSET +
+               ICE_SR_PFA_LINK_OVERRIDE_PHY_WORDS;
+       for (i = 0; i < ICE_SR_PFA_LINK_OVERRIDE_PHY_WORDS; i++) {
+               status = ice_read_sr_word(hw, (offset + i), &buf);
+               if (status) {
+                       ice_debug(hw, ICE_DBG_INIT, "Failed to read override link options.\n");
+                       return status;
+               }
+               /* shift 16 bits at a time to fill 64 bits */
+               ldo->phy_type_high |= ((u64)buf << (i * 16));
+       }
+
+       return status;
+}
+
+/**
+ * ice_is_phy_caps_an_enabled - check if PHY capabilities autoneg is enabled
+ * @caps: get PHY capability data
+ */
+bool ice_is_phy_caps_an_enabled(struct ice_aqc_get_phy_caps_data *caps)
+{
+       if (caps->caps & ICE_AQC_PHY_AN_MODE ||
+           caps->low_power_ctrl_an & (ICE_AQC_PHY_AN_EN_CLAUSE28 |
+                                      ICE_AQC_PHY_AN_EN_CLAUSE73 |
+                                      ICE_AQC_PHY_AN_EN_CLAUSE37))
+               return true;
+
+       return false;
+}
+
+/**
+ * ice_aq_set_lldp_mib - Set the LLDP MIB
+ * @hw: pointer to the HW struct
+ * @mib_type: Local, Remote or both Local and Remote MIBs
+ * @buf: pointer to the caller-supplied buffer to store the MIB block
+ * @buf_size: size of the buffer (in bytes)
+ * @cd: pointer to command details structure or NULL
+ *
+ * Set the LLDP MIB. (0x0A08)
+ */
+enum ice_status
+ice_aq_set_lldp_mib(struct ice_hw *hw, u8 mib_type, void *buf, u16 buf_size,
+                   struct ice_sq_cd *cd)
+{
+       struct ice_aqc_lldp_set_local_mib *cmd;
+       struct ice_aq_desc desc;
+
+       cmd = &desc.params.lldp_set_mib;
+
+       if (buf_size == 0 || !buf)
+               return ICE_ERR_PARAM;
+
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_set_local_mib);
+
+       desc.flags |= CPU_TO_LE16((u16)ICE_AQ_FLAG_RD);
+       desc.datalen = CPU_TO_LE16(buf_size);
+
+       cmd->type = mib_type;
+       cmd->length = CPU_TO_LE16(buf_size);
+
+       return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
+}
+
+/**
+ * ice_fw_supports_lldp_fltr - check NVM version supports lldp_fltr_ctrl
+ * @hw: pointer to HW struct
+ */
+bool ice_fw_supports_lldp_fltr_ctrl(struct ice_hw *hw)
+{
+       if (hw->mac_type != ICE_MAC_E810)
+               return false;
+
+       if (hw->api_maj_ver == ICE_FW_API_LLDP_FLTR_MAJ) {
+               if (hw->api_min_ver > ICE_FW_API_LLDP_FLTR_MIN)
+                       return true;
+               if (hw->api_min_ver == ICE_FW_API_LLDP_FLTR_MIN &&
+                   hw->api_patch >= ICE_FW_API_LLDP_FLTR_PATCH)
+                       return true;
+       } else if (hw->api_maj_ver > ICE_FW_API_LLDP_FLTR_MAJ) {
+               return true;
+       }
+       return false;
+}
+
+/**
+ * ice_lldp_fltr_add_remove - add or remove a LLDP Rx switch filter
+ * @hw: pointer to HW struct
+ * @vsi_num: absolute HW index for VSI
+ * @add: boolean for if adding or removing a filter
+ */
+enum ice_status
+ice_lldp_fltr_add_remove(struct ice_hw *hw, u16 vsi_num, bool add)
+{
+       struct ice_aqc_lldp_filter_ctrl *cmd;
+       struct ice_aq_desc desc;
+
+       cmd = &desc.params.lldp_filter_ctrl;
+
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_filter_ctrl);
+
+       if (add)
+               cmd->cmd_flags = ICE_AQC_LLDP_FILTER_ACTION_ADD;
+       else
+               cmd->cmd_flags = ICE_AQC_LLDP_FILTER_ACTION_DELETE;
+
+       cmd->vsi_num = CPU_TO_LE16(vsi_num);
+
+       return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
 }