xref: /linux/drivers/net/ethernet/intel/ice/ice_ddp.c (revision 6d51d44ecddb5c2962688ef06e55e4fbc949f04a)
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  */
33708b352fSJan 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  */
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  */
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  */
121708b352fSJan 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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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  */
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  */
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 /**
1156708b352fSJan Sokolowski  * ice_aq_download_pkg
1157708b352fSJan Sokolowski  * @hw: pointer to the hardware structure
1158708b352fSJan Sokolowski  * @pkg_buf: the package buffer to transfer
1159708b352fSJan Sokolowski  * @buf_size: the size of the package buffer
1160708b352fSJan Sokolowski  * @last_buf: last buffer indicator
1161708b352fSJan Sokolowski  * @error_offset: returns error offset
1162708b352fSJan Sokolowski  * @error_info: returns error information
1163708b352fSJan Sokolowski  * @cd: pointer to command details structure or NULL
1164708b352fSJan Sokolowski  *
1165708b352fSJan Sokolowski  * Download Package (0x0C40)
1166708b352fSJan Sokolowski  */
1167708b352fSJan Sokolowski static int
1168708b352fSJan Sokolowski ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
1169708b352fSJan Sokolowski 		    u16 buf_size, bool last_buf, u32 *error_offset,
1170708b352fSJan Sokolowski 		    u32 *error_info, struct ice_sq_cd *cd)
1171708b352fSJan Sokolowski {
1172708b352fSJan Sokolowski 	struct ice_aqc_download_pkg *cmd;
1173708b352fSJan Sokolowski 	struct ice_aq_desc desc;
1174708b352fSJan Sokolowski 	int status;
1175708b352fSJan Sokolowski 
1176708b352fSJan Sokolowski 	if (error_offset)
1177708b352fSJan Sokolowski 		*error_offset = 0;
1178708b352fSJan Sokolowski 	if (error_info)
1179708b352fSJan Sokolowski 		*error_info = 0;
1180708b352fSJan Sokolowski 
1181708b352fSJan Sokolowski 	cmd = &desc.params.download_pkg;
1182708b352fSJan Sokolowski 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg);
1183708b352fSJan Sokolowski 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1184708b352fSJan Sokolowski 
1185708b352fSJan Sokolowski 	if (last_buf)
1186708b352fSJan Sokolowski 		cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
1187708b352fSJan Sokolowski 
1188708b352fSJan Sokolowski 	status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
1189708b352fSJan Sokolowski 	if (status == -EIO) {
1190708b352fSJan Sokolowski 		/* Read error from buffer only when the FW returned an error */
1191708b352fSJan Sokolowski 		struct ice_aqc_download_pkg_resp *resp;
1192708b352fSJan Sokolowski 
1193708b352fSJan Sokolowski 		resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
1194708b352fSJan Sokolowski 		if (error_offset)
1195708b352fSJan Sokolowski 			*error_offset = le32_to_cpu(resp->error_offset);
1196708b352fSJan Sokolowski 		if (error_info)
1197708b352fSJan Sokolowski 			*error_info = le32_to_cpu(resp->error_info);
1198708b352fSJan Sokolowski 	}
1199708b352fSJan Sokolowski 
1200708b352fSJan Sokolowski 	return status;
1201708b352fSJan Sokolowski }
1202708b352fSJan Sokolowski 
1203708b352fSJan Sokolowski /**
12043cbdb034SDan Nowlin  * ice_get_pkg_seg_by_idx
12053cbdb034SDan Nowlin  * @pkg_hdr: pointer to the package header to be searched
12063cbdb034SDan Nowlin  * @idx: index of segment
12073cbdb034SDan Nowlin  */
12083cbdb034SDan Nowlin static struct ice_generic_seg_hdr *
12093cbdb034SDan Nowlin ice_get_pkg_seg_by_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx)
12103cbdb034SDan Nowlin {
12113cbdb034SDan Nowlin 	if (idx < le32_to_cpu(pkg_hdr->seg_count))
12123cbdb034SDan Nowlin 		return (struct ice_generic_seg_hdr *)
12133cbdb034SDan Nowlin 			((u8 *)pkg_hdr +
12143cbdb034SDan Nowlin 			 le32_to_cpu(pkg_hdr->seg_offset[idx]));
12153cbdb034SDan Nowlin 
12163cbdb034SDan Nowlin 	return NULL;
12173cbdb034SDan Nowlin }
12183cbdb034SDan Nowlin 
12193cbdb034SDan Nowlin /**
12203cbdb034SDan Nowlin  * ice_is_signing_seg_at_idx - determine if segment is a signing segment
12213cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
12223cbdb034SDan Nowlin  * @idx: segment index
12233cbdb034SDan Nowlin  */
12243cbdb034SDan Nowlin static bool ice_is_signing_seg_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx)
12253cbdb034SDan Nowlin {
12263cbdb034SDan Nowlin 	struct ice_generic_seg_hdr *seg;
12273cbdb034SDan Nowlin 
12283cbdb034SDan Nowlin 	seg = ice_get_pkg_seg_by_idx(pkg_hdr, idx);
12293cbdb034SDan Nowlin 	if (!seg)
12303cbdb034SDan Nowlin 		return false;
12313cbdb034SDan Nowlin 
12323cbdb034SDan Nowlin 	return le32_to_cpu(seg->seg_type) == SEGMENT_TYPE_SIGNING;
12333cbdb034SDan Nowlin }
12343cbdb034SDan Nowlin 
12353cbdb034SDan Nowlin /**
12363cbdb034SDan Nowlin  * ice_is_signing_seg_type_at_idx
12373cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
12383cbdb034SDan Nowlin  * @idx: segment index
12393cbdb034SDan Nowlin  * @seg_id: segment id that is expected
12403cbdb034SDan Nowlin  * @sign_type: signing type
12413cbdb034SDan Nowlin  *
12423cbdb034SDan Nowlin  * Determine if a segment is a signing segment of the correct type
12433cbdb034SDan Nowlin  */
12443cbdb034SDan Nowlin static bool
12453cbdb034SDan Nowlin ice_is_signing_seg_type_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx,
12463cbdb034SDan Nowlin 			       u32 seg_id, u32 sign_type)
12473cbdb034SDan Nowlin {
12483cbdb034SDan Nowlin 	struct ice_sign_seg *seg;
12493cbdb034SDan Nowlin 
12503cbdb034SDan Nowlin 	if (!ice_is_signing_seg_at_idx(pkg_hdr, idx))
12513cbdb034SDan Nowlin 		return false;
12523cbdb034SDan Nowlin 
12533cbdb034SDan Nowlin 	seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
12543cbdb034SDan Nowlin 
12553cbdb034SDan Nowlin 	if (seg && le32_to_cpu(seg->seg_id) == seg_id &&
12563cbdb034SDan Nowlin 	    le32_to_cpu(seg->sign_type) == sign_type)
12573cbdb034SDan Nowlin 		return true;
12583cbdb034SDan Nowlin 
12593cbdb034SDan Nowlin 	return false;
12603cbdb034SDan Nowlin }
12613cbdb034SDan Nowlin 
12623cbdb034SDan Nowlin /**
12633cbdb034SDan Nowlin  * ice_is_buffer_metadata - determine if package buffer is a metadata buffer
12643cbdb034SDan Nowlin  * @buf: pointer to buffer header
12653cbdb034SDan Nowlin  */
12663cbdb034SDan Nowlin static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf)
12673cbdb034SDan Nowlin {
12683cbdb034SDan Nowlin 	if (le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF)
12693cbdb034SDan Nowlin 		return true;
12703cbdb034SDan Nowlin 
12713cbdb034SDan Nowlin 	return false;
12723cbdb034SDan Nowlin }
12733cbdb034SDan Nowlin 
12743cbdb034SDan Nowlin /**
12753cbdb034SDan Nowlin  * ice_is_last_download_buffer
12763cbdb034SDan Nowlin  * @buf: pointer to current buffer header
12773cbdb034SDan Nowlin  * @idx: index of the buffer in the current sequence
12783cbdb034SDan Nowlin  * @count: the buffer count in the current sequence
12793cbdb034SDan Nowlin  *
12803cbdb034SDan Nowlin  * Note: this routine should only be called if the buffer is not the last buffer
12813cbdb034SDan Nowlin  */
12823cbdb034SDan Nowlin static bool
12833cbdb034SDan Nowlin ice_is_last_download_buffer(struct ice_buf_hdr *buf, u32 idx, u32 count)
12843cbdb034SDan Nowlin {
12853cbdb034SDan Nowlin 	struct ice_buf *next_buf;
12863cbdb034SDan Nowlin 
12873cbdb034SDan Nowlin 	if ((idx + 1) == count)
12883cbdb034SDan Nowlin 		return true;
12893cbdb034SDan Nowlin 
12903cbdb034SDan Nowlin 	/* A set metadata flag in the next buffer will signal that the current
12913cbdb034SDan Nowlin 	 * buffer will be the last buffer downloaded
12923cbdb034SDan Nowlin 	 */
12933cbdb034SDan Nowlin 	next_buf = ((struct ice_buf *)buf) + 1;
12943cbdb034SDan Nowlin 
12953cbdb034SDan Nowlin 	return ice_is_buffer_metadata((struct ice_buf_hdr *)next_buf);
12963cbdb034SDan Nowlin }
12973cbdb034SDan Nowlin 
12983cbdb034SDan Nowlin /**
12993cbdb034SDan Nowlin  * ice_dwnld_cfg_bufs_no_lock
13002ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
13012ffd87d3SSergey Temerkhanov  * @bufs: pointer to an array of buffers
13023cbdb034SDan Nowlin  * @start: buffer index of first buffer to download
13033cbdb034SDan Nowlin  * @count: the number of buffers to download
13043cbdb034SDan Nowlin  * @indicate_last: if true, then set last buffer flag on last buffer download
13052ffd87d3SSergey Temerkhanov  *
13063cbdb034SDan Nowlin  * Downloads package configuration buffers to the firmware. Metadata buffers
13073cbdb034SDan Nowlin  * are skipped, and the first metadata buffer found indicates that the rest
13083cbdb034SDan Nowlin  * of the buffers are all metadata buffers.
13092ffd87d3SSergey Temerkhanov  */
13103cbdb034SDan Nowlin static enum ice_ddp_state
13113cbdb034SDan Nowlin ice_dwnld_cfg_bufs_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 start,
13123cbdb034SDan Nowlin 			   u32 count, bool indicate_last)
13132ffd87d3SSergey Temerkhanov {
13142ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS;
13152ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *bh;
13162ffd87d3SSergey Temerkhanov 	enum ice_aq_err err;
13172ffd87d3SSergey Temerkhanov 	u32 offset, info, i;
13182ffd87d3SSergey Temerkhanov 
13192ffd87d3SSergey Temerkhanov 	if (!bufs || !count)
13202ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
13212ffd87d3SSergey Temerkhanov 
13222ffd87d3SSergey Temerkhanov 	/* If the first buffer's first section has its metadata bit set
13232ffd87d3SSergey Temerkhanov 	 * then there are no buffers to be downloaded, and the operation is
13242ffd87d3SSergey Temerkhanov 	 * considered a success.
13252ffd87d3SSergey Temerkhanov 	 */
13263cbdb034SDan Nowlin 	bh = (struct ice_buf_hdr *)(bufs + start);
13272ffd87d3SSergey Temerkhanov 	if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF)
13282ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_SUCCESS;
13292ffd87d3SSergey Temerkhanov 
13302ffd87d3SSergey Temerkhanov 	for (i = 0; i < count; i++) {
13313cbdb034SDan Nowlin 		bool last = false;
13323cbdb034SDan Nowlin 		int status;
13332ffd87d3SSergey Temerkhanov 
13343cbdb034SDan Nowlin 		bh = (struct ice_buf_hdr *)(bufs + start + i);
13352ffd87d3SSergey Temerkhanov 
13363cbdb034SDan Nowlin 		if (indicate_last)
13373cbdb034SDan Nowlin 			last = ice_is_last_download_buffer(bh, i, count);
13382ffd87d3SSergey Temerkhanov 
13392ffd87d3SSergey Temerkhanov 		status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE, last,
13402ffd87d3SSergey Temerkhanov 					     &offset, &info, NULL);
13412ffd87d3SSergey Temerkhanov 
13422ffd87d3SSergey Temerkhanov 		/* Save AQ status from download package */
13432ffd87d3SSergey Temerkhanov 		if (status) {
13443cbdb034SDan Nowlin 			ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n",
13452ffd87d3SSergey Temerkhanov 				  status, offset, info);
13462ffd87d3SSergey Temerkhanov 			err = hw->adminq.sq_last_status;
13472ffd87d3SSergey Temerkhanov 			state = ice_map_aq_err_to_ddp_state(err);
13482ffd87d3SSergey Temerkhanov 			break;
13492ffd87d3SSergey Temerkhanov 		}
13502ffd87d3SSergey Temerkhanov 
13512ffd87d3SSergey Temerkhanov 		if (last)
13522ffd87d3SSergey Temerkhanov 			break;
13532ffd87d3SSergey Temerkhanov 	}
13542ffd87d3SSergey Temerkhanov 
13553cbdb034SDan Nowlin 	return state;
13562ffd87d3SSergey Temerkhanov }
13572ffd87d3SSergey Temerkhanov 
13583cbdb034SDan Nowlin /**
13593cbdb034SDan Nowlin  * ice_download_pkg_sig_seg - download a signature segment
13603cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
13613cbdb034SDan Nowlin  * @seg: pointer to signature segment
13623cbdb034SDan Nowlin  */
13633cbdb034SDan Nowlin static enum ice_ddp_state
13643cbdb034SDan Nowlin ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg)
13653cbdb034SDan Nowlin {
13663cbdb034SDan Nowlin 	return  ice_dwnld_cfg_bufs_no_lock(hw, seg->buf_tbl.buf_array, 0,
13673cbdb034SDan Nowlin 					   le32_to_cpu(seg->buf_tbl.buf_count),
13683cbdb034SDan Nowlin 					   false);
13693cbdb034SDan Nowlin }
13703cbdb034SDan Nowlin 
13713cbdb034SDan Nowlin /**
13723cbdb034SDan Nowlin  * ice_download_pkg_config_seg - download a config segment
13733cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
13743cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
13753cbdb034SDan Nowlin  * @idx: segment index
13763cbdb034SDan Nowlin  * @start: starting buffer
13773cbdb034SDan Nowlin  * @count: buffer count
13783cbdb034SDan Nowlin  *
13793cbdb034SDan Nowlin  * Note: idx must reference a ICE segment
13803cbdb034SDan Nowlin  */
13813cbdb034SDan Nowlin static enum ice_ddp_state
13823cbdb034SDan Nowlin ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
13833cbdb034SDan Nowlin 			    u32 idx, u32 start, u32 count)
13843cbdb034SDan Nowlin {
13853cbdb034SDan Nowlin 	struct ice_buf_table *bufs;
13863cbdb034SDan Nowlin 	struct ice_seg *seg;
13873cbdb034SDan Nowlin 	u32 buf_count;
13883cbdb034SDan Nowlin 
13893cbdb034SDan Nowlin 	seg = (struct ice_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
13903cbdb034SDan Nowlin 	if (!seg)
13913cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
13923cbdb034SDan Nowlin 
13933cbdb034SDan Nowlin 	bufs = ice_find_buf_table(seg);
13943cbdb034SDan Nowlin 	buf_count = le32_to_cpu(bufs->buf_count);
13953cbdb034SDan Nowlin 
13963cbdb034SDan Nowlin 	if (start >= buf_count || start + count > buf_count)
13973cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
13983cbdb034SDan Nowlin 
13993cbdb034SDan Nowlin 	return  ice_dwnld_cfg_bufs_no_lock(hw, bufs->buf_array, start, count,
14003cbdb034SDan Nowlin 					   true);
14013cbdb034SDan Nowlin }
14023cbdb034SDan Nowlin 
14033cbdb034SDan Nowlin /**
14043cbdb034SDan Nowlin  * ice_dwnld_sign_and_cfg_segs - download a signing segment and config segment
14053cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
14063cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
14073cbdb034SDan Nowlin  * @idx: segment index (must be a signature segment)
14083cbdb034SDan Nowlin  *
14093cbdb034SDan Nowlin  * Note: idx must reference a signature segment
14103cbdb034SDan Nowlin  */
14113cbdb034SDan Nowlin static enum ice_ddp_state
14123cbdb034SDan Nowlin ice_dwnld_sign_and_cfg_segs(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
14133cbdb034SDan Nowlin 			    u32 idx)
14143cbdb034SDan Nowlin {
14153cbdb034SDan Nowlin 	enum ice_ddp_state state;
14163cbdb034SDan Nowlin 	struct ice_sign_seg *seg;
14173cbdb034SDan Nowlin 	u32 conf_idx;
14183cbdb034SDan Nowlin 	u32 start;
14193cbdb034SDan Nowlin 	u32 count;
14203cbdb034SDan Nowlin 
14213cbdb034SDan Nowlin 	seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
14223cbdb034SDan Nowlin 	if (!seg) {
14233cbdb034SDan Nowlin 		state = ICE_DDP_PKG_ERR;
14243cbdb034SDan Nowlin 		goto exit;
14253cbdb034SDan Nowlin 	}
14263cbdb034SDan Nowlin 
1427*6d51d44eSDan Nowlin 	count = le32_to_cpu(seg->signed_buf_count);
1428*6d51d44eSDan Nowlin 	state = ice_download_pkg_sig_seg(hw, seg);
1429*6d51d44eSDan Nowlin 	if (state || !count)
1430*6d51d44eSDan Nowlin 		goto exit;
1431*6d51d44eSDan Nowlin 
14323cbdb034SDan Nowlin 	conf_idx = le32_to_cpu(seg->signed_seg_idx);
14333cbdb034SDan Nowlin 	start = le32_to_cpu(seg->signed_buf_start);
14343cbdb034SDan Nowlin 
14353cbdb034SDan Nowlin 	state = ice_download_pkg_config_seg(hw, pkg_hdr, conf_idx, start,
14363cbdb034SDan Nowlin 					    count);
14373cbdb034SDan Nowlin 
14383cbdb034SDan Nowlin exit:
14393cbdb034SDan Nowlin 	return state;
14403cbdb034SDan Nowlin }
14413cbdb034SDan Nowlin 
14423cbdb034SDan Nowlin /**
14433cbdb034SDan Nowlin  * ice_match_signing_seg - determine if a matching signing segment exists
14443cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
14453cbdb034SDan Nowlin  * @seg_id: segment id that is expected
14463cbdb034SDan Nowlin  * @sign_type: signing type
14473cbdb034SDan Nowlin  */
14483cbdb034SDan Nowlin static bool
14493cbdb034SDan Nowlin ice_match_signing_seg(struct ice_pkg_hdr *pkg_hdr, u32 seg_id, u32 sign_type)
14503cbdb034SDan Nowlin {
14513cbdb034SDan Nowlin 	u32 i;
14523cbdb034SDan Nowlin 
14533cbdb034SDan Nowlin 	for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) {
14543cbdb034SDan Nowlin 		if (ice_is_signing_seg_type_at_idx(pkg_hdr, i, seg_id,
14553cbdb034SDan Nowlin 						   sign_type))
14563cbdb034SDan Nowlin 			return true;
14573cbdb034SDan Nowlin 	}
14583cbdb034SDan Nowlin 
14593cbdb034SDan Nowlin 	return false;
14603cbdb034SDan Nowlin }
14613cbdb034SDan Nowlin 
14623cbdb034SDan Nowlin /**
14633cbdb034SDan Nowlin  * ice_post_dwnld_pkg_actions - perform post download package actions
14643cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
14653cbdb034SDan Nowlin  */
14663cbdb034SDan Nowlin static enum ice_ddp_state
14673cbdb034SDan Nowlin ice_post_dwnld_pkg_actions(struct ice_hw *hw)
14683cbdb034SDan Nowlin {
14693cbdb034SDan Nowlin 	int status;
14703cbdb034SDan Nowlin 
14713cbdb034SDan Nowlin 	status = ice_set_vlan_mode(hw);
14723cbdb034SDan Nowlin 	if (status) {
14733cbdb034SDan Nowlin 		ice_debug(hw, ICE_DBG_PKG, "Failed to set VLAN mode: err %d\n",
14743cbdb034SDan Nowlin 			  status);
14753cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
14763cbdb034SDan Nowlin 	}
14773cbdb034SDan Nowlin 
14783cbdb034SDan Nowlin 	return ICE_DDP_PKG_SUCCESS;
14793cbdb034SDan Nowlin }
14803cbdb034SDan Nowlin 
14813cbdb034SDan Nowlin /**
1482a778616eSDan Nowlin  * ice_download_pkg_with_sig_seg
14833cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
14843cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
14853cbdb034SDan Nowlin  *
14863cbdb034SDan Nowlin  * Handles the download of a complete package.
14873cbdb034SDan Nowlin  */
14883cbdb034SDan Nowlin static enum ice_ddp_state
1489a778616eSDan Nowlin ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
14903cbdb034SDan Nowlin {
14913cbdb034SDan Nowlin 	enum ice_aq_err aq_err = hw->adminq.sq_last_status;
14923cbdb034SDan Nowlin 	enum ice_ddp_state state = ICE_DDP_PKG_ERR;
14933cbdb034SDan Nowlin 	int status;
14943cbdb034SDan Nowlin 	u32 i;
14953cbdb034SDan Nowlin 
14963cbdb034SDan Nowlin 	ice_debug(hw, ICE_DBG_INIT, "Segment ID %d\n", hw->pkg_seg_id);
14973cbdb034SDan Nowlin 	ice_debug(hw, ICE_DBG_INIT, "Signature type %d\n", hw->pkg_sign_type);
14983cbdb034SDan Nowlin 
14993cbdb034SDan Nowlin 	status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
15003cbdb034SDan Nowlin 	if (status) {
15013cbdb034SDan Nowlin 		if (status == -EALREADY)
15023cbdb034SDan Nowlin 			state = ICE_DDP_PKG_ALREADY_LOADED;
15033cbdb034SDan Nowlin 		else
15043cbdb034SDan Nowlin 			state = ice_map_aq_err_to_ddp_state(aq_err);
15053cbdb034SDan Nowlin 		return state;
15063cbdb034SDan Nowlin 	}
15073cbdb034SDan Nowlin 
15083cbdb034SDan Nowlin 	for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) {
15093cbdb034SDan Nowlin 		if (!ice_is_signing_seg_type_at_idx(pkg_hdr, i, hw->pkg_seg_id,
15103cbdb034SDan Nowlin 						    hw->pkg_sign_type))
15113cbdb034SDan Nowlin 			continue;
15123cbdb034SDan Nowlin 
15133cbdb034SDan Nowlin 		state = ice_dwnld_sign_and_cfg_segs(hw, pkg_hdr, i);
15143cbdb034SDan Nowlin 		if (state)
15153cbdb034SDan Nowlin 			break;
15163cbdb034SDan Nowlin 	}
15173cbdb034SDan Nowlin 
15183cbdb034SDan Nowlin 	if (!state)
15193cbdb034SDan Nowlin 		state = ice_post_dwnld_pkg_actions(hw);
15203cbdb034SDan Nowlin 
15212ffd87d3SSergey Temerkhanov 	ice_release_global_cfg_lock(hw);
1522a778616eSDan Nowlin 
1523a778616eSDan Nowlin 	return state;
1524a778616eSDan Nowlin }
1525a778616eSDan Nowlin 
1526a778616eSDan Nowlin /**
1527a778616eSDan Nowlin  * ice_dwnld_cfg_bufs
1528a778616eSDan Nowlin  * @hw: pointer to the hardware structure
1529a778616eSDan Nowlin  * @bufs: pointer to an array of buffers
1530a778616eSDan Nowlin  * @count: the number of buffers in the array
1531a778616eSDan Nowlin  *
1532a778616eSDan Nowlin  * Obtains global config lock and downloads the package configuration buffers
1533a778616eSDan Nowlin  * to the firmware.
1534a778616eSDan Nowlin  */
1535a778616eSDan Nowlin static enum ice_ddp_state
1536a778616eSDan Nowlin ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
1537a778616eSDan Nowlin {
1538a778616eSDan Nowlin 	enum ice_ddp_state state;
1539a778616eSDan Nowlin 	struct ice_buf_hdr *bh;
1540a778616eSDan Nowlin 	int status;
1541a778616eSDan Nowlin 
1542a778616eSDan Nowlin 	if (!bufs || !count)
1543a778616eSDan Nowlin 		return ICE_DDP_PKG_ERR;
1544a778616eSDan Nowlin 
1545a778616eSDan Nowlin 	/* If the first buffer's first section has its metadata bit set
1546a778616eSDan Nowlin 	 * then there are no buffers to be downloaded, and the operation is
1547a778616eSDan Nowlin 	 * considered a success.
1548a778616eSDan Nowlin 	 */
1549a778616eSDan Nowlin 	bh = (struct ice_buf_hdr *)bufs;
1550a778616eSDan Nowlin 	if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF)
1551a778616eSDan Nowlin 		return ICE_DDP_PKG_SUCCESS;
1552a778616eSDan Nowlin 
1553a778616eSDan Nowlin 	status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
1554a778616eSDan Nowlin 	if (status) {
1555a778616eSDan Nowlin 		if (status == -EALREADY)
1556a778616eSDan Nowlin 			return ICE_DDP_PKG_ALREADY_LOADED;
1557a778616eSDan Nowlin 		return ice_map_aq_err_to_ddp_state(hw->adminq.sq_last_status);
1558a778616eSDan Nowlin 	}
1559a778616eSDan Nowlin 
1560a778616eSDan Nowlin 	state = ice_dwnld_cfg_bufs_no_lock(hw, bufs, 0, count, true);
1561a778616eSDan Nowlin 	if (!state)
1562a778616eSDan Nowlin 		state = ice_post_dwnld_pkg_actions(hw);
1563a778616eSDan Nowlin 
1564a778616eSDan Nowlin 	ice_release_global_cfg_lock(hw);
1565a778616eSDan Nowlin 
1566a778616eSDan Nowlin 	return state;
1567a778616eSDan Nowlin }
1568a778616eSDan Nowlin 
1569a778616eSDan Nowlin /**
1570a778616eSDan Nowlin  * ice_download_pkg_without_sig_seg
1571a778616eSDan Nowlin  * @hw: pointer to the hardware structure
1572a778616eSDan Nowlin  * @ice_seg: pointer to the segment of the package to be downloaded
1573a778616eSDan Nowlin  *
1574a778616eSDan Nowlin  * Handles the download of a complete package without signature segment.
1575a778616eSDan Nowlin  */
1576a778616eSDan Nowlin static enum ice_ddp_state
1577a778616eSDan Nowlin ice_download_pkg_without_sig_seg(struct ice_hw *hw, struct ice_seg *ice_seg)
1578a778616eSDan Nowlin {
1579a778616eSDan Nowlin 	struct ice_buf_table *ice_buf_tbl;
1580a778616eSDan Nowlin 
1581a778616eSDan Nowlin 	ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n",
1582a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.major,
1583a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.minor,
1584a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.update,
1585a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.draft);
1586a778616eSDan Nowlin 
1587a778616eSDan Nowlin 	ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n",
1588a778616eSDan Nowlin 		  le32_to_cpu(ice_seg->hdr.seg_type),
1589a778616eSDan Nowlin 		  le32_to_cpu(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id);
1590a778616eSDan Nowlin 
1591a778616eSDan Nowlin 	ice_buf_tbl = ice_find_buf_table(ice_seg);
1592a778616eSDan Nowlin 
1593a778616eSDan Nowlin 	ice_debug(hw, ICE_DBG_PKG, "Seg buf count: %d\n",
1594a778616eSDan Nowlin 		  le32_to_cpu(ice_buf_tbl->buf_count));
1595a778616eSDan Nowlin 
1596a778616eSDan Nowlin 	return ice_dwnld_cfg_bufs(hw, ice_buf_tbl->buf_array,
1597a778616eSDan Nowlin 				  le32_to_cpu(ice_buf_tbl->buf_count));
1598a778616eSDan Nowlin }
1599a778616eSDan Nowlin 
1600a778616eSDan Nowlin /**
1601a778616eSDan Nowlin  * ice_download_pkg
1602a778616eSDan Nowlin  * @hw: pointer to the hardware structure
1603a778616eSDan Nowlin  * @pkg_hdr: pointer to package header
1604a778616eSDan Nowlin  * @ice_seg: pointer to the segment of the package to be downloaded
1605a778616eSDan Nowlin  *
1606a778616eSDan Nowlin  * Handles the download of a complete package.
1607a778616eSDan Nowlin  */
1608a778616eSDan Nowlin static enum ice_ddp_state
1609a778616eSDan Nowlin ice_download_pkg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
1610a778616eSDan Nowlin 		 struct ice_seg *ice_seg)
1611a778616eSDan Nowlin {
1612a778616eSDan Nowlin 	enum ice_ddp_state state;
1613a778616eSDan Nowlin 
1614a778616eSDan Nowlin 	if (hw->pkg_has_signing_seg)
1615a778616eSDan Nowlin 		state = ice_download_pkg_with_sig_seg(hw, pkg_hdr);
1616a778616eSDan Nowlin 	else
1617a778616eSDan Nowlin 		state = ice_download_pkg_without_sig_seg(hw, ice_seg);
1618a778616eSDan Nowlin 
16193cbdb034SDan Nowlin 	ice_post_pkg_dwnld_vlan_mode_cfg(hw);
16202ffd87d3SSergey Temerkhanov 
16212ffd87d3SSergey Temerkhanov 	return state;
16222ffd87d3SSergey Temerkhanov }
16232ffd87d3SSergey Temerkhanov 
16242ffd87d3SSergey Temerkhanov /**
16252ffd87d3SSergey Temerkhanov  * ice_aq_get_pkg_info_list
16262ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
16272ffd87d3SSergey Temerkhanov  * @pkg_info: the buffer which will receive the information list
16282ffd87d3SSergey Temerkhanov  * @buf_size: the size of the pkg_info information buffer
16292ffd87d3SSergey Temerkhanov  * @cd: pointer to command details structure or NULL
16302ffd87d3SSergey Temerkhanov  *
16312ffd87d3SSergey Temerkhanov  * Get Package Info List (0x0C43)
16322ffd87d3SSergey Temerkhanov  */
16332ffd87d3SSergey Temerkhanov static int ice_aq_get_pkg_info_list(struct ice_hw *hw,
16342ffd87d3SSergey Temerkhanov 				    struct ice_aqc_get_pkg_info_resp *pkg_info,
16352ffd87d3SSergey Temerkhanov 				    u16 buf_size, struct ice_sq_cd *cd)
16362ffd87d3SSergey Temerkhanov {
16372ffd87d3SSergey Temerkhanov 	struct ice_aq_desc desc;
16382ffd87d3SSergey Temerkhanov 
16392ffd87d3SSergey Temerkhanov 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list);
16402ffd87d3SSergey Temerkhanov 
16412ffd87d3SSergey Temerkhanov 	return ice_aq_send_cmd(hw, &desc, pkg_info, buf_size, cd);
16422ffd87d3SSergey Temerkhanov }
16432ffd87d3SSergey Temerkhanov 
16442ffd87d3SSergey Temerkhanov /**
16452ffd87d3SSergey Temerkhanov  * ice_aq_update_pkg
16462ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
16472ffd87d3SSergey Temerkhanov  * @pkg_buf: the package cmd buffer
16482ffd87d3SSergey Temerkhanov  * @buf_size: the size of the package cmd buffer
16492ffd87d3SSergey Temerkhanov  * @last_buf: last buffer indicator
16502ffd87d3SSergey Temerkhanov  * @error_offset: returns error offset
16512ffd87d3SSergey Temerkhanov  * @error_info: returns error information
16522ffd87d3SSergey Temerkhanov  * @cd: pointer to command details structure or NULL
16532ffd87d3SSergey Temerkhanov  *
16542ffd87d3SSergey Temerkhanov  * Update Package (0x0C42)
16552ffd87d3SSergey Temerkhanov  */
16562ffd87d3SSergey Temerkhanov static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
16572ffd87d3SSergey Temerkhanov 			     u16 buf_size, bool last_buf, u32 *error_offset,
16582ffd87d3SSergey Temerkhanov 			     u32 *error_info, struct ice_sq_cd *cd)
16592ffd87d3SSergey Temerkhanov {
16602ffd87d3SSergey Temerkhanov 	struct ice_aqc_download_pkg *cmd;
16612ffd87d3SSergey Temerkhanov 	struct ice_aq_desc desc;
16622ffd87d3SSergey Temerkhanov 	int status;
16632ffd87d3SSergey Temerkhanov 
16642ffd87d3SSergey Temerkhanov 	if (error_offset)
16652ffd87d3SSergey Temerkhanov 		*error_offset = 0;
16662ffd87d3SSergey Temerkhanov 	if (error_info)
16672ffd87d3SSergey Temerkhanov 		*error_info = 0;
16682ffd87d3SSergey Temerkhanov 
16692ffd87d3SSergey Temerkhanov 	cmd = &desc.params.download_pkg;
16702ffd87d3SSergey Temerkhanov 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg);
16712ffd87d3SSergey Temerkhanov 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
16722ffd87d3SSergey Temerkhanov 
16732ffd87d3SSergey Temerkhanov 	if (last_buf)
16742ffd87d3SSergey Temerkhanov 		cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
16752ffd87d3SSergey Temerkhanov 
16762ffd87d3SSergey Temerkhanov 	status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
16772ffd87d3SSergey Temerkhanov 	if (status == -EIO) {
16782ffd87d3SSergey Temerkhanov 		/* Read error from buffer only when the FW returned an error */
16792ffd87d3SSergey Temerkhanov 		struct ice_aqc_download_pkg_resp *resp;
16802ffd87d3SSergey Temerkhanov 
16812ffd87d3SSergey Temerkhanov 		resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
16822ffd87d3SSergey Temerkhanov 		if (error_offset)
16832ffd87d3SSergey Temerkhanov 			*error_offset = le32_to_cpu(resp->error_offset);
16842ffd87d3SSergey Temerkhanov 		if (error_info)
16852ffd87d3SSergey Temerkhanov 			*error_info = le32_to_cpu(resp->error_info);
16862ffd87d3SSergey Temerkhanov 	}
16872ffd87d3SSergey Temerkhanov 
16882ffd87d3SSergey Temerkhanov 	return status;
16892ffd87d3SSergey Temerkhanov }
16902ffd87d3SSergey Temerkhanov 
16912ffd87d3SSergey Temerkhanov /**
1692708b352fSJan Sokolowski  * ice_aq_upload_section
1693708b352fSJan Sokolowski  * @hw: pointer to the hardware structure
1694708b352fSJan Sokolowski  * @pkg_buf: the package buffer which will receive the section
1695708b352fSJan Sokolowski  * @buf_size: the size of the package buffer
1696708b352fSJan Sokolowski  * @cd: pointer to command details structure or NULL
1697708b352fSJan Sokolowski  *
1698708b352fSJan Sokolowski  * Upload Section (0x0C41)
1699708b352fSJan Sokolowski  */
1700708b352fSJan Sokolowski int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
1701708b352fSJan Sokolowski 			  u16 buf_size, struct ice_sq_cd *cd)
1702708b352fSJan Sokolowski {
1703708b352fSJan Sokolowski 	struct ice_aq_desc desc;
1704708b352fSJan Sokolowski 
1705708b352fSJan Sokolowski 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section);
1706708b352fSJan Sokolowski 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1707708b352fSJan Sokolowski 
1708708b352fSJan Sokolowski 	return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
1709708b352fSJan Sokolowski }
1710708b352fSJan Sokolowski 
1711708b352fSJan Sokolowski /**
17122ffd87d3SSergey Temerkhanov  * ice_update_pkg_no_lock
17132ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
17142ffd87d3SSergey Temerkhanov  * @bufs: pointer to an array of buffers
17152ffd87d3SSergey Temerkhanov  * @count: the number of buffers in the array
17162ffd87d3SSergey Temerkhanov  */
17172ffd87d3SSergey Temerkhanov int ice_update_pkg_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
17182ffd87d3SSergey Temerkhanov {
17192ffd87d3SSergey Temerkhanov 	int status = 0;
17202ffd87d3SSergey Temerkhanov 	u32 i;
17212ffd87d3SSergey Temerkhanov 
17222ffd87d3SSergey Temerkhanov 	for (i = 0; i < count; i++) {
17232ffd87d3SSergey Temerkhanov 		struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i);
17242ffd87d3SSergey Temerkhanov 		bool last = ((i + 1) == count);
17252ffd87d3SSergey Temerkhanov 		u32 offset, info;
17262ffd87d3SSergey Temerkhanov 
17272ffd87d3SSergey Temerkhanov 		status = ice_aq_update_pkg(hw, bh, le16_to_cpu(bh->data_end),
17282ffd87d3SSergey Temerkhanov 					   last, &offset, &info, NULL);
17292ffd87d3SSergey Temerkhanov 
17302ffd87d3SSergey Temerkhanov 		if (status) {
17312ffd87d3SSergey Temerkhanov 			ice_debug(hw, ICE_DBG_PKG,
17322ffd87d3SSergey Temerkhanov 				  "Update pkg failed: err %d off %d inf %d\n",
17332ffd87d3SSergey Temerkhanov 				  status, offset, info);
17342ffd87d3SSergey Temerkhanov 			break;
17352ffd87d3SSergey Temerkhanov 		}
17362ffd87d3SSergey Temerkhanov 	}
17372ffd87d3SSergey Temerkhanov 
17382ffd87d3SSergey Temerkhanov 	return status;
17392ffd87d3SSergey Temerkhanov }
17402ffd87d3SSergey Temerkhanov 
17412ffd87d3SSergey Temerkhanov /**
17422ffd87d3SSergey Temerkhanov  * ice_update_pkg
17432ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
17442ffd87d3SSergey Temerkhanov  * @bufs: pointer to an array of buffers
17452ffd87d3SSergey Temerkhanov  * @count: the number of buffers in the array
17462ffd87d3SSergey Temerkhanov  *
17472ffd87d3SSergey Temerkhanov  * Obtains change lock and updates package.
17482ffd87d3SSergey Temerkhanov  */
17492ffd87d3SSergey Temerkhanov int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
17502ffd87d3SSergey Temerkhanov {
17512ffd87d3SSergey Temerkhanov 	int status;
17522ffd87d3SSergey Temerkhanov 
17532ffd87d3SSergey Temerkhanov 	status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
17542ffd87d3SSergey Temerkhanov 	if (status)
17552ffd87d3SSergey Temerkhanov 		return status;
17562ffd87d3SSergey Temerkhanov 
17572ffd87d3SSergey Temerkhanov 	status = ice_update_pkg_no_lock(hw, bufs, count);
17582ffd87d3SSergey Temerkhanov 
17592ffd87d3SSergey Temerkhanov 	ice_release_change_lock(hw);
17602ffd87d3SSergey Temerkhanov 
17612ffd87d3SSergey Temerkhanov 	return status;
17622ffd87d3SSergey Temerkhanov }
17632ffd87d3SSergey Temerkhanov 
17642ffd87d3SSergey Temerkhanov /**
17652ffd87d3SSergey Temerkhanov  * ice_find_seg_in_pkg
17662ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
17672ffd87d3SSergey Temerkhanov  * @seg_type: the segment type to search for (i.e., SEGMENT_TYPE_CPK)
17682ffd87d3SSergey Temerkhanov  * @pkg_hdr: pointer to the package header to be searched
17692ffd87d3SSergey Temerkhanov  *
17702ffd87d3SSergey Temerkhanov  * This function searches a package file for a particular segment type. On
17712ffd87d3SSergey Temerkhanov  * success it returns a pointer to the segment header, otherwise it will
17722ffd87d3SSergey Temerkhanov  * return NULL.
17732ffd87d3SSergey Temerkhanov  */
1774708b352fSJan Sokolowski static struct ice_generic_seg_hdr *
1775708b352fSJan Sokolowski ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
17762ffd87d3SSergey Temerkhanov 		    struct ice_pkg_hdr *pkg_hdr)
17772ffd87d3SSergey Temerkhanov {
17782ffd87d3SSergey Temerkhanov 	u32 i;
17792ffd87d3SSergey Temerkhanov 
17802ffd87d3SSergey Temerkhanov 	ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n",
17812ffd87d3SSergey Temerkhanov 		  pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor,
17822ffd87d3SSergey Temerkhanov 		  pkg_hdr->pkg_format_ver.update,
17832ffd87d3SSergey Temerkhanov 		  pkg_hdr->pkg_format_ver.draft);
17842ffd87d3SSergey Temerkhanov 
17852ffd87d3SSergey Temerkhanov 	/* Search all package segments for the requested segment type */
17862ffd87d3SSergey Temerkhanov 	for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) {
17872ffd87d3SSergey Temerkhanov 		struct ice_generic_seg_hdr *seg;
17882ffd87d3SSergey Temerkhanov 
17892ffd87d3SSergey Temerkhanov 		seg = (struct ice_generic_seg_hdr
17902ffd87d3SSergey Temerkhanov 			       *)((u8 *)pkg_hdr +
17912ffd87d3SSergey Temerkhanov 				  le32_to_cpu(pkg_hdr->seg_offset[i]));
17922ffd87d3SSergey Temerkhanov 
17932ffd87d3SSergey Temerkhanov 		if (le32_to_cpu(seg->seg_type) == seg_type)
17942ffd87d3SSergey Temerkhanov 			return seg;
17952ffd87d3SSergey Temerkhanov 	}
17962ffd87d3SSergey Temerkhanov 
17972ffd87d3SSergey Temerkhanov 	return NULL;
17982ffd87d3SSergey Temerkhanov }
17992ffd87d3SSergey Temerkhanov 
18002ffd87d3SSergey Temerkhanov /**
18013cbdb034SDan Nowlin  * ice_has_signing_seg - determine if package has a signing segment
18023cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
18033cbdb034SDan Nowlin  * @pkg_hdr: pointer to the driver's package hdr
18043cbdb034SDan Nowlin  */
18053cbdb034SDan Nowlin static bool ice_has_signing_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
18063cbdb034SDan Nowlin {
18073cbdb034SDan Nowlin 	struct ice_generic_seg_hdr *seg_hdr;
18083cbdb034SDan Nowlin 
18093cbdb034SDan Nowlin 	seg_hdr = (struct ice_generic_seg_hdr *)
18103cbdb034SDan Nowlin 		ice_find_seg_in_pkg(hw, SEGMENT_TYPE_SIGNING, pkg_hdr);
18113cbdb034SDan Nowlin 
18123cbdb034SDan Nowlin 	return seg_hdr ? true : false;
18133cbdb034SDan Nowlin }
18143cbdb034SDan Nowlin 
18153cbdb034SDan Nowlin /**
18163cbdb034SDan Nowlin  * ice_get_pkg_segment_id - get correct package segment id, based on device
18173cbdb034SDan Nowlin  * @mac_type: MAC type of the device
18183cbdb034SDan Nowlin  */
18193cbdb034SDan Nowlin static u32 ice_get_pkg_segment_id(enum ice_mac_type mac_type)
18203cbdb034SDan Nowlin {
18213cbdb034SDan Nowlin 	u32 seg_id;
18223cbdb034SDan Nowlin 
18233cbdb034SDan Nowlin 	switch (mac_type) {
18243cbdb034SDan Nowlin 	case ICE_MAC_E830:
18253cbdb034SDan Nowlin 		seg_id = SEGMENT_TYPE_ICE_E830;
18263cbdb034SDan Nowlin 		break;
18273cbdb034SDan Nowlin 	case ICE_MAC_GENERIC:
1828372e27deSGrzegorz Nitka 	case ICE_MAC_GENERIC_3K_E825:
18293cbdb034SDan Nowlin 	default:
18303cbdb034SDan Nowlin 		seg_id = SEGMENT_TYPE_ICE_E810;
18313cbdb034SDan Nowlin 		break;
18323cbdb034SDan Nowlin 	}
18333cbdb034SDan Nowlin 
18343cbdb034SDan Nowlin 	return seg_id;
18353cbdb034SDan Nowlin }
18363cbdb034SDan Nowlin 
18373cbdb034SDan Nowlin /**
18383cbdb034SDan Nowlin  * ice_get_pkg_sign_type - get package segment sign type, based on device
18393cbdb034SDan Nowlin  * @mac_type: MAC type of the device
18403cbdb034SDan Nowlin  */
18413cbdb034SDan Nowlin static u32 ice_get_pkg_sign_type(enum ice_mac_type mac_type)
18423cbdb034SDan Nowlin {
18433cbdb034SDan Nowlin 	u32 sign_type;
18443cbdb034SDan Nowlin 
18453cbdb034SDan Nowlin 	switch (mac_type) {
18463cbdb034SDan Nowlin 	case ICE_MAC_E830:
18473cbdb034SDan Nowlin 		sign_type = SEGMENT_SIGN_TYPE_RSA3K_SBB;
18483cbdb034SDan Nowlin 		break;
1849372e27deSGrzegorz Nitka 	case ICE_MAC_GENERIC_3K_E825:
1850372e27deSGrzegorz Nitka 		sign_type = SEGMENT_SIGN_TYPE_RSA3K_E825;
1851372e27deSGrzegorz Nitka 		break;
18523cbdb034SDan Nowlin 	case ICE_MAC_GENERIC:
18533cbdb034SDan Nowlin 	default:
18543cbdb034SDan Nowlin 		sign_type = SEGMENT_SIGN_TYPE_RSA2K;
18553cbdb034SDan Nowlin 		break;
18563cbdb034SDan Nowlin 	}
18573cbdb034SDan Nowlin 
18583cbdb034SDan Nowlin 	return sign_type;
18593cbdb034SDan Nowlin }
18603cbdb034SDan Nowlin 
18613cbdb034SDan Nowlin /**
18623cbdb034SDan Nowlin  * ice_get_signing_req - get correct package requirements, based on device
18633cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
18643cbdb034SDan Nowlin  */
18653cbdb034SDan Nowlin static void ice_get_signing_req(struct ice_hw *hw)
18663cbdb034SDan Nowlin {
18673cbdb034SDan Nowlin 	hw->pkg_seg_id = ice_get_pkg_segment_id(hw->mac_type);
18683cbdb034SDan Nowlin 	hw->pkg_sign_type = ice_get_pkg_sign_type(hw->mac_type);
18693cbdb034SDan Nowlin }
18703cbdb034SDan Nowlin 
18713cbdb034SDan Nowlin /**
18722ffd87d3SSergey Temerkhanov  * ice_init_pkg_info
18732ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
18742ffd87d3SSergey Temerkhanov  * @pkg_hdr: pointer to the driver's package hdr
18752ffd87d3SSergey Temerkhanov  *
18762ffd87d3SSergey Temerkhanov  * Saves off the package details into the HW structure.
18772ffd87d3SSergey Temerkhanov  */
18782ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_init_pkg_info(struct ice_hw *hw,
18792ffd87d3SSergey Temerkhanov 					    struct ice_pkg_hdr *pkg_hdr)
18802ffd87d3SSergey Temerkhanov {
18812ffd87d3SSergey Temerkhanov 	struct ice_generic_seg_hdr *seg_hdr;
18822ffd87d3SSergey Temerkhanov 
18832ffd87d3SSergey Temerkhanov 	if (!pkg_hdr)
18842ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
18852ffd87d3SSergey Temerkhanov 
18863cbdb034SDan Nowlin 	hw->pkg_has_signing_seg = ice_has_signing_seg(hw, pkg_hdr);
18873cbdb034SDan Nowlin 	ice_get_signing_req(hw);
18883cbdb034SDan Nowlin 
18893cbdb034SDan Nowlin 	ice_debug(hw, ICE_DBG_INIT, "Pkg using segment id: 0x%08X\n",
18903cbdb034SDan Nowlin 		  hw->pkg_seg_id);
18913cbdb034SDan Nowlin 
18923cbdb034SDan Nowlin 	seg_hdr = (struct ice_generic_seg_hdr *)
18933cbdb034SDan Nowlin 		ice_find_seg_in_pkg(hw, hw->pkg_seg_id, pkg_hdr);
18942ffd87d3SSergey Temerkhanov 	if (seg_hdr) {
18952ffd87d3SSergey Temerkhanov 		struct ice_meta_sect *meta;
18962ffd87d3SSergey Temerkhanov 		struct ice_pkg_enum state;
18972ffd87d3SSergey Temerkhanov 
18982ffd87d3SSergey Temerkhanov 		memset(&state, 0, sizeof(state));
18992ffd87d3SSergey Temerkhanov 
19002ffd87d3SSergey Temerkhanov 		/* Get package information from the Metadata Section */
19012ffd87d3SSergey Temerkhanov 		meta = ice_pkg_enum_section((struct ice_seg *)seg_hdr, &state,
19022ffd87d3SSergey Temerkhanov 					    ICE_SID_METADATA);
19032ffd87d3SSergey Temerkhanov 		if (!meta) {
19042ffd87d3SSergey Temerkhanov 			ice_debug(hw, ICE_DBG_INIT,
19052ffd87d3SSergey Temerkhanov 				  "Did not find ice metadata section in package\n");
19062ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_INVALID_FILE;
19072ffd87d3SSergey Temerkhanov 		}
19082ffd87d3SSergey Temerkhanov 
19092ffd87d3SSergey Temerkhanov 		hw->pkg_ver = meta->ver;
19102ffd87d3SSergey Temerkhanov 		memcpy(hw->pkg_name, meta->name, sizeof(meta->name));
19112ffd87d3SSergey Temerkhanov 
19122ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG, "Pkg: %d.%d.%d.%d, %s\n",
19132ffd87d3SSergey Temerkhanov 			  meta->ver.major, meta->ver.minor, meta->ver.update,
19142ffd87d3SSergey Temerkhanov 			  meta->ver.draft, meta->name);
19152ffd87d3SSergey Temerkhanov 
19162ffd87d3SSergey Temerkhanov 		hw->ice_seg_fmt_ver = seg_hdr->seg_format_ver;
19172ffd87d3SSergey Temerkhanov 		memcpy(hw->ice_seg_id, seg_hdr->seg_id, sizeof(hw->ice_seg_id));
19182ffd87d3SSergey Temerkhanov 
19192ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n",
19202ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.major,
19212ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.minor,
19222ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.update,
19232ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.draft, seg_hdr->seg_id);
19242ffd87d3SSergey Temerkhanov 	} else {
19252ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT,
19262ffd87d3SSergey Temerkhanov 			  "Did not find ice segment in driver package\n");
19272ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
19282ffd87d3SSergey Temerkhanov 	}
19292ffd87d3SSergey Temerkhanov 
19302ffd87d3SSergey Temerkhanov 	return ICE_DDP_PKG_SUCCESS;
19312ffd87d3SSergey Temerkhanov }
19322ffd87d3SSergey Temerkhanov 
19332ffd87d3SSergey Temerkhanov /**
19342ffd87d3SSergey Temerkhanov  * ice_get_pkg_info
19352ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
19362ffd87d3SSergey Temerkhanov  *
19372ffd87d3SSergey Temerkhanov  * Store details of the package currently loaded in HW into the HW structure.
19382ffd87d3SSergey Temerkhanov  */
19392ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw)
19402ffd87d3SSergey Temerkhanov {
1941d8e45f29SKees Cook 	DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg_info, pkg_info,
1942230064baSPrzemek Kitszel 			ICE_PKG_CNT);
1943230064baSPrzemek Kitszel 	u16 size = __struct_size(pkg_info);
19442ffd87d3SSergey Temerkhanov 	u32 i;
19452ffd87d3SSergey Temerkhanov 
1946230064baSPrzemek Kitszel 	if (ice_aq_get_pkg_info_list(hw, pkg_info, size, NULL))
19472ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
19482ffd87d3SSergey Temerkhanov 
19492ffd87d3SSergey Temerkhanov 	for (i = 0; i < le32_to_cpu(pkg_info->count); i++) {
19502ffd87d3SSergey Temerkhanov #define ICE_PKG_FLAG_COUNT 4
19512ffd87d3SSergey Temerkhanov 		char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 };
19522ffd87d3SSergey Temerkhanov 		u8 place = 0;
19532ffd87d3SSergey Temerkhanov 
19542ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_active) {
19552ffd87d3SSergey Temerkhanov 			flags[place++] = 'A';
19562ffd87d3SSergey Temerkhanov 			hw->active_pkg_ver = pkg_info->pkg_info[i].ver;
19572ffd87d3SSergey Temerkhanov 			hw->active_track_id =
19582ffd87d3SSergey Temerkhanov 				le32_to_cpu(pkg_info->pkg_info[i].track_id);
19592ffd87d3SSergey Temerkhanov 			memcpy(hw->active_pkg_name, pkg_info->pkg_info[i].name,
19602ffd87d3SSergey Temerkhanov 			       sizeof(pkg_info->pkg_info[i].name));
19612ffd87d3SSergey Temerkhanov 			hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm;
19622ffd87d3SSergey Temerkhanov 		}
19632ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_active_at_boot)
19642ffd87d3SSergey Temerkhanov 			flags[place++] = 'B';
19652ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_modified)
19662ffd87d3SSergey Temerkhanov 			flags[place++] = 'M';
19672ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_in_nvm)
19682ffd87d3SSergey Temerkhanov 			flags[place++] = 'N';
19692ffd87d3SSergey Temerkhanov 
19702ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG, "Pkg[%d]: %d.%d.%d.%d,%s,%s\n", i,
19712ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.major,
19722ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.minor,
19732ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.update,
19742ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.draft,
19752ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].name, flags);
19762ffd87d3SSergey Temerkhanov 	}
19772ffd87d3SSergey Temerkhanov 
1978230064baSPrzemek Kitszel 	return ICE_DDP_PKG_SUCCESS;
19792ffd87d3SSergey Temerkhanov }
19802ffd87d3SSergey Temerkhanov 
19812ffd87d3SSergey Temerkhanov /**
19822ffd87d3SSergey Temerkhanov  * ice_chk_pkg_compat
19832ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
19842ffd87d3SSergey Temerkhanov  * @ospkg: pointer to the package hdr
19852ffd87d3SSergey Temerkhanov  * @seg: pointer to the package segment hdr
19862ffd87d3SSergey Temerkhanov  *
19872ffd87d3SSergey Temerkhanov  * This function checks the package version compatibility with driver and NVM
19882ffd87d3SSergey Temerkhanov  */
19892ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_compat(struct ice_hw *hw,
19902ffd87d3SSergey Temerkhanov 					     struct ice_pkg_hdr *ospkg,
19912ffd87d3SSergey Temerkhanov 					     struct ice_seg **seg)
19922ffd87d3SSergey Temerkhanov {
1993d8e45f29SKees Cook 	DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg, pkg_info,
1994230064baSPrzemek Kitszel 			ICE_PKG_CNT);
1995230064baSPrzemek Kitszel 	u16 size = __struct_size(pkg);
19962ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state;
19972ffd87d3SSergey Temerkhanov 	u32 i;
19982ffd87d3SSergey Temerkhanov 
19992ffd87d3SSergey Temerkhanov 	/* Check package version compatibility */
20002ffd87d3SSergey Temerkhanov 	state = ice_chk_pkg_version(&hw->pkg_ver);
20012ffd87d3SSergey Temerkhanov 	if (state) {
20022ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n");
20032ffd87d3SSergey Temerkhanov 		return state;
20042ffd87d3SSergey Temerkhanov 	}
20052ffd87d3SSergey Temerkhanov 
20062ffd87d3SSergey Temerkhanov 	/* find ICE segment in given package */
20073cbdb034SDan Nowlin 	*seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, hw->pkg_seg_id,
20082ffd87d3SSergey Temerkhanov 						     ospkg);
20092ffd87d3SSergey Temerkhanov 	if (!*seg) {
20102ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n");
20112ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
20122ffd87d3SSergey Temerkhanov 	}
20132ffd87d3SSergey Temerkhanov 
20142ffd87d3SSergey Temerkhanov 	/* Check if FW is compatible with the OS package */
2015230064baSPrzemek Kitszel 	if (ice_aq_get_pkg_info_list(hw, pkg, size, NULL))
2016230064baSPrzemek Kitszel 		return ICE_DDP_PKG_LOAD_ERROR;
20172ffd87d3SSergey Temerkhanov 
20182ffd87d3SSergey Temerkhanov 	for (i = 0; i < le32_to_cpu(pkg->count); i++) {
20192ffd87d3SSergey Temerkhanov 		/* loop till we find the NVM package */
20202ffd87d3SSergey Temerkhanov 		if (!pkg->pkg_info[i].is_in_nvm)
20212ffd87d3SSergey Temerkhanov 			continue;
20222ffd87d3SSergey Temerkhanov 		if ((*seg)->hdr.seg_format_ver.major !=
20232ffd87d3SSergey Temerkhanov 			    pkg->pkg_info[i].ver.major ||
20242ffd87d3SSergey Temerkhanov 		    (*seg)->hdr.seg_format_ver.minor >
20252ffd87d3SSergey Temerkhanov 			    pkg->pkg_info[i].ver.minor) {
20262ffd87d3SSergey Temerkhanov 			state = ICE_DDP_PKG_FW_MISMATCH;
20272ffd87d3SSergey Temerkhanov 			ice_debug(hw, ICE_DBG_INIT,
20282ffd87d3SSergey Temerkhanov 				  "OS package is not compatible with NVM.\n");
20292ffd87d3SSergey Temerkhanov 		}
20302ffd87d3SSergey Temerkhanov 		/* done processing NVM package so break */
20312ffd87d3SSergey Temerkhanov 		break;
20322ffd87d3SSergey Temerkhanov 	}
2033230064baSPrzemek Kitszel 
20342ffd87d3SSergey Temerkhanov 	return state;
20352ffd87d3SSergey Temerkhanov }
20362ffd87d3SSergey Temerkhanov 
20372ffd87d3SSergey Temerkhanov /**
20382ffd87d3SSergey Temerkhanov  * ice_init_pkg_hints
20392ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
20402ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the segment of the package scan (non-NULL)
20412ffd87d3SSergey Temerkhanov  *
20422ffd87d3SSergey Temerkhanov  * This function will scan the package and save off relevant information
20432ffd87d3SSergey Temerkhanov  * (hints or metadata) for driver use. The ice_seg parameter must not be NULL
20442ffd87d3SSergey Temerkhanov  * since the first call to ice_enum_labels requires a pointer to an actual
20452ffd87d3SSergey Temerkhanov  * ice_seg structure.
20462ffd87d3SSergey Temerkhanov  */
20472ffd87d3SSergey Temerkhanov static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg)
20482ffd87d3SSergey Temerkhanov {
20492ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
20502ffd87d3SSergey Temerkhanov 	char *label_name;
20512ffd87d3SSergey Temerkhanov 	u16 val;
20522ffd87d3SSergey Temerkhanov 	int i;
20532ffd87d3SSergey Temerkhanov 
20542ffd87d3SSergey Temerkhanov 	memset(&hw->tnl, 0, sizeof(hw->tnl));
20552ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
20562ffd87d3SSergey Temerkhanov 
20572ffd87d3SSergey Temerkhanov 	if (!ice_seg)
20582ffd87d3SSergey Temerkhanov 		return;
20592ffd87d3SSergey Temerkhanov 
20602ffd87d3SSergey Temerkhanov 	label_name = ice_enum_labels(ice_seg, ICE_SID_LBL_RXPARSER_TMEM, &state,
20612ffd87d3SSergey Temerkhanov 				     &val);
20622ffd87d3SSergey Temerkhanov 
20632ffd87d3SSergey Temerkhanov 	while (label_name) {
20642ffd87d3SSergey Temerkhanov 		if (!strncmp(label_name, ICE_TNL_PRE, strlen(ICE_TNL_PRE)))
20652ffd87d3SSergey Temerkhanov 			/* check for a tunnel entry */
20662ffd87d3SSergey Temerkhanov 			ice_add_tunnel_hint(hw, label_name, val);
20672ffd87d3SSergey Temerkhanov 
20682ffd87d3SSergey Temerkhanov 		/* check for a dvm mode entry */
20692ffd87d3SSergey Temerkhanov 		else if (!strncmp(label_name, ICE_DVM_PRE, strlen(ICE_DVM_PRE)))
20702ffd87d3SSergey Temerkhanov 			ice_add_dvm_hint(hw, val, true);
20712ffd87d3SSergey Temerkhanov 
20722ffd87d3SSergey Temerkhanov 		/* check for a svm mode entry */
20732ffd87d3SSergey Temerkhanov 		else if (!strncmp(label_name, ICE_SVM_PRE, strlen(ICE_SVM_PRE)))
20742ffd87d3SSergey Temerkhanov 			ice_add_dvm_hint(hw, val, false);
20752ffd87d3SSergey Temerkhanov 
20762ffd87d3SSergey Temerkhanov 		label_name = ice_enum_labels(NULL, 0, &state, &val);
20772ffd87d3SSergey Temerkhanov 	}
20782ffd87d3SSergey Temerkhanov 
20792ffd87d3SSergey Temerkhanov 	/* Cache the appropriate boost TCAM entry pointers for tunnels */
20802ffd87d3SSergey Temerkhanov 	for (i = 0; i < hw->tnl.count; i++) {
20812ffd87d3SSergey Temerkhanov 		ice_find_boost_entry(ice_seg, hw->tnl.tbl[i].boost_addr,
20822ffd87d3SSergey Temerkhanov 				     &hw->tnl.tbl[i].boost_entry);
20832ffd87d3SSergey Temerkhanov 		if (hw->tnl.tbl[i].boost_entry) {
20842ffd87d3SSergey Temerkhanov 			hw->tnl.tbl[i].valid = true;
20852ffd87d3SSergey Temerkhanov 			if (hw->tnl.tbl[i].type < __TNL_TYPE_CNT)
20862ffd87d3SSergey Temerkhanov 				hw->tnl.valid_count[hw->tnl.tbl[i].type]++;
20872ffd87d3SSergey Temerkhanov 		}
20882ffd87d3SSergey Temerkhanov 	}
20892ffd87d3SSergey Temerkhanov 
20902ffd87d3SSergey Temerkhanov 	/* Cache the appropriate boost TCAM entry pointers for DVM and SVM */
20912ffd87d3SSergey Temerkhanov 	for (i = 0; i < hw->dvm_upd.count; i++)
20922ffd87d3SSergey Temerkhanov 		ice_find_boost_entry(ice_seg, hw->dvm_upd.tbl[i].boost_addr,
20932ffd87d3SSergey Temerkhanov 				     &hw->dvm_upd.tbl[i].boost_entry);
20942ffd87d3SSergey Temerkhanov }
20952ffd87d3SSergey Temerkhanov 
20962ffd87d3SSergey Temerkhanov /**
20972ffd87d3SSergey Temerkhanov  * ice_fill_hw_ptype - fill the enabled PTYPE bit information
20982ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
20992ffd87d3SSergey Temerkhanov  */
21002ffd87d3SSergey Temerkhanov static void ice_fill_hw_ptype(struct ice_hw *hw)
21012ffd87d3SSergey Temerkhanov {
21022ffd87d3SSergey Temerkhanov 	struct ice_marker_ptype_tcam_entry *tcam;
21032ffd87d3SSergey Temerkhanov 	struct ice_seg *seg = hw->seg;
21042ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
21052ffd87d3SSergey Temerkhanov 
21062ffd87d3SSergey Temerkhanov 	bitmap_zero(hw->hw_ptype, ICE_FLOW_PTYPE_MAX);
21072ffd87d3SSergey Temerkhanov 	if (!seg)
21082ffd87d3SSergey Temerkhanov 		return;
21092ffd87d3SSergey Temerkhanov 
21102ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
21112ffd87d3SSergey Temerkhanov 
21122ffd87d3SSergey Temerkhanov 	do {
21132ffd87d3SSergey Temerkhanov 		tcam = ice_pkg_enum_entry(seg, &state,
21142ffd87d3SSergey Temerkhanov 					  ICE_SID_RXPARSER_MARKER_PTYPE, NULL,
21152ffd87d3SSergey Temerkhanov 					  ice_marker_ptype_tcam_handler);
21162ffd87d3SSergey Temerkhanov 		if (tcam &&
21172ffd87d3SSergey Temerkhanov 		    le16_to_cpu(tcam->addr) < ICE_MARKER_PTYPE_TCAM_ADDR_MAX &&
21182ffd87d3SSergey Temerkhanov 		    le16_to_cpu(tcam->ptype) < ICE_FLOW_PTYPE_MAX)
21192ffd87d3SSergey Temerkhanov 			set_bit(le16_to_cpu(tcam->ptype), hw->hw_ptype);
21202ffd87d3SSergey Temerkhanov 
21212ffd87d3SSergey Temerkhanov 		seg = NULL;
21222ffd87d3SSergey Temerkhanov 	} while (tcam);
21232ffd87d3SSergey Temerkhanov }
21242ffd87d3SSergey Temerkhanov 
21252ffd87d3SSergey Temerkhanov /**
21262ffd87d3SSergey Temerkhanov  * ice_init_pkg - initialize/download package
21272ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
21282ffd87d3SSergey Temerkhanov  * @buf: pointer to the package buffer
21292ffd87d3SSergey Temerkhanov  * @len: size of the package buffer
21302ffd87d3SSergey Temerkhanov  *
21312ffd87d3SSergey Temerkhanov  * This function initializes a package. The package contains HW tables
21322ffd87d3SSergey Temerkhanov  * required to do packet processing. First, the function extracts package
21332ffd87d3SSergey Temerkhanov  * information such as version. Then it finds the ice configuration segment
21342ffd87d3SSergey Temerkhanov  * within the package; this function then saves a copy of the segment pointer
21352ffd87d3SSergey Temerkhanov  * within the supplied package buffer. Next, the function will cache any hints
21362ffd87d3SSergey Temerkhanov  * from the package, followed by downloading the package itself. Note, that if
21372ffd87d3SSergey Temerkhanov  * a previous PF driver has already downloaded the package successfully, then
21382ffd87d3SSergey Temerkhanov  * the current driver will not have to download the package again.
21392ffd87d3SSergey Temerkhanov  *
21402ffd87d3SSergey Temerkhanov  * The local package contents will be used to query default behavior and to
21412ffd87d3SSergey Temerkhanov  * update specific sections of the HW's version of the package (e.g. to update
21422ffd87d3SSergey Temerkhanov  * the parse graph to understand new protocols).
21432ffd87d3SSergey Temerkhanov  *
21442ffd87d3SSergey Temerkhanov  * This function stores a pointer to the package buffer memory, and it is
21452ffd87d3SSergey Temerkhanov  * expected that the supplied buffer will not be freed immediately. If the
21462ffd87d3SSergey Temerkhanov  * package buffer needs to be freed, such as when read from a file, use
21472ffd87d3SSergey Temerkhanov  * ice_copy_and_init_pkg() instead of directly calling ice_init_pkg() in this
21482ffd87d3SSergey Temerkhanov  * case.
21492ffd87d3SSergey Temerkhanov  */
21502ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len)
21512ffd87d3SSergey Temerkhanov {
21522ffd87d3SSergey Temerkhanov 	bool already_loaded = false;
21532ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state;
21542ffd87d3SSergey Temerkhanov 	struct ice_pkg_hdr *pkg;
21552ffd87d3SSergey Temerkhanov 	struct ice_seg *seg;
21562ffd87d3SSergey Temerkhanov 
21572ffd87d3SSergey Temerkhanov 	if (!buf || !len)
21582ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
21592ffd87d3SSergey Temerkhanov 
21602ffd87d3SSergey Temerkhanov 	pkg = (struct ice_pkg_hdr *)buf;
21612ffd87d3SSergey Temerkhanov 	state = ice_verify_pkg(pkg, len);
21622ffd87d3SSergey Temerkhanov 	if (state) {
21632ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n",
21642ffd87d3SSergey Temerkhanov 			  state);
21652ffd87d3SSergey Temerkhanov 		return state;
21662ffd87d3SSergey Temerkhanov 	}
21672ffd87d3SSergey Temerkhanov 
21682ffd87d3SSergey Temerkhanov 	/* initialize package info */
21692ffd87d3SSergey Temerkhanov 	state = ice_init_pkg_info(hw, pkg);
21702ffd87d3SSergey Temerkhanov 	if (state)
21712ffd87d3SSergey Temerkhanov 		return state;
21722ffd87d3SSergey Temerkhanov 
21733cbdb034SDan Nowlin 	/* must be a matching segment */
21743cbdb034SDan Nowlin 	if (hw->pkg_has_signing_seg &&
21753cbdb034SDan Nowlin 	    !ice_match_signing_seg(pkg, hw->pkg_seg_id, hw->pkg_sign_type))
21763cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
21773cbdb034SDan Nowlin 
21782ffd87d3SSergey Temerkhanov 	/* before downloading the package, check package version for
21792ffd87d3SSergey Temerkhanov 	 * compatibility with driver
21802ffd87d3SSergey Temerkhanov 	 */
21812ffd87d3SSergey Temerkhanov 	state = ice_chk_pkg_compat(hw, pkg, &seg);
21822ffd87d3SSergey Temerkhanov 	if (state)
21832ffd87d3SSergey Temerkhanov 		return state;
21842ffd87d3SSergey Temerkhanov 
21852ffd87d3SSergey Temerkhanov 	/* initialize package hints and then download package */
21862ffd87d3SSergey Temerkhanov 	ice_init_pkg_hints(hw, seg);
2187a778616eSDan Nowlin 	state = ice_download_pkg(hw, pkg, seg);
21882ffd87d3SSergey Temerkhanov 	if (state == ICE_DDP_PKG_ALREADY_LOADED) {
21892ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT,
21902ffd87d3SSergey Temerkhanov 			  "package previously loaded - no work.\n");
21912ffd87d3SSergey Temerkhanov 		already_loaded = true;
21922ffd87d3SSergey Temerkhanov 	}
21932ffd87d3SSergey Temerkhanov 
21942ffd87d3SSergey Temerkhanov 	/* Get information on the package currently loaded in HW, then make sure
21952ffd87d3SSergey Temerkhanov 	 * the driver is compatible with this version.
21962ffd87d3SSergey Temerkhanov 	 */
21972ffd87d3SSergey Temerkhanov 	if (!state || state == ICE_DDP_PKG_ALREADY_LOADED) {
21982ffd87d3SSergey Temerkhanov 		state = ice_get_pkg_info(hw);
21992ffd87d3SSergey Temerkhanov 		if (!state)
22002ffd87d3SSergey Temerkhanov 			state = ice_get_ddp_pkg_state(hw, already_loaded);
22012ffd87d3SSergey Temerkhanov 	}
22022ffd87d3SSergey Temerkhanov 
22032ffd87d3SSergey Temerkhanov 	if (ice_is_init_pkg_successful(state)) {
22042ffd87d3SSergey Temerkhanov 		hw->seg = seg;
22052ffd87d3SSergey Temerkhanov 		/* on successful package download update other required
22062ffd87d3SSergey Temerkhanov 		 * registers to support the package and fill HW tables
22072ffd87d3SSergey Temerkhanov 		 * with package content.
22082ffd87d3SSergey Temerkhanov 		 */
22092ffd87d3SSergey Temerkhanov 		ice_init_pkg_regs(hw);
22102ffd87d3SSergey Temerkhanov 		ice_fill_blk_tbls(hw);
22112ffd87d3SSergey Temerkhanov 		ice_fill_hw_ptype(hw);
22122ffd87d3SSergey Temerkhanov 		ice_get_prof_index_max(hw);
22132ffd87d3SSergey Temerkhanov 	} else {
22142ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n", state);
22152ffd87d3SSergey Temerkhanov 	}
22162ffd87d3SSergey Temerkhanov 
22172ffd87d3SSergey Temerkhanov 	return state;
22182ffd87d3SSergey Temerkhanov }
22192ffd87d3SSergey Temerkhanov 
22202ffd87d3SSergey Temerkhanov /**
22212ffd87d3SSergey Temerkhanov  * ice_copy_and_init_pkg - initialize/download a copy of the package
22222ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
22232ffd87d3SSergey Temerkhanov  * @buf: pointer to the package buffer
22242ffd87d3SSergey Temerkhanov  * @len: size of the package buffer
22252ffd87d3SSergey Temerkhanov  *
22262ffd87d3SSergey Temerkhanov  * This function copies the package buffer, and then calls ice_init_pkg() to
22272ffd87d3SSergey Temerkhanov  * initialize the copied package contents.
22282ffd87d3SSergey Temerkhanov  *
22292ffd87d3SSergey Temerkhanov  * The copying is necessary if the package buffer supplied is constant, or if
22302ffd87d3SSergey Temerkhanov  * the memory may disappear shortly after calling this function.
22312ffd87d3SSergey Temerkhanov  *
22322ffd87d3SSergey Temerkhanov  * If the package buffer resides in the data segment and can be modified, the
22332ffd87d3SSergey Temerkhanov  * caller is free to use ice_init_pkg() instead of ice_copy_and_init_pkg().
22342ffd87d3SSergey Temerkhanov  *
22352ffd87d3SSergey Temerkhanov  * However, if the package buffer needs to be copied first, such as when being
22362ffd87d3SSergey Temerkhanov  * read from a file, the caller should use ice_copy_and_init_pkg().
22372ffd87d3SSergey Temerkhanov  *
22382ffd87d3SSergey Temerkhanov  * This function will first copy the package buffer, before calling
22392ffd87d3SSergey Temerkhanov  * ice_init_pkg(). The caller is free to immediately destroy the original
22402ffd87d3SSergey Temerkhanov  * package buffer, as the new copy will be managed by this function and
22412ffd87d3SSergey Temerkhanov  * related routines.
22422ffd87d3SSergey Temerkhanov  */
22432ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf,
22442ffd87d3SSergey Temerkhanov 					 u32 len)
22452ffd87d3SSergey Temerkhanov {
22462ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state;
22472ffd87d3SSergey Temerkhanov 	u8 *buf_copy;
22482ffd87d3SSergey Temerkhanov 
22492ffd87d3SSergey Temerkhanov 	if (!buf || !len)
22502ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
22512ffd87d3SSergey Temerkhanov 
22522ffd87d3SSergey Temerkhanov 	buf_copy = devm_kmemdup(ice_hw_to_dev(hw), buf, len, GFP_KERNEL);
22532ffd87d3SSergey Temerkhanov 
22542ffd87d3SSergey Temerkhanov 	state = ice_init_pkg(hw, buf_copy, len);
22552ffd87d3SSergey Temerkhanov 	if (!ice_is_init_pkg_successful(state)) {
22562ffd87d3SSergey Temerkhanov 		/* Free the copy, since we failed to initialize the package */
22572ffd87d3SSergey Temerkhanov 		devm_kfree(ice_hw_to_dev(hw), buf_copy);
22582ffd87d3SSergey Temerkhanov 	} else {
22592ffd87d3SSergey Temerkhanov 		/* Track the copied pkg so we can free it later */
22602ffd87d3SSergey Temerkhanov 		hw->pkg_copy = buf_copy;
22612ffd87d3SSergey Temerkhanov 		hw->pkg_size = len;
22622ffd87d3SSergey Temerkhanov 	}
22632ffd87d3SSergey Temerkhanov 
22642ffd87d3SSergey Temerkhanov 	return state;
22652ffd87d3SSergey Temerkhanov }
2266