net/ice: support src MAC filter for flow director
[dpdk.git] / drivers / net / ice / base / ice_common.c
index 2c822d7..6168fb4 100644 (file)
@@ -193,14 +193,12 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
        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;
@@ -882,23 +880,23 @@ void ice_deinit_hw(struct ice_hw *hw)
  */
 enum ice_status ice_check_reset(struct ice_hw *hw)
 {
-       u32 cnt, reg = 0, grst_delay, uld_mask;
+       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.
         */
-       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) {
+       if (cnt == grst_timeout) {
                ice_debug(hw, ICE_DBG_INIT,
                          "Global reset polling failed to complete.\n");
                return ICE_ERR_RESET_FAILED;
@@ -1823,206 +1821,386 @@ 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
  *
- * Helper function to parse function(0x000a)/device(0x000b) capabilities list.
+ * Given a capability element, extract relevant details into the common
+ * capability structure.
+ *
+ * Returns: true if the capability matches one of the common capability ids,
+ * false otherwise.
+ */
+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)
+{
+       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;
+       }
+
+       return found;
+}
+
+/**
+ * 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_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
-              enum ice_adminq_opc opc)
+ice_recalc_port_limited_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps)
 {
-       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;
+       /* 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);
+       }
+}
 
-       if (!buf)
-               return;
+/**
+ * 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);
+}
 
-       cap_resp = (struct ice_aqc_list_caps_elem *)buf;
+/**
+ * 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
+ * @cap: pointer to the capability element to parse
+ *
+ * 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,
+                        struct ice_aqc_list_caps_elem *cap)
+{
+       u32 reg_val, val;
 
-       if (opc == ice_aqc_opc_list_dev_caps) {
-               dev_p = &hw->dev_caps;
-               caps = &dev_p->common_cap;
+       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_memset(dev_p, 0, sizeof(*dev_p), ICE_NONDMA_MEM);
+/**
+ * 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;
 
-               prefix = "dev cap";
-       } else if (opc == ice_aqc_opc_list_func_caps) {
-               func_p = &hw->func_caps;
-               caps = &func_p->common_cap;
+       cap_resp = (struct ice_aqc_list_caps_elem *)buf;
 
-               ice_memset(func_p, 0, sizeof(*func_p), ICE_NONDMA_MEM);
+       ice_memset(func_p, 0, sizeof(*func_p), ICE_NONDMA_MEM);
 
-               prefix = "func cap";
-       } else {
-               ice_debug(hw, ICE_DBG_INIT, "wrong opcode\n");
-               return;
-       }
+       for (i = 0; i < cap_count; i++) {
+               u16 cap = LE16_TO_CPU(cap_resp[i].cap);
+               bool found;
 
-       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);
+               found = ice_parse_common_caps(hw, &func_p->common_cap,
+                                             &cap_resp[i], "func caps");
 
                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);
-
-                       /* store func count for resource management purposes */
-                       if (dev_p)
-                               dev_p->num_funcs = ice_hweight32(number);
-                       break;
                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_allocd_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: guar_num_vsi (fw) = %d\n",
-                                         prefix, number);
-                               ice_debug(hw, ICE_DBG_INIT,
-                                         "%s: guar_num_vsi = %d\n",
-                                         prefix, func_p->guar_num_vsi);
-                       }
-                       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);
+                       ice_parse_vsi_func_caps(hw, func_p, &cap_resp[i]);
                        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);
+               case ICE_AQC_CAPS_FD:
+                       ice_parse_fdir_func_caps(hw, func_p, &cap_resp[i]);
                        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);
+               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: 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);
+               }
+       }
+
+       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 device, 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:
-                       if (dev_p) {
-                               dev_p->num_flow_director_fltr = number;
-                               ice_debug(hw, ICE_DBG_INIT,
-                                         "%s: num_flow_director_fltr = %d\n",
-                                         prefix,
-                                         dev_p->num_flow_director_fltr);
-                       }
-                       if (func_p) {
-                               u32 reg_val, val;
-
-                               if (hw->dcf_enabled)
-                                       break;
-                               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: fd_fltr_guar = %d\n",
-                                         prefix, func_p->fd_fltr_guar);
-                               ice_debug(hw, ICE_DBG_INIT,
-                                         "%s: fd_fltr_best_effort = %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 (hw->dev_caps.num_funcs > 4) {
-               /* Max 4 TCs per port */
-               caps->maxtc = 4;
-               ice_debug(hw, ICE_DBG_INIT,
-                         "%s: maxtc = %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_parse_caps - parse 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: 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
+ *
+ * Helper function to parse function(0x000a)/device(0x000b) capabilities list.
+ */
+static void
+ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
+              enum ice_adminq_opc opc)
+{
+       if (!buf)
+               return;
+
+       if (opc == ice_aqc_opc_list_dev_caps)
+               ice_parse_dev_caps(hw, &hw->dev_caps, buf, cap_count);
+       else if (opc == ice_aqc_opc_list_func_caps)
+               ice_parse_func_caps(hw, &hw->func_caps, buf, cap_count);
+       else
+               ice_debug(hw, ICE_DBG_INIT, "wrong opcode\n");
+}
+
+/**
+ * ice_aq_list_caps - query function/device capabilities
+ * @hw: pointer to the HW struct
+ * @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;
@@ -2035,12 +2213,43 @@ 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 (cap_count)
+               *cap_count = LE32_TO_CPU(cmd->count);
+
+       return status;
+}
+
+/**
+ * ice_aq_discover_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
+ * @cd: pointer to command details structure or NULL
+ *
+ * Get the function(0x000a)/device(0x000b) capabilities description from
+ * the firmware.
+ *
+ * NOTE: this function has the side effect of updating the hw->dev_caps or
+ * hw->func_caps by way of calling ice_parse_caps.
+ */
+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)
+{
+       u32 local_cap_count = 0;
+       enum ice_status status;
+
+       status = ice_aq_list_caps(hw, buf, buf_size, &local_cap_count,
+                                 opc, cd);
        if (!status)
-               ice_parse_caps(hw, buf, LE32_TO_CPU(cmd->count), opc);
+               ice_parse_caps(hw, buf, local_cap_count, opc);
        else if (hw->adminq.sq_last_status == ICE_AQ_RC_ENOMEM)
-               *cap_count = LE32_TO_CPU(cmd->count);
+               *cap_count = local_cap_count;
+
        return status;
 }
 
@@ -2054,40 +2263,21 @@ ice_discover_caps(struct ice_hw *hw, enum ice_adminq_opc opc)
 {
        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.
-        */
-#define ICE_GET_CAP_BUF_COUNT  40
-#define ICE_GET_CAP_RETRY_COUNT        2
-
-       cap_count = ICE_GET_CAP_BUF_COUNT;
-       retries = ICE_GET_CAP_RETRY_COUNT;
-
-       do {
-               void *cbuf;
-
-               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;
+       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_discover_caps(hw, cbuf, ICE_AQ_MAX_BUF_LEN, &cap_count,
+                                     opc, NULL);
+       ice_free(hw, cbuf);
 
        return status;
 }
@@ -2833,9 +3023,9 @@ ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
                 * 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
@@ -2843,7 +3033,7 @@ ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
                 */
                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. */
@@ -4578,3 +4768,36 @@ bool ice_is_phy_caps_an_enabled(struct ice_aqc_get_phy_caps_data *caps)
 
        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);
+}