12ffd87d3SSergey Temerkhanov // SPDX-License-Identifier: GPL-2.0
22ffd87d3SSergey Temerkhanov /* Copyright (c) 2022, Intel Corporation. */
32ffd87d3SSergey Temerkhanov
42ffd87d3SSergey Temerkhanov #include "ice_common.h"
52ffd87d3SSergey Temerkhanov #include "ice.h"
62ffd87d3SSergey Temerkhanov #include "ice_ddp.h"
72ffd87d3SSergey Temerkhanov
82ffd87d3SSergey Temerkhanov /* For supporting double VLAN mode, it is necessary to enable or disable certain
92ffd87d3SSergey Temerkhanov * boost tcam entries. The metadata labels names that match the following
102ffd87d3SSergey Temerkhanov * prefixes will be saved to allow enabling double VLAN mode.
112ffd87d3SSergey Temerkhanov */
122ffd87d3SSergey Temerkhanov #define ICE_DVM_PRE "BOOST_MAC_VLAN_DVM" /* enable these entries */
132ffd87d3SSergey Temerkhanov #define ICE_SVM_PRE "BOOST_MAC_VLAN_SVM" /* disable these entries */
142ffd87d3SSergey Temerkhanov
152ffd87d3SSergey Temerkhanov /* To support tunneling entries by PF, the package will append the PF number to
162ffd87d3SSergey Temerkhanov * the label; for example TNL_VXLAN_PF0, TNL_VXLAN_PF1, TNL_VXLAN_PF2, etc.
172ffd87d3SSergey Temerkhanov */
182ffd87d3SSergey Temerkhanov #define ICE_TNL_PRE "TNL_"
192ffd87d3SSergey Temerkhanov static const struct ice_tunnel_type_scan tnls[] = {
202ffd87d3SSergey Temerkhanov { TNL_VXLAN, "TNL_VXLAN_PF" },
212ffd87d3SSergey Temerkhanov { TNL_GENEVE, "TNL_GENEVE_PF" },
222ffd87d3SSergey Temerkhanov { TNL_LAST, "" }
232ffd87d3SSergey Temerkhanov };
242ffd87d3SSergey Temerkhanov
252ffd87d3SSergey Temerkhanov /**
262ffd87d3SSergey Temerkhanov * ice_verify_pkg - verify package
272ffd87d3SSergey Temerkhanov * @pkg: pointer to the package buffer
282ffd87d3SSergey Temerkhanov * @len: size of the package buffer
292ffd87d3SSergey Temerkhanov *
302ffd87d3SSergey Temerkhanov * Verifies various attributes of the package file, including length, format
312ffd87d3SSergey Temerkhanov * version, and the requirement of at least one segment.
322ffd87d3SSergey Temerkhanov */
ice_verify_pkg(struct ice_pkg_hdr * pkg,u32 len)33*708b352fSJan Sokolowski static enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
342ffd87d3SSergey Temerkhanov {
352ffd87d3SSergey Temerkhanov u32 seg_count;
362ffd87d3SSergey Temerkhanov u32 i;
372ffd87d3SSergey Temerkhanov
382ffd87d3SSergey Temerkhanov if (len < struct_size(pkg, seg_offset, 1))
392ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE;
402ffd87d3SSergey Temerkhanov
412ffd87d3SSergey Temerkhanov if (pkg->pkg_format_ver.major != ICE_PKG_FMT_VER_MAJ ||
422ffd87d3SSergey Temerkhanov pkg->pkg_format_ver.minor != ICE_PKG_FMT_VER_MNR ||
432ffd87d3SSergey Temerkhanov pkg->pkg_format_ver.update != ICE_PKG_FMT_VER_UPD ||
442ffd87d3SSergey Temerkhanov pkg->pkg_format_ver.draft != ICE_PKG_FMT_VER_DFT)
452ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE;
462ffd87d3SSergey Temerkhanov
472ffd87d3SSergey Temerkhanov /* pkg must have at least one segment */
482ffd87d3SSergey Temerkhanov seg_count = le32_to_cpu(pkg->seg_count);
492ffd87d3SSergey Temerkhanov if (seg_count < 1)
502ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE;
512ffd87d3SSergey Temerkhanov
522ffd87d3SSergey Temerkhanov /* make sure segment array fits in package length */
532ffd87d3SSergey Temerkhanov if (len < struct_size(pkg, seg_offset, seg_count))
542ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE;
552ffd87d3SSergey Temerkhanov
562ffd87d3SSergey Temerkhanov /* all segments must fit within length */
572ffd87d3SSergey Temerkhanov for (i = 0; i < seg_count; i++) {
582ffd87d3SSergey Temerkhanov u32 off = le32_to_cpu(pkg->seg_offset[i]);
592ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg;
602ffd87d3SSergey Temerkhanov
612ffd87d3SSergey Temerkhanov /* segment header must fit */
622ffd87d3SSergey Temerkhanov if (len < off + sizeof(*seg))
632ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE;
642ffd87d3SSergey Temerkhanov
652ffd87d3SSergey Temerkhanov seg = (struct ice_generic_seg_hdr *)((u8 *)pkg + off);
662ffd87d3SSergey Temerkhanov
672ffd87d3SSergey Temerkhanov /* segment body must fit */
682ffd87d3SSergey Temerkhanov if (len < off + le32_to_cpu(seg->seg_size))
692ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE;
702ffd87d3SSergey Temerkhanov }
712ffd87d3SSergey Temerkhanov
722ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS;
732ffd87d3SSergey Temerkhanov }
742ffd87d3SSergey Temerkhanov
752ffd87d3SSergey Temerkhanov /**
762ffd87d3SSergey Temerkhanov * ice_free_seg - free package segment pointer
772ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
782ffd87d3SSergey Temerkhanov *
792ffd87d3SSergey Temerkhanov * Frees the package segment pointer in the proper manner, depending on if the
802ffd87d3SSergey Temerkhanov * segment was allocated or just the passed in pointer was stored.
812ffd87d3SSergey Temerkhanov */
ice_free_seg(struct ice_hw * hw)822ffd87d3SSergey Temerkhanov void ice_free_seg(struct ice_hw *hw)
832ffd87d3SSergey Temerkhanov {
842ffd87d3SSergey Temerkhanov if (hw->pkg_copy) {
852ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), hw->pkg_copy);
862ffd87d3SSergey Temerkhanov hw->pkg_copy = NULL;
872ffd87d3SSergey Temerkhanov hw->pkg_size = 0;
882ffd87d3SSergey Temerkhanov }
892ffd87d3SSergey Temerkhanov hw->seg = NULL;
902ffd87d3SSergey Temerkhanov }
912ffd87d3SSergey Temerkhanov
922ffd87d3SSergey Temerkhanov /**
932ffd87d3SSergey Temerkhanov * ice_chk_pkg_version - check package version for compatibility with driver
942ffd87d3SSergey Temerkhanov * @pkg_ver: pointer to a version structure to check
952ffd87d3SSergey Temerkhanov *
962ffd87d3SSergey Temerkhanov * Check to make sure that the package about to be downloaded is compatible with
972ffd87d3SSergey Temerkhanov * the driver. To be compatible, the major and minor components of the package
982ffd87d3SSergey Temerkhanov * version must match our ICE_PKG_SUPP_VER_MAJ and ICE_PKG_SUPP_VER_MNR
992ffd87d3SSergey Temerkhanov * definitions.
1002ffd87d3SSergey Temerkhanov */
ice_chk_pkg_version(struct ice_pkg_ver * pkg_ver)1012ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver)
1022ffd87d3SSergey Temerkhanov {
1032ffd87d3SSergey Temerkhanov if (pkg_ver->major > ICE_PKG_SUPP_VER_MAJ ||
1042ffd87d3SSergey Temerkhanov (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ &&
1052ffd87d3SSergey Temerkhanov pkg_ver->minor > ICE_PKG_SUPP_VER_MNR))
1062ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_VERSION_TOO_HIGH;
1072ffd87d3SSergey Temerkhanov else if (pkg_ver->major < ICE_PKG_SUPP_VER_MAJ ||
1082ffd87d3SSergey Temerkhanov (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ &&
1092ffd87d3SSergey Temerkhanov pkg_ver->minor < ICE_PKG_SUPP_VER_MNR))
1102ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_VERSION_TOO_LOW;
1112ffd87d3SSergey Temerkhanov
1122ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS;
1132ffd87d3SSergey Temerkhanov }
1142ffd87d3SSergey Temerkhanov
1152ffd87d3SSergey Temerkhanov /**
1162ffd87d3SSergey Temerkhanov * ice_pkg_val_buf
1172ffd87d3SSergey Temerkhanov * @buf: pointer to the ice buffer
1182ffd87d3SSergey Temerkhanov *
1192ffd87d3SSergey Temerkhanov * This helper function validates a buffer's header.
1202ffd87d3SSergey Temerkhanov */
ice_pkg_val_buf(struct ice_buf * buf)121*708b352fSJan Sokolowski static struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf)
1222ffd87d3SSergey Temerkhanov {
1232ffd87d3SSergey Temerkhanov struct ice_buf_hdr *hdr;
1242ffd87d3SSergey Temerkhanov u16 section_count;
1252ffd87d3SSergey Temerkhanov u16 data_end;
1262ffd87d3SSergey Temerkhanov
1272ffd87d3SSergey Temerkhanov hdr = (struct ice_buf_hdr *)buf->buf;
1282ffd87d3SSergey Temerkhanov /* verify data */
1292ffd87d3SSergey Temerkhanov section_count = le16_to_cpu(hdr->section_count);
1302ffd87d3SSergey Temerkhanov if (section_count < ICE_MIN_S_COUNT || section_count > ICE_MAX_S_COUNT)
1312ffd87d3SSergey Temerkhanov return NULL;
1322ffd87d3SSergey Temerkhanov
1332ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(hdr->data_end);
1342ffd87d3SSergey Temerkhanov if (data_end < ICE_MIN_S_DATA_END || data_end > ICE_MAX_S_DATA_END)
1352ffd87d3SSergey Temerkhanov return NULL;
1362ffd87d3SSergey Temerkhanov
1372ffd87d3SSergey Temerkhanov return hdr;
1382ffd87d3SSergey Temerkhanov }
1392ffd87d3SSergey Temerkhanov
1402ffd87d3SSergey Temerkhanov /**
1412ffd87d3SSergey Temerkhanov * ice_find_buf_table
1422ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment
1432ffd87d3SSergey Temerkhanov *
1442ffd87d3SSergey Temerkhanov * Returns the address of the buffer table within the ice segment.
1452ffd87d3SSergey Temerkhanov */
ice_find_buf_table(struct ice_seg * ice_seg)1462ffd87d3SSergey Temerkhanov static struct ice_buf_table *ice_find_buf_table(struct ice_seg *ice_seg)
1472ffd87d3SSergey Temerkhanov {
1482ffd87d3SSergey Temerkhanov struct ice_nvm_table *nvms = (struct ice_nvm_table *)
1492ffd87d3SSergey Temerkhanov (ice_seg->device_table + le32_to_cpu(ice_seg->device_table_count));
1502ffd87d3SSergey Temerkhanov
1512ffd87d3SSergey Temerkhanov return (__force struct ice_buf_table *)(nvms->vers +
1522ffd87d3SSergey Temerkhanov le32_to_cpu(nvms->table_count));
1532ffd87d3SSergey Temerkhanov }
1542ffd87d3SSergey Temerkhanov
1552ffd87d3SSergey Temerkhanov /**
1562ffd87d3SSergey Temerkhanov * ice_pkg_enum_buf
1572ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
1582ffd87d3SSergey Temerkhanov * @state: pointer to the enum state
1592ffd87d3SSergey Temerkhanov *
1602ffd87d3SSergey Temerkhanov * This function will enumerate all the buffers in the ice segment. The first
1612ffd87d3SSergey Temerkhanov * call is made with the ice_seg parameter non-NULL; on subsequent calls,
1622ffd87d3SSergey Temerkhanov * ice_seg is set to NULL which continues the enumeration. When the function
1632ffd87d3SSergey Temerkhanov * returns a NULL pointer, then the end of the buffers has been reached, or an
1642ffd87d3SSergey Temerkhanov * unexpected value has been detected (for example an invalid section count or
1652ffd87d3SSergey Temerkhanov * an invalid buffer end value).
1662ffd87d3SSergey Temerkhanov */
ice_pkg_enum_buf(struct ice_seg * ice_seg,struct ice_pkg_enum * state)1672ffd87d3SSergey Temerkhanov static struct ice_buf_hdr *ice_pkg_enum_buf(struct ice_seg *ice_seg,
1682ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state)
1692ffd87d3SSergey Temerkhanov {
1702ffd87d3SSergey Temerkhanov if (ice_seg) {
1712ffd87d3SSergey Temerkhanov state->buf_table = ice_find_buf_table(ice_seg);
1722ffd87d3SSergey Temerkhanov if (!state->buf_table)
1732ffd87d3SSergey Temerkhanov return NULL;
1742ffd87d3SSergey Temerkhanov
1752ffd87d3SSergey Temerkhanov state->buf_idx = 0;
1762ffd87d3SSergey Temerkhanov return ice_pkg_val_buf(state->buf_table->buf_array);
1772ffd87d3SSergey Temerkhanov }
1782ffd87d3SSergey Temerkhanov
1792ffd87d3SSergey Temerkhanov if (++state->buf_idx < le32_to_cpu(state->buf_table->buf_count))
1802ffd87d3SSergey Temerkhanov return ice_pkg_val_buf(state->buf_table->buf_array +
1812ffd87d3SSergey Temerkhanov state->buf_idx);
1822ffd87d3SSergey Temerkhanov else
1832ffd87d3SSergey Temerkhanov return NULL;
1842ffd87d3SSergey Temerkhanov }
1852ffd87d3SSergey Temerkhanov
1862ffd87d3SSergey Temerkhanov /**
1872ffd87d3SSergey Temerkhanov * ice_pkg_advance_sect
1882ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
1892ffd87d3SSergey Temerkhanov * @state: pointer to the enum state
1902ffd87d3SSergey Temerkhanov *
1912ffd87d3SSergey Temerkhanov * This helper function will advance the section within the ice segment,
1922ffd87d3SSergey Temerkhanov * also advancing the buffer if needed.
1932ffd87d3SSergey Temerkhanov */
ice_pkg_advance_sect(struct ice_seg * ice_seg,struct ice_pkg_enum * state)1942ffd87d3SSergey Temerkhanov static bool ice_pkg_advance_sect(struct ice_seg *ice_seg,
1952ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state)
1962ffd87d3SSergey Temerkhanov {
1972ffd87d3SSergey Temerkhanov if (!ice_seg && !state->buf)
1982ffd87d3SSergey Temerkhanov return false;
1992ffd87d3SSergey Temerkhanov
2002ffd87d3SSergey Temerkhanov if (!ice_seg && state->buf)
2012ffd87d3SSergey Temerkhanov if (++state->sect_idx < le16_to_cpu(state->buf->section_count))
2022ffd87d3SSergey Temerkhanov return true;
2032ffd87d3SSergey Temerkhanov
2042ffd87d3SSergey Temerkhanov state->buf = ice_pkg_enum_buf(ice_seg, state);
2052ffd87d3SSergey Temerkhanov if (!state->buf)
2062ffd87d3SSergey Temerkhanov return false;
2072ffd87d3SSergey Temerkhanov
2082ffd87d3SSergey Temerkhanov /* start of new buffer, reset section index */
2092ffd87d3SSergey Temerkhanov state->sect_idx = 0;
2102ffd87d3SSergey Temerkhanov return true;
2112ffd87d3SSergey Temerkhanov }
2122ffd87d3SSergey Temerkhanov
2132ffd87d3SSergey Temerkhanov /**
2142ffd87d3SSergey Temerkhanov * ice_pkg_enum_section
2152ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
2162ffd87d3SSergey Temerkhanov * @state: pointer to the enum state
2172ffd87d3SSergey Temerkhanov * @sect_type: section type to enumerate
2182ffd87d3SSergey Temerkhanov *
2192ffd87d3SSergey Temerkhanov * This function will enumerate all the sections of a particular type in the
2202ffd87d3SSergey Temerkhanov * ice segment. The first call is made with the ice_seg parameter non-NULL;
2212ffd87d3SSergey Temerkhanov * on subsequent calls, ice_seg is set to NULL which continues the enumeration.
2222ffd87d3SSergey Temerkhanov * When the function returns a NULL pointer, then the end of the matching
2232ffd87d3SSergey Temerkhanov * sections has been reached.
2242ffd87d3SSergey Temerkhanov */
ice_pkg_enum_section(struct ice_seg * ice_seg,struct ice_pkg_enum * state,u32 sect_type)2252ffd87d3SSergey Temerkhanov void *ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
2262ffd87d3SSergey Temerkhanov u32 sect_type)
2272ffd87d3SSergey Temerkhanov {
2282ffd87d3SSergey Temerkhanov u16 offset, size;
2292ffd87d3SSergey Temerkhanov
2302ffd87d3SSergey Temerkhanov if (ice_seg)
2312ffd87d3SSergey Temerkhanov state->type = sect_type;
2322ffd87d3SSergey Temerkhanov
2332ffd87d3SSergey Temerkhanov if (!ice_pkg_advance_sect(ice_seg, state))
2342ffd87d3SSergey Temerkhanov return NULL;
2352ffd87d3SSergey Temerkhanov
2362ffd87d3SSergey Temerkhanov /* scan for next matching section */
2372ffd87d3SSergey Temerkhanov while (state->buf->section_entry[state->sect_idx].type !=
2382ffd87d3SSergey Temerkhanov cpu_to_le32(state->type))
2392ffd87d3SSergey Temerkhanov if (!ice_pkg_advance_sect(NULL, state))
2402ffd87d3SSergey Temerkhanov return NULL;
2412ffd87d3SSergey Temerkhanov
2422ffd87d3SSergey Temerkhanov /* validate section */
2432ffd87d3SSergey Temerkhanov offset = le16_to_cpu(state->buf->section_entry[state->sect_idx].offset);
2442ffd87d3SSergey Temerkhanov if (offset < ICE_MIN_S_OFF || offset > ICE_MAX_S_OFF)
2452ffd87d3SSergey Temerkhanov return NULL;
2462ffd87d3SSergey Temerkhanov
2472ffd87d3SSergey Temerkhanov size = le16_to_cpu(state->buf->section_entry[state->sect_idx].size);
2482ffd87d3SSergey Temerkhanov if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ)
2492ffd87d3SSergey Temerkhanov return NULL;
2502ffd87d3SSergey Temerkhanov
2512ffd87d3SSergey Temerkhanov /* make sure the section fits in the buffer */
2522ffd87d3SSergey Temerkhanov if (offset + size > ICE_PKG_BUF_SIZE)
2532ffd87d3SSergey Temerkhanov return NULL;
2542ffd87d3SSergey Temerkhanov
2552ffd87d3SSergey Temerkhanov state->sect_type =
2562ffd87d3SSergey Temerkhanov le32_to_cpu(state->buf->section_entry[state->sect_idx].type);
2572ffd87d3SSergey Temerkhanov
2582ffd87d3SSergey Temerkhanov /* calc pointer to this section */
2592ffd87d3SSergey Temerkhanov state->sect =
2602ffd87d3SSergey Temerkhanov ((u8 *)state->buf) +
2612ffd87d3SSergey Temerkhanov le16_to_cpu(state->buf->section_entry[state->sect_idx].offset);
2622ffd87d3SSergey Temerkhanov
2632ffd87d3SSergey Temerkhanov return state->sect;
2642ffd87d3SSergey Temerkhanov }
2652ffd87d3SSergey Temerkhanov
2662ffd87d3SSergey Temerkhanov /**
2672ffd87d3SSergey Temerkhanov * ice_pkg_enum_entry
2682ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
2692ffd87d3SSergey Temerkhanov * @state: pointer to the enum state
2702ffd87d3SSergey Temerkhanov * @sect_type: section type to enumerate
2712ffd87d3SSergey Temerkhanov * @offset: pointer to variable that receives the offset in the table (optional)
2722ffd87d3SSergey Temerkhanov * @handler: function that handles access to the entries into the section type
2732ffd87d3SSergey Temerkhanov *
2742ffd87d3SSergey Temerkhanov * This function will enumerate all the entries in particular section type in
2752ffd87d3SSergey Temerkhanov * the ice segment. The first call is made with the ice_seg parameter non-NULL;
2762ffd87d3SSergey Temerkhanov * on subsequent calls, ice_seg is set to NULL which continues the enumeration.
2772ffd87d3SSergey Temerkhanov * When the function returns a NULL pointer, then the end of the entries has
2782ffd87d3SSergey Temerkhanov * been reached.
2792ffd87d3SSergey Temerkhanov *
2802ffd87d3SSergey Temerkhanov * Since each section may have a different header and entry size, the handler
2812ffd87d3SSergey Temerkhanov * function is needed to determine the number and location entries in each
2822ffd87d3SSergey Temerkhanov * section.
2832ffd87d3SSergey Temerkhanov *
2842ffd87d3SSergey Temerkhanov * The offset parameter is optional, but should be used for sections that
2852ffd87d3SSergey Temerkhanov * contain an offset for each section table. For such cases, the section handler
2862ffd87d3SSergey Temerkhanov * function must return the appropriate offset + index to give the absolution
2872ffd87d3SSergey Temerkhanov * offset for each entry. For example, if the base for a section's header
2882ffd87d3SSergey Temerkhanov * indicates a base offset of 10, and the index for the entry is 2, then
2892ffd87d3SSergey Temerkhanov * section handler function should set the offset to 10 + 2 = 12.
2902ffd87d3SSergey Temerkhanov */
ice_pkg_enum_entry(struct ice_seg * ice_seg,struct ice_pkg_enum * state,u32 sect_type,u32 * offset,void * (* handler)(u32 sect_type,void * section,u32 index,u32 * offset))2912ffd87d3SSergey Temerkhanov static void *ice_pkg_enum_entry(struct ice_seg *ice_seg,
2922ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state, u32 sect_type,
2932ffd87d3SSergey Temerkhanov u32 *offset,
2942ffd87d3SSergey Temerkhanov void *(*handler)(u32 sect_type, void *section,
2952ffd87d3SSergey Temerkhanov u32 index, u32 *offset))
2962ffd87d3SSergey Temerkhanov {
2972ffd87d3SSergey Temerkhanov void *entry;
2982ffd87d3SSergey Temerkhanov
2992ffd87d3SSergey Temerkhanov if (ice_seg) {
3002ffd87d3SSergey Temerkhanov if (!handler)
3012ffd87d3SSergey Temerkhanov return NULL;
3022ffd87d3SSergey Temerkhanov
3032ffd87d3SSergey Temerkhanov if (!ice_pkg_enum_section(ice_seg, state, sect_type))
3042ffd87d3SSergey Temerkhanov return NULL;
3052ffd87d3SSergey Temerkhanov
3062ffd87d3SSergey Temerkhanov state->entry_idx = 0;
3072ffd87d3SSergey Temerkhanov state->handler = handler;
3082ffd87d3SSergey Temerkhanov } else {
3092ffd87d3SSergey Temerkhanov state->entry_idx++;
3102ffd87d3SSergey Temerkhanov }
3112ffd87d3SSergey Temerkhanov
3122ffd87d3SSergey Temerkhanov if (!state->handler)
3132ffd87d3SSergey Temerkhanov return NULL;
3142ffd87d3SSergey Temerkhanov
3152ffd87d3SSergey Temerkhanov /* get entry */
3162ffd87d3SSergey Temerkhanov entry = state->handler(state->sect_type, state->sect, state->entry_idx,
3172ffd87d3SSergey Temerkhanov offset);
3182ffd87d3SSergey Temerkhanov if (!entry) {
3192ffd87d3SSergey Temerkhanov /* end of a section, look for another section of this type */
3202ffd87d3SSergey Temerkhanov if (!ice_pkg_enum_section(NULL, state, 0))
3212ffd87d3SSergey Temerkhanov return NULL;
3222ffd87d3SSergey Temerkhanov
3232ffd87d3SSergey Temerkhanov state->entry_idx = 0;
3242ffd87d3SSergey Temerkhanov entry = state->handler(state->sect_type, state->sect,
3252ffd87d3SSergey Temerkhanov state->entry_idx, offset);
3262ffd87d3SSergey Temerkhanov }
3272ffd87d3SSergey Temerkhanov
3282ffd87d3SSergey Temerkhanov return entry;
3292ffd87d3SSergey Temerkhanov }
3302ffd87d3SSergey Temerkhanov
3312ffd87d3SSergey Temerkhanov /**
3322ffd87d3SSergey Temerkhanov * ice_sw_fv_handler
3332ffd87d3SSergey Temerkhanov * @sect_type: section type
3342ffd87d3SSergey Temerkhanov * @section: pointer to section
3352ffd87d3SSergey Temerkhanov * @index: index of the field vector entry to be returned
3362ffd87d3SSergey Temerkhanov * @offset: ptr to variable that receives the offset in the field vector table
3372ffd87d3SSergey Temerkhanov *
3382ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry.
3392ffd87d3SSergey Temerkhanov * This function treats the given section as of type ice_sw_fv_section and
3402ffd87d3SSergey Temerkhanov * enumerates offset field. "offset" is an index into the field vector table.
3412ffd87d3SSergey Temerkhanov */
ice_sw_fv_handler(u32 sect_type,void * section,u32 index,u32 * offset)3422ffd87d3SSergey Temerkhanov static void *ice_sw_fv_handler(u32 sect_type, void *section, u32 index,
3432ffd87d3SSergey Temerkhanov u32 *offset)
3442ffd87d3SSergey Temerkhanov {
3452ffd87d3SSergey Temerkhanov struct ice_sw_fv_section *fv_section = section;
3462ffd87d3SSergey Temerkhanov
3472ffd87d3SSergey Temerkhanov if (!section || sect_type != ICE_SID_FLD_VEC_SW)
3482ffd87d3SSergey Temerkhanov return NULL;
3492ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(fv_section->count))
3502ffd87d3SSergey Temerkhanov return NULL;
3512ffd87d3SSergey Temerkhanov if (offset)
3522ffd87d3SSergey Temerkhanov /* "index" passed in to this function is relative to a given
3532ffd87d3SSergey Temerkhanov * 4k block. To get to the true index into the field vector
3542ffd87d3SSergey Temerkhanov * table need to add the relative index to the base_offset
3552ffd87d3SSergey Temerkhanov * field of this section
3562ffd87d3SSergey Temerkhanov */
3572ffd87d3SSergey Temerkhanov *offset = le16_to_cpu(fv_section->base_offset) + index;
3582ffd87d3SSergey Temerkhanov return fv_section->fv + index;
3592ffd87d3SSergey Temerkhanov }
3602ffd87d3SSergey Temerkhanov
3612ffd87d3SSergey Temerkhanov /**
3622ffd87d3SSergey Temerkhanov * ice_get_prof_index_max - get the max profile index for used profile
3632ffd87d3SSergey Temerkhanov * @hw: pointer to the HW struct
3642ffd87d3SSergey Temerkhanov *
3652ffd87d3SSergey Temerkhanov * Calling this function will get the max profile index for used profile
3662ffd87d3SSergey Temerkhanov * and store the index number in struct ice_switch_info *switch_info
3672ffd87d3SSergey Temerkhanov * in HW for following use.
3682ffd87d3SSergey Temerkhanov */
ice_get_prof_index_max(struct ice_hw * hw)3692ffd87d3SSergey Temerkhanov static int ice_get_prof_index_max(struct ice_hw *hw)
3702ffd87d3SSergey Temerkhanov {
3712ffd87d3SSergey Temerkhanov u16 prof_index = 0, j, max_prof_index = 0;
3722ffd87d3SSergey Temerkhanov struct ice_pkg_enum state;
3732ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg;
3742ffd87d3SSergey Temerkhanov bool flag = false;
3752ffd87d3SSergey Temerkhanov struct ice_fv *fv;
3762ffd87d3SSergey Temerkhanov u32 offset;
3772ffd87d3SSergey Temerkhanov
3782ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state));
3792ffd87d3SSergey Temerkhanov
3802ffd87d3SSergey Temerkhanov if (!hw->seg)
3812ffd87d3SSergey Temerkhanov return -EINVAL;
3822ffd87d3SSergey Temerkhanov
3832ffd87d3SSergey Temerkhanov ice_seg = hw->seg;
3842ffd87d3SSergey Temerkhanov
3852ffd87d3SSergey Temerkhanov do {
3862ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
3872ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler);
3882ffd87d3SSergey Temerkhanov if (!fv)
3892ffd87d3SSergey Temerkhanov break;
3902ffd87d3SSergey Temerkhanov ice_seg = NULL;
3912ffd87d3SSergey Temerkhanov
3922ffd87d3SSergey Temerkhanov /* in the profile that not be used, the prot_id is set to 0xff
3932ffd87d3SSergey Temerkhanov * and the off is set to 0x1ff for all the field vectors.
3942ffd87d3SSergey Temerkhanov */
3952ffd87d3SSergey Temerkhanov for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
3962ffd87d3SSergey Temerkhanov if (fv->ew[j].prot_id != ICE_PROT_INVALID ||
3972ffd87d3SSergey Temerkhanov fv->ew[j].off != ICE_FV_OFFSET_INVAL)
3982ffd87d3SSergey Temerkhanov flag = true;
3992ffd87d3SSergey Temerkhanov if (flag && prof_index > max_prof_index)
4002ffd87d3SSergey Temerkhanov max_prof_index = prof_index;
4012ffd87d3SSergey Temerkhanov
4022ffd87d3SSergey Temerkhanov prof_index++;
4032ffd87d3SSergey Temerkhanov flag = false;
4042ffd87d3SSergey Temerkhanov } while (fv);
4052ffd87d3SSergey Temerkhanov
4062ffd87d3SSergey Temerkhanov hw->switch_info->max_used_prof_index = max_prof_index;
4072ffd87d3SSergey Temerkhanov
4082ffd87d3SSergey Temerkhanov return 0;
4092ffd87d3SSergey Temerkhanov }
4102ffd87d3SSergey Temerkhanov
4112ffd87d3SSergey Temerkhanov /**
4122ffd87d3SSergey Temerkhanov * ice_get_ddp_pkg_state - get DDP pkg state after download
4132ffd87d3SSergey Temerkhanov * @hw: pointer to the HW struct
4142ffd87d3SSergey Temerkhanov * @already_loaded: indicates if pkg was already loaded onto the device
4152ffd87d3SSergey Temerkhanov */
ice_get_ddp_pkg_state(struct ice_hw * hw,bool already_loaded)4162ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_ddp_pkg_state(struct ice_hw *hw,
4172ffd87d3SSergey Temerkhanov bool already_loaded)
4182ffd87d3SSergey Temerkhanov {
4192ffd87d3SSergey Temerkhanov if (hw->pkg_ver.major == hw->active_pkg_ver.major &&
4202ffd87d3SSergey Temerkhanov hw->pkg_ver.minor == hw->active_pkg_ver.minor &&
4212ffd87d3SSergey Temerkhanov hw->pkg_ver.update == hw->active_pkg_ver.update &&
4222ffd87d3SSergey Temerkhanov hw->pkg_ver.draft == hw->active_pkg_ver.draft &&
4232ffd87d3SSergey Temerkhanov !memcmp(hw->pkg_name, hw->active_pkg_name, sizeof(hw->pkg_name))) {
4242ffd87d3SSergey Temerkhanov if (already_loaded)
4252ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED;
4262ffd87d3SSergey Temerkhanov else
4272ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS;
4282ffd87d3SSergey Temerkhanov } else if (hw->active_pkg_ver.major != ICE_PKG_SUPP_VER_MAJ ||
4292ffd87d3SSergey Temerkhanov hw->active_pkg_ver.minor != ICE_PKG_SUPP_VER_MNR) {
4302ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ALREADY_LOADED_NOT_SUPPORTED;
4312ffd87d3SSergey Temerkhanov } else if (hw->active_pkg_ver.major == ICE_PKG_SUPP_VER_MAJ &&
4322ffd87d3SSergey Temerkhanov hw->active_pkg_ver.minor == ICE_PKG_SUPP_VER_MNR) {
4332ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED;
4342ffd87d3SSergey Temerkhanov } else {
4352ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR;
4362ffd87d3SSergey Temerkhanov }
4372ffd87d3SSergey Temerkhanov }
4382ffd87d3SSergey Temerkhanov
4392ffd87d3SSergey Temerkhanov /**
4402ffd87d3SSergey Temerkhanov * ice_init_pkg_regs - initialize additional package registers
4412ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
4422ffd87d3SSergey Temerkhanov */
ice_init_pkg_regs(struct ice_hw * hw)4432ffd87d3SSergey Temerkhanov static void ice_init_pkg_regs(struct ice_hw *hw)
4442ffd87d3SSergey Temerkhanov {
4452ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_INP_MASK_L 0xFFFFFFFF
4462ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_INP_MASK_H 0x0000FFFF
4472ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_IDX 0
4482ffd87d3SSergey Temerkhanov
4492ffd87d3SSergey Temerkhanov /* setup Switch block input mask, which is 48-bits in two parts */
4502ffd87d3SSergey Temerkhanov wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L);
4512ffd87d3SSergey Temerkhanov wr32(hw, GL_PREEXT_L2_PMASK1(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_H);
4522ffd87d3SSergey Temerkhanov }
4532ffd87d3SSergey Temerkhanov
4542ffd87d3SSergey Temerkhanov /**
4552ffd87d3SSergey Temerkhanov * ice_marker_ptype_tcam_handler
4562ffd87d3SSergey Temerkhanov * @sect_type: section type
4572ffd87d3SSergey Temerkhanov * @section: pointer to section
4582ffd87d3SSergey Temerkhanov * @index: index of the Marker PType TCAM entry to be returned
4592ffd87d3SSergey Temerkhanov * @offset: pointer to receive absolute offset, always 0 for ptype TCAM sections
4602ffd87d3SSergey Temerkhanov *
4612ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry.
4622ffd87d3SSergey Temerkhanov * Handles enumeration of individual Marker PType TCAM entries.
4632ffd87d3SSergey Temerkhanov */
ice_marker_ptype_tcam_handler(u32 sect_type,void * section,u32 index,u32 * offset)4642ffd87d3SSergey Temerkhanov static void *ice_marker_ptype_tcam_handler(u32 sect_type, void *section,
4652ffd87d3SSergey Temerkhanov u32 index, u32 *offset)
4662ffd87d3SSergey Temerkhanov {
4672ffd87d3SSergey Temerkhanov struct ice_marker_ptype_tcam_section *marker_ptype;
4682ffd87d3SSergey Temerkhanov
4692ffd87d3SSergey Temerkhanov if (sect_type != ICE_SID_RXPARSER_MARKER_PTYPE)
4702ffd87d3SSergey Temerkhanov return NULL;
4712ffd87d3SSergey Temerkhanov
4722ffd87d3SSergey Temerkhanov if (index > ICE_MAX_MARKER_PTYPE_TCAMS_IN_BUF)
4732ffd87d3SSergey Temerkhanov return NULL;
4742ffd87d3SSergey Temerkhanov
4752ffd87d3SSergey Temerkhanov if (offset)
4762ffd87d3SSergey Temerkhanov *offset = 0;
4772ffd87d3SSergey Temerkhanov
4782ffd87d3SSergey Temerkhanov marker_ptype = section;
4792ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(marker_ptype->count))
4802ffd87d3SSergey Temerkhanov return NULL;
4812ffd87d3SSergey Temerkhanov
4822ffd87d3SSergey Temerkhanov return marker_ptype->tcam + index;
4832ffd87d3SSergey Temerkhanov }
4842ffd87d3SSergey Temerkhanov
4852ffd87d3SSergey Temerkhanov /**
4862ffd87d3SSergey Temerkhanov * ice_add_dvm_hint
4872ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
4882ffd87d3SSergey Temerkhanov * @val: value of the boost entry
4892ffd87d3SSergey Temerkhanov * @enable: true if entry needs to be enabled, or false if needs to be disabled
4902ffd87d3SSergey Temerkhanov */
ice_add_dvm_hint(struct ice_hw * hw,u16 val,bool enable)4912ffd87d3SSergey Temerkhanov static void ice_add_dvm_hint(struct ice_hw *hw, u16 val, bool enable)
4922ffd87d3SSergey Temerkhanov {
4932ffd87d3SSergey Temerkhanov if (hw->dvm_upd.count < ICE_DVM_MAX_ENTRIES) {
4942ffd87d3SSergey Temerkhanov hw->dvm_upd.tbl[hw->dvm_upd.count].boost_addr = val;
4952ffd87d3SSergey Temerkhanov hw->dvm_upd.tbl[hw->dvm_upd.count].enable = enable;
4962ffd87d3SSergey Temerkhanov hw->dvm_upd.count++;
4972ffd87d3SSergey Temerkhanov }
4982ffd87d3SSergey Temerkhanov }
4992ffd87d3SSergey Temerkhanov
5002ffd87d3SSergey Temerkhanov /**
5012ffd87d3SSergey Temerkhanov * ice_add_tunnel_hint
5022ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
5032ffd87d3SSergey Temerkhanov * @label_name: label text
5042ffd87d3SSergey Temerkhanov * @val: value of the tunnel port boost entry
5052ffd87d3SSergey Temerkhanov */
ice_add_tunnel_hint(struct ice_hw * hw,char * label_name,u16 val)5062ffd87d3SSergey Temerkhanov static void ice_add_tunnel_hint(struct ice_hw *hw, char *label_name, u16 val)
5072ffd87d3SSergey Temerkhanov {
5082ffd87d3SSergey Temerkhanov if (hw->tnl.count < ICE_TUNNEL_MAX_ENTRIES) {
5092ffd87d3SSergey Temerkhanov u16 i;
5102ffd87d3SSergey Temerkhanov
5112ffd87d3SSergey Temerkhanov for (i = 0; tnls[i].type != TNL_LAST; i++) {
5122ffd87d3SSergey Temerkhanov size_t len = strlen(tnls[i].label_prefix);
5132ffd87d3SSergey Temerkhanov
5142ffd87d3SSergey Temerkhanov /* Look for matching label start, before continuing */
5152ffd87d3SSergey Temerkhanov if (strncmp(label_name, tnls[i].label_prefix, len))
5162ffd87d3SSergey Temerkhanov continue;
5172ffd87d3SSergey Temerkhanov
5182ffd87d3SSergey Temerkhanov /* Make sure this label matches our PF. Note that the PF
5192ffd87d3SSergey Temerkhanov * character ('0' - '7') will be located where our
5202ffd87d3SSergey Temerkhanov * prefix string's null terminator is located.
5212ffd87d3SSergey Temerkhanov */
5222ffd87d3SSergey Temerkhanov if ((label_name[len] - '0') == hw->pf_id) {
5232ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].type = tnls[i].type;
5242ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].valid = false;
5252ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].boost_addr = val;
5262ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].port = 0;
5272ffd87d3SSergey Temerkhanov hw->tnl.count++;
5282ffd87d3SSergey Temerkhanov break;
5292ffd87d3SSergey Temerkhanov }
5302ffd87d3SSergey Temerkhanov }
5312ffd87d3SSergey Temerkhanov }
5322ffd87d3SSergey Temerkhanov }
5332ffd87d3SSergey Temerkhanov
5342ffd87d3SSergey Temerkhanov /**
5352ffd87d3SSergey Temerkhanov * ice_label_enum_handler
5362ffd87d3SSergey Temerkhanov * @sect_type: section type
5372ffd87d3SSergey Temerkhanov * @section: pointer to section
5382ffd87d3SSergey Temerkhanov * @index: index of the label entry to be returned
5392ffd87d3SSergey Temerkhanov * @offset: pointer to receive absolute offset, always zero for label sections
5402ffd87d3SSergey Temerkhanov *
5412ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry.
5422ffd87d3SSergey Temerkhanov * Handles enumeration of individual label entries.
5432ffd87d3SSergey Temerkhanov */
ice_label_enum_handler(u32 __always_unused sect_type,void * section,u32 index,u32 * offset)5442ffd87d3SSergey Temerkhanov static void *ice_label_enum_handler(u32 __always_unused sect_type,
5452ffd87d3SSergey Temerkhanov void *section, u32 index, u32 *offset)
5462ffd87d3SSergey Temerkhanov {
5472ffd87d3SSergey Temerkhanov struct ice_label_section *labels;
5482ffd87d3SSergey Temerkhanov
5492ffd87d3SSergey Temerkhanov if (!section)
5502ffd87d3SSergey Temerkhanov return NULL;
5512ffd87d3SSergey Temerkhanov
5522ffd87d3SSergey Temerkhanov if (index > ICE_MAX_LABELS_IN_BUF)
5532ffd87d3SSergey Temerkhanov return NULL;
5542ffd87d3SSergey Temerkhanov
5552ffd87d3SSergey Temerkhanov if (offset)
5562ffd87d3SSergey Temerkhanov *offset = 0;
5572ffd87d3SSergey Temerkhanov
5582ffd87d3SSergey Temerkhanov labels = section;
5592ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(labels->count))
5602ffd87d3SSergey Temerkhanov return NULL;
5612ffd87d3SSergey Temerkhanov
5622ffd87d3SSergey Temerkhanov return labels->label + index;
5632ffd87d3SSergey Temerkhanov }
5642ffd87d3SSergey Temerkhanov
5652ffd87d3SSergey Temerkhanov /**
5662ffd87d3SSergey Temerkhanov * ice_enum_labels
5672ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (NULL on subsequent calls)
5682ffd87d3SSergey Temerkhanov * @type: the section type that will contain the label (0 on subsequent calls)
5692ffd87d3SSergey Temerkhanov * @state: ice_pkg_enum structure that will hold the state of the enumeration
5702ffd87d3SSergey Temerkhanov * @value: pointer to a value that will return the label's value if found
5712ffd87d3SSergey Temerkhanov *
5722ffd87d3SSergey Temerkhanov * Enumerates a list of labels in the package. The caller will call
5732ffd87d3SSergey Temerkhanov * ice_enum_labels(ice_seg, type, ...) to start the enumeration, then call
5742ffd87d3SSergey Temerkhanov * ice_enum_labels(NULL, 0, ...) to continue. When the function returns a NULL
5752ffd87d3SSergey Temerkhanov * the end of the list has been reached.
5762ffd87d3SSergey Temerkhanov */
ice_enum_labels(struct ice_seg * ice_seg,u32 type,struct ice_pkg_enum * state,u16 * value)5772ffd87d3SSergey Temerkhanov static char *ice_enum_labels(struct ice_seg *ice_seg, u32 type,
5782ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state, u16 *value)
5792ffd87d3SSergey Temerkhanov {
5802ffd87d3SSergey Temerkhanov struct ice_label *label;
5812ffd87d3SSergey Temerkhanov
5822ffd87d3SSergey Temerkhanov /* Check for valid label section on first call */
5832ffd87d3SSergey Temerkhanov if (type && !(type >= ICE_SID_LBL_FIRST && type <= ICE_SID_LBL_LAST))
5842ffd87d3SSergey Temerkhanov return NULL;
5852ffd87d3SSergey Temerkhanov
5862ffd87d3SSergey Temerkhanov label = ice_pkg_enum_entry(ice_seg, state, type, NULL,
5872ffd87d3SSergey Temerkhanov ice_label_enum_handler);
5882ffd87d3SSergey Temerkhanov if (!label)
5892ffd87d3SSergey Temerkhanov return NULL;
5902ffd87d3SSergey Temerkhanov
5912ffd87d3SSergey Temerkhanov *value = le16_to_cpu(label->value);
5922ffd87d3SSergey Temerkhanov return label->name;
5932ffd87d3SSergey Temerkhanov }
5942ffd87d3SSergey Temerkhanov
5952ffd87d3SSergey Temerkhanov /**
5962ffd87d3SSergey Temerkhanov * ice_boost_tcam_handler
5972ffd87d3SSergey Temerkhanov * @sect_type: section type
5982ffd87d3SSergey Temerkhanov * @section: pointer to section
5992ffd87d3SSergey Temerkhanov * @index: index of the boost TCAM entry to be returned
6002ffd87d3SSergey Temerkhanov * @offset: pointer to receive absolute offset, always 0 for boost TCAM sections
6012ffd87d3SSergey Temerkhanov *
6022ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry.
6032ffd87d3SSergey Temerkhanov * Handles enumeration of individual boost TCAM entries.
6042ffd87d3SSergey Temerkhanov */
ice_boost_tcam_handler(u32 sect_type,void * section,u32 index,u32 * offset)6052ffd87d3SSergey Temerkhanov static void *ice_boost_tcam_handler(u32 sect_type, void *section, u32 index,
6062ffd87d3SSergey Temerkhanov u32 *offset)
6072ffd87d3SSergey Temerkhanov {
6082ffd87d3SSergey Temerkhanov struct ice_boost_tcam_section *boost;
6092ffd87d3SSergey Temerkhanov
6102ffd87d3SSergey Temerkhanov if (!section)
6112ffd87d3SSergey Temerkhanov return NULL;
6122ffd87d3SSergey Temerkhanov
6132ffd87d3SSergey Temerkhanov if (sect_type != ICE_SID_RXPARSER_BOOST_TCAM)
6142ffd87d3SSergey Temerkhanov return NULL;
6152ffd87d3SSergey Temerkhanov
6162ffd87d3SSergey Temerkhanov if (index > ICE_MAX_BST_TCAMS_IN_BUF)
6172ffd87d3SSergey Temerkhanov return NULL;
6182ffd87d3SSergey Temerkhanov
6192ffd87d3SSergey Temerkhanov if (offset)
6202ffd87d3SSergey Temerkhanov *offset = 0;
6212ffd87d3SSergey Temerkhanov
6222ffd87d3SSergey Temerkhanov boost = section;
6232ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(boost->count))
6242ffd87d3SSergey Temerkhanov return NULL;
6252ffd87d3SSergey Temerkhanov
6262ffd87d3SSergey Temerkhanov return boost->tcam + index;
6272ffd87d3SSergey Temerkhanov }
6282ffd87d3SSergey Temerkhanov
6292ffd87d3SSergey Temerkhanov /**
6302ffd87d3SSergey Temerkhanov * ice_find_boost_entry
6312ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (non-NULL)
6322ffd87d3SSergey Temerkhanov * @addr: Boost TCAM address of entry to search for
6332ffd87d3SSergey Temerkhanov * @entry: returns pointer to the entry
6342ffd87d3SSergey Temerkhanov *
6352ffd87d3SSergey Temerkhanov * Finds a particular Boost TCAM entry and returns a pointer to that entry
6362ffd87d3SSergey Temerkhanov * if it is found. The ice_seg parameter must not be NULL since the first call
6372ffd87d3SSergey Temerkhanov * to ice_pkg_enum_entry requires a pointer to an actual ice_segment structure.
6382ffd87d3SSergey Temerkhanov */
ice_find_boost_entry(struct ice_seg * ice_seg,u16 addr,struct ice_boost_tcam_entry ** entry)6392ffd87d3SSergey Temerkhanov static int ice_find_boost_entry(struct ice_seg *ice_seg, u16 addr,
6402ffd87d3SSergey Temerkhanov struct ice_boost_tcam_entry **entry)
6412ffd87d3SSergey Temerkhanov {
6422ffd87d3SSergey Temerkhanov struct ice_boost_tcam_entry *tcam;
6432ffd87d3SSergey Temerkhanov struct ice_pkg_enum state;
6442ffd87d3SSergey Temerkhanov
6452ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state));
6462ffd87d3SSergey Temerkhanov
6472ffd87d3SSergey Temerkhanov if (!ice_seg)
6482ffd87d3SSergey Temerkhanov return -EINVAL;
6492ffd87d3SSergey Temerkhanov
6502ffd87d3SSergey Temerkhanov do {
6512ffd87d3SSergey Temerkhanov tcam = ice_pkg_enum_entry(ice_seg, &state,
6522ffd87d3SSergey Temerkhanov ICE_SID_RXPARSER_BOOST_TCAM, NULL,
6532ffd87d3SSergey Temerkhanov ice_boost_tcam_handler);
6542ffd87d3SSergey Temerkhanov if (tcam && le16_to_cpu(tcam->addr) == addr) {
6552ffd87d3SSergey Temerkhanov *entry = tcam;
6562ffd87d3SSergey Temerkhanov return 0;
6572ffd87d3SSergey Temerkhanov }
6582ffd87d3SSergey Temerkhanov
6592ffd87d3SSergey Temerkhanov ice_seg = NULL;
6602ffd87d3SSergey Temerkhanov } while (tcam);
6612ffd87d3SSergey Temerkhanov
6622ffd87d3SSergey Temerkhanov *entry = NULL;
6632ffd87d3SSergey Temerkhanov return -EIO;
6642ffd87d3SSergey Temerkhanov }
6652ffd87d3SSergey Temerkhanov
6662ffd87d3SSergey Temerkhanov /**
6672ffd87d3SSergey Temerkhanov * ice_is_init_pkg_successful - check if DDP init was successful
6682ffd87d3SSergey Temerkhanov * @state: state of the DDP pkg after download
6692ffd87d3SSergey Temerkhanov */
ice_is_init_pkg_successful(enum ice_ddp_state state)6702ffd87d3SSergey Temerkhanov bool ice_is_init_pkg_successful(enum ice_ddp_state state)
6712ffd87d3SSergey Temerkhanov {
6722ffd87d3SSergey Temerkhanov switch (state) {
6732ffd87d3SSergey Temerkhanov case ICE_DDP_PKG_SUCCESS:
6742ffd87d3SSergey Temerkhanov case ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED:
6752ffd87d3SSergey Temerkhanov case ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED:
6762ffd87d3SSergey Temerkhanov return true;
6772ffd87d3SSergey Temerkhanov default:
6782ffd87d3SSergey Temerkhanov return false;
6792ffd87d3SSergey Temerkhanov }
6802ffd87d3SSergey Temerkhanov }
6812ffd87d3SSergey Temerkhanov
6822ffd87d3SSergey Temerkhanov /**
6832ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc
6842ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
6852ffd87d3SSergey Temerkhanov *
6862ffd87d3SSergey Temerkhanov * Allocates a package buffer and returns a pointer to the buffer header.
6872ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form.
6882ffd87d3SSergey Temerkhanov */
ice_pkg_buf_alloc(struct ice_hw * hw)6892ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
6902ffd87d3SSergey Temerkhanov {
6912ffd87d3SSergey Temerkhanov struct ice_buf_build *bld;
6922ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf;
6932ffd87d3SSergey Temerkhanov
6942ffd87d3SSergey Temerkhanov bld = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*bld), GFP_KERNEL);
6952ffd87d3SSergey Temerkhanov if (!bld)
6962ffd87d3SSergey Temerkhanov return NULL;
6972ffd87d3SSergey Temerkhanov
6982ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)bld;
6992ffd87d3SSergey Temerkhanov buf->data_end =
7002ffd87d3SSergey Temerkhanov cpu_to_le16(offsetof(struct ice_buf_hdr, section_entry));
7012ffd87d3SSergey Temerkhanov return bld;
7022ffd87d3SSergey Temerkhanov }
7032ffd87d3SSergey Temerkhanov
ice_is_gtp_u_profile(u16 prof_idx)7042ffd87d3SSergey Temerkhanov static bool ice_is_gtp_u_profile(u16 prof_idx)
7052ffd87d3SSergey Temerkhanov {
7062ffd87d3SSergey Temerkhanov return (prof_idx >= ICE_PROFID_IPV6_GTPU_TEID &&
7072ffd87d3SSergey Temerkhanov prof_idx <= ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER) ||
7082ffd87d3SSergey Temerkhanov prof_idx == ICE_PROFID_IPV4_GTPU_TEID;
7092ffd87d3SSergey Temerkhanov }
7102ffd87d3SSergey Temerkhanov
ice_is_gtp_c_profile(u16 prof_idx)7112ffd87d3SSergey Temerkhanov static bool ice_is_gtp_c_profile(u16 prof_idx)
7122ffd87d3SSergey Temerkhanov {
7132ffd87d3SSergey Temerkhanov switch (prof_idx) {
7142ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV4_GTPC_TEID:
7152ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV4_GTPC_NO_TEID:
7162ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV6_GTPC_TEID:
7172ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV6_GTPC_NO_TEID:
7182ffd87d3SSergey Temerkhanov return true;
7192ffd87d3SSergey Temerkhanov default:
7202ffd87d3SSergey Temerkhanov return false;
7212ffd87d3SSergey Temerkhanov }
7222ffd87d3SSergey Temerkhanov }
7232ffd87d3SSergey Temerkhanov
7242ffd87d3SSergey Temerkhanov /**
7252ffd87d3SSergey Temerkhanov * ice_get_sw_prof_type - determine switch profile type
7262ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
7272ffd87d3SSergey Temerkhanov * @fv: pointer to the switch field vector
7282ffd87d3SSergey Temerkhanov * @prof_idx: profile index to check
7292ffd87d3SSergey Temerkhanov */
ice_get_sw_prof_type(struct ice_hw * hw,struct ice_fv * fv,u32 prof_idx)7302ffd87d3SSergey Temerkhanov static enum ice_prof_type ice_get_sw_prof_type(struct ice_hw *hw,
7312ffd87d3SSergey Temerkhanov struct ice_fv *fv, u32 prof_idx)
7322ffd87d3SSergey Temerkhanov {
7332ffd87d3SSergey Temerkhanov u16 i;
7342ffd87d3SSergey Temerkhanov
7352ffd87d3SSergey Temerkhanov if (ice_is_gtp_c_profile(prof_idx))
7362ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GTPC;
7372ffd87d3SSergey Temerkhanov
7382ffd87d3SSergey Temerkhanov if (ice_is_gtp_u_profile(prof_idx))
7392ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GTPU;
7402ffd87d3SSergey Temerkhanov
7412ffd87d3SSergey Temerkhanov for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) {
7422ffd87d3SSergey Temerkhanov /* UDP tunnel will have UDP_OF protocol ID and VNI offset */
7432ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF &&
7442ffd87d3SSergey Temerkhanov fv->ew[i].off == ICE_VNI_OFFSET)
7452ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_UDP;
7462ffd87d3SSergey Temerkhanov
7472ffd87d3SSergey Temerkhanov /* GRE tunnel will have GRE protocol */
7482ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == (u8)ICE_PROT_GRE_OF)
7492ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GRE;
7502ffd87d3SSergey Temerkhanov }
7512ffd87d3SSergey Temerkhanov
7522ffd87d3SSergey Temerkhanov return ICE_PROF_NON_TUN;
7532ffd87d3SSergey Temerkhanov }
7542ffd87d3SSergey Temerkhanov
7552ffd87d3SSergey Temerkhanov /**
7562ffd87d3SSergey Temerkhanov * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type
7572ffd87d3SSergey Temerkhanov * @hw: pointer to hardware structure
7582ffd87d3SSergey Temerkhanov * @req_profs: type of profiles requested
7592ffd87d3SSergey Temerkhanov * @bm: pointer to memory for returning the bitmap of field vectors
7602ffd87d3SSergey Temerkhanov */
ice_get_sw_fv_bitmap(struct ice_hw * hw,enum ice_prof_type req_profs,unsigned long * bm)7612ffd87d3SSergey Temerkhanov void ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
7622ffd87d3SSergey Temerkhanov unsigned long *bm)
7632ffd87d3SSergey Temerkhanov {
7642ffd87d3SSergey Temerkhanov struct ice_pkg_enum state;
7652ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg;
7662ffd87d3SSergey Temerkhanov struct ice_fv *fv;
7672ffd87d3SSergey Temerkhanov
7682ffd87d3SSergey Temerkhanov if (req_profs == ICE_PROF_ALL) {
7692ffd87d3SSergey Temerkhanov bitmap_set(bm, 0, ICE_MAX_NUM_PROFILES);
7702ffd87d3SSergey Temerkhanov return;
7712ffd87d3SSergey Temerkhanov }
7722ffd87d3SSergey Temerkhanov
7732ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state));
7742ffd87d3SSergey Temerkhanov bitmap_zero(bm, ICE_MAX_NUM_PROFILES);
7752ffd87d3SSergey Temerkhanov ice_seg = hw->seg;
7762ffd87d3SSergey Temerkhanov do {
7772ffd87d3SSergey Temerkhanov enum ice_prof_type prof_type;
7782ffd87d3SSergey Temerkhanov u32 offset;
7792ffd87d3SSergey Temerkhanov
7802ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
7812ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler);
7822ffd87d3SSergey Temerkhanov ice_seg = NULL;
7832ffd87d3SSergey Temerkhanov
7842ffd87d3SSergey Temerkhanov if (fv) {
7852ffd87d3SSergey Temerkhanov /* Determine field vector type */
7862ffd87d3SSergey Temerkhanov prof_type = ice_get_sw_prof_type(hw, fv, offset);
7872ffd87d3SSergey Temerkhanov
7882ffd87d3SSergey Temerkhanov if (req_profs & prof_type)
7892ffd87d3SSergey Temerkhanov set_bit((u16)offset, bm);
7902ffd87d3SSergey Temerkhanov }
7912ffd87d3SSergey Temerkhanov } while (fv);
7922ffd87d3SSergey Temerkhanov }
7932ffd87d3SSergey Temerkhanov
7942ffd87d3SSergey Temerkhanov /**
7952ffd87d3SSergey Temerkhanov * ice_get_sw_fv_list
7962ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
7972ffd87d3SSergey Temerkhanov * @lkups: list of protocol types
7982ffd87d3SSergey Temerkhanov * @bm: bitmap of field vectors to consider
7992ffd87d3SSergey Temerkhanov * @fv_list: Head of a list
8002ffd87d3SSergey Temerkhanov *
8012ffd87d3SSergey Temerkhanov * Finds all the field vector entries from switch block that contain
8022ffd87d3SSergey Temerkhanov * a given protocol ID and offset and returns a list of structures of type
8032ffd87d3SSergey Temerkhanov * "ice_sw_fv_list_entry". Every structure in the list has a field vector
8042ffd87d3SSergey Temerkhanov * definition and profile ID information
8052ffd87d3SSergey Temerkhanov * NOTE: The caller of the function is responsible for freeing the memory
8062ffd87d3SSergey Temerkhanov * allocated for every list entry.
8072ffd87d3SSergey Temerkhanov */
ice_get_sw_fv_list(struct ice_hw * hw,struct ice_prot_lkup_ext * lkups,unsigned long * bm,struct list_head * fv_list)8082ffd87d3SSergey Temerkhanov int ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups,
8092ffd87d3SSergey Temerkhanov unsigned long *bm, struct list_head *fv_list)
8102ffd87d3SSergey Temerkhanov {
8112ffd87d3SSergey Temerkhanov struct ice_sw_fv_list_entry *fvl;
8122ffd87d3SSergey Temerkhanov struct ice_sw_fv_list_entry *tmp;
8132ffd87d3SSergey Temerkhanov struct ice_pkg_enum state;
8142ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg;
8152ffd87d3SSergey Temerkhanov struct ice_fv *fv;
8162ffd87d3SSergey Temerkhanov u32 offset;
8172ffd87d3SSergey Temerkhanov
8182ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state));
8192ffd87d3SSergey Temerkhanov
8202ffd87d3SSergey Temerkhanov if (!lkups->n_val_words || !hw->seg)
8212ffd87d3SSergey Temerkhanov return -EINVAL;
8222ffd87d3SSergey Temerkhanov
8232ffd87d3SSergey Temerkhanov ice_seg = hw->seg;
8242ffd87d3SSergey Temerkhanov do {
8252ffd87d3SSergey Temerkhanov u16 i;
8262ffd87d3SSergey Temerkhanov
8272ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
8282ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler);
8292ffd87d3SSergey Temerkhanov if (!fv)
8302ffd87d3SSergey Temerkhanov break;
8312ffd87d3SSergey Temerkhanov ice_seg = NULL;
8322ffd87d3SSergey Temerkhanov
8332ffd87d3SSergey Temerkhanov /* If field vector is not in the bitmap list, then skip this
8342ffd87d3SSergey Temerkhanov * profile.
8352ffd87d3SSergey Temerkhanov */
8362ffd87d3SSergey Temerkhanov if (!test_bit((u16)offset, bm))
8372ffd87d3SSergey Temerkhanov continue;
8382ffd87d3SSergey Temerkhanov
8392ffd87d3SSergey Temerkhanov for (i = 0; i < lkups->n_val_words; i++) {
8402ffd87d3SSergey Temerkhanov int j;
8412ffd87d3SSergey Temerkhanov
8422ffd87d3SSergey Temerkhanov for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
8432ffd87d3SSergey Temerkhanov if (fv->ew[j].prot_id ==
8442ffd87d3SSergey Temerkhanov lkups->fv_words[i].prot_id &&
8452ffd87d3SSergey Temerkhanov fv->ew[j].off == lkups->fv_words[i].off)
8462ffd87d3SSergey Temerkhanov break;
8472ffd87d3SSergey Temerkhanov if (j >= hw->blk[ICE_BLK_SW].es.fvw)
8482ffd87d3SSergey Temerkhanov break;
8492ffd87d3SSergey Temerkhanov if (i + 1 == lkups->n_val_words) {
8502ffd87d3SSergey Temerkhanov fvl = devm_kzalloc(ice_hw_to_dev(hw),
8512ffd87d3SSergey Temerkhanov sizeof(*fvl), GFP_KERNEL);
8522ffd87d3SSergey Temerkhanov if (!fvl)
8532ffd87d3SSergey Temerkhanov goto err;
8542ffd87d3SSergey Temerkhanov fvl->fv_ptr = fv;
8552ffd87d3SSergey Temerkhanov fvl->profile_id = offset;
8562ffd87d3SSergey Temerkhanov list_add(&fvl->list_entry, fv_list);
8572ffd87d3SSergey Temerkhanov break;
8582ffd87d3SSergey Temerkhanov }
8592ffd87d3SSergey Temerkhanov }
8602ffd87d3SSergey Temerkhanov } while (fv);
8612ffd87d3SSergey Temerkhanov if (list_empty(fv_list)) {
8622ffd87d3SSergey Temerkhanov dev_warn(ice_hw_to_dev(hw),
8632ffd87d3SSergey Temerkhanov "Required profiles not found in currently loaded DDP package");
8642ffd87d3SSergey Temerkhanov return -EIO;
8652ffd87d3SSergey Temerkhanov }
8662ffd87d3SSergey Temerkhanov
8672ffd87d3SSergey Temerkhanov return 0;
8682ffd87d3SSergey Temerkhanov
8692ffd87d3SSergey Temerkhanov err:
8702ffd87d3SSergey Temerkhanov list_for_each_entry_safe(fvl, tmp, fv_list, list_entry) {
8712ffd87d3SSergey Temerkhanov list_del(&fvl->list_entry);
8722ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), fvl);
8732ffd87d3SSergey Temerkhanov }
8742ffd87d3SSergey Temerkhanov
8752ffd87d3SSergey Temerkhanov return -ENOMEM;
8762ffd87d3SSergey Temerkhanov }
8772ffd87d3SSergey Temerkhanov
8782ffd87d3SSergey Temerkhanov /**
8792ffd87d3SSergey Temerkhanov * ice_init_prof_result_bm - Initialize the profile result index bitmap
8802ffd87d3SSergey Temerkhanov * @hw: pointer to hardware structure
8812ffd87d3SSergey Temerkhanov */
ice_init_prof_result_bm(struct ice_hw * hw)8822ffd87d3SSergey Temerkhanov void ice_init_prof_result_bm(struct ice_hw *hw)
8832ffd87d3SSergey Temerkhanov {
8842ffd87d3SSergey Temerkhanov struct ice_pkg_enum state;
8852ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg;
8862ffd87d3SSergey Temerkhanov struct ice_fv *fv;
8872ffd87d3SSergey Temerkhanov
8882ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state));
8892ffd87d3SSergey Temerkhanov
8902ffd87d3SSergey Temerkhanov if (!hw->seg)
8912ffd87d3SSergey Temerkhanov return;
8922ffd87d3SSergey Temerkhanov
8932ffd87d3SSergey Temerkhanov ice_seg = hw->seg;
8942ffd87d3SSergey Temerkhanov do {
8952ffd87d3SSergey Temerkhanov u32 off;
8962ffd87d3SSergey Temerkhanov u16 i;
8972ffd87d3SSergey Temerkhanov
8982ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
8992ffd87d3SSergey Temerkhanov &off, ice_sw_fv_handler);
9002ffd87d3SSergey Temerkhanov ice_seg = NULL;
9012ffd87d3SSergey Temerkhanov if (!fv)
9022ffd87d3SSergey Temerkhanov break;
9032ffd87d3SSergey Temerkhanov
9042ffd87d3SSergey Temerkhanov bitmap_zero(hw->switch_info->prof_res_bm[off],
9052ffd87d3SSergey Temerkhanov ICE_MAX_FV_WORDS);
9062ffd87d3SSergey Temerkhanov
9072ffd87d3SSergey Temerkhanov /* Determine empty field vector indices, these can be
9082ffd87d3SSergey Temerkhanov * used for recipe results. Skip index 0, since it is
9092ffd87d3SSergey Temerkhanov * always used for Switch ID.
9102ffd87d3SSergey Temerkhanov */
9112ffd87d3SSergey Temerkhanov for (i = 1; i < ICE_MAX_FV_WORDS; i++)
9122ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == ICE_PROT_INVALID &&
9132ffd87d3SSergey Temerkhanov fv->ew[i].off == ICE_FV_OFFSET_INVAL)
9142ffd87d3SSergey Temerkhanov set_bit(i, hw->switch_info->prof_res_bm[off]);
9152ffd87d3SSergey Temerkhanov } while (fv);
9162ffd87d3SSergey Temerkhanov }
9172ffd87d3SSergey Temerkhanov
9182ffd87d3SSergey Temerkhanov /**
9192ffd87d3SSergey Temerkhanov * ice_pkg_buf_free
9202ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
9212ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
9222ffd87d3SSergey Temerkhanov *
9232ffd87d3SSergey Temerkhanov * Frees a package buffer
9242ffd87d3SSergey Temerkhanov */
ice_pkg_buf_free(struct ice_hw * hw,struct ice_buf_build * bld)9252ffd87d3SSergey Temerkhanov void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld)
9262ffd87d3SSergey Temerkhanov {
9272ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), bld);
9282ffd87d3SSergey Temerkhanov }
9292ffd87d3SSergey Temerkhanov
9302ffd87d3SSergey Temerkhanov /**
9312ffd87d3SSergey Temerkhanov * ice_pkg_buf_reserve_section
9322ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
9332ffd87d3SSergey Temerkhanov * @count: the number of sections to reserve
9342ffd87d3SSergey Temerkhanov *
9352ffd87d3SSergey Temerkhanov * Reserves one or more section table entries in a package buffer. This routine
9362ffd87d3SSergey Temerkhanov * can be called multiple times as long as they are made before calling
9372ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section()
9382ffd87d3SSergey Temerkhanov * is called once, the number of sections that can be allocated will not be able
9392ffd87d3SSergey Temerkhanov * to be increased; not using all reserved sections is fine, but this will
9402ffd87d3SSergey Temerkhanov * result in some wasted space in the buffer.
9412ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form.
9422ffd87d3SSergey Temerkhanov */
ice_pkg_buf_reserve_section(struct ice_buf_build * bld,u16 count)9432ffd87d3SSergey Temerkhanov int ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count)
9442ffd87d3SSergey Temerkhanov {
9452ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf;
9462ffd87d3SSergey Temerkhanov u16 section_count;
9472ffd87d3SSergey Temerkhanov u16 data_end;
9482ffd87d3SSergey Temerkhanov
9492ffd87d3SSergey Temerkhanov if (!bld)
9502ffd87d3SSergey Temerkhanov return -EINVAL;
9512ffd87d3SSergey Temerkhanov
9522ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf;
9532ffd87d3SSergey Temerkhanov
9542ffd87d3SSergey Temerkhanov /* already an active section, can't increase table size */
9552ffd87d3SSergey Temerkhanov section_count = le16_to_cpu(buf->section_count);
9562ffd87d3SSergey Temerkhanov if (section_count > 0)
9572ffd87d3SSergey Temerkhanov return -EIO;
9582ffd87d3SSergey Temerkhanov
9592ffd87d3SSergey Temerkhanov if (bld->reserved_section_table_entries + count > ICE_MAX_S_COUNT)
9602ffd87d3SSergey Temerkhanov return -EIO;
9612ffd87d3SSergey Temerkhanov bld->reserved_section_table_entries += count;
9622ffd87d3SSergey Temerkhanov
9632ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(buf->data_end) +
9642ffd87d3SSergey Temerkhanov flex_array_size(buf, section_entry, count);
9652ffd87d3SSergey Temerkhanov buf->data_end = cpu_to_le16(data_end);
9662ffd87d3SSergey Temerkhanov
9672ffd87d3SSergey Temerkhanov return 0;
9682ffd87d3SSergey Temerkhanov }
9692ffd87d3SSergey Temerkhanov
9702ffd87d3SSergey Temerkhanov /**
9712ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_section
9722ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
9732ffd87d3SSergey Temerkhanov * @type: the section type value
9742ffd87d3SSergey Temerkhanov * @size: the size of the section to reserve (in bytes)
9752ffd87d3SSergey Temerkhanov *
9762ffd87d3SSergey Temerkhanov * Reserves memory in the buffer for a section's content and updates the
9772ffd87d3SSergey Temerkhanov * buffers' status accordingly. This routine returns a pointer to the first
9782ffd87d3SSergey Temerkhanov * byte of the section start within the buffer, which is used to fill in the
9792ffd87d3SSergey Temerkhanov * section contents.
9802ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form.
9812ffd87d3SSergey Temerkhanov */
ice_pkg_buf_alloc_section(struct ice_buf_build * bld,u32 type,u16 size)9822ffd87d3SSergey Temerkhanov void *ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size)
9832ffd87d3SSergey Temerkhanov {
9842ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf;
9852ffd87d3SSergey Temerkhanov u16 sect_count;
9862ffd87d3SSergey Temerkhanov u16 data_end;
9872ffd87d3SSergey Temerkhanov
9882ffd87d3SSergey Temerkhanov if (!bld || !type || !size)
9892ffd87d3SSergey Temerkhanov return NULL;
9902ffd87d3SSergey Temerkhanov
9912ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf;
9922ffd87d3SSergey Temerkhanov
9932ffd87d3SSergey Temerkhanov /* check for enough space left in buffer */
9942ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(buf->data_end);
9952ffd87d3SSergey Temerkhanov
9962ffd87d3SSergey Temerkhanov /* section start must align on 4 byte boundary */
9972ffd87d3SSergey Temerkhanov data_end = ALIGN(data_end, 4);
9982ffd87d3SSergey Temerkhanov
9992ffd87d3SSergey Temerkhanov if ((data_end + size) > ICE_MAX_S_DATA_END)
10002ffd87d3SSergey Temerkhanov return NULL;
10012ffd87d3SSergey Temerkhanov
10022ffd87d3SSergey Temerkhanov /* check for more available section table entries */
10032ffd87d3SSergey Temerkhanov sect_count = le16_to_cpu(buf->section_count);
10042ffd87d3SSergey Temerkhanov if (sect_count < bld->reserved_section_table_entries) {
10052ffd87d3SSergey Temerkhanov void *section_ptr = ((u8 *)buf) + data_end;
10062ffd87d3SSergey Temerkhanov
10072ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].offset = cpu_to_le16(data_end);
10082ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].size = cpu_to_le16(size);
10092ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].type = cpu_to_le32(type);
10102ffd87d3SSergey Temerkhanov
10112ffd87d3SSergey Temerkhanov data_end += size;
10122ffd87d3SSergey Temerkhanov buf->data_end = cpu_to_le16(data_end);
10132ffd87d3SSergey Temerkhanov
10142ffd87d3SSergey Temerkhanov buf->section_count = cpu_to_le16(sect_count + 1);
10152ffd87d3SSergey Temerkhanov return section_ptr;
10162ffd87d3SSergey Temerkhanov }
10172ffd87d3SSergey Temerkhanov
10182ffd87d3SSergey Temerkhanov /* no free section table entries */
10192ffd87d3SSergey Temerkhanov return NULL;
10202ffd87d3SSergey Temerkhanov }
10212ffd87d3SSergey Temerkhanov
10222ffd87d3SSergey Temerkhanov /**
10232ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_single_section
10242ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
10252ffd87d3SSergey Temerkhanov * @type: the section type value
10262ffd87d3SSergey Temerkhanov * @size: the size of the section to reserve (in bytes)
10272ffd87d3SSergey Temerkhanov * @section: returns pointer to the section
10282ffd87d3SSergey Temerkhanov *
10292ffd87d3SSergey Temerkhanov * Allocates a package buffer with a single section.
10302ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form.
10312ffd87d3SSergey Temerkhanov */
ice_pkg_buf_alloc_single_section(struct ice_hw * hw,u32 type,u16 size,void ** section)10322ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc_single_section(struct ice_hw *hw,
10332ffd87d3SSergey Temerkhanov u32 type, u16 size,
10342ffd87d3SSergey Temerkhanov void **section)
10352ffd87d3SSergey Temerkhanov {
10362ffd87d3SSergey Temerkhanov struct ice_buf_build *buf;
10372ffd87d3SSergey Temerkhanov
10382ffd87d3SSergey Temerkhanov if (!section)
10392ffd87d3SSergey Temerkhanov return NULL;
10402ffd87d3SSergey Temerkhanov
10412ffd87d3SSergey Temerkhanov buf = ice_pkg_buf_alloc(hw);
10422ffd87d3SSergey Temerkhanov if (!buf)
10432ffd87d3SSergey Temerkhanov return NULL;
10442ffd87d3SSergey Temerkhanov
10452ffd87d3SSergey Temerkhanov if (ice_pkg_buf_reserve_section(buf, 1))
10462ffd87d3SSergey Temerkhanov goto ice_pkg_buf_alloc_single_section_err;
10472ffd87d3SSergey Temerkhanov
10482ffd87d3SSergey Temerkhanov *section = ice_pkg_buf_alloc_section(buf, type, size);
10492ffd87d3SSergey Temerkhanov if (!*section)
10502ffd87d3SSergey Temerkhanov goto ice_pkg_buf_alloc_single_section_err;
10512ffd87d3SSergey Temerkhanov
10522ffd87d3SSergey Temerkhanov return buf;
10532ffd87d3SSergey Temerkhanov
10542ffd87d3SSergey Temerkhanov ice_pkg_buf_alloc_single_section_err:
10552ffd87d3SSergey Temerkhanov ice_pkg_buf_free(hw, buf);
10562ffd87d3SSergey Temerkhanov return NULL;
10572ffd87d3SSergey Temerkhanov }
10582ffd87d3SSergey Temerkhanov
10592ffd87d3SSergey Temerkhanov /**
10602ffd87d3SSergey Temerkhanov * ice_pkg_buf_get_active_sections
10612ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
10622ffd87d3SSergey Temerkhanov *
10632ffd87d3SSergey Temerkhanov * Returns the number of active sections. Before using the package buffer
10642ffd87d3SSergey Temerkhanov * in an update package command, the caller should make sure that there is at
10652ffd87d3SSergey Temerkhanov * least one active section - otherwise, the buffer is not legal and should
10662ffd87d3SSergey Temerkhanov * not be used.
10672ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form.
10682ffd87d3SSergey Temerkhanov */
ice_pkg_buf_get_active_sections(struct ice_buf_build * bld)10692ffd87d3SSergey Temerkhanov u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld)
10702ffd87d3SSergey Temerkhanov {
10712ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf;
10722ffd87d3SSergey Temerkhanov
10732ffd87d3SSergey Temerkhanov if (!bld)
10742ffd87d3SSergey Temerkhanov return 0;
10752ffd87d3SSergey Temerkhanov
10762ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf;
10772ffd87d3SSergey Temerkhanov return le16_to_cpu(buf->section_count);
10782ffd87d3SSergey Temerkhanov }
10792ffd87d3SSergey Temerkhanov
10802ffd87d3SSergey Temerkhanov /**
10812ffd87d3SSergey Temerkhanov * ice_pkg_buf
10822ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
10832ffd87d3SSergey Temerkhanov *
10842ffd87d3SSergey Temerkhanov * Return a pointer to the buffer's header
10852ffd87d3SSergey Temerkhanov */
ice_pkg_buf(struct ice_buf_build * bld)10862ffd87d3SSergey Temerkhanov struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
10872ffd87d3SSergey Temerkhanov {
10882ffd87d3SSergey Temerkhanov if (!bld)
10892ffd87d3SSergey Temerkhanov return NULL;
10902ffd87d3SSergey Temerkhanov
10912ffd87d3SSergey Temerkhanov return &bld->buf;
10922ffd87d3SSergey Temerkhanov }
10932ffd87d3SSergey Temerkhanov
ice_map_aq_err_to_ddp_state(enum ice_aq_err aq_err)10942ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_map_aq_err_to_ddp_state(enum ice_aq_err aq_err)
10952ffd87d3SSergey Temerkhanov {
10962ffd87d3SSergey Temerkhanov switch (aq_err) {
10972ffd87d3SSergey Temerkhanov case ICE_AQ_RC_ENOSEC:
10982ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADSIG:
10992ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_SIGNATURE_INVALID;
11002ffd87d3SSergey Temerkhanov case ICE_AQ_RC_ESVN:
11012ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_REVISION_TOO_LOW;
11022ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADMAN:
11032ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADBUF:
11042ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_LOAD_ERROR;
11052ffd87d3SSergey Temerkhanov default:
11062ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR;
11072ffd87d3SSergey Temerkhanov }
11082ffd87d3SSergey Temerkhanov }
11092ffd87d3SSergey Temerkhanov
11102ffd87d3SSergey Temerkhanov /**
11112ffd87d3SSergey Temerkhanov * ice_acquire_global_cfg_lock
11122ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
11132ffd87d3SSergey Temerkhanov * @access: access type (read or write)
11142ffd87d3SSergey Temerkhanov *
11152ffd87d3SSergey Temerkhanov * This function will request ownership of the global config lock for reading
11162ffd87d3SSergey Temerkhanov * or writing of the package. When attempting to obtain write access, the
11172ffd87d3SSergey Temerkhanov * caller must check for the following two return values:
11182ffd87d3SSergey Temerkhanov *
11192ffd87d3SSergey Temerkhanov * 0 - Means the caller has acquired the global config lock
11202ffd87d3SSergey Temerkhanov * and can perform writing of the package.
11212ffd87d3SSergey Temerkhanov * -EALREADY - Indicates another driver has already written the
11222ffd87d3SSergey Temerkhanov * package or has found that no update was necessary; in
11232ffd87d3SSergey Temerkhanov * this case, the caller can just skip performing any
11242ffd87d3SSergey Temerkhanov * update of the package.
11252ffd87d3SSergey Temerkhanov */
ice_acquire_global_cfg_lock(struct ice_hw * hw,enum ice_aq_res_access_type access)11262ffd87d3SSergey Temerkhanov static int ice_acquire_global_cfg_lock(struct ice_hw *hw,
11272ffd87d3SSergey Temerkhanov enum ice_aq_res_access_type access)
11282ffd87d3SSergey Temerkhanov {
11292ffd87d3SSergey Temerkhanov int status;
11302ffd87d3SSergey Temerkhanov
11312ffd87d3SSergey Temerkhanov status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, access,
11322ffd87d3SSergey Temerkhanov ICE_GLOBAL_CFG_LOCK_TIMEOUT);
11332ffd87d3SSergey Temerkhanov
11342ffd87d3SSergey Temerkhanov if (!status)
11352ffd87d3SSergey Temerkhanov mutex_lock(&ice_global_cfg_lock_sw);
11362ffd87d3SSergey Temerkhanov else if (status == -EALREADY)
11372ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG,
11382ffd87d3SSergey Temerkhanov "Global config lock: No work to do\n");
11392ffd87d3SSergey Temerkhanov
11402ffd87d3SSergey Temerkhanov return status;
11412ffd87d3SSergey Temerkhanov }
11422ffd87d3SSergey Temerkhanov
11432ffd87d3SSergey Temerkhanov /**
11442ffd87d3SSergey Temerkhanov * ice_release_global_cfg_lock
11452ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
11462ffd87d3SSergey Temerkhanov *
11472ffd87d3SSergey Temerkhanov * This function will release the global config lock.
11482ffd87d3SSergey Temerkhanov */
ice_release_global_cfg_lock(struct ice_hw * hw)11492ffd87d3SSergey Temerkhanov static void ice_release_global_cfg_lock(struct ice_hw *hw)
11502ffd87d3SSergey Temerkhanov {
11512ffd87d3SSergey Temerkhanov mutex_unlock(&ice_global_cfg_lock_sw);
11522ffd87d3SSergey Temerkhanov ice_release_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID);
11532ffd87d3SSergey Temerkhanov }
11542ffd87d3SSergey Temerkhanov
11552ffd87d3SSergey Temerkhanov /**
1156*708b352fSJan Sokolowski * ice_aq_download_pkg
1157*708b352fSJan Sokolowski * @hw: pointer to the hardware structure
1158*708b352fSJan Sokolowski * @pkg_buf: the package buffer to transfer
1159*708b352fSJan Sokolowski * @buf_size: the size of the package buffer
1160*708b352fSJan Sokolowski * @last_buf: last buffer indicator
1161*708b352fSJan Sokolowski * @error_offset: returns error offset
1162*708b352fSJan Sokolowski * @error_info: returns error information
1163*708b352fSJan Sokolowski * @cd: pointer to command details structure or NULL
1164*708b352fSJan Sokolowski *
1165*708b352fSJan Sokolowski * Download Package (0x0C40)
1166*708b352fSJan Sokolowski */
1167*708b352fSJan Sokolowski static int
ice_aq_download_pkg(struct ice_hw * hw,struct ice_buf_hdr * pkg_buf,u16 buf_size,bool last_buf,u32 * error_offset,u32 * error_info,struct ice_sq_cd * cd)1168*708b352fSJan Sokolowski ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
1169*708b352fSJan Sokolowski u16 buf_size, bool last_buf, u32 *error_offset,
1170*708b352fSJan Sokolowski u32 *error_info, struct ice_sq_cd *cd)
1171*708b352fSJan Sokolowski {
1172*708b352fSJan Sokolowski struct ice_aqc_download_pkg *cmd;
1173*708b352fSJan Sokolowski struct ice_aq_desc desc;
1174*708b352fSJan Sokolowski int status;
1175*708b352fSJan Sokolowski
1176*708b352fSJan Sokolowski if (error_offset)
1177*708b352fSJan Sokolowski *error_offset = 0;
1178*708b352fSJan Sokolowski if (error_info)
1179*708b352fSJan Sokolowski *error_info = 0;
1180*708b352fSJan Sokolowski
1181*708b352fSJan Sokolowski cmd = &desc.params.download_pkg;
1182*708b352fSJan Sokolowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg);
1183*708b352fSJan Sokolowski desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1184*708b352fSJan Sokolowski
1185*708b352fSJan Sokolowski if (last_buf)
1186*708b352fSJan Sokolowski cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
1187*708b352fSJan Sokolowski
1188*708b352fSJan Sokolowski status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
1189*708b352fSJan Sokolowski if (status == -EIO) {
1190*708b352fSJan Sokolowski /* Read error from buffer only when the FW returned an error */
1191*708b352fSJan Sokolowski struct ice_aqc_download_pkg_resp *resp;
1192*708b352fSJan Sokolowski
1193*708b352fSJan Sokolowski resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
1194*708b352fSJan Sokolowski if (error_offset)
1195*708b352fSJan Sokolowski *error_offset = le32_to_cpu(resp->error_offset);
1196*708b352fSJan Sokolowski if (error_info)
1197*708b352fSJan Sokolowski *error_info = le32_to_cpu(resp->error_info);
1198*708b352fSJan Sokolowski }
1199*708b352fSJan Sokolowski
1200*708b352fSJan Sokolowski return status;
1201*708b352fSJan Sokolowski }
1202*708b352fSJan Sokolowski
1203*708b352fSJan Sokolowski /**
12042ffd87d3SSergey Temerkhanov * ice_dwnld_cfg_bufs
12052ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
12062ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers
12072ffd87d3SSergey Temerkhanov * @count: the number of buffers in the array
12082ffd87d3SSergey Temerkhanov *
12092ffd87d3SSergey Temerkhanov * Obtains global config lock and downloads the package configuration buffers
12102ffd87d3SSergey Temerkhanov * to the firmware. Metadata buffers are skipped, and the first metadata buffer
12112ffd87d3SSergey Temerkhanov * found indicates that the rest of the buffers are all metadata buffers.
12122ffd87d3SSergey Temerkhanov */
ice_dwnld_cfg_bufs(struct ice_hw * hw,struct ice_buf * bufs,u32 count)12132ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_dwnld_cfg_bufs(struct ice_hw *hw,
12142ffd87d3SSergey Temerkhanov struct ice_buf *bufs, u32 count)
12152ffd87d3SSergey Temerkhanov {
12162ffd87d3SSergey Temerkhanov enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS;
12172ffd87d3SSergey Temerkhanov struct ice_buf_hdr *bh;
12182ffd87d3SSergey Temerkhanov enum ice_aq_err err;
12192ffd87d3SSergey Temerkhanov u32 offset, info, i;
12202ffd87d3SSergey Temerkhanov int status;
12212ffd87d3SSergey Temerkhanov
12222ffd87d3SSergey Temerkhanov if (!bufs || !count)
12232ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR;
12242ffd87d3SSergey Temerkhanov
12252ffd87d3SSergey Temerkhanov /* If the first buffer's first section has its metadata bit set
12262ffd87d3SSergey Temerkhanov * then there are no buffers to be downloaded, and the operation is
12272ffd87d3SSergey Temerkhanov * considered a success.
12282ffd87d3SSergey Temerkhanov */
12292ffd87d3SSergey Temerkhanov bh = (struct ice_buf_hdr *)bufs;
12302ffd87d3SSergey Temerkhanov if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF)
12312ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS;
12322ffd87d3SSergey Temerkhanov
12332ffd87d3SSergey Temerkhanov status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
12342ffd87d3SSergey Temerkhanov if (status) {
12352ffd87d3SSergey Temerkhanov if (status == -EALREADY)
12362ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ALREADY_LOADED;
12372ffd87d3SSergey Temerkhanov return ice_map_aq_err_to_ddp_state(hw->adminq.sq_last_status);
12382ffd87d3SSergey Temerkhanov }
12392ffd87d3SSergey Temerkhanov
12402ffd87d3SSergey Temerkhanov for (i = 0; i < count; i++) {
12412ffd87d3SSergey Temerkhanov bool last = ((i + 1) == count);
12422ffd87d3SSergey Temerkhanov
12432ffd87d3SSergey Temerkhanov if (!last) {
12442ffd87d3SSergey Temerkhanov /* check next buffer for metadata flag */
12452ffd87d3SSergey Temerkhanov bh = (struct ice_buf_hdr *)(bufs + i + 1);
12462ffd87d3SSergey Temerkhanov
12472ffd87d3SSergey Temerkhanov /* A set metadata flag in the next buffer will signal
12482ffd87d3SSergey Temerkhanov * that the current buffer will be the last buffer
12492ffd87d3SSergey Temerkhanov * downloaded
12502ffd87d3SSergey Temerkhanov */
12512ffd87d3SSergey Temerkhanov if (le16_to_cpu(bh->section_count))
12522ffd87d3SSergey Temerkhanov if (le32_to_cpu(bh->section_entry[0].type) &
12532ffd87d3SSergey Temerkhanov ICE_METADATA_BUF)
12542ffd87d3SSergey Temerkhanov last = true;
12552ffd87d3SSergey Temerkhanov }
12562ffd87d3SSergey Temerkhanov
12572ffd87d3SSergey Temerkhanov bh = (struct ice_buf_hdr *)(bufs + i);
12582ffd87d3SSergey Temerkhanov
12592ffd87d3SSergey Temerkhanov status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE, last,
12602ffd87d3SSergey Temerkhanov &offset, &info, NULL);
12612ffd87d3SSergey Temerkhanov
12622ffd87d3SSergey Temerkhanov /* Save AQ status from download package */
12632ffd87d3SSergey Temerkhanov if (status) {
12642ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG,
12652ffd87d3SSergey Temerkhanov "Pkg download failed: err %d off %d inf %d\n",
12662ffd87d3SSergey Temerkhanov status, offset, info);
12672ffd87d3SSergey Temerkhanov err = hw->adminq.sq_last_status;
12682ffd87d3SSergey Temerkhanov state = ice_map_aq_err_to_ddp_state(err);
12692ffd87d3SSergey Temerkhanov break;
12702ffd87d3SSergey Temerkhanov }
12712ffd87d3SSergey Temerkhanov
12722ffd87d3SSergey Temerkhanov if (last)
12732ffd87d3SSergey Temerkhanov break;
12742ffd87d3SSergey Temerkhanov }
12752ffd87d3SSergey Temerkhanov
12762ffd87d3SSergey Temerkhanov if (!status) {
12772ffd87d3SSergey Temerkhanov status = ice_set_vlan_mode(hw);
12782ffd87d3SSergey Temerkhanov if (status)
12792ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG,
12802ffd87d3SSergey Temerkhanov "Failed to set VLAN mode: err %d\n", status);
12812ffd87d3SSergey Temerkhanov }
12822ffd87d3SSergey Temerkhanov
12832ffd87d3SSergey Temerkhanov ice_release_global_cfg_lock(hw);
12842ffd87d3SSergey Temerkhanov
12852ffd87d3SSergey Temerkhanov return state;
12862ffd87d3SSergey Temerkhanov }
12872ffd87d3SSergey Temerkhanov
12882ffd87d3SSergey Temerkhanov /**
12892ffd87d3SSergey Temerkhanov * ice_aq_get_pkg_info_list
12902ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
12912ffd87d3SSergey Temerkhanov * @pkg_info: the buffer which will receive the information list
12922ffd87d3SSergey Temerkhanov * @buf_size: the size of the pkg_info information buffer
12932ffd87d3SSergey Temerkhanov * @cd: pointer to command details structure or NULL
12942ffd87d3SSergey Temerkhanov *
12952ffd87d3SSergey Temerkhanov * Get Package Info List (0x0C43)
12962ffd87d3SSergey Temerkhanov */
ice_aq_get_pkg_info_list(struct ice_hw * hw,struct ice_aqc_get_pkg_info_resp * pkg_info,u16 buf_size,struct ice_sq_cd * cd)12972ffd87d3SSergey Temerkhanov static int ice_aq_get_pkg_info_list(struct ice_hw *hw,
12982ffd87d3SSergey Temerkhanov struct ice_aqc_get_pkg_info_resp *pkg_info,
12992ffd87d3SSergey Temerkhanov u16 buf_size, struct ice_sq_cd *cd)
13002ffd87d3SSergey Temerkhanov {
13012ffd87d3SSergey Temerkhanov struct ice_aq_desc desc;
13022ffd87d3SSergey Temerkhanov
13032ffd87d3SSergey Temerkhanov ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list);
13042ffd87d3SSergey Temerkhanov
13052ffd87d3SSergey Temerkhanov return ice_aq_send_cmd(hw, &desc, pkg_info, buf_size, cd);
13062ffd87d3SSergey Temerkhanov }
13072ffd87d3SSergey Temerkhanov
13082ffd87d3SSergey Temerkhanov /**
13092ffd87d3SSergey Temerkhanov * ice_download_pkg
13102ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
13112ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the segment of the package to be downloaded
13122ffd87d3SSergey Temerkhanov *
13132ffd87d3SSergey Temerkhanov * Handles the download of a complete package.
13142ffd87d3SSergey Temerkhanov */
ice_download_pkg(struct ice_hw * hw,struct ice_seg * ice_seg)13152ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_download_pkg(struct ice_hw *hw,
13162ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg)
13172ffd87d3SSergey Temerkhanov {
13182ffd87d3SSergey Temerkhanov struct ice_buf_table *ice_buf_tbl;
13192ffd87d3SSergey Temerkhanov int status;
13202ffd87d3SSergey Temerkhanov
13212ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n",
13222ffd87d3SSergey Temerkhanov ice_seg->hdr.seg_format_ver.major,
13232ffd87d3SSergey Temerkhanov ice_seg->hdr.seg_format_ver.minor,
13242ffd87d3SSergey Temerkhanov ice_seg->hdr.seg_format_ver.update,
13252ffd87d3SSergey Temerkhanov ice_seg->hdr.seg_format_ver.draft);
13262ffd87d3SSergey Temerkhanov
13272ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n",
13282ffd87d3SSergey Temerkhanov le32_to_cpu(ice_seg->hdr.seg_type),
13292ffd87d3SSergey Temerkhanov le32_to_cpu(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id);
13302ffd87d3SSergey Temerkhanov
13312ffd87d3SSergey Temerkhanov ice_buf_tbl = ice_find_buf_table(ice_seg);
13322ffd87d3SSergey Temerkhanov
13332ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Seg buf count: %d\n",
13342ffd87d3SSergey Temerkhanov le32_to_cpu(ice_buf_tbl->buf_count));
13352ffd87d3SSergey Temerkhanov
13362ffd87d3SSergey Temerkhanov status = ice_dwnld_cfg_bufs(hw, ice_buf_tbl->buf_array,
13372ffd87d3SSergey Temerkhanov le32_to_cpu(ice_buf_tbl->buf_count));
13382ffd87d3SSergey Temerkhanov
13392ffd87d3SSergey Temerkhanov ice_post_pkg_dwnld_vlan_mode_cfg(hw);
13402ffd87d3SSergey Temerkhanov
13412ffd87d3SSergey Temerkhanov return status;
13422ffd87d3SSergey Temerkhanov }
13432ffd87d3SSergey Temerkhanov
13442ffd87d3SSergey Temerkhanov /**
13452ffd87d3SSergey Temerkhanov * ice_aq_update_pkg
13462ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
13472ffd87d3SSergey Temerkhanov * @pkg_buf: the package cmd buffer
13482ffd87d3SSergey Temerkhanov * @buf_size: the size of the package cmd buffer
13492ffd87d3SSergey Temerkhanov * @last_buf: last buffer indicator
13502ffd87d3SSergey Temerkhanov * @error_offset: returns error offset
13512ffd87d3SSergey Temerkhanov * @error_info: returns error information
13522ffd87d3SSergey Temerkhanov * @cd: pointer to command details structure or NULL
13532ffd87d3SSergey Temerkhanov *
13542ffd87d3SSergey Temerkhanov * Update Package (0x0C42)
13552ffd87d3SSergey Temerkhanov */
ice_aq_update_pkg(struct ice_hw * hw,struct ice_buf_hdr * pkg_buf,u16 buf_size,bool last_buf,u32 * error_offset,u32 * error_info,struct ice_sq_cd * cd)13562ffd87d3SSergey Temerkhanov static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
13572ffd87d3SSergey Temerkhanov u16 buf_size, bool last_buf, u32 *error_offset,
13582ffd87d3SSergey Temerkhanov u32 *error_info, struct ice_sq_cd *cd)
13592ffd87d3SSergey Temerkhanov {
13602ffd87d3SSergey Temerkhanov struct ice_aqc_download_pkg *cmd;
13612ffd87d3SSergey Temerkhanov struct ice_aq_desc desc;
13622ffd87d3SSergey Temerkhanov int status;
13632ffd87d3SSergey Temerkhanov
13642ffd87d3SSergey Temerkhanov if (error_offset)
13652ffd87d3SSergey Temerkhanov *error_offset = 0;
13662ffd87d3SSergey Temerkhanov if (error_info)
13672ffd87d3SSergey Temerkhanov *error_info = 0;
13682ffd87d3SSergey Temerkhanov
13692ffd87d3SSergey Temerkhanov cmd = &desc.params.download_pkg;
13702ffd87d3SSergey Temerkhanov ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg);
13712ffd87d3SSergey Temerkhanov desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
13722ffd87d3SSergey Temerkhanov
13732ffd87d3SSergey Temerkhanov if (last_buf)
13742ffd87d3SSergey Temerkhanov cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
13752ffd87d3SSergey Temerkhanov
13762ffd87d3SSergey Temerkhanov status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
13772ffd87d3SSergey Temerkhanov if (status == -EIO) {
13782ffd87d3SSergey Temerkhanov /* Read error from buffer only when the FW returned an error */
13792ffd87d3SSergey Temerkhanov struct ice_aqc_download_pkg_resp *resp;
13802ffd87d3SSergey Temerkhanov
13812ffd87d3SSergey Temerkhanov resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
13822ffd87d3SSergey Temerkhanov if (error_offset)
13832ffd87d3SSergey Temerkhanov *error_offset = le32_to_cpu(resp->error_offset);
13842ffd87d3SSergey Temerkhanov if (error_info)
13852ffd87d3SSergey Temerkhanov *error_info = le32_to_cpu(resp->error_info);
13862ffd87d3SSergey Temerkhanov }
13872ffd87d3SSergey Temerkhanov
13882ffd87d3SSergey Temerkhanov return status;
13892ffd87d3SSergey Temerkhanov }
13902ffd87d3SSergey Temerkhanov
13912ffd87d3SSergey Temerkhanov /**
1392*708b352fSJan Sokolowski * ice_aq_upload_section
1393*708b352fSJan Sokolowski * @hw: pointer to the hardware structure
1394*708b352fSJan Sokolowski * @pkg_buf: the package buffer which will receive the section
1395*708b352fSJan Sokolowski * @buf_size: the size of the package buffer
1396*708b352fSJan Sokolowski * @cd: pointer to command details structure or NULL
1397*708b352fSJan Sokolowski *
1398*708b352fSJan Sokolowski * Upload Section (0x0C41)
1399*708b352fSJan Sokolowski */
ice_aq_upload_section(struct ice_hw * hw,struct ice_buf_hdr * pkg_buf,u16 buf_size,struct ice_sq_cd * cd)1400*708b352fSJan Sokolowski int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
1401*708b352fSJan Sokolowski u16 buf_size, struct ice_sq_cd *cd)
1402*708b352fSJan Sokolowski {
1403*708b352fSJan Sokolowski struct ice_aq_desc desc;
1404*708b352fSJan Sokolowski
1405*708b352fSJan Sokolowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section);
1406*708b352fSJan Sokolowski desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1407*708b352fSJan Sokolowski
1408*708b352fSJan Sokolowski return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
1409*708b352fSJan Sokolowski }
1410*708b352fSJan Sokolowski
1411*708b352fSJan Sokolowski /**
14122ffd87d3SSergey Temerkhanov * ice_update_pkg_no_lock
14132ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
14142ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers
14152ffd87d3SSergey Temerkhanov * @count: the number of buffers in the array
14162ffd87d3SSergey Temerkhanov */
ice_update_pkg_no_lock(struct ice_hw * hw,struct ice_buf * bufs,u32 count)14172ffd87d3SSergey Temerkhanov int ice_update_pkg_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
14182ffd87d3SSergey Temerkhanov {
14192ffd87d3SSergey Temerkhanov int status = 0;
14202ffd87d3SSergey Temerkhanov u32 i;
14212ffd87d3SSergey Temerkhanov
14222ffd87d3SSergey Temerkhanov for (i = 0; i < count; i++) {
14232ffd87d3SSergey Temerkhanov struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i);
14242ffd87d3SSergey Temerkhanov bool last = ((i + 1) == count);
14252ffd87d3SSergey Temerkhanov u32 offset, info;
14262ffd87d3SSergey Temerkhanov
14272ffd87d3SSergey Temerkhanov status = ice_aq_update_pkg(hw, bh, le16_to_cpu(bh->data_end),
14282ffd87d3SSergey Temerkhanov last, &offset, &info, NULL);
14292ffd87d3SSergey Temerkhanov
14302ffd87d3SSergey Temerkhanov if (status) {
14312ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG,
14322ffd87d3SSergey Temerkhanov "Update pkg failed: err %d off %d inf %d\n",
14332ffd87d3SSergey Temerkhanov status, offset, info);
14342ffd87d3SSergey Temerkhanov break;
14352ffd87d3SSergey Temerkhanov }
14362ffd87d3SSergey Temerkhanov }
14372ffd87d3SSergey Temerkhanov
14382ffd87d3SSergey Temerkhanov return status;
14392ffd87d3SSergey Temerkhanov }
14402ffd87d3SSergey Temerkhanov
14412ffd87d3SSergey Temerkhanov /**
14422ffd87d3SSergey Temerkhanov * ice_update_pkg
14432ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
14442ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers
14452ffd87d3SSergey Temerkhanov * @count: the number of buffers in the array
14462ffd87d3SSergey Temerkhanov *
14472ffd87d3SSergey Temerkhanov * Obtains change lock and updates package.
14482ffd87d3SSergey Temerkhanov */
ice_update_pkg(struct ice_hw * hw,struct ice_buf * bufs,u32 count)14492ffd87d3SSergey Temerkhanov int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
14502ffd87d3SSergey Temerkhanov {
14512ffd87d3SSergey Temerkhanov int status;
14522ffd87d3SSergey Temerkhanov
14532ffd87d3SSergey Temerkhanov status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
14542ffd87d3SSergey Temerkhanov if (status)
14552ffd87d3SSergey Temerkhanov return status;
14562ffd87d3SSergey Temerkhanov
14572ffd87d3SSergey Temerkhanov status = ice_update_pkg_no_lock(hw, bufs, count);
14582ffd87d3SSergey Temerkhanov
14592ffd87d3SSergey Temerkhanov ice_release_change_lock(hw);
14602ffd87d3SSergey Temerkhanov
14612ffd87d3SSergey Temerkhanov return status;
14622ffd87d3SSergey Temerkhanov }
14632ffd87d3SSergey Temerkhanov
14642ffd87d3SSergey Temerkhanov /**
14652ffd87d3SSergey Temerkhanov * ice_find_seg_in_pkg
14662ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
14672ffd87d3SSergey Temerkhanov * @seg_type: the segment type to search for (i.e., SEGMENT_TYPE_CPK)
14682ffd87d3SSergey Temerkhanov * @pkg_hdr: pointer to the package header to be searched
14692ffd87d3SSergey Temerkhanov *
14702ffd87d3SSergey Temerkhanov * This function searches a package file for a particular segment type. On
14712ffd87d3SSergey Temerkhanov * success it returns a pointer to the segment header, otherwise it will
14722ffd87d3SSergey Temerkhanov * return NULL.
14732ffd87d3SSergey Temerkhanov */
1474*708b352fSJan Sokolowski static struct ice_generic_seg_hdr *
ice_find_seg_in_pkg(struct ice_hw * hw,u32 seg_type,struct ice_pkg_hdr * pkg_hdr)1475*708b352fSJan Sokolowski ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
14762ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg_hdr)
14772ffd87d3SSergey Temerkhanov {
14782ffd87d3SSergey Temerkhanov u32 i;
14792ffd87d3SSergey Temerkhanov
14802ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n",
14812ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor,
14822ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.update,
14832ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.draft);
14842ffd87d3SSergey Temerkhanov
14852ffd87d3SSergey Temerkhanov /* Search all package segments for the requested segment type */
14862ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) {
14872ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg;
14882ffd87d3SSergey Temerkhanov
14892ffd87d3SSergey Temerkhanov seg = (struct ice_generic_seg_hdr
14902ffd87d3SSergey Temerkhanov *)((u8 *)pkg_hdr +
14912ffd87d3SSergey Temerkhanov le32_to_cpu(pkg_hdr->seg_offset[i]));
14922ffd87d3SSergey Temerkhanov
14932ffd87d3SSergey Temerkhanov if (le32_to_cpu(seg->seg_type) == seg_type)
14942ffd87d3SSergey Temerkhanov return seg;
14952ffd87d3SSergey Temerkhanov }
14962ffd87d3SSergey Temerkhanov
14972ffd87d3SSergey Temerkhanov return NULL;
14982ffd87d3SSergey Temerkhanov }
14992ffd87d3SSergey Temerkhanov
15002ffd87d3SSergey Temerkhanov /**
15012ffd87d3SSergey Temerkhanov * ice_init_pkg_info
15022ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
15032ffd87d3SSergey Temerkhanov * @pkg_hdr: pointer to the driver's package hdr
15042ffd87d3SSergey Temerkhanov *
15052ffd87d3SSergey Temerkhanov * Saves off the package details into the HW structure.
15062ffd87d3SSergey Temerkhanov */
ice_init_pkg_info(struct ice_hw * hw,struct ice_pkg_hdr * pkg_hdr)15072ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_init_pkg_info(struct ice_hw *hw,
15082ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg_hdr)
15092ffd87d3SSergey Temerkhanov {
15102ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg_hdr;
15112ffd87d3SSergey Temerkhanov
15122ffd87d3SSergey Temerkhanov if (!pkg_hdr)
15132ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR;
15142ffd87d3SSergey Temerkhanov
15152ffd87d3SSergey Temerkhanov seg_hdr = ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE, pkg_hdr);
15162ffd87d3SSergey Temerkhanov if (seg_hdr) {
15172ffd87d3SSergey Temerkhanov struct ice_meta_sect *meta;
15182ffd87d3SSergey Temerkhanov struct ice_pkg_enum state;
15192ffd87d3SSergey Temerkhanov
15202ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state));
15212ffd87d3SSergey Temerkhanov
15222ffd87d3SSergey Temerkhanov /* Get package information from the Metadata Section */
15232ffd87d3SSergey Temerkhanov meta = ice_pkg_enum_section((struct ice_seg *)seg_hdr, &state,
15242ffd87d3SSergey Temerkhanov ICE_SID_METADATA);
15252ffd87d3SSergey Temerkhanov if (!meta) {
15262ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT,
15272ffd87d3SSergey Temerkhanov "Did not find ice metadata section in package\n");
15282ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE;
15292ffd87d3SSergey Temerkhanov }
15302ffd87d3SSergey Temerkhanov
15312ffd87d3SSergey Temerkhanov hw->pkg_ver = meta->ver;
15322ffd87d3SSergey Temerkhanov memcpy(hw->pkg_name, meta->name, sizeof(meta->name));
15332ffd87d3SSergey Temerkhanov
15342ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Pkg: %d.%d.%d.%d, %s\n",
15352ffd87d3SSergey Temerkhanov meta->ver.major, meta->ver.minor, meta->ver.update,
15362ffd87d3SSergey Temerkhanov meta->ver.draft, meta->name);
15372ffd87d3SSergey Temerkhanov
15382ffd87d3SSergey Temerkhanov hw->ice_seg_fmt_ver = seg_hdr->seg_format_ver;
15392ffd87d3SSergey Temerkhanov memcpy(hw->ice_seg_id, seg_hdr->seg_id, sizeof(hw->ice_seg_id));
15402ffd87d3SSergey Temerkhanov
15412ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n",
15422ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.major,
15432ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.minor,
15442ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.update,
15452ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.draft, seg_hdr->seg_id);
15462ffd87d3SSergey Temerkhanov } else {
15472ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT,
15482ffd87d3SSergey Temerkhanov "Did not find ice segment in driver package\n");
15492ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE;
15502ffd87d3SSergey Temerkhanov }
15512ffd87d3SSergey Temerkhanov
15522ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS;
15532ffd87d3SSergey Temerkhanov }
15542ffd87d3SSergey Temerkhanov
15552ffd87d3SSergey Temerkhanov /**
15562ffd87d3SSergey Temerkhanov * ice_get_pkg_info
15572ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
15582ffd87d3SSergey Temerkhanov *
15592ffd87d3SSergey Temerkhanov * Store details of the package currently loaded in HW into the HW structure.
15602ffd87d3SSergey Temerkhanov */
ice_get_pkg_info(struct ice_hw * hw)15612ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw)
15622ffd87d3SSergey Temerkhanov {
15632ffd87d3SSergey Temerkhanov enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS;
15642ffd87d3SSergey Temerkhanov struct ice_aqc_get_pkg_info_resp *pkg_info;
15652ffd87d3SSergey Temerkhanov u16 size;
15662ffd87d3SSergey Temerkhanov u32 i;
15672ffd87d3SSergey Temerkhanov
15682ffd87d3SSergey Temerkhanov size = struct_size(pkg_info, pkg_info, ICE_PKG_CNT);
15692ffd87d3SSergey Temerkhanov pkg_info = kzalloc(size, GFP_KERNEL);
15702ffd87d3SSergey Temerkhanov if (!pkg_info)
15712ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR;
15722ffd87d3SSergey Temerkhanov
15732ffd87d3SSergey Temerkhanov if (ice_aq_get_pkg_info_list(hw, pkg_info, size, NULL)) {
15742ffd87d3SSergey Temerkhanov state = ICE_DDP_PKG_ERR;
15752ffd87d3SSergey Temerkhanov goto init_pkg_free_alloc;
15762ffd87d3SSergey Temerkhanov }
15772ffd87d3SSergey Temerkhanov
15782ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg_info->count); i++) {
15792ffd87d3SSergey Temerkhanov #define ICE_PKG_FLAG_COUNT 4
15802ffd87d3SSergey Temerkhanov char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 };
15812ffd87d3SSergey Temerkhanov u8 place = 0;
15822ffd87d3SSergey Temerkhanov
15832ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_active) {
15842ffd87d3SSergey Temerkhanov flags[place++] = 'A';
15852ffd87d3SSergey Temerkhanov hw->active_pkg_ver = pkg_info->pkg_info[i].ver;
15862ffd87d3SSergey Temerkhanov hw->active_track_id =
15872ffd87d3SSergey Temerkhanov le32_to_cpu(pkg_info->pkg_info[i].track_id);
15882ffd87d3SSergey Temerkhanov memcpy(hw->active_pkg_name, pkg_info->pkg_info[i].name,
15892ffd87d3SSergey Temerkhanov sizeof(pkg_info->pkg_info[i].name));
15902ffd87d3SSergey Temerkhanov hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm;
15912ffd87d3SSergey Temerkhanov }
15922ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_active_at_boot)
15932ffd87d3SSergey Temerkhanov flags[place++] = 'B';
15942ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_modified)
15952ffd87d3SSergey Temerkhanov flags[place++] = 'M';
15962ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_in_nvm)
15972ffd87d3SSergey Temerkhanov flags[place++] = 'N';
15982ffd87d3SSergey Temerkhanov
15992ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Pkg[%d]: %d.%d.%d.%d,%s,%s\n", i,
16002ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.major,
16012ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.minor,
16022ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.update,
16032ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.draft,
16042ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].name, flags);
16052ffd87d3SSergey Temerkhanov }
16062ffd87d3SSergey Temerkhanov
16072ffd87d3SSergey Temerkhanov init_pkg_free_alloc:
16082ffd87d3SSergey Temerkhanov kfree(pkg_info);
16092ffd87d3SSergey Temerkhanov
16102ffd87d3SSergey Temerkhanov return state;
16112ffd87d3SSergey Temerkhanov }
16122ffd87d3SSergey Temerkhanov
16132ffd87d3SSergey Temerkhanov /**
16142ffd87d3SSergey Temerkhanov * ice_chk_pkg_compat
16152ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
16162ffd87d3SSergey Temerkhanov * @ospkg: pointer to the package hdr
16172ffd87d3SSergey Temerkhanov * @seg: pointer to the package segment hdr
16182ffd87d3SSergey Temerkhanov *
16192ffd87d3SSergey Temerkhanov * This function checks the package version compatibility with driver and NVM
16202ffd87d3SSergey Temerkhanov */
ice_chk_pkg_compat(struct ice_hw * hw,struct ice_pkg_hdr * ospkg,struct ice_seg ** seg)16212ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_compat(struct ice_hw *hw,
16222ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *ospkg,
16232ffd87d3SSergey Temerkhanov struct ice_seg **seg)
16242ffd87d3SSergey Temerkhanov {
16252ffd87d3SSergey Temerkhanov struct ice_aqc_get_pkg_info_resp *pkg;
16262ffd87d3SSergey Temerkhanov enum ice_ddp_state state;
16272ffd87d3SSergey Temerkhanov u16 size;
16282ffd87d3SSergey Temerkhanov u32 i;
16292ffd87d3SSergey Temerkhanov
16302ffd87d3SSergey Temerkhanov /* Check package version compatibility */
16312ffd87d3SSergey Temerkhanov state = ice_chk_pkg_version(&hw->pkg_ver);
16322ffd87d3SSergey Temerkhanov if (state) {
16332ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n");
16342ffd87d3SSergey Temerkhanov return state;
16352ffd87d3SSergey Temerkhanov }
16362ffd87d3SSergey Temerkhanov
16372ffd87d3SSergey Temerkhanov /* find ICE segment in given package */
16382ffd87d3SSergey Temerkhanov *seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE,
16392ffd87d3SSergey Temerkhanov ospkg);
16402ffd87d3SSergey Temerkhanov if (!*seg) {
16412ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n");
16422ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE;
16432ffd87d3SSergey Temerkhanov }
16442ffd87d3SSergey Temerkhanov
16452ffd87d3SSergey Temerkhanov /* Check if FW is compatible with the OS package */
16462ffd87d3SSergey Temerkhanov size = struct_size(pkg, pkg_info, ICE_PKG_CNT);
16472ffd87d3SSergey Temerkhanov pkg = kzalloc(size, GFP_KERNEL);
16482ffd87d3SSergey Temerkhanov if (!pkg)
16492ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR;
16502ffd87d3SSergey Temerkhanov
16512ffd87d3SSergey Temerkhanov if (ice_aq_get_pkg_info_list(hw, pkg, size, NULL)) {
16522ffd87d3SSergey Temerkhanov state = ICE_DDP_PKG_LOAD_ERROR;
16532ffd87d3SSergey Temerkhanov goto fw_ddp_compat_free_alloc;
16542ffd87d3SSergey Temerkhanov }
16552ffd87d3SSergey Temerkhanov
16562ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg->count); i++) {
16572ffd87d3SSergey Temerkhanov /* loop till we find the NVM package */
16582ffd87d3SSergey Temerkhanov if (!pkg->pkg_info[i].is_in_nvm)
16592ffd87d3SSergey Temerkhanov continue;
16602ffd87d3SSergey Temerkhanov if ((*seg)->hdr.seg_format_ver.major !=
16612ffd87d3SSergey Temerkhanov pkg->pkg_info[i].ver.major ||
16622ffd87d3SSergey Temerkhanov (*seg)->hdr.seg_format_ver.minor >
16632ffd87d3SSergey Temerkhanov pkg->pkg_info[i].ver.minor) {
16642ffd87d3SSergey Temerkhanov state = ICE_DDP_PKG_FW_MISMATCH;
16652ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT,
16662ffd87d3SSergey Temerkhanov "OS package is not compatible with NVM.\n");
16672ffd87d3SSergey Temerkhanov }
16682ffd87d3SSergey Temerkhanov /* done processing NVM package so break */
16692ffd87d3SSergey Temerkhanov break;
16702ffd87d3SSergey Temerkhanov }
16712ffd87d3SSergey Temerkhanov fw_ddp_compat_free_alloc:
16722ffd87d3SSergey Temerkhanov kfree(pkg);
16732ffd87d3SSergey Temerkhanov return state;
16742ffd87d3SSergey Temerkhanov }
16752ffd87d3SSergey Temerkhanov
16762ffd87d3SSergey Temerkhanov /**
16772ffd87d3SSergey Temerkhanov * ice_init_pkg_hints
16782ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
16792ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the segment of the package scan (non-NULL)
16802ffd87d3SSergey Temerkhanov *
16812ffd87d3SSergey Temerkhanov * This function will scan the package and save off relevant information
16822ffd87d3SSergey Temerkhanov * (hints or metadata) for driver use. The ice_seg parameter must not be NULL
16832ffd87d3SSergey Temerkhanov * since the first call to ice_enum_labels requires a pointer to an actual
16842ffd87d3SSergey Temerkhanov * ice_seg structure.
16852ffd87d3SSergey Temerkhanov */
ice_init_pkg_hints(struct ice_hw * hw,struct ice_seg * ice_seg)16862ffd87d3SSergey Temerkhanov static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg)
16872ffd87d3SSergey Temerkhanov {
16882ffd87d3SSergey Temerkhanov struct ice_pkg_enum state;
16892ffd87d3SSergey Temerkhanov char *label_name;
16902ffd87d3SSergey Temerkhanov u16 val;
16912ffd87d3SSergey Temerkhanov int i;
16922ffd87d3SSergey Temerkhanov
16932ffd87d3SSergey Temerkhanov memset(&hw->tnl, 0, sizeof(hw->tnl));
16942ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state));
16952ffd87d3SSergey Temerkhanov
16962ffd87d3SSergey Temerkhanov if (!ice_seg)
16972ffd87d3SSergey Temerkhanov return;
16982ffd87d3SSergey Temerkhanov
16992ffd87d3SSergey Temerkhanov label_name = ice_enum_labels(ice_seg, ICE_SID_LBL_RXPARSER_TMEM, &state,
17002ffd87d3SSergey Temerkhanov &val);
17012ffd87d3SSergey Temerkhanov
17022ffd87d3SSergey Temerkhanov while (label_name) {
17032ffd87d3SSergey Temerkhanov if (!strncmp(label_name, ICE_TNL_PRE, strlen(ICE_TNL_PRE)))
17042ffd87d3SSergey Temerkhanov /* check for a tunnel entry */
17052ffd87d3SSergey Temerkhanov ice_add_tunnel_hint(hw, label_name, val);
17062ffd87d3SSergey Temerkhanov
17072ffd87d3SSergey Temerkhanov /* check for a dvm mode entry */
17082ffd87d3SSergey Temerkhanov else if (!strncmp(label_name, ICE_DVM_PRE, strlen(ICE_DVM_PRE)))
17092ffd87d3SSergey Temerkhanov ice_add_dvm_hint(hw, val, true);
17102ffd87d3SSergey Temerkhanov
17112ffd87d3SSergey Temerkhanov /* check for a svm mode entry */
17122ffd87d3SSergey Temerkhanov else if (!strncmp(label_name, ICE_SVM_PRE, strlen(ICE_SVM_PRE)))
17132ffd87d3SSergey Temerkhanov ice_add_dvm_hint(hw, val, false);
17142ffd87d3SSergey Temerkhanov
17152ffd87d3SSergey Temerkhanov label_name = ice_enum_labels(NULL, 0, &state, &val);
17162ffd87d3SSergey Temerkhanov }
17172ffd87d3SSergey Temerkhanov
17182ffd87d3SSergey Temerkhanov /* Cache the appropriate boost TCAM entry pointers for tunnels */
17192ffd87d3SSergey Temerkhanov for (i = 0; i < hw->tnl.count; i++) {
17202ffd87d3SSergey Temerkhanov ice_find_boost_entry(ice_seg, hw->tnl.tbl[i].boost_addr,
17212ffd87d3SSergey Temerkhanov &hw->tnl.tbl[i].boost_entry);
17222ffd87d3SSergey Temerkhanov if (hw->tnl.tbl[i].boost_entry) {
17232ffd87d3SSergey Temerkhanov hw->tnl.tbl[i].valid = true;
17242ffd87d3SSergey Temerkhanov if (hw->tnl.tbl[i].type < __TNL_TYPE_CNT)
17252ffd87d3SSergey Temerkhanov hw->tnl.valid_count[hw->tnl.tbl[i].type]++;
17262ffd87d3SSergey Temerkhanov }
17272ffd87d3SSergey Temerkhanov }
17282ffd87d3SSergey Temerkhanov
17292ffd87d3SSergey Temerkhanov /* Cache the appropriate boost TCAM entry pointers for DVM and SVM */
17302ffd87d3SSergey Temerkhanov for (i = 0; i < hw->dvm_upd.count; i++)
17312ffd87d3SSergey Temerkhanov ice_find_boost_entry(ice_seg, hw->dvm_upd.tbl[i].boost_addr,
17322ffd87d3SSergey Temerkhanov &hw->dvm_upd.tbl[i].boost_entry);
17332ffd87d3SSergey Temerkhanov }
17342ffd87d3SSergey Temerkhanov
17352ffd87d3SSergey Temerkhanov /**
17362ffd87d3SSergey Temerkhanov * ice_fill_hw_ptype - fill the enabled PTYPE bit information
17372ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure
17382ffd87d3SSergey Temerkhanov */
ice_fill_hw_ptype(struct ice_hw * hw)17392ffd87d3SSergey Temerkhanov static void ice_fill_hw_ptype(struct ice_hw *hw)
17402ffd87d3SSergey Temerkhanov {
17412ffd87d3SSergey Temerkhanov struct ice_marker_ptype_tcam_entry *tcam;
17422ffd87d3SSergey Temerkhanov struct ice_seg *seg = hw->seg;
17432ffd87d3SSergey Temerkhanov struct ice_pkg_enum state;
17442ffd87d3SSergey Temerkhanov
17452ffd87d3SSergey Temerkhanov bitmap_zero(hw->hw_ptype, ICE_FLOW_PTYPE_MAX);
17462ffd87d3SSergey Temerkhanov if (!seg)
17472ffd87d3SSergey Temerkhanov return;
17482ffd87d3SSergey Temerkhanov
17492ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state));
17502ffd87d3SSergey Temerkhanov
17512ffd87d3SSergey Temerkhanov do {
17522ffd87d3SSergey Temerkhanov tcam = ice_pkg_enum_entry(seg, &state,
17532ffd87d3SSergey Temerkhanov ICE_SID_RXPARSER_MARKER_PTYPE, NULL,
17542ffd87d3SSergey Temerkhanov ice_marker_ptype_tcam_handler);
17552ffd87d3SSergey Temerkhanov if (tcam &&
17562ffd87d3SSergey Temerkhanov le16_to_cpu(tcam->addr) < ICE_MARKER_PTYPE_TCAM_ADDR_MAX &&
17572ffd87d3SSergey Temerkhanov le16_to_cpu(tcam->ptype) < ICE_FLOW_PTYPE_MAX)
17582ffd87d3SSergey Temerkhanov set_bit(le16_to_cpu(tcam->ptype), hw->hw_ptype);
17592ffd87d3SSergey Temerkhanov
17602ffd87d3SSergey Temerkhanov seg = NULL;
17612ffd87d3SSergey Temerkhanov } while (tcam);
17622ffd87d3SSergey Temerkhanov }
17632ffd87d3SSergey Temerkhanov
17642ffd87d3SSergey Temerkhanov /**
17652ffd87d3SSergey Temerkhanov * ice_init_pkg - initialize/download package
17662ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
17672ffd87d3SSergey Temerkhanov * @buf: pointer to the package buffer
17682ffd87d3SSergey Temerkhanov * @len: size of the package buffer
17692ffd87d3SSergey Temerkhanov *
17702ffd87d3SSergey Temerkhanov * This function initializes a package. The package contains HW tables
17712ffd87d3SSergey Temerkhanov * required to do packet processing. First, the function extracts package
17722ffd87d3SSergey Temerkhanov * information such as version. Then it finds the ice configuration segment
17732ffd87d3SSergey Temerkhanov * within the package; this function then saves a copy of the segment pointer
17742ffd87d3SSergey Temerkhanov * within the supplied package buffer. Next, the function will cache any hints
17752ffd87d3SSergey Temerkhanov * from the package, followed by downloading the package itself. Note, that if
17762ffd87d3SSergey Temerkhanov * a previous PF driver has already downloaded the package successfully, then
17772ffd87d3SSergey Temerkhanov * the current driver will not have to download the package again.
17782ffd87d3SSergey Temerkhanov *
17792ffd87d3SSergey Temerkhanov * The local package contents will be used to query default behavior and to
17802ffd87d3SSergey Temerkhanov * update specific sections of the HW's version of the package (e.g. to update
17812ffd87d3SSergey Temerkhanov * the parse graph to understand new protocols).
17822ffd87d3SSergey Temerkhanov *
17832ffd87d3SSergey Temerkhanov * This function stores a pointer to the package buffer memory, and it is
17842ffd87d3SSergey Temerkhanov * expected that the supplied buffer will not be freed immediately. If the
17852ffd87d3SSergey Temerkhanov * package buffer needs to be freed, such as when read from a file, use
17862ffd87d3SSergey Temerkhanov * ice_copy_and_init_pkg() instead of directly calling ice_init_pkg() in this
17872ffd87d3SSergey Temerkhanov * case.
17882ffd87d3SSergey Temerkhanov */
ice_init_pkg(struct ice_hw * hw,u8 * buf,u32 len)17892ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len)
17902ffd87d3SSergey Temerkhanov {
17912ffd87d3SSergey Temerkhanov bool already_loaded = false;
17922ffd87d3SSergey Temerkhanov enum ice_ddp_state state;
17932ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg;
17942ffd87d3SSergey Temerkhanov struct ice_seg *seg;
17952ffd87d3SSergey Temerkhanov
17962ffd87d3SSergey Temerkhanov if (!buf || !len)
17972ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR;
17982ffd87d3SSergey Temerkhanov
17992ffd87d3SSergey Temerkhanov pkg = (struct ice_pkg_hdr *)buf;
18002ffd87d3SSergey Temerkhanov state = ice_verify_pkg(pkg, len);
18012ffd87d3SSergey Temerkhanov if (state) {
18022ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n",
18032ffd87d3SSergey Temerkhanov state);
18042ffd87d3SSergey Temerkhanov return state;
18052ffd87d3SSergey Temerkhanov }
18062ffd87d3SSergey Temerkhanov
18072ffd87d3SSergey Temerkhanov /* initialize package info */
18082ffd87d3SSergey Temerkhanov state = ice_init_pkg_info(hw, pkg);
18092ffd87d3SSergey Temerkhanov if (state)
18102ffd87d3SSergey Temerkhanov return state;
18112ffd87d3SSergey Temerkhanov
18122ffd87d3SSergey Temerkhanov /* before downloading the package, check package version for
18132ffd87d3SSergey Temerkhanov * compatibility with driver
18142ffd87d3SSergey Temerkhanov */
18152ffd87d3SSergey Temerkhanov state = ice_chk_pkg_compat(hw, pkg, &seg);
18162ffd87d3SSergey Temerkhanov if (state)
18172ffd87d3SSergey Temerkhanov return state;
18182ffd87d3SSergey Temerkhanov
18192ffd87d3SSergey Temerkhanov /* initialize package hints and then download package */
18202ffd87d3SSergey Temerkhanov ice_init_pkg_hints(hw, seg);
18212ffd87d3SSergey Temerkhanov state = ice_download_pkg(hw, seg);
18222ffd87d3SSergey Temerkhanov if (state == ICE_DDP_PKG_ALREADY_LOADED) {
18232ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT,
18242ffd87d3SSergey Temerkhanov "package previously loaded - no work.\n");
18252ffd87d3SSergey Temerkhanov already_loaded = true;
18262ffd87d3SSergey Temerkhanov }
18272ffd87d3SSergey Temerkhanov
18282ffd87d3SSergey Temerkhanov /* Get information on the package currently loaded in HW, then make sure
18292ffd87d3SSergey Temerkhanov * the driver is compatible with this version.
18302ffd87d3SSergey Temerkhanov */
18312ffd87d3SSergey Temerkhanov if (!state || state == ICE_DDP_PKG_ALREADY_LOADED) {
18322ffd87d3SSergey Temerkhanov state = ice_get_pkg_info(hw);
18332ffd87d3SSergey Temerkhanov if (!state)
18342ffd87d3SSergey Temerkhanov state = ice_get_ddp_pkg_state(hw, already_loaded);
18352ffd87d3SSergey Temerkhanov }
18362ffd87d3SSergey Temerkhanov
18372ffd87d3SSergey Temerkhanov if (ice_is_init_pkg_successful(state)) {
18382ffd87d3SSergey Temerkhanov hw->seg = seg;
18392ffd87d3SSergey Temerkhanov /* on successful package download update other required
18402ffd87d3SSergey Temerkhanov * registers to support the package and fill HW tables
18412ffd87d3SSergey Temerkhanov * with package content.
18422ffd87d3SSergey Temerkhanov */
18432ffd87d3SSergey Temerkhanov ice_init_pkg_regs(hw);
18442ffd87d3SSergey Temerkhanov ice_fill_blk_tbls(hw);
18452ffd87d3SSergey Temerkhanov ice_fill_hw_ptype(hw);
18462ffd87d3SSergey Temerkhanov ice_get_prof_index_max(hw);
18472ffd87d3SSergey Temerkhanov } else {
18482ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n", state);
18492ffd87d3SSergey Temerkhanov }
18502ffd87d3SSergey Temerkhanov
18512ffd87d3SSergey Temerkhanov return state;
18522ffd87d3SSergey Temerkhanov }
18532ffd87d3SSergey Temerkhanov
18542ffd87d3SSergey Temerkhanov /**
18552ffd87d3SSergey Temerkhanov * ice_copy_and_init_pkg - initialize/download a copy of the package
18562ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure
18572ffd87d3SSergey Temerkhanov * @buf: pointer to the package buffer
18582ffd87d3SSergey Temerkhanov * @len: size of the package buffer
18592ffd87d3SSergey Temerkhanov *
18602ffd87d3SSergey Temerkhanov * This function copies the package buffer, and then calls ice_init_pkg() to
18612ffd87d3SSergey Temerkhanov * initialize the copied package contents.
18622ffd87d3SSergey Temerkhanov *
18632ffd87d3SSergey Temerkhanov * The copying is necessary if the package buffer supplied is constant, or if
18642ffd87d3SSergey Temerkhanov * the memory may disappear shortly after calling this function.
18652ffd87d3SSergey Temerkhanov *
18662ffd87d3SSergey Temerkhanov * If the package buffer resides in the data segment and can be modified, the
18672ffd87d3SSergey Temerkhanov * caller is free to use ice_init_pkg() instead of ice_copy_and_init_pkg().
18682ffd87d3SSergey Temerkhanov *
18692ffd87d3SSergey Temerkhanov * However, if the package buffer needs to be copied first, such as when being
18702ffd87d3SSergey Temerkhanov * read from a file, the caller should use ice_copy_and_init_pkg().
18712ffd87d3SSergey Temerkhanov *
18722ffd87d3SSergey Temerkhanov * This function will first copy the package buffer, before calling
18732ffd87d3SSergey Temerkhanov * ice_init_pkg(). The caller is free to immediately destroy the original
18742ffd87d3SSergey Temerkhanov * package buffer, as the new copy will be managed by this function and
18752ffd87d3SSergey Temerkhanov * related routines.
18762ffd87d3SSergey Temerkhanov */
ice_copy_and_init_pkg(struct ice_hw * hw,const u8 * buf,u32 len)18772ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf,
18782ffd87d3SSergey Temerkhanov u32 len)
18792ffd87d3SSergey Temerkhanov {
18802ffd87d3SSergey Temerkhanov enum ice_ddp_state state;
18812ffd87d3SSergey Temerkhanov u8 *buf_copy;
18822ffd87d3SSergey Temerkhanov
18832ffd87d3SSergey Temerkhanov if (!buf || !len)
18842ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR;
18852ffd87d3SSergey Temerkhanov
18862ffd87d3SSergey Temerkhanov buf_copy = devm_kmemdup(ice_hw_to_dev(hw), buf, len, GFP_KERNEL);
18872ffd87d3SSergey Temerkhanov
18882ffd87d3SSergey Temerkhanov state = ice_init_pkg(hw, buf_copy, len);
18892ffd87d3SSergey Temerkhanov if (!ice_is_init_pkg_successful(state)) {
18902ffd87d3SSergey Temerkhanov /* Free the copy, since we failed to initialize the package */
18912ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), buf_copy);
18922ffd87d3SSergey Temerkhanov } else {
18932ffd87d3SSergey Temerkhanov /* Track the copied pkg so we can free it later */
18942ffd87d3SSergey Temerkhanov hw->pkg_copy = buf_copy;
18952ffd87d3SSergey Temerkhanov hw->pkg_size = len;
18962ffd87d3SSergey Temerkhanov }
18972ffd87d3SSergey Temerkhanov
18982ffd87d3SSergey Temerkhanov return state;
18992ffd87d3SSergey Temerkhanov }
1900