xref: /linux/drivers/net/ethernet/intel/ice/ice_ddp.c (revision 75b4a938a947785cdda8908cb700c58e95f8ff69)
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"
791427e6dSRaj Victor #include "ice_sched.h"
82ffd87d3SSergey Temerkhanov 
92ffd87d3SSergey Temerkhanov /* For supporting double VLAN mode, it is necessary to enable or disable certain
102ffd87d3SSergey Temerkhanov  * boost tcam entries. The metadata labels names that match the following
112ffd87d3SSergey Temerkhanov  * prefixes will be saved to allow enabling double VLAN mode.
122ffd87d3SSergey Temerkhanov  */
132ffd87d3SSergey Temerkhanov #define ICE_DVM_PRE "BOOST_MAC_VLAN_DVM" /* enable these entries */
142ffd87d3SSergey Temerkhanov #define ICE_SVM_PRE "BOOST_MAC_VLAN_SVM" /* disable these entries */
152ffd87d3SSergey Temerkhanov 
162ffd87d3SSergey Temerkhanov /* To support tunneling entries by PF, the package will append the PF number to
172ffd87d3SSergey Temerkhanov  * the label; for example TNL_VXLAN_PF0, TNL_VXLAN_PF1, TNL_VXLAN_PF2, etc.
182ffd87d3SSergey Temerkhanov  */
192ffd87d3SSergey Temerkhanov #define ICE_TNL_PRE "TNL_"
202ffd87d3SSergey Temerkhanov static const struct ice_tunnel_type_scan tnls[] = {
212ffd87d3SSergey Temerkhanov 	{ TNL_VXLAN, "TNL_VXLAN_PF" },
222ffd87d3SSergey Temerkhanov 	{ TNL_GENEVE, "TNL_GENEVE_PF" },
232ffd87d3SSergey Temerkhanov 	{ TNL_LAST, "" }
242ffd87d3SSergey Temerkhanov };
252ffd87d3SSergey Temerkhanov 
262ffd87d3SSergey Temerkhanov /**
272ffd87d3SSergey Temerkhanov  * ice_verify_pkg - verify package
282ffd87d3SSergey Temerkhanov  * @pkg: pointer to the package buffer
292ffd87d3SSergey Temerkhanov  * @len: size of the package buffer
302ffd87d3SSergey Temerkhanov  *
312ffd87d3SSergey Temerkhanov  * Verifies various attributes of the package file, including length, format
322ffd87d3SSergey Temerkhanov  * version, and the requirement of at least one segment.
332ffd87d3SSergey Temerkhanov  */
34708b352fSJan Sokolowski static enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
352ffd87d3SSergey Temerkhanov {
362ffd87d3SSergey Temerkhanov 	u32 seg_count;
372ffd87d3SSergey Temerkhanov 	u32 i;
382ffd87d3SSergey Temerkhanov 
392ffd87d3SSergey Temerkhanov 	if (len < struct_size(pkg, seg_offset, 1))
402ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
412ffd87d3SSergey Temerkhanov 
422ffd87d3SSergey Temerkhanov 	if (pkg->pkg_format_ver.major != ICE_PKG_FMT_VER_MAJ ||
432ffd87d3SSergey Temerkhanov 	    pkg->pkg_format_ver.minor != ICE_PKG_FMT_VER_MNR ||
442ffd87d3SSergey Temerkhanov 	    pkg->pkg_format_ver.update != ICE_PKG_FMT_VER_UPD ||
452ffd87d3SSergey Temerkhanov 	    pkg->pkg_format_ver.draft != ICE_PKG_FMT_VER_DFT)
462ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
472ffd87d3SSergey Temerkhanov 
482ffd87d3SSergey Temerkhanov 	/* pkg must have at least one segment */
492ffd87d3SSergey Temerkhanov 	seg_count = le32_to_cpu(pkg->seg_count);
502ffd87d3SSergey Temerkhanov 	if (seg_count < 1)
512ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
522ffd87d3SSergey Temerkhanov 
532ffd87d3SSergey Temerkhanov 	/* make sure segment array fits in package length */
542ffd87d3SSergey Temerkhanov 	if (len < struct_size(pkg, seg_offset, seg_count))
552ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
562ffd87d3SSergey Temerkhanov 
572ffd87d3SSergey Temerkhanov 	/* all segments must fit within length */
582ffd87d3SSergey Temerkhanov 	for (i = 0; i < seg_count; i++) {
592ffd87d3SSergey Temerkhanov 		u32 off = le32_to_cpu(pkg->seg_offset[i]);
602ffd87d3SSergey Temerkhanov 		struct ice_generic_seg_hdr *seg;
612ffd87d3SSergey Temerkhanov 
622ffd87d3SSergey Temerkhanov 		/* segment header must fit */
632ffd87d3SSergey Temerkhanov 		if (len < off + sizeof(*seg))
642ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_INVALID_FILE;
652ffd87d3SSergey Temerkhanov 
662ffd87d3SSergey Temerkhanov 		seg = (struct ice_generic_seg_hdr *)((u8 *)pkg + off);
672ffd87d3SSergey Temerkhanov 
682ffd87d3SSergey Temerkhanov 		/* segment body must fit */
692ffd87d3SSergey Temerkhanov 		if (len < off + le32_to_cpu(seg->seg_size))
702ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_INVALID_FILE;
712ffd87d3SSergey Temerkhanov 	}
722ffd87d3SSergey Temerkhanov 
732ffd87d3SSergey Temerkhanov 	return ICE_DDP_PKG_SUCCESS;
742ffd87d3SSergey Temerkhanov }
752ffd87d3SSergey Temerkhanov 
762ffd87d3SSergey Temerkhanov /**
772ffd87d3SSergey Temerkhanov  * ice_free_seg - free package segment pointer
782ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
792ffd87d3SSergey Temerkhanov  *
802ffd87d3SSergey Temerkhanov  * Frees the package segment pointer in the proper manner, depending on if the
812ffd87d3SSergey Temerkhanov  * segment was allocated or just the passed in pointer was stored.
822ffd87d3SSergey Temerkhanov  */
832ffd87d3SSergey Temerkhanov void ice_free_seg(struct ice_hw *hw)
842ffd87d3SSergey Temerkhanov {
852ffd87d3SSergey Temerkhanov 	if (hw->pkg_copy) {
862ffd87d3SSergey Temerkhanov 		devm_kfree(ice_hw_to_dev(hw), hw->pkg_copy);
872ffd87d3SSergey Temerkhanov 		hw->pkg_copy = NULL;
882ffd87d3SSergey Temerkhanov 		hw->pkg_size = 0;
892ffd87d3SSergey Temerkhanov 	}
902ffd87d3SSergey Temerkhanov 	hw->seg = NULL;
912ffd87d3SSergey Temerkhanov }
922ffd87d3SSergey Temerkhanov 
932ffd87d3SSergey Temerkhanov /**
942ffd87d3SSergey Temerkhanov  * ice_chk_pkg_version - check package version for compatibility with driver
952ffd87d3SSergey Temerkhanov  * @pkg_ver: pointer to a version structure to check
962ffd87d3SSergey Temerkhanov  *
972ffd87d3SSergey Temerkhanov  * Check to make sure that the package about to be downloaded is compatible with
982ffd87d3SSergey Temerkhanov  * the driver. To be compatible, the major and minor components of the package
992ffd87d3SSergey Temerkhanov  * version must match our ICE_PKG_SUPP_VER_MAJ and ICE_PKG_SUPP_VER_MNR
1002ffd87d3SSergey Temerkhanov  * definitions.
1012ffd87d3SSergey Temerkhanov  */
1022ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver)
1032ffd87d3SSergey Temerkhanov {
1042ffd87d3SSergey Temerkhanov 	if (pkg_ver->major > ICE_PKG_SUPP_VER_MAJ ||
1052ffd87d3SSergey Temerkhanov 	    (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ &&
1062ffd87d3SSergey Temerkhanov 	     pkg_ver->minor > ICE_PKG_SUPP_VER_MNR))
1072ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_FILE_VERSION_TOO_HIGH;
1082ffd87d3SSergey Temerkhanov 	else if (pkg_ver->major < ICE_PKG_SUPP_VER_MAJ ||
1092ffd87d3SSergey Temerkhanov 		 (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ &&
1102ffd87d3SSergey Temerkhanov 		  pkg_ver->minor < ICE_PKG_SUPP_VER_MNR))
1112ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_FILE_VERSION_TOO_LOW;
1122ffd87d3SSergey Temerkhanov 
1132ffd87d3SSergey Temerkhanov 	return ICE_DDP_PKG_SUCCESS;
1142ffd87d3SSergey Temerkhanov }
1152ffd87d3SSergey Temerkhanov 
1162ffd87d3SSergey Temerkhanov /**
1172ffd87d3SSergey Temerkhanov  * ice_pkg_val_buf
1182ffd87d3SSergey Temerkhanov  * @buf: pointer to the ice buffer
1192ffd87d3SSergey Temerkhanov  *
1202ffd87d3SSergey Temerkhanov  * This helper function validates a buffer's header.
1212ffd87d3SSergey Temerkhanov  */
122708b352fSJan Sokolowski static struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf)
1232ffd87d3SSergey Temerkhanov {
1242ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *hdr;
1252ffd87d3SSergey Temerkhanov 	u16 section_count;
1262ffd87d3SSergey Temerkhanov 	u16 data_end;
1272ffd87d3SSergey Temerkhanov 
1282ffd87d3SSergey Temerkhanov 	hdr = (struct ice_buf_hdr *)buf->buf;
1292ffd87d3SSergey Temerkhanov 	/* verify data */
1302ffd87d3SSergey Temerkhanov 	section_count = le16_to_cpu(hdr->section_count);
1312ffd87d3SSergey Temerkhanov 	if (section_count < ICE_MIN_S_COUNT || section_count > ICE_MAX_S_COUNT)
1322ffd87d3SSergey Temerkhanov 		return NULL;
1332ffd87d3SSergey Temerkhanov 
1342ffd87d3SSergey Temerkhanov 	data_end = le16_to_cpu(hdr->data_end);
1352ffd87d3SSergey Temerkhanov 	if (data_end < ICE_MIN_S_DATA_END || data_end > ICE_MAX_S_DATA_END)
1362ffd87d3SSergey Temerkhanov 		return NULL;
1372ffd87d3SSergey Temerkhanov 
1382ffd87d3SSergey Temerkhanov 	return hdr;
1392ffd87d3SSergey Temerkhanov }
1402ffd87d3SSergey Temerkhanov 
1412ffd87d3SSergey Temerkhanov /**
1422ffd87d3SSergey Temerkhanov  * ice_find_buf_table
1432ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment
1442ffd87d3SSergey Temerkhanov  *
1452ffd87d3SSergey Temerkhanov  * Returns the address of the buffer table within the ice segment.
1462ffd87d3SSergey Temerkhanov  */
1472ffd87d3SSergey Temerkhanov static struct ice_buf_table *ice_find_buf_table(struct ice_seg *ice_seg)
1482ffd87d3SSergey Temerkhanov {
1492ffd87d3SSergey Temerkhanov 	struct ice_nvm_table *nvms = (struct ice_nvm_table *)
1502ffd87d3SSergey Temerkhanov 		(ice_seg->device_table + le32_to_cpu(ice_seg->device_table_count));
1512ffd87d3SSergey Temerkhanov 
1522ffd87d3SSergey Temerkhanov 	return (__force struct ice_buf_table *)(nvms->vers +
1532ffd87d3SSergey Temerkhanov 						le32_to_cpu(nvms->table_count));
1542ffd87d3SSergey Temerkhanov }
1552ffd87d3SSergey Temerkhanov 
1562ffd87d3SSergey Temerkhanov /**
1572ffd87d3SSergey Temerkhanov  * ice_pkg_enum_buf
1582ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
1592ffd87d3SSergey Temerkhanov  * @state: pointer to the enum state
1602ffd87d3SSergey Temerkhanov  *
1612ffd87d3SSergey Temerkhanov  * This function will enumerate all the buffers in the ice segment. The first
1622ffd87d3SSergey Temerkhanov  * call is made with the ice_seg parameter non-NULL; on subsequent calls,
1632ffd87d3SSergey Temerkhanov  * ice_seg is set to NULL which continues the enumeration. When the function
1642ffd87d3SSergey Temerkhanov  * returns a NULL pointer, then the end of the buffers has been reached, or an
1652ffd87d3SSergey Temerkhanov  * unexpected value has been detected (for example an invalid section count or
1662ffd87d3SSergey Temerkhanov  * an invalid buffer end value).
1672ffd87d3SSergey Temerkhanov  */
1682ffd87d3SSergey Temerkhanov static struct ice_buf_hdr *ice_pkg_enum_buf(struct ice_seg *ice_seg,
1692ffd87d3SSergey Temerkhanov 					    struct ice_pkg_enum *state)
1702ffd87d3SSergey Temerkhanov {
1712ffd87d3SSergey Temerkhanov 	if (ice_seg) {
1722ffd87d3SSergey Temerkhanov 		state->buf_table = ice_find_buf_table(ice_seg);
1732ffd87d3SSergey Temerkhanov 		if (!state->buf_table)
1742ffd87d3SSergey Temerkhanov 			return NULL;
1752ffd87d3SSergey Temerkhanov 
1762ffd87d3SSergey Temerkhanov 		state->buf_idx = 0;
1772ffd87d3SSergey Temerkhanov 		return ice_pkg_val_buf(state->buf_table->buf_array);
1782ffd87d3SSergey Temerkhanov 	}
1792ffd87d3SSergey Temerkhanov 
1802ffd87d3SSergey Temerkhanov 	if (++state->buf_idx < le32_to_cpu(state->buf_table->buf_count))
1812ffd87d3SSergey Temerkhanov 		return ice_pkg_val_buf(state->buf_table->buf_array +
1822ffd87d3SSergey Temerkhanov 				       state->buf_idx);
1832ffd87d3SSergey Temerkhanov 	else
1842ffd87d3SSergey Temerkhanov 		return NULL;
1852ffd87d3SSergey Temerkhanov }
1862ffd87d3SSergey Temerkhanov 
1872ffd87d3SSergey Temerkhanov /**
1882ffd87d3SSergey Temerkhanov  * ice_pkg_advance_sect
1892ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
1902ffd87d3SSergey Temerkhanov  * @state: pointer to the enum state
1912ffd87d3SSergey Temerkhanov  *
1922ffd87d3SSergey Temerkhanov  * This helper function will advance the section within the ice segment,
1932ffd87d3SSergey Temerkhanov  * also advancing the buffer if needed.
1942ffd87d3SSergey Temerkhanov  */
1952ffd87d3SSergey Temerkhanov static bool ice_pkg_advance_sect(struct ice_seg *ice_seg,
1962ffd87d3SSergey Temerkhanov 				 struct ice_pkg_enum *state)
1972ffd87d3SSergey Temerkhanov {
1982ffd87d3SSergey Temerkhanov 	if (!ice_seg && !state->buf)
1992ffd87d3SSergey Temerkhanov 		return false;
2002ffd87d3SSergey Temerkhanov 
2012ffd87d3SSergey Temerkhanov 	if (!ice_seg && state->buf)
2022ffd87d3SSergey Temerkhanov 		if (++state->sect_idx < le16_to_cpu(state->buf->section_count))
2032ffd87d3SSergey Temerkhanov 			return true;
2042ffd87d3SSergey Temerkhanov 
2052ffd87d3SSergey Temerkhanov 	state->buf = ice_pkg_enum_buf(ice_seg, state);
2062ffd87d3SSergey Temerkhanov 	if (!state->buf)
2072ffd87d3SSergey Temerkhanov 		return false;
2082ffd87d3SSergey Temerkhanov 
2092ffd87d3SSergey Temerkhanov 	/* start of new buffer, reset section index */
2102ffd87d3SSergey Temerkhanov 	state->sect_idx = 0;
2112ffd87d3SSergey Temerkhanov 	return true;
2122ffd87d3SSergey Temerkhanov }
2132ffd87d3SSergey Temerkhanov 
2142ffd87d3SSergey Temerkhanov /**
2152ffd87d3SSergey Temerkhanov  * ice_pkg_enum_section
2162ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
2172ffd87d3SSergey Temerkhanov  * @state: pointer to the enum state
2182ffd87d3SSergey Temerkhanov  * @sect_type: section type to enumerate
2192ffd87d3SSergey Temerkhanov  *
2202ffd87d3SSergey Temerkhanov  * This function will enumerate all the sections of a particular type in the
2212ffd87d3SSergey Temerkhanov  * ice segment. The first call is made with the ice_seg parameter non-NULL;
2222ffd87d3SSergey Temerkhanov  * on subsequent calls, ice_seg is set to NULL which continues the enumeration.
2232ffd87d3SSergey Temerkhanov  * When the function returns a NULL pointer, then the end of the matching
2242ffd87d3SSergey Temerkhanov  * sections has been reached.
2252ffd87d3SSergey Temerkhanov  */
2262ffd87d3SSergey Temerkhanov void *ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
2272ffd87d3SSergey Temerkhanov 			   u32 sect_type)
2282ffd87d3SSergey Temerkhanov {
2292ffd87d3SSergey Temerkhanov 	u16 offset, size;
2302ffd87d3SSergey Temerkhanov 
2312ffd87d3SSergey Temerkhanov 	if (ice_seg)
2322ffd87d3SSergey Temerkhanov 		state->type = sect_type;
2332ffd87d3SSergey Temerkhanov 
2342ffd87d3SSergey Temerkhanov 	if (!ice_pkg_advance_sect(ice_seg, state))
2352ffd87d3SSergey Temerkhanov 		return NULL;
2362ffd87d3SSergey Temerkhanov 
2372ffd87d3SSergey Temerkhanov 	/* scan for next matching section */
2382ffd87d3SSergey Temerkhanov 	while (state->buf->section_entry[state->sect_idx].type !=
2392ffd87d3SSergey Temerkhanov 	       cpu_to_le32(state->type))
2402ffd87d3SSergey Temerkhanov 		if (!ice_pkg_advance_sect(NULL, state))
2412ffd87d3SSergey Temerkhanov 			return NULL;
2422ffd87d3SSergey Temerkhanov 
2432ffd87d3SSergey Temerkhanov 	/* validate section */
2442ffd87d3SSergey Temerkhanov 	offset = le16_to_cpu(state->buf->section_entry[state->sect_idx].offset);
2452ffd87d3SSergey Temerkhanov 	if (offset < ICE_MIN_S_OFF || offset > ICE_MAX_S_OFF)
2462ffd87d3SSergey Temerkhanov 		return NULL;
2472ffd87d3SSergey Temerkhanov 
2482ffd87d3SSergey Temerkhanov 	size = le16_to_cpu(state->buf->section_entry[state->sect_idx].size);
2492ffd87d3SSergey Temerkhanov 	if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ)
2502ffd87d3SSergey Temerkhanov 		return NULL;
2512ffd87d3SSergey Temerkhanov 
2522ffd87d3SSergey Temerkhanov 	/* make sure the section fits in the buffer */
2532ffd87d3SSergey Temerkhanov 	if (offset + size > ICE_PKG_BUF_SIZE)
2542ffd87d3SSergey Temerkhanov 		return NULL;
2552ffd87d3SSergey Temerkhanov 
2562ffd87d3SSergey Temerkhanov 	state->sect_type =
2572ffd87d3SSergey Temerkhanov 		le32_to_cpu(state->buf->section_entry[state->sect_idx].type);
2582ffd87d3SSergey Temerkhanov 
2592ffd87d3SSergey Temerkhanov 	/* calc pointer to this section */
2602ffd87d3SSergey Temerkhanov 	state->sect =
2612ffd87d3SSergey Temerkhanov 		((u8 *)state->buf) +
2622ffd87d3SSergey Temerkhanov 		le16_to_cpu(state->buf->section_entry[state->sect_idx].offset);
2632ffd87d3SSergey Temerkhanov 
2642ffd87d3SSergey Temerkhanov 	return state->sect;
2652ffd87d3SSergey Temerkhanov }
2662ffd87d3SSergey Temerkhanov 
2672ffd87d3SSergey Temerkhanov /**
2682ffd87d3SSergey Temerkhanov  * ice_pkg_enum_entry
2692ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
2702ffd87d3SSergey Temerkhanov  * @state: pointer to the enum state
2712ffd87d3SSergey Temerkhanov  * @sect_type: section type to enumerate
2722ffd87d3SSergey Temerkhanov  * @offset: pointer to variable that receives the offset in the table (optional)
2732ffd87d3SSergey Temerkhanov  * @handler: function that handles access to the entries into the section type
2742ffd87d3SSergey Temerkhanov  *
2752ffd87d3SSergey Temerkhanov  * This function will enumerate all the entries in particular section type in
2762ffd87d3SSergey Temerkhanov  * the ice segment. The first call is made with the ice_seg parameter non-NULL;
2772ffd87d3SSergey Temerkhanov  * on subsequent calls, ice_seg is set to NULL which continues the enumeration.
2782ffd87d3SSergey Temerkhanov  * When the function returns a NULL pointer, then the end of the entries has
2792ffd87d3SSergey Temerkhanov  * been reached.
2802ffd87d3SSergey Temerkhanov  *
2812ffd87d3SSergey Temerkhanov  * Since each section may have a different header and entry size, the handler
2822ffd87d3SSergey Temerkhanov  * function is needed to determine the number and location entries in each
2832ffd87d3SSergey Temerkhanov  * section.
2842ffd87d3SSergey Temerkhanov  *
2852ffd87d3SSergey Temerkhanov  * The offset parameter is optional, but should be used for sections that
2862ffd87d3SSergey Temerkhanov  * contain an offset for each section table. For such cases, the section handler
2872ffd87d3SSergey Temerkhanov  * function must return the appropriate offset + index to give the absolution
2882ffd87d3SSergey Temerkhanov  * offset for each entry. For example, if the base for a section's header
2892ffd87d3SSergey Temerkhanov  * indicates a base offset of 10, and the index for the entry is 2, then
2902ffd87d3SSergey Temerkhanov  * section handler function should set the offset to 10 + 2 = 12.
2912ffd87d3SSergey Temerkhanov  */
292*75b4a938SJunfeng Guo void *ice_pkg_enum_entry(struct ice_seg *ice_seg,
2932ffd87d3SSergey Temerkhanov 			 struct ice_pkg_enum *state, u32 sect_type,
2942ffd87d3SSergey Temerkhanov 			 u32 *offset,
2952ffd87d3SSergey Temerkhanov 			 void *(*handler)(u32 sect_type, void *section,
2962ffd87d3SSergey Temerkhanov 					  u32 index, u32 *offset))
2972ffd87d3SSergey Temerkhanov {
2982ffd87d3SSergey Temerkhanov 	void *entry;
2992ffd87d3SSergey Temerkhanov 
3002ffd87d3SSergey Temerkhanov 	if (ice_seg) {
3012ffd87d3SSergey Temerkhanov 		if (!handler)
3022ffd87d3SSergey Temerkhanov 			return NULL;
3032ffd87d3SSergey Temerkhanov 
3042ffd87d3SSergey Temerkhanov 		if (!ice_pkg_enum_section(ice_seg, state, sect_type))
3052ffd87d3SSergey Temerkhanov 			return NULL;
3062ffd87d3SSergey Temerkhanov 
3072ffd87d3SSergey Temerkhanov 		state->entry_idx = 0;
3082ffd87d3SSergey Temerkhanov 		state->handler = handler;
3092ffd87d3SSergey Temerkhanov 	} else {
3102ffd87d3SSergey Temerkhanov 		state->entry_idx++;
3112ffd87d3SSergey Temerkhanov 	}
3122ffd87d3SSergey Temerkhanov 
3132ffd87d3SSergey Temerkhanov 	if (!state->handler)
3142ffd87d3SSergey Temerkhanov 		return NULL;
3152ffd87d3SSergey Temerkhanov 
3162ffd87d3SSergey Temerkhanov 	/* get entry */
3172ffd87d3SSergey Temerkhanov 	entry = state->handler(state->sect_type, state->sect, state->entry_idx,
3182ffd87d3SSergey Temerkhanov 			       offset);
3192ffd87d3SSergey Temerkhanov 	if (!entry) {
3202ffd87d3SSergey Temerkhanov 		/* end of a section, look for another section of this type */
3212ffd87d3SSergey Temerkhanov 		if (!ice_pkg_enum_section(NULL, state, 0))
3222ffd87d3SSergey Temerkhanov 			return NULL;
3232ffd87d3SSergey Temerkhanov 
3242ffd87d3SSergey Temerkhanov 		state->entry_idx = 0;
3252ffd87d3SSergey Temerkhanov 		entry = state->handler(state->sect_type, state->sect,
3262ffd87d3SSergey Temerkhanov 				       state->entry_idx, offset);
3272ffd87d3SSergey Temerkhanov 	}
3282ffd87d3SSergey Temerkhanov 
3292ffd87d3SSergey Temerkhanov 	return entry;
3302ffd87d3SSergey Temerkhanov }
3312ffd87d3SSergey Temerkhanov 
3322ffd87d3SSergey Temerkhanov /**
3332ffd87d3SSergey Temerkhanov  * ice_sw_fv_handler
3342ffd87d3SSergey Temerkhanov  * @sect_type: section type
3352ffd87d3SSergey Temerkhanov  * @section: pointer to section
3362ffd87d3SSergey Temerkhanov  * @index: index of the field vector entry to be returned
3372ffd87d3SSergey Temerkhanov  * @offset: ptr to variable that receives the offset in the field vector table
3382ffd87d3SSergey Temerkhanov  *
3392ffd87d3SSergey Temerkhanov  * This is a callback function that can be passed to ice_pkg_enum_entry.
3402ffd87d3SSergey Temerkhanov  * This function treats the given section as of type ice_sw_fv_section and
3412ffd87d3SSergey Temerkhanov  * enumerates offset field. "offset" is an index into the field vector table.
3422ffd87d3SSergey Temerkhanov  */
3432ffd87d3SSergey Temerkhanov static void *ice_sw_fv_handler(u32 sect_type, void *section, u32 index,
3442ffd87d3SSergey Temerkhanov 			       u32 *offset)
3452ffd87d3SSergey Temerkhanov {
3462ffd87d3SSergey Temerkhanov 	struct ice_sw_fv_section *fv_section = section;
3472ffd87d3SSergey Temerkhanov 
3482ffd87d3SSergey Temerkhanov 	if (!section || sect_type != ICE_SID_FLD_VEC_SW)
3492ffd87d3SSergey Temerkhanov 		return NULL;
3502ffd87d3SSergey Temerkhanov 	if (index >= le16_to_cpu(fv_section->count))
3512ffd87d3SSergey Temerkhanov 		return NULL;
3522ffd87d3SSergey Temerkhanov 	if (offset)
3532ffd87d3SSergey Temerkhanov 		/* "index" passed in to this function is relative to a given
3542ffd87d3SSergey Temerkhanov 		 * 4k block. To get to the true index into the field vector
3552ffd87d3SSergey Temerkhanov 		 * table need to add the relative index to the base_offset
3562ffd87d3SSergey Temerkhanov 		 * field of this section
3572ffd87d3SSergey Temerkhanov 		 */
3582ffd87d3SSergey Temerkhanov 		*offset = le16_to_cpu(fv_section->base_offset) + index;
3592ffd87d3SSergey Temerkhanov 	return fv_section->fv + index;
3602ffd87d3SSergey Temerkhanov }
3612ffd87d3SSergey Temerkhanov 
3622ffd87d3SSergey Temerkhanov /**
3632ffd87d3SSergey Temerkhanov  * ice_get_prof_index_max - get the max profile index for used profile
3642ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW struct
3652ffd87d3SSergey Temerkhanov  *
3662ffd87d3SSergey Temerkhanov  * Calling this function will get the max profile index for used profile
3672ffd87d3SSergey Temerkhanov  * and store the index number in struct ice_switch_info *switch_info
3682ffd87d3SSergey Temerkhanov  * in HW for following use.
3692ffd87d3SSergey Temerkhanov  */
3702ffd87d3SSergey Temerkhanov static int ice_get_prof_index_max(struct ice_hw *hw)
3712ffd87d3SSergey Temerkhanov {
3722ffd87d3SSergey Temerkhanov 	u16 prof_index = 0, j, max_prof_index = 0;
3732ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
3742ffd87d3SSergey Temerkhanov 	struct ice_seg *ice_seg;
3752ffd87d3SSergey Temerkhanov 	bool flag = false;
3762ffd87d3SSergey Temerkhanov 	struct ice_fv *fv;
3772ffd87d3SSergey Temerkhanov 	u32 offset;
3782ffd87d3SSergey Temerkhanov 
3792ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
3802ffd87d3SSergey Temerkhanov 
3812ffd87d3SSergey Temerkhanov 	if (!hw->seg)
3822ffd87d3SSergey Temerkhanov 		return -EINVAL;
3832ffd87d3SSergey Temerkhanov 
3842ffd87d3SSergey Temerkhanov 	ice_seg = hw->seg;
3852ffd87d3SSergey Temerkhanov 
3862ffd87d3SSergey Temerkhanov 	do {
3872ffd87d3SSergey Temerkhanov 		fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
3882ffd87d3SSergey Temerkhanov 					&offset, ice_sw_fv_handler);
3892ffd87d3SSergey Temerkhanov 		if (!fv)
3902ffd87d3SSergey Temerkhanov 			break;
3912ffd87d3SSergey Temerkhanov 		ice_seg = NULL;
3922ffd87d3SSergey Temerkhanov 
3932ffd87d3SSergey Temerkhanov 		/* in the profile that not be used, the prot_id is set to 0xff
3942ffd87d3SSergey Temerkhanov 		 * and the off is set to 0x1ff for all the field vectors.
3952ffd87d3SSergey Temerkhanov 		 */
3962ffd87d3SSergey Temerkhanov 		for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
3972ffd87d3SSergey Temerkhanov 			if (fv->ew[j].prot_id != ICE_PROT_INVALID ||
3982ffd87d3SSergey Temerkhanov 			    fv->ew[j].off != ICE_FV_OFFSET_INVAL)
3992ffd87d3SSergey Temerkhanov 				flag = true;
4002ffd87d3SSergey Temerkhanov 		if (flag && prof_index > max_prof_index)
4012ffd87d3SSergey Temerkhanov 			max_prof_index = prof_index;
4022ffd87d3SSergey Temerkhanov 
4032ffd87d3SSergey Temerkhanov 		prof_index++;
4042ffd87d3SSergey Temerkhanov 		flag = false;
4052ffd87d3SSergey Temerkhanov 	} while (fv);
4062ffd87d3SSergey Temerkhanov 
4072ffd87d3SSergey Temerkhanov 	hw->switch_info->max_used_prof_index = max_prof_index;
4082ffd87d3SSergey Temerkhanov 
4092ffd87d3SSergey Temerkhanov 	return 0;
4102ffd87d3SSergey Temerkhanov }
4112ffd87d3SSergey Temerkhanov 
4122ffd87d3SSergey Temerkhanov /**
4132ffd87d3SSergey Temerkhanov  * ice_get_ddp_pkg_state - get DDP pkg state after download
4142ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW struct
4152ffd87d3SSergey Temerkhanov  * @already_loaded: indicates if pkg was already loaded onto the device
4162ffd87d3SSergey Temerkhanov  */
4172ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_ddp_pkg_state(struct ice_hw *hw,
4182ffd87d3SSergey Temerkhanov 						bool already_loaded)
4192ffd87d3SSergey Temerkhanov {
4202ffd87d3SSergey Temerkhanov 	if (hw->pkg_ver.major == hw->active_pkg_ver.major &&
4212ffd87d3SSergey Temerkhanov 	    hw->pkg_ver.minor == hw->active_pkg_ver.minor &&
4222ffd87d3SSergey Temerkhanov 	    hw->pkg_ver.update == hw->active_pkg_ver.update &&
4232ffd87d3SSergey Temerkhanov 	    hw->pkg_ver.draft == hw->active_pkg_ver.draft &&
4242ffd87d3SSergey Temerkhanov 	    !memcmp(hw->pkg_name, hw->active_pkg_name, sizeof(hw->pkg_name))) {
4252ffd87d3SSergey Temerkhanov 		if (already_loaded)
4262ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED;
4272ffd87d3SSergey Temerkhanov 		else
4282ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_SUCCESS;
4292ffd87d3SSergey Temerkhanov 	} else if (hw->active_pkg_ver.major != ICE_PKG_SUPP_VER_MAJ ||
4302ffd87d3SSergey Temerkhanov 		   hw->active_pkg_ver.minor != ICE_PKG_SUPP_VER_MNR) {
4312ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ALREADY_LOADED_NOT_SUPPORTED;
4322ffd87d3SSergey Temerkhanov 	} else if (hw->active_pkg_ver.major == ICE_PKG_SUPP_VER_MAJ &&
4332ffd87d3SSergey Temerkhanov 		   hw->active_pkg_ver.minor == ICE_PKG_SUPP_VER_MNR) {
4342ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED;
4352ffd87d3SSergey Temerkhanov 	} else {
4362ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
4372ffd87d3SSergey Temerkhanov 	}
4382ffd87d3SSergey Temerkhanov }
4392ffd87d3SSergey Temerkhanov 
4402ffd87d3SSergey Temerkhanov /**
4412ffd87d3SSergey Temerkhanov  * ice_init_pkg_regs - initialize additional package registers
4422ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
4432ffd87d3SSergey Temerkhanov  */
4442ffd87d3SSergey Temerkhanov static void ice_init_pkg_regs(struct ice_hw *hw)
4452ffd87d3SSergey Temerkhanov {
4462ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_INP_MASK_L 0xFFFFFFFF
4472ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_INP_MASK_H 0x0000FFFF
4482ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_IDX 0
4492ffd87d3SSergey Temerkhanov 
4502ffd87d3SSergey Temerkhanov 	/* setup Switch block input mask, which is 48-bits in two parts */
4512ffd87d3SSergey Temerkhanov 	wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L);
4522ffd87d3SSergey Temerkhanov 	wr32(hw, GL_PREEXT_L2_PMASK1(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_H);
4532ffd87d3SSergey Temerkhanov }
4542ffd87d3SSergey Temerkhanov 
4552ffd87d3SSergey Temerkhanov /**
4562ffd87d3SSergey Temerkhanov  * ice_marker_ptype_tcam_handler
4572ffd87d3SSergey Temerkhanov  * @sect_type: section type
4582ffd87d3SSergey Temerkhanov  * @section: pointer to section
4592ffd87d3SSergey Temerkhanov  * @index: index of the Marker PType TCAM entry to be returned
4602ffd87d3SSergey Temerkhanov  * @offset: pointer to receive absolute offset, always 0 for ptype TCAM sections
4612ffd87d3SSergey Temerkhanov  *
4622ffd87d3SSergey Temerkhanov  * This is a callback function that can be passed to ice_pkg_enum_entry.
4632ffd87d3SSergey Temerkhanov  * Handles enumeration of individual Marker PType TCAM entries.
4642ffd87d3SSergey Temerkhanov  */
4652ffd87d3SSergey Temerkhanov static void *ice_marker_ptype_tcam_handler(u32 sect_type, void *section,
4662ffd87d3SSergey Temerkhanov 					   u32 index, u32 *offset)
4672ffd87d3SSergey Temerkhanov {
4682ffd87d3SSergey Temerkhanov 	struct ice_marker_ptype_tcam_section *marker_ptype;
4692ffd87d3SSergey Temerkhanov 
4702ffd87d3SSergey Temerkhanov 	if (sect_type != ICE_SID_RXPARSER_MARKER_PTYPE)
4712ffd87d3SSergey Temerkhanov 		return NULL;
4722ffd87d3SSergey Temerkhanov 
4732ffd87d3SSergey Temerkhanov 	if (index > ICE_MAX_MARKER_PTYPE_TCAMS_IN_BUF)
4742ffd87d3SSergey Temerkhanov 		return NULL;
4752ffd87d3SSergey Temerkhanov 
4762ffd87d3SSergey Temerkhanov 	if (offset)
4772ffd87d3SSergey Temerkhanov 		*offset = 0;
4782ffd87d3SSergey Temerkhanov 
4792ffd87d3SSergey Temerkhanov 	marker_ptype = section;
4802ffd87d3SSergey Temerkhanov 	if (index >= le16_to_cpu(marker_ptype->count))
4812ffd87d3SSergey Temerkhanov 		return NULL;
4822ffd87d3SSergey Temerkhanov 
4832ffd87d3SSergey Temerkhanov 	return marker_ptype->tcam + index;
4842ffd87d3SSergey Temerkhanov }
4852ffd87d3SSergey Temerkhanov 
4862ffd87d3SSergey Temerkhanov /**
4872ffd87d3SSergey Temerkhanov  * ice_add_dvm_hint
4882ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
4892ffd87d3SSergey Temerkhanov  * @val: value of the boost entry
4902ffd87d3SSergey Temerkhanov  * @enable: true if entry needs to be enabled, or false if needs to be disabled
4912ffd87d3SSergey Temerkhanov  */
4922ffd87d3SSergey Temerkhanov static void ice_add_dvm_hint(struct ice_hw *hw, u16 val, bool enable)
4932ffd87d3SSergey Temerkhanov {
4942ffd87d3SSergey Temerkhanov 	if (hw->dvm_upd.count < ICE_DVM_MAX_ENTRIES) {
4952ffd87d3SSergey Temerkhanov 		hw->dvm_upd.tbl[hw->dvm_upd.count].boost_addr = val;
4962ffd87d3SSergey Temerkhanov 		hw->dvm_upd.tbl[hw->dvm_upd.count].enable = enable;
4972ffd87d3SSergey Temerkhanov 		hw->dvm_upd.count++;
4982ffd87d3SSergey Temerkhanov 	}
4992ffd87d3SSergey Temerkhanov }
5002ffd87d3SSergey Temerkhanov 
5012ffd87d3SSergey Temerkhanov /**
5022ffd87d3SSergey Temerkhanov  * ice_add_tunnel_hint
5032ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
5042ffd87d3SSergey Temerkhanov  * @label_name: label text
5052ffd87d3SSergey Temerkhanov  * @val: value of the tunnel port boost entry
5062ffd87d3SSergey Temerkhanov  */
5072ffd87d3SSergey Temerkhanov static void ice_add_tunnel_hint(struct ice_hw *hw, char *label_name, u16 val)
5082ffd87d3SSergey Temerkhanov {
5092ffd87d3SSergey Temerkhanov 	if (hw->tnl.count < ICE_TUNNEL_MAX_ENTRIES) {
5102ffd87d3SSergey Temerkhanov 		u16 i;
5112ffd87d3SSergey Temerkhanov 
5122ffd87d3SSergey Temerkhanov 		for (i = 0; tnls[i].type != TNL_LAST; i++) {
5132ffd87d3SSergey Temerkhanov 			size_t len = strlen(tnls[i].label_prefix);
5142ffd87d3SSergey Temerkhanov 
5152ffd87d3SSergey Temerkhanov 			/* Look for matching label start, before continuing */
5162ffd87d3SSergey Temerkhanov 			if (strncmp(label_name, tnls[i].label_prefix, len))
5172ffd87d3SSergey Temerkhanov 				continue;
5182ffd87d3SSergey Temerkhanov 
5192ffd87d3SSergey Temerkhanov 			/* Make sure this label matches our PF. Note that the PF
5202ffd87d3SSergey Temerkhanov 			 * character ('0' - '7') will be located where our
5212ffd87d3SSergey Temerkhanov 			 * prefix string's null terminator is located.
5222ffd87d3SSergey Temerkhanov 			 */
5232ffd87d3SSergey Temerkhanov 			if ((label_name[len] - '0') == hw->pf_id) {
5242ffd87d3SSergey Temerkhanov 				hw->tnl.tbl[hw->tnl.count].type = tnls[i].type;
5252ffd87d3SSergey Temerkhanov 				hw->tnl.tbl[hw->tnl.count].valid = false;
5262ffd87d3SSergey Temerkhanov 				hw->tnl.tbl[hw->tnl.count].boost_addr = val;
5272ffd87d3SSergey Temerkhanov 				hw->tnl.tbl[hw->tnl.count].port = 0;
5282ffd87d3SSergey Temerkhanov 				hw->tnl.count++;
5292ffd87d3SSergey Temerkhanov 				break;
5302ffd87d3SSergey Temerkhanov 			}
5312ffd87d3SSergey Temerkhanov 		}
5322ffd87d3SSergey Temerkhanov 	}
5332ffd87d3SSergey Temerkhanov }
5342ffd87d3SSergey Temerkhanov 
5352ffd87d3SSergey Temerkhanov /**
5362ffd87d3SSergey Temerkhanov  * ice_label_enum_handler
5372ffd87d3SSergey Temerkhanov  * @sect_type: section type
5382ffd87d3SSergey Temerkhanov  * @section: pointer to section
5392ffd87d3SSergey Temerkhanov  * @index: index of the label entry to be returned
5402ffd87d3SSergey Temerkhanov  * @offset: pointer to receive absolute offset, always zero for label sections
5412ffd87d3SSergey Temerkhanov  *
5422ffd87d3SSergey Temerkhanov  * This is a callback function that can be passed to ice_pkg_enum_entry.
5432ffd87d3SSergey Temerkhanov  * Handles enumeration of individual label entries.
5442ffd87d3SSergey Temerkhanov  */
5452ffd87d3SSergey Temerkhanov static void *ice_label_enum_handler(u32 __always_unused sect_type,
5462ffd87d3SSergey Temerkhanov 				    void *section, u32 index, u32 *offset)
5472ffd87d3SSergey Temerkhanov {
5482ffd87d3SSergey Temerkhanov 	struct ice_label_section *labels;
5492ffd87d3SSergey Temerkhanov 
5502ffd87d3SSergey Temerkhanov 	if (!section)
5512ffd87d3SSergey Temerkhanov 		return NULL;
5522ffd87d3SSergey Temerkhanov 
5532ffd87d3SSergey Temerkhanov 	if (index > ICE_MAX_LABELS_IN_BUF)
5542ffd87d3SSergey Temerkhanov 		return NULL;
5552ffd87d3SSergey Temerkhanov 
5562ffd87d3SSergey Temerkhanov 	if (offset)
5572ffd87d3SSergey Temerkhanov 		*offset = 0;
5582ffd87d3SSergey Temerkhanov 
5592ffd87d3SSergey Temerkhanov 	labels = section;
5602ffd87d3SSergey Temerkhanov 	if (index >= le16_to_cpu(labels->count))
5612ffd87d3SSergey Temerkhanov 		return NULL;
5622ffd87d3SSergey Temerkhanov 
5632ffd87d3SSergey Temerkhanov 	return labels->label + index;
5642ffd87d3SSergey Temerkhanov }
5652ffd87d3SSergey Temerkhanov 
5662ffd87d3SSergey Temerkhanov /**
5672ffd87d3SSergey Temerkhanov  * ice_enum_labels
5682ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (NULL on subsequent calls)
5692ffd87d3SSergey Temerkhanov  * @type: the section type that will contain the label (0 on subsequent calls)
5702ffd87d3SSergey Temerkhanov  * @state: ice_pkg_enum structure that will hold the state of the enumeration
5712ffd87d3SSergey Temerkhanov  * @value: pointer to a value that will return the label's value if found
5722ffd87d3SSergey Temerkhanov  *
5732ffd87d3SSergey Temerkhanov  * Enumerates a list of labels in the package. The caller will call
5742ffd87d3SSergey Temerkhanov  * ice_enum_labels(ice_seg, type, ...) to start the enumeration, then call
5752ffd87d3SSergey Temerkhanov  * ice_enum_labels(NULL, 0, ...) to continue. When the function returns a NULL
5762ffd87d3SSergey Temerkhanov  * the end of the list has been reached.
5772ffd87d3SSergey Temerkhanov  */
5782ffd87d3SSergey Temerkhanov static char *ice_enum_labels(struct ice_seg *ice_seg, u32 type,
5792ffd87d3SSergey Temerkhanov 			     struct ice_pkg_enum *state, u16 *value)
5802ffd87d3SSergey Temerkhanov {
5812ffd87d3SSergey Temerkhanov 	struct ice_label *label;
5822ffd87d3SSergey Temerkhanov 
5832ffd87d3SSergey Temerkhanov 	/* Check for valid label section on first call */
5842ffd87d3SSergey Temerkhanov 	if (type && !(type >= ICE_SID_LBL_FIRST && type <= ICE_SID_LBL_LAST))
5852ffd87d3SSergey Temerkhanov 		return NULL;
5862ffd87d3SSergey Temerkhanov 
5872ffd87d3SSergey Temerkhanov 	label = ice_pkg_enum_entry(ice_seg, state, type, NULL,
5882ffd87d3SSergey Temerkhanov 				   ice_label_enum_handler);
5892ffd87d3SSergey Temerkhanov 	if (!label)
5902ffd87d3SSergey Temerkhanov 		return NULL;
5912ffd87d3SSergey Temerkhanov 
5922ffd87d3SSergey Temerkhanov 	*value = le16_to_cpu(label->value);
5932ffd87d3SSergey Temerkhanov 	return label->name;
5942ffd87d3SSergey Temerkhanov }
5952ffd87d3SSergey Temerkhanov 
5962ffd87d3SSergey Temerkhanov /**
5972ffd87d3SSergey Temerkhanov  * ice_boost_tcam_handler
5982ffd87d3SSergey Temerkhanov  * @sect_type: section type
5992ffd87d3SSergey Temerkhanov  * @section: pointer to section
6002ffd87d3SSergey Temerkhanov  * @index: index of the boost TCAM entry to be returned
6012ffd87d3SSergey Temerkhanov  * @offset: pointer to receive absolute offset, always 0 for boost TCAM sections
6022ffd87d3SSergey Temerkhanov  *
6032ffd87d3SSergey Temerkhanov  * This is a callback function that can be passed to ice_pkg_enum_entry.
6042ffd87d3SSergey Temerkhanov  * Handles enumeration of individual boost TCAM entries.
6052ffd87d3SSergey Temerkhanov  */
6062ffd87d3SSergey Temerkhanov static void *ice_boost_tcam_handler(u32 sect_type, void *section, u32 index,
6072ffd87d3SSergey Temerkhanov 				    u32 *offset)
6082ffd87d3SSergey Temerkhanov {
6092ffd87d3SSergey Temerkhanov 	struct ice_boost_tcam_section *boost;
6102ffd87d3SSergey Temerkhanov 
6112ffd87d3SSergey Temerkhanov 	if (!section)
6122ffd87d3SSergey Temerkhanov 		return NULL;
6132ffd87d3SSergey Temerkhanov 
6142ffd87d3SSergey Temerkhanov 	if (sect_type != ICE_SID_RXPARSER_BOOST_TCAM)
6152ffd87d3SSergey Temerkhanov 		return NULL;
6162ffd87d3SSergey Temerkhanov 
6172ffd87d3SSergey Temerkhanov 	if (index > ICE_MAX_BST_TCAMS_IN_BUF)
6182ffd87d3SSergey Temerkhanov 		return NULL;
6192ffd87d3SSergey Temerkhanov 
6202ffd87d3SSergey Temerkhanov 	if (offset)
6212ffd87d3SSergey Temerkhanov 		*offset = 0;
6222ffd87d3SSergey Temerkhanov 
6232ffd87d3SSergey Temerkhanov 	boost = section;
6242ffd87d3SSergey Temerkhanov 	if (index >= le16_to_cpu(boost->count))
6252ffd87d3SSergey Temerkhanov 		return NULL;
6262ffd87d3SSergey Temerkhanov 
6272ffd87d3SSergey Temerkhanov 	return boost->tcam + index;
6282ffd87d3SSergey Temerkhanov }
6292ffd87d3SSergey Temerkhanov 
6302ffd87d3SSergey Temerkhanov /**
6312ffd87d3SSergey Temerkhanov  * ice_find_boost_entry
6322ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (non-NULL)
6332ffd87d3SSergey Temerkhanov  * @addr: Boost TCAM address of entry to search for
6342ffd87d3SSergey Temerkhanov  * @entry: returns pointer to the entry
6352ffd87d3SSergey Temerkhanov  *
6362ffd87d3SSergey Temerkhanov  * Finds a particular Boost TCAM entry and returns a pointer to that entry
6372ffd87d3SSergey Temerkhanov  * if it is found. The ice_seg parameter must not be NULL since the first call
6382ffd87d3SSergey Temerkhanov  * to ice_pkg_enum_entry requires a pointer to an actual ice_segment structure.
6392ffd87d3SSergey Temerkhanov  */
6402ffd87d3SSergey Temerkhanov static int ice_find_boost_entry(struct ice_seg *ice_seg, u16 addr,
6412ffd87d3SSergey Temerkhanov 				struct ice_boost_tcam_entry **entry)
6422ffd87d3SSergey Temerkhanov {
6432ffd87d3SSergey Temerkhanov 	struct ice_boost_tcam_entry *tcam;
6442ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
6452ffd87d3SSergey Temerkhanov 
6462ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
6472ffd87d3SSergey Temerkhanov 
6482ffd87d3SSergey Temerkhanov 	if (!ice_seg)
6492ffd87d3SSergey Temerkhanov 		return -EINVAL;
6502ffd87d3SSergey Temerkhanov 
6512ffd87d3SSergey Temerkhanov 	do {
6522ffd87d3SSergey Temerkhanov 		tcam = ice_pkg_enum_entry(ice_seg, &state,
6532ffd87d3SSergey Temerkhanov 					  ICE_SID_RXPARSER_BOOST_TCAM, NULL,
6542ffd87d3SSergey Temerkhanov 					  ice_boost_tcam_handler);
6552ffd87d3SSergey Temerkhanov 		if (tcam && le16_to_cpu(tcam->addr) == addr) {
6562ffd87d3SSergey Temerkhanov 			*entry = tcam;
6572ffd87d3SSergey Temerkhanov 			return 0;
6582ffd87d3SSergey Temerkhanov 		}
6592ffd87d3SSergey Temerkhanov 
6602ffd87d3SSergey Temerkhanov 		ice_seg = NULL;
6612ffd87d3SSergey Temerkhanov 	} while (tcam);
6622ffd87d3SSergey Temerkhanov 
6632ffd87d3SSergey Temerkhanov 	*entry = NULL;
6642ffd87d3SSergey Temerkhanov 	return -EIO;
6652ffd87d3SSergey Temerkhanov }
6662ffd87d3SSergey Temerkhanov 
6672ffd87d3SSergey Temerkhanov /**
6682ffd87d3SSergey Temerkhanov  * ice_is_init_pkg_successful - check if DDP init was successful
6692ffd87d3SSergey Temerkhanov  * @state: state of the DDP pkg after download
6702ffd87d3SSergey Temerkhanov  */
6712ffd87d3SSergey Temerkhanov bool ice_is_init_pkg_successful(enum ice_ddp_state state)
6722ffd87d3SSergey Temerkhanov {
6732ffd87d3SSergey Temerkhanov 	switch (state) {
6742ffd87d3SSergey Temerkhanov 	case ICE_DDP_PKG_SUCCESS:
6752ffd87d3SSergey Temerkhanov 	case ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED:
6762ffd87d3SSergey Temerkhanov 	case ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED:
6772ffd87d3SSergey Temerkhanov 		return true;
6782ffd87d3SSergey Temerkhanov 	default:
6792ffd87d3SSergey Temerkhanov 		return false;
6802ffd87d3SSergey Temerkhanov 	}
6812ffd87d3SSergey Temerkhanov }
6822ffd87d3SSergey Temerkhanov 
6832ffd87d3SSergey Temerkhanov /**
6842ffd87d3SSergey Temerkhanov  * ice_pkg_buf_alloc
6852ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
6862ffd87d3SSergey Temerkhanov  *
6872ffd87d3SSergey Temerkhanov  * Allocates a package buffer and returns a pointer to the buffer header.
6882ffd87d3SSergey Temerkhanov  * Note: all package contents must be in Little Endian form.
6892ffd87d3SSergey Temerkhanov  */
6902ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
6912ffd87d3SSergey Temerkhanov {
6922ffd87d3SSergey Temerkhanov 	struct ice_buf_build *bld;
6932ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *buf;
6942ffd87d3SSergey Temerkhanov 
6952ffd87d3SSergey Temerkhanov 	bld = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*bld), GFP_KERNEL);
6962ffd87d3SSergey Temerkhanov 	if (!bld)
6972ffd87d3SSergey Temerkhanov 		return NULL;
6982ffd87d3SSergey Temerkhanov 
6992ffd87d3SSergey Temerkhanov 	buf = (struct ice_buf_hdr *)bld;
7002ffd87d3SSergey Temerkhanov 	buf->data_end =
7012ffd87d3SSergey Temerkhanov 		cpu_to_le16(offsetof(struct ice_buf_hdr, section_entry));
7022ffd87d3SSergey Temerkhanov 	return bld;
7032ffd87d3SSergey Temerkhanov }
7042ffd87d3SSergey Temerkhanov 
7052ffd87d3SSergey Temerkhanov static bool ice_is_gtp_u_profile(u16 prof_idx)
7062ffd87d3SSergey Temerkhanov {
7072ffd87d3SSergey Temerkhanov 	return (prof_idx >= ICE_PROFID_IPV6_GTPU_TEID &&
7082ffd87d3SSergey Temerkhanov 		prof_idx <= ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER) ||
7092ffd87d3SSergey Temerkhanov 	       prof_idx == ICE_PROFID_IPV4_GTPU_TEID;
7102ffd87d3SSergey Temerkhanov }
7112ffd87d3SSergey Temerkhanov 
7122ffd87d3SSergey Temerkhanov static bool ice_is_gtp_c_profile(u16 prof_idx)
7132ffd87d3SSergey Temerkhanov {
7142ffd87d3SSergey Temerkhanov 	switch (prof_idx) {
7152ffd87d3SSergey Temerkhanov 	case ICE_PROFID_IPV4_GTPC_TEID:
7162ffd87d3SSergey Temerkhanov 	case ICE_PROFID_IPV4_GTPC_NO_TEID:
7172ffd87d3SSergey Temerkhanov 	case ICE_PROFID_IPV6_GTPC_TEID:
7182ffd87d3SSergey Temerkhanov 	case ICE_PROFID_IPV6_GTPC_NO_TEID:
7192ffd87d3SSergey Temerkhanov 		return true;
7202ffd87d3SSergey Temerkhanov 	default:
7212ffd87d3SSergey Temerkhanov 		return false;
7222ffd87d3SSergey Temerkhanov 	}
7232ffd87d3SSergey Temerkhanov }
7242ffd87d3SSergey Temerkhanov 
725784feaa6SMarcin Szycik static bool ice_is_pfcp_profile(u16 prof_idx)
726784feaa6SMarcin Szycik {
727784feaa6SMarcin Szycik 	return prof_idx >= ICE_PROFID_IPV4_PFCP_NODE &&
728784feaa6SMarcin Szycik 	       prof_idx <= ICE_PROFID_IPV6_PFCP_SESSION;
729784feaa6SMarcin Szycik }
730784feaa6SMarcin Szycik 
7312ffd87d3SSergey Temerkhanov /**
7322ffd87d3SSergey Temerkhanov  * ice_get_sw_prof_type - determine switch profile type
7332ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
7342ffd87d3SSergey Temerkhanov  * @fv: pointer to the switch field vector
7352ffd87d3SSergey Temerkhanov  * @prof_idx: profile index to check
7362ffd87d3SSergey Temerkhanov  */
7372ffd87d3SSergey Temerkhanov static enum ice_prof_type ice_get_sw_prof_type(struct ice_hw *hw,
7382ffd87d3SSergey Temerkhanov 					       struct ice_fv *fv, u32 prof_idx)
7392ffd87d3SSergey Temerkhanov {
7402ffd87d3SSergey Temerkhanov 	u16 i;
7412ffd87d3SSergey Temerkhanov 
7422ffd87d3SSergey Temerkhanov 	if (ice_is_gtp_c_profile(prof_idx))
7432ffd87d3SSergey Temerkhanov 		return ICE_PROF_TUN_GTPC;
7442ffd87d3SSergey Temerkhanov 
7452ffd87d3SSergey Temerkhanov 	if (ice_is_gtp_u_profile(prof_idx))
7462ffd87d3SSergey Temerkhanov 		return ICE_PROF_TUN_GTPU;
7472ffd87d3SSergey Temerkhanov 
748784feaa6SMarcin Szycik 	if (ice_is_pfcp_profile(prof_idx))
749784feaa6SMarcin Szycik 		return ICE_PROF_TUN_PFCP;
750784feaa6SMarcin Szycik 
7512ffd87d3SSergey Temerkhanov 	for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) {
7522ffd87d3SSergey Temerkhanov 		/* UDP tunnel will have UDP_OF protocol ID and VNI offset */
7532ffd87d3SSergey Temerkhanov 		if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF &&
7542ffd87d3SSergey Temerkhanov 		    fv->ew[i].off == ICE_VNI_OFFSET)
7552ffd87d3SSergey Temerkhanov 			return ICE_PROF_TUN_UDP;
7562ffd87d3SSergey Temerkhanov 
7572ffd87d3SSergey Temerkhanov 		/* GRE tunnel will have GRE protocol */
7582ffd87d3SSergey Temerkhanov 		if (fv->ew[i].prot_id == (u8)ICE_PROT_GRE_OF)
7592ffd87d3SSergey Temerkhanov 			return ICE_PROF_TUN_GRE;
7602ffd87d3SSergey Temerkhanov 	}
7612ffd87d3SSergey Temerkhanov 
7622ffd87d3SSergey Temerkhanov 	return ICE_PROF_NON_TUN;
7632ffd87d3SSergey Temerkhanov }
7642ffd87d3SSergey Temerkhanov 
7652ffd87d3SSergey Temerkhanov /**
7662ffd87d3SSergey Temerkhanov  * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type
7672ffd87d3SSergey Temerkhanov  * @hw: pointer to hardware structure
7682ffd87d3SSergey Temerkhanov  * @req_profs: type of profiles requested
7692ffd87d3SSergey Temerkhanov  * @bm: pointer to memory for returning the bitmap of field vectors
7702ffd87d3SSergey Temerkhanov  */
7712ffd87d3SSergey Temerkhanov void ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
7722ffd87d3SSergey Temerkhanov 			  unsigned long *bm)
7732ffd87d3SSergey Temerkhanov {
7742ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
7752ffd87d3SSergey Temerkhanov 	struct ice_seg *ice_seg;
7762ffd87d3SSergey Temerkhanov 	struct ice_fv *fv;
7772ffd87d3SSergey Temerkhanov 
7782ffd87d3SSergey Temerkhanov 	if (req_profs == ICE_PROF_ALL) {
7792ffd87d3SSergey Temerkhanov 		bitmap_set(bm, 0, ICE_MAX_NUM_PROFILES);
7802ffd87d3SSergey Temerkhanov 		return;
7812ffd87d3SSergey Temerkhanov 	}
7822ffd87d3SSergey Temerkhanov 
7832ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
7842ffd87d3SSergey Temerkhanov 	bitmap_zero(bm, ICE_MAX_NUM_PROFILES);
7852ffd87d3SSergey Temerkhanov 	ice_seg = hw->seg;
7862ffd87d3SSergey Temerkhanov 	do {
7872ffd87d3SSergey Temerkhanov 		enum ice_prof_type prof_type;
7882ffd87d3SSergey Temerkhanov 		u32 offset;
7892ffd87d3SSergey Temerkhanov 
7902ffd87d3SSergey Temerkhanov 		fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
7912ffd87d3SSergey Temerkhanov 					&offset, ice_sw_fv_handler);
7922ffd87d3SSergey Temerkhanov 		ice_seg = NULL;
7932ffd87d3SSergey Temerkhanov 
7942ffd87d3SSergey Temerkhanov 		if (fv) {
7952ffd87d3SSergey Temerkhanov 			/* Determine field vector type */
7962ffd87d3SSergey Temerkhanov 			prof_type = ice_get_sw_prof_type(hw, fv, offset);
7972ffd87d3SSergey Temerkhanov 
7982ffd87d3SSergey Temerkhanov 			if (req_profs & prof_type)
7992ffd87d3SSergey Temerkhanov 				set_bit((u16)offset, bm);
8002ffd87d3SSergey Temerkhanov 		}
8012ffd87d3SSergey Temerkhanov 	} while (fv);
8022ffd87d3SSergey Temerkhanov }
8032ffd87d3SSergey Temerkhanov 
8042ffd87d3SSergey Temerkhanov /**
8052ffd87d3SSergey Temerkhanov  * ice_get_sw_fv_list
8062ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
8072ffd87d3SSergey Temerkhanov  * @lkups: list of protocol types
8082ffd87d3SSergey Temerkhanov  * @bm: bitmap of field vectors to consider
8092ffd87d3SSergey Temerkhanov  * @fv_list: Head of a list
8102ffd87d3SSergey Temerkhanov  *
8112ffd87d3SSergey Temerkhanov  * Finds all the field vector entries from switch block that contain
8122ffd87d3SSergey Temerkhanov  * a given protocol ID and offset and returns a list of structures of type
8132ffd87d3SSergey Temerkhanov  * "ice_sw_fv_list_entry". Every structure in the list has a field vector
8142ffd87d3SSergey Temerkhanov  * definition and profile ID information
8152ffd87d3SSergey Temerkhanov  * NOTE: The caller of the function is responsible for freeing the memory
8162ffd87d3SSergey Temerkhanov  * allocated for every list entry.
8172ffd87d3SSergey Temerkhanov  */
8182ffd87d3SSergey Temerkhanov int ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups,
8192ffd87d3SSergey Temerkhanov 		       unsigned long *bm, struct list_head *fv_list)
8202ffd87d3SSergey Temerkhanov {
8212ffd87d3SSergey Temerkhanov 	struct ice_sw_fv_list_entry *fvl;
8222ffd87d3SSergey Temerkhanov 	struct ice_sw_fv_list_entry *tmp;
8232ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
8242ffd87d3SSergey Temerkhanov 	struct ice_seg *ice_seg;
8252ffd87d3SSergey Temerkhanov 	struct ice_fv *fv;
8262ffd87d3SSergey Temerkhanov 	u32 offset;
8272ffd87d3SSergey Temerkhanov 
8282ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
8292ffd87d3SSergey Temerkhanov 
8302ffd87d3SSergey Temerkhanov 	if (!lkups->n_val_words || !hw->seg)
8312ffd87d3SSergey Temerkhanov 		return -EINVAL;
8322ffd87d3SSergey Temerkhanov 
8332ffd87d3SSergey Temerkhanov 	ice_seg = hw->seg;
8342ffd87d3SSergey Temerkhanov 	do {
8352ffd87d3SSergey Temerkhanov 		u16 i;
8362ffd87d3SSergey Temerkhanov 
8372ffd87d3SSergey Temerkhanov 		fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
8382ffd87d3SSergey Temerkhanov 					&offset, ice_sw_fv_handler);
8392ffd87d3SSergey Temerkhanov 		if (!fv)
8402ffd87d3SSergey Temerkhanov 			break;
8412ffd87d3SSergey Temerkhanov 		ice_seg = NULL;
8422ffd87d3SSergey Temerkhanov 
8432ffd87d3SSergey Temerkhanov 		/* If field vector is not in the bitmap list, then skip this
8442ffd87d3SSergey Temerkhanov 		 * profile.
8452ffd87d3SSergey Temerkhanov 		 */
8462ffd87d3SSergey Temerkhanov 		if (!test_bit((u16)offset, bm))
8472ffd87d3SSergey Temerkhanov 			continue;
8482ffd87d3SSergey Temerkhanov 
8492ffd87d3SSergey Temerkhanov 		for (i = 0; i < lkups->n_val_words; i++) {
8502ffd87d3SSergey Temerkhanov 			int j;
8512ffd87d3SSergey Temerkhanov 
8522ffd87d3SSergey Temerkhanov 			for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
8532ffd87d3SSergey Temerkhanov 				if (fv->ew[j].prot_id ==
8542ffd87d3SSergey Temerkhanov 					    lkups->fv_words[i].prot_id &&
8552ffd87d3SSergey Temerkhanov 				    fv->ew[j].off == lkups->fv_words[i].off)
8562ffd87d3SSergey Temerkhanov 					break;
8572ffd87d3SSergey Temerkhanov 			if (j >= hw->blk[ICE_BLK_SW].es.fvw)
8582ffd87d3SSergey Temerkhanov 				break;
8592ffd87d3SSergey Temerkhanov 			if (i + 1 == lkups->n_val_words) {
8602ffd87d3SSergey Temerkhanov 				fvl = devm_kzalloc(ice_hw_to_dev(hw),
8612ffd87d3SSergey Temerkhanov 						   sizeof(*fvl), GFP_KERNEL);
8622ffd87d3SSergey Temerkhanov 				if (!fvl)
8632ffd87d3SSergey Temerkhanov 					goto err;
8642ffd87d3SSergey Temerkhanov 				fvl->fv_ptr = fv;
8652ffd87d3SSergey Temerkhanov 				fvl->profile_id = offset;
8662ffd87d3SSergey Temerkhanov 				list_add(&fvl->list_entry, fv_list);
8672ffd87d3SSergey Temerkhanov 				break;
8682ffd87d3SSergey Temerkhanov 			}
8692ffd87d3SSergey Temerkhanov 		}
8702ffd87d3SSergey Temerkhanov 	} while (fv);
8712ffd87d3SSergey Temerkhanov 	if (list_empty(fv_list)) {
8722ffd87d3SSergey Temerkhanov 		dev_warn(ice_hw_to_dev(hw),
8732ffd87d3SSergey Temerkhanov 			 "Required profiles not found in currently loaded DDP package");
8742ffd87d3SSergey Temerkhanov 		return -EIO;
8752ffd87d3SSergey Temerkhanov 	}
8762ffd87d3SSergey Temerkhanov 
8772ffd87d3SSergey Temerkhanov 	return 0;
8782ffd87d3SSergey Temerkhanov 
8792ffd87d3SSergey Temerkhanov err:
8802ffd87d3SSergey Temerkhanov 	list_for_each_entry_safe(fvl, tmp, fv_list, list_entry) {
8812ffd87d3SSergey Temerkhanov 		list_del(&fvl->list_entry);
8822ffd87d3SSergey Temerkhanov 		devm_kfree(ice_hw_to_dev(hw), fvl);
8832ffd87d3SSergey Temerkhanov 	}
8842ffd87d3SSergey Temerkhanov 
8852ffd87d3SSergey Temerkhanov 	return -ENOMEM;
8862ffd87d3SSergey Temerkhanov }
8872ffd87d3SSergey Temerkhanov 
8882ffd87d3SSergey Temerkhanov /**
8892ffd87d3SSergey Temerkhanov  * ice_init_prof_result_bm - Initialize the profile result index bitmap
8902ffd87d3SSergey Temerkhanov  * @hw: pointer to hardware structure
8912ffd87d3SSergey Temerkhanov  */
8922ffd87d3SSergey Temerkhanov void ice_init_prof_result_bm(struct ice_hw *hw)
8932ffd87d3SSergey Temerkhanov {
8942ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
8952ffd87d3SSergey Temerkhanov 	struct ice_seg *ice_seg;
8962ffd87d3SSergey Temerkhanov 	struct ice_fv *fv;
8972ffd87d3SSergey Temerkhanov 
8982ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
8992ffd87d3SSergey Temerkhanov 
9002ffd87d3SSergey Temerkhanov 	if (!hw->seg)
9012ffd87d3SSergey Temerkhanov 		return;
9022ffd87d3SSergey Temerkhanov 
9032ffd87d3SSergey Temerkhanov 	ice_seg = hw->seg;
9042ffd87d3SSergey Temerkhanov 	do {
9052ffd87d3SSergey Temerkhanov 		u32 off;
9062ffd87d3SSergey Temerkhanov 		u16 i;
9072ffd87d3SSergey Temerkhanov 
9082ffd87d3SSergey Temerkhanov 		fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
9092ffd87d3SSergey Temerkhanov 					&off, ice_sw_fv_handler);
9102ffd87d3SSergey Temerkhanov 		ice_seg = NULL;
9112ffd87d3SSergey Temerkhanov 		if (!fv)
9122ffd87d3SSergey Temerkhanov 			break;
9132ffd87d3SSergey Temerkhanov 
9142ffd87d3SSergey Temerkhanov 		bitmap_zero(hw->switch_info->prof_res_bm[off],
9152ffd87d3SSergey Temerkhanov 			    ICE_MAX_FV_WORDS);
9162ffd87d3SSergey Temerkhanov 
9172ffd87d3SSergey Temerkhanov 		/* Determine empty field vector indices, these can be
9182ffd87d3SSergey Temerkhanov 		 * used for recipe results. Skip index 0, since it is
9192ffd87d3SSergey Temerkhanov 		 * always used for Switch ID.
9202ffd87d3SSergey Temerkhanov 		 */
9212ffd87d3SSergey Temerkhanov 		for (i = 1; i < ICE_MAX_FV_WORDS; i++)
9222ffd87d3SSergey Temerkhanov 			if (fv->ew[i].prot_id == ICE_PROT_INVALID &&
9232ffd87d3SSergey Temerkhanov 			    fv->ew[i].off == ICE_FV_OFFSET_INVAL)
9242ffd87d3SSergey Temerkhanov 				set_bit(i, hw->switch_info->prof_res_bm[off]);
9252ffd87d3SSergey Temerkhanov 	} while (fv);
9262ffd87d3SSergey Temerkhanov }
9272ffd87d3SSergey Temerkhanov 
9282ffd87d3SSergey Temerkhanov /**
9292ffd87d3SSergey Temerkhanov  * ice_pkg_buf_free
9302ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
9312ffd87d3SSergey Temerkhanov  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
9322ffd87d3SSergey Temerkhanov  *
9332ffd87d3SSergey Temerkhanov  * Frees a package buffer
9342ffd87d3SSergey Temerkhanov  */
9352ffd87d3SSergey Temerkhanov void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld)
9362ffd87d3SSergey Temerkhanov {
9372ffd87d3SSergey Temerkhanov 	devm_kfree(ice_hw_to_dev(hw), bld);
9382ffd87d3SSergey Temerkhanov }
9392ffd87d3SSergey Temerkhanov 
9402ffd87d3SSergey Temerkhanov /**
9412ffd87d3SSergey Temerkhanov  * ice_pkg_buf_reserve_section
9422ffd87d3SSergey Temerkhanov  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
9432ffd87d3SSergey Temerkhanov  * @count: the number of sections to reserve
9442ffd87d3SSergey Temerkhanov  *
9452ffd87d3SSergey Temerkhanov  * Reserves one or more section table entries in a package buffer. This routine
9462ffd87d3SSergey Temerkhanov  * can be called multiple times as long as they are made before calling
9472ffd87d3SSergey Temerkhanov  * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section()
9482ffd87d3SSergey Temerkhanov  * is called once, the number of sections that can be allocated will not be able
9492ffd87d3SSergey Temerkhanov  * to be increased; not using all reserved sections is fine, but this will
9502ffd87d3SSergey Temerkhanov  * result in some wasted space in the buffer.
9512ffd87d3SSergey Temerkhanov  * Note: all package contents must be in Little Endian form.
9522ffd87d3SSergey Temerkhanov  */
9532ffd87d3SSergey Temerkhanov int ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count)
9542ffd87d3SSergey Temerkhanov {
9552ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *buf;
9562ffd87d3SSergey Temerkhanov 	u16 section_count;
9572ffd87d3SSergey Temerkhanov 	u16 data_end;
9582ffd87d3SSergey Temerkhanov 
9592ffd87d3SSergey Temerkhanov 	if (!bld)
9602ffd87d3SSergey Temerkhanov 		return -EINVAL;
9612ffd87d3SSergey Temerkhanov 
9622ffd87d3SSergey Temerkhanov 	buf = (struct ice_buf_hdr *)&bld->buf;
9632ffd87d3SSergey Temerkhanov 
9642ffd87d3SSergey Temerkhanov 	/* already an active section, can't increase table size */
9652ffd87d3SSergey Temerkhanov 	section_count = le16_to_cpu(buf->section_count);
9662ffd87d3SSergey Temerkhanov 	if (section_count > 0)
9672ffd87d3SSergey Temerkhanov 		return -EIO;
9682ffd87d3SSergey Temerkhanov 
9692ffd87d3SSergey Temerkhanov 	if (bld->reserved_section_table_entries + count > ICE_MAX_S_COUNT)
9702ffd87d3SSergey Temerkhanov 		return -EIO;
9712ffd87d3SSergey Temerkhanov 	bld->reserved_section_table_entries += count;
9722ffd87d3SSergey Temerkhanov 
9732ffd87d3SSergey Temerkhanov 	data_end = le16_to_cpu(buf->data_end) +
9742ffd87d3SSergey Temerkhanov 		   flex_array_size(buf, section_entry, count);
9752ffd87d3SSergey Temerkhanov 	buf->data_end = cpu_to_le16(data_end);
9762ffd87d3SSergey Temerkhanov 
9772ffd87d3SSergey Temerkhanov 	return 0;
9782ffd87d3SSergey Temerkhanov }
9792ffd87d3SSergey Temerkhanov 
9802ffd87d3SSergey Temerkhanov /**
9812ffd87d3SSergey Temerkhanov  * ice_pkg_buf_alloc_section
9822ffd87d3SSergey Temerkhanov  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
9832ffd87d3SSergey Temerkhanov  * @type: the section type value
9842ffd87d3SSergey Temerkhanov  * @size: the size of the section to reserve (in bytes)
9852ffd87d3SSergey Temerkhanov  *
9862ffd87d3SSergey Temerkhanov  * Reserves memory in the buffer for a section's content and updates the
9872ffd87d3SSergey Temerkhanov  * buffers' status accordingly. This routine returns a pointer to the first
9882ffd87d3SSergey Temerkhanov  * byte of the section start within the buffer, which is used to fill in the
9892ffd87d3SSergey Temerkhanov  * section contents.
9902ffd87d3SSergey Temerkhanov  * Note: all package contents must be in Little Endian form.
9912ffd87d3SSergey Temerkhanov  */
9922ffd87d3SSergey Temerkhanov void *ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size)
9932ffd87d3SSergey Temerkhanov {
9942ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *buf;
9952ffd87d3SSergey Temerkhanov 	u16 sect_count;
9962ffd87d3SSergey Temerkhanov 	u16 data_end;
9972ffd87d3SSergey Temerkhanov 
9982ffd87d3SSergey Temerkhanov 	if (!bld || !type || !size)
9992ffd87d3SSergey Temerkhanov 		return NULL;
10002ffd87d3SSergey Temerkhanov 
10012ffd87d3SSergey Temerkhanov 	buf = (struct ice_buf_hdr *)&bld->buf;
10022ffd87d3SSergey Temerkhanov 
10032ffd87d3SSergey Temerkhanov 	/* check for enough space left in buffer */
10042ffd87d3SSergey Temerkhanov 	data_end = le16_to_cpu(buf->data_end);
10052ffd87d3SSergey Temerkhanov 
10062ffd87d3SSergey Temerkhanov 	/* section start must align on 4 byte boundary */
10072ffd87d3SSergey Temerkhanov 	data_end = ALIGN(data_end, 4);
10082ffd87d3SSergey Temerkhanov 
10092ffd87d3SSergey Temerkhanov 	if ((data_end + size) > ICE_MAX_S_DATA_END)
10102ffd87d3SSergey Temerkhanov 		return NULL;
10112ffd87d3SSergey Temerkhanov 
10122ffd87d3SSergey Temerkhanov 	/* check for more available section table entries */
10132ffd87d3SSergey Temerkhanov 	sect_count = le16_to_cpu(buf->section_count);
10142ffd87d3SSergey Temerkhanov 	if (sect_count < bld->reserved_section_table_entries) {
10152ffd87d3SSergey Temerkhanov 		void *section_ptr = ((u8 *)buf) + data_end;
10162ffd87d3SSergey Temerkhanov 
10172ffd87d3SSergey Temerkhanov 		buf->section_entry[sect_count].offset = cpu_to_le16(data_end);
10182ffd87d3SSergey Temerkhanov 		buf->section_entry[sect_count].size = cpu_to_le16(size);
10192ffd87d3SSergey Temerkhanov 		buf->section_entry[sect_count].type = cpu_to_le32(type);
10202ffd87d3SSergey Temerkhanov 
10212ffd87d3SSergey Temerkhanov 		data_end += size;
10222ffd87d3SSergey Temerkhanov 		buf->data_end = cpu_to_le16(data_end);
10232ffd87d3SSergey Temerkhanov 
10242ffd87d3SSergey Temerkhanov 		buf->section_count = cpu_to_le16(sect_count + 1);
10252ffd87d3SSergey Temerkhanov 		return section_ptr;
10262ffd87d3SSergey Temerkhanov 	}
10272ffd87d3SSergey Temerkhanov 
10282ffd87d3SSergey Temerkhanov 	/* no free section table entries */
10292ffd87d3SSergey Temerkhanov 	return NULL;
10302ffd87d3SSergey Temerkhanov }
10312ffd87d3SSergey Temerkhanov 
10322ffd87d3SSergey Temerkhanov /**
10332ffd87d3SSergey Temerkhanov  * ice_pkg_buf_alloc_single_section
10342ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
10352ffd87d3SSergey Temerkhanov  * @type: the section type value
10362ffd87d3SSergey Temerkhanov  * @size: the size of the section to reserve (in bytes)
10372ffd87d3SSergey Temerkhanov  * @section: returns pointer to the section
10382ffd87d3SSergey Temerkhanov  *
10392ffd87d3SSergey Temerkhanov  * Allocates a package buffer with a single section.
10402ffd87d3SSergey Temerkhanov  * Note: all package contents must be in Little Endian form.
10412ffd87d3SSergey Temerkhanov  */
10422ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc_single_section(struct ice_hw *hw,
10432ffd87d3SSergey Temerkhanov 						       u32 type, u16 size,
10442ffd87d3SSergey Temerkhanov 						       void **section)
10452ffd87d3SSergey Temerkhanov {
10462ffd87d3SSergey Temerkhanov 	struct ice_buf_build *buf;
10472ffd87d3SSergey Temerkhanov 
10482ffd87d3SSergey Temerkhanov 	if (!section)
10492ffd87d3SSergey Temerkhanov 		return NULL;
10502ffd87d3SSergey Temerkhanov 
10512ffd87d3SSergey Temerkhanov 	buf = ice_pkg_buf_alloc(hw);
10522ffd87d3SSergey Temerkhanov 	if (!buf)
10532ffd87d3SSergey Temerkhanov 		return NULL;
10542ffd87d3SSergey Temerkhanov 
10552ffd87d3SSergey Temerkhanov 	if (ice_pkg_buf_reserve_section(buf, 1))
10562ffd87d3SSergey Temerkhanov 		goto ice_pkg_buf_alloc_single_section_err;
10572ffd87d3SSergey Temerkhanov 
10582ffd87d3SSergey Temerkhanov 	*section = ice_pkg_buf_alloc_section(buf, type, size);
10592ffd87d3SSergey Temerkhanov 	if (!*section)
10602ffd87d3SSergey Temerkhanov 		goto ice_pkg_buf_alloc_single_section_err;
10612ffd87d3SSergey Temerkhanov 
10622ffd87d3SSergey Temerkhanov 	return buf;
10632ffd87d3SSergey Temerkhanov 
10642ffd87d3SSergey Temerkhanov ice_pkg_buf_alloc_single_section_err:
10652ffd87d3SSergey Temerkhanov 	ice_pkg_buf_free(hw, buf);
10662ffd87d3SSergey Temerkhanov 	return NULL;
10672ffd87d3SSergey Temerkhanov }
10682ffd87d3SSergey Temerkhanov 
10692ffd87d3SSergey Temerkhanov /**
10702ffd87d3SSergey Temerkhanov  * ice_pkg_buf_get_active_sections
10712ffd87d3SSergey Temerkhanov  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
10722ffd87d3SSergey Temerkhanov  *
10732ffd87d3SSergey Temerkhanov  * Returns the number of active sections. Before using the package buffer
10742ffd87d3SSergey Temerkhanov  * in an update package command, the caller should make sure that there is at
10752ffd87d3SSergey Temerkhanov  * least one active section - otherwise, the buffer is not legal and should
10762ffd87d3SSergey Temerkhanov  * not be used.
10772ffd87d3SSergey Temerkhanov  * Note: all package contents must be in Little Endian form.
10782ffd87d3SSergey Temerkhanov  */
10792ffd87d3SSergey Temerkhanov u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld)
10802ffd87d3SSergey Temerkhanov {
10812ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *buf;
10822ffd87d3SSergey Temerkhanov 
10832ffd87d3SSergey Temerkhanov 	if (!bld)
10842ffd87d3SSergey Temerkhanov 		return 0;
10852ffd87d3SSergey Temerkhanov 
10862ffd87d3SSergey Temerkhanov 	buf = (struct ice_buf_hdr *)&bld->buf;
10872ffd87d3SSergey Temerkhanov 	return le16_to_cpu(buf->section_count);
10882ffd87d3SSergey Temerkhanov }
10892ffd87d3SSergey Temerkhanov 
10902ffd87d3SSergey Temerkhanov /**
10912ffd87d3SSergey Temerkhanov  * ice_pkg_buf
10922ffd87d3SSergey Temerkhanov  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
10932ffd87d3SSergey Temerkhanov  *
10942ffd87d3SSergey Temerkhanov  * Return a pointer to the buffer's header
10952ffd87d3SSergey Temerkhanov  */
10962ffd87d3SSergey Temerkhanov struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
10972ffd87d3SSergey Temerkhanov {
10982ffd87d3SSergey Temerkhanov 	if (!bld)
10992ffd87d3SSergey Temerkhanov 		return NULL;
11002ffd87d3SSergey Temerkhanov 
11012ffd87d3SSergey Temerkhanov 	return &bld->buf;
11022ffd87d3SSergey Temerkhanov }
11032ffd87d3SSergey Temerkhanov 
11042ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_map_aq_err_to_ddp_state(enum ice_aq_err aq_err)
11052ffd87d3SSergey Temerkhanov {
11062ffd87d3SSergey Temerkhanov 	switch (aq_err) {
11072ffd87d3SSergey Temerkhanov 	case ICE_AQ_RC_ENOSEC:
11082ffd87d3SSergey Temerkhanov 	case ICE_AQ_RC_EBADSIG:
11092ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_FILE_SIGNATURE_INVALID;
11102ffd87d3SSergey Temerkhanov 	case ICE_AQ_RC_ESVN:
11112ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_FILE_REVISION_TOO_LOW;
11122ffd87d3SSergey Temerkhanov 	case ICE_AQ_RC_EBADMAN:
11132ffd87d3SSergey Temerkhanov 	case ICE_AQ_RC_EBADBUF:
11142ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_LOAD_ERROR;
11152ffd87d3SSergey Temerkhanov 	default:
11162ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
11172ffd87d3SSergey Temerkhanov 	}
11182ffd87d3SSergey Temerkhanov }
11192ffd87d3SSergey Temerkhanov 
11202ffd87d3SSergey Temerkhanov /**
11212ffd87d3SSergey Temerkhanov  * ice_acquire_global_cfg_lock
11222ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
11232ffd87d3SSergey Temerkhanov  * @access: access type (read or write)
11242ffd87d3SSergey Temerkhanov  *
11252ffd87d3SSergey Temerkhanov  * This function will request ownership of the global config lock for reading
11262ffd87d3SSergey Temerkhanov  * or writing of the package. When attempting to obtain write access, the
11272ffd87d3SSergey Temerkhanov  * caller must check for the following two return values:
11282ffd87d3SSergey Temerkhanov  *
11292ffd87d3SSergey Temerkhanov  * 0         -  Means the caller has acquired the global config lock
11302ffd87d3SSergey Temerkhanov  *              and can perform writing of the package.
11312ffd87d3SSergey Temerkhanov  * -EALREADY - Indicates another driver has already written the
11322ffd87d3SSergey Temerkhanov  *             package or has found that no update was necessary; in
11332ffd87d3SSergey Temerkhanov  *             this case, the caller can just skip performing any
11342ffd87d3SSergey Temerkhanov  *             update of the package.
11352ffd87d3SSergey Temerkhanov  */
11362ffd87d3SSergey Temerkhanov static int ice_acquire_global_cfg_lock(struct ice_hw *hw,
11372ffd87d3SSergey Temerkhanov 				       enum ice_aq_res_access_type access)
11382ffd87d3SSergey Temerkhanov {
11392ffd87d3SSergey Temerkhanov 	int status;
11402ffd87d3SSergey Temerkhanov 
11412ffd87d3SSergey Temerkhanov 	status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, access,
11422ffd87d3SSergey Temerkhanov 				 ICE_GLOBAL_CFG_LOCK_TIMEOUT);
11432ffd87d3SSergey Temerkhanov 
11442ffd87d3SSergey Temerkhanov 	if (!status)
11452ffd87d3SSergey Temerkhanov 		mutex_lock(&ice_global_cfg_lock_sw);
11462ffd87d3SSergey Temerkhanov 	else if (status == -EALREADY)
11472ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG,
11482ffd87d3SSergey Temerkhanov 			  "Global config lock: No work to do\n");
11492ffd87d3SSergey Temerkhanov 
11502ffd87d3SSergey Temerkhanov 	return status;
11512ffd87d3SSergey Temerkhanov }
11522ffd87d3SSergey Temerkhanov 
11532ffd87d3SSergey Temerkhanov /**
11542ffd87d3SSergey Temerkhanov  * ice_release_global_cfg_lock
11552ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
11562ffd87d3SSergey Temerkhanov  *
11572ffd87d3SSergey Temerkhanov  * This function will release the global config lock.
11582ffd87d3SSergey Temerkhanov  */
11592ffd87d3SSergey Temerkhanov static void ice_release_global_cfg_lock(struct ice_hw *hw)
11602ffd87d3SSergey Temerkhanov {
11612ffd87d3SSergey Temerkhanov 	mutex_unlock(&ice_global_cfg_lock_sw);
11622ffd87d3SSergey Temerkhanov 	ice_release_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID);
11632ffd87d3SSergey Temerkhanov }
11642ffd87d3SSergey Temerkhanov 
11652ffd87d3SSergey Temerkhanov /**
1166708b352fSJan Sokolowski  * ice_aq_download_pkg
1167708b352fSJan Sokolowski  * @hw: pointer to the hardware structure
1168708b352fSJan Sokolowski  * @pkg_buf: the package buffer to transfer
1169708b352fSJan Sokolowski  * @buf_size: the size of the package buffer
1170708b352fSJan Sokolowski  * @last_buf: last buffer indicator
1171708b352fSJan Sokolowski  * @error_offset: returns error offset
1172708b352fSJan Sokolowski  * @error_info: returns error information
1173708b352fSJan Sokolowski  * @cd: pointer to command details structure or NULL
1174708b352fSJan Sokolowski  *
1175708b352fSJan Sokolowski  * Download Package (0x0C40)
1176708b352fSJan Sokolowski  */
1177708b352fSJan Sokolowski static int
1178708b352fSJan Sokolowski ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
1179708b352fSJan Sokolowski 		    u16 buf_size, bool last_buf, u32 *error_offset,
1180708b352fSJan Sokolowski 		    u32 *error_info, struct ice_sq_cd *cd)
1181708b352fSJan Sokolowski {
1182708b352fSJan Sokolowski 	struct ice_aqc_download_pkg *cmd;
1183708b352fSJan Sokolowski 	struct ice_aq_desc desc;
1184708b352fSJan Sokolowski 	int status;
1185708b352fSJan Sokolowski 
1186708b352fSJan Sokolowski 	if (error_offset)
1187708b352fSJan Sokolowski 		*error_offset = 0;
1188708b352fSJan Sokolowski 	if (error_info)
1189708b352fSJan Sokolowski 		*error_info = 0;
1190708b352fSJan Sokolowski 
1191708b352fSJan Sokolowski 	cmd = &desc.params.download_pkg;
1192708b352fSJan Sokolowski 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg);
1193708b352fSJan Sokolowski 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1194708b352fSJan Sokolowski 
1195708b352fSJan Sokolowski 	if (last_buf)
1196708b352fSJan Sokolowski 		cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
1197708b352fSJan Sokolowski 
1198708b352fSJan Sokolowski 	status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
1199708b352fSJan Sokolowski 	if (status == -EIO) {
1200708b352fSJan Sokolowski 		/* Read error from buffer only when the FW returned an error */
1201708b352fSJan Sokolowski 		struct ice_aqc_download_pkg_resp *resp;
1202708b352fSJan Sokolowski 
1203708b352fSJan Sokolowski 		resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
1204708b352fSJan Sokolowski 		if (error_offset)
1205708b352fSJan Sokolowski 			*error_offset = le32_to_cpu(resp->error_offset);
1206708b352fSJan Sokolowski 		if (error_info)
1207708b352fSJan Sokolowski 			*error_info = le32_to_cpu(resp->error_info);
1208708b352fSJan Sokolowski 	}
1209708b352fSJan Sokolowski 
1210708b352fSJan Sokolowski 	return status;
1211708b352fSJan Sokolowski }
1212708b352fSJan Sokolowski 
1213708b352fSJan Sokolowski /**
12143cbdb034SDan Nowlin  * ice_get_pkg_seg_by_idx
12153cbdb034SDan Nowlin  * @pkg_hdr: pointer to the package header to be searched
12163cbdb034SDan Nowlin  * @idx: index of segment
12173cbdb034SDan Nowlin  */
12183cbdb034SDan Nowlin static struct ice_generic_seg_hdr *
12193cbdb034SDan Nowlin ice_get_pkg_seg_by_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx)
12203cbdb034SDan Nowlin {
12213cbdb034SDan Nowlin 	if (idx < le32_to_cpu(pkg_hdr->seg_count))
12223cbdb034SDan Nowlin 		return (struct ice_generic_seg_hdr *)
12233cbdb034SDan Nowlin 			((u8 *)pkg_hdr +
12243cbdb034SDan Nowlin 			 le32_to_cpu(pkg_hdr->seg_offset[idx]));
12253cbdb034SDan Nowlin 
12263cbdb034SDan Nowlin 	return NULL;
12273cbdb034SDan Nowlin }
12283cbdb034SDan Nowlin 
12293cbdb034SDan Nowlin /**
12303cbdb034SDan Nowlin  * ice_is_signing_seg_at_idx - determine if segment is a signing segment
12313cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
12323cbdb034SDan Nowlin  * @idx: segment index
12333cbdb034SDan Nowlin  */
12343cbdb034SDan Nowlin static bool ice_is_signing_seg_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx)
12353cbdb034SDan Nowlin {
12363cbdb034SDan Nowlin 	struct ice_generic_seg_hdr *seg;
12373cbdb034SDan Nowlin 
12383cbdb034SDan Nowlin 	seg = ice_get_pkg_seg_by_idx(pkg_hdr, idx);
12393cbdb034SDan Nowlin 	if (!seg)
12403cbdb034SDan Nowlin 		return false;
12413cbdb034SDan Nowlin 
12423cbdb034SDan Nowlin 	return le32_to_cpu(seg->seg_type) == SEGMENT_TYPE_SIGNING;
12433cbdb034SDan Nowlin }
12443cbdb034SDan Nowlin 
12453cbdb034SDan Nowlin /**
12463cbdb034SDan Nowlin  * ice_is_signing_seg_type_at_idx
12473cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
12483cbdb034SDan Nowlin  * @idx: segment index
12493cbdb034SDan Nowlin  * @seg_id: segment id that is expected
12503cbdb034SDan Nowlin  * @sign_type: signing type
12513cbdb034SDan Nowlin  *
12523cbdb034SDan Nowlin  * Determine if a segment is a signing segment of the correct type
12533cbdb034SDan Nowlin  */
12543cbdb034SDan Nowlin static bool
12553cbdb034SDan Nowlin ice_is_signing_seg_type_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx,
12563cbdb034SDan Nowlin 			       u32 seg_id, u32 sign_type)
12573cbdb034SDan Nowlin {
12583cbdb034SDan Nowlin 	struct ice_sign_seg *seg;
12593cbdb034SDan Nowlin 
12603cbdb034SDan Nowlin 	if (!ice_is_signing_seg_at_idx(pkg_hdr, idx))
12613cbdb034SDan Nowlin 		return false;
12623cbdb034SDan Nowlin 
12633cbdb034SDan Nowlin 	seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
12643cbdb034SDan Nowlin 
12653cbdb034SDan Nowlin 	if (seg && le32_to_cpu(seg->seg_id) == seg_id &&
12663cbdb034SDan Nowlin 	    le32_to_cpu(seg->sign_type) == sign_type)
12673cbdb034SDan Nowlin 		return true;
12683cbdb034SDan Nowlin 
12693cbdb034SDan Nowlin 	return false;
12703cbdb034SDan Nowlin }
12713cbdb034SDan Nowlin 
12723cbdb034SDan Nowlin /**
12733cbdb034SDan Nowlin  * ice_is_buffer_metadata - determine if package buffer is a metadata buffer
12743cbdb034SDan Nowlin  * @buf: pointer to buffer header
12753cbdb034SDan Nowlin  */
12763cbdb034SDan Nowlin static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf)
12773cbdb034SDan Nowlin {
12783cbdb034SDan Nowlin 	if (le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF)
12793cbdb034SDan Nowlin 		return true;
12803cbdb034SDan Nowlin 
12813cbdb034SDan Nowlin 	return false;
12823cbdb034SDan Nowlin }
12833cbdb034SDan Nowlin 
12843cbdb034SDan Nowlin /**
12853cbdb034SDan Nowlin  * ice_is_last_download_buffer
12863cbdb034SDan Nowlin  * @buf: pointer to current buffer header
12873cbdb034SDan Nowlin  * @idx: index of the buffer in the current sequence
12883cbdb034SDan Nowlin  * @count: the buffer count in the current sequence
12893cbdb034SDan Nowlin  *
12903cbdb034SDan Nowlin  * Note: this routine should only be called if the buffer is not the last buffer
12913cbdb034SDan Nowlin  */
12923cbdb034SDan Nowlin static bool
12933cbdb034SDan Nowlin ice_is_last_download_buffer(struct ice_buf_hdr *buf, u32 idx, u32 count)
12943cbdb034SDan Nowlin {
12953cbdb034SDan Nowlin 	struct ice_buf *next_buf;
12963cbdb034SDan Nowlin 
12973cbdb034SDan Nowlin 	if ((idx + 1) == count)
12983cbdb034SDan Nowlin 		return true;
12993cbdb034SDan Nowlin 
13003cbdb034SDan Nowlin 	/* A set metadata flag in the next buffer will signal that the current
13013cbdb034SDan Nowlin 	 * buffer will be the last buffer downloaded
13023cbdb034SDan Nowlin 	 */
13033cbdb034SDan Nowlin 	next_buf = ((struct ice_buf *)buf) + 1;
13043cbdb034SDan Nowlin 
13053cbdb034SDan Nowlin 	return ice_is_buffer_metadata((struct ice_buf_hdr *)next_buf);
13063cbdb034SDan Nowlin }
13073cbdb034SDan Nowlin 
13083cbdb034SDan Nowlin /**
13093cbdb034SDan Nowlin  * ice_dwnld_cfg_bufs_no_lock
13102ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
13112ffd87d3SSergey Temerkhanov  * @bufs: pointer to an array of buffers
13123cbdb034SDan Nowlin  * @start: buffer index of first buffer to download
13133cbdb034SDan Nowlin  * @count: the number of buffers to download
13143cbdb034SDan Nowlin  * @indicate_last: if true, then set last buffer flag on last buffer download
13152ffd87d3SSergey Temerkhanov  *
13163cbdb034SDan Nowlin  * Downloads package configuration buffers to the firmware. Metadata buffers
13173cbdb034SDan Nowlin  * are skipped, and the first metadata buffer found indicates that the rest
13183cbdb034SDan Nowlin  * of the buffers are all metadata buffers.
13192ffd87d3SSergey Temerkhanov  */
13203cbdb034SDan Nowlin static enum ice_ddp_state
13213cbdb034SDan Nowlin ice_dwnld_cfg_bufs_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 start,
13223cbdb034SDan Nowlin 			   u32 count, bool indicate_last)
13232ffd87d3SSergey Temerkhanov {
13242ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS;
13252ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *bh;
13262ffd87d3SSergey Temerkhanov 	enum ice_aq_err err;
13272ffd87d3SSergey Temerkhanov 	u32 offset, info, i;
13282ffd87d3SSergey Temerkhanov 
13292ffd87d3SSergey Temerkhanov 	if (!bufs || !count)
13302ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
13312ffd87d3SSergey Temerkhanov 
13322ffd87d3SSergey Temerkhanov 	/* If the first buffer's first section has its metadata bit set
13332ffd87d3SSergey Temerkhanov 	 * then there are no buffers to be downloaded, and the operation is
13342ffd87d3SSergey Temerkhanov 	 * considered a success.
13352ffd87d3SSergey Temerkhanov 	 */
13363cbdb034SDan Nowlin 	bh = (struct ice_buf_hdr *)(bufs + start);
13372ffd87d3SSergey Temerkhanov 	if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF)
13382ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_SUCCESS;
13392ffd87d3SSergey Temerkhanov 
13402ffd87d3SSergey Temerkhanov 	for (i = 0; i < count; i++) {
13413cbdb034SDan Nowlin 		bool last = false;
1342a27f6ac9SWojciech Drewek 		int try_cnt = 0;
13433cbdb034SDan Nowlin 		int status;
13442ffd87d3SSergey Temerkhanov 
13453cbdb034SDan Nowlin 		bh = (struct ice_buf_hdr *)(bufs + start + i);
13462ffd87d3SSergey Temerkhanov 
13473cbdb034SDan Nowlin 		if (indicate_last)
13483cbdb034SDan Nowlin 			last = ice_is_last_download_buffer(bh, i, count);
13492ffd87d3SSergey Temerkhanov 
1350a27f6ac9SWojciech Drewek 		while (1) {
1351a27f6ac9SWojciech Drewek 			status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE,
1352a27f6ac9SWojciech Drewek 						     last, &offset, &info,
1353a27f6ac9SWojciech Drewek 						     NULL);
1354a27f6ac9SWojciech Drewek 			if (hw->adminq.sq_last_status != ICE_AQ_RC_ENOSEC &&
1355a27f6ac9SWojciech Drewek 			    hw->adminq.sq_last_status != ICE_AQ_RC_EBADSIG)
1356a27f6ac9SWojciech Drewek 				break;
1357a27f6ac9SWojciech Drewek 
1358a27f6ac9SWojciech Drewek 			try_cnt++;
1359a27f6ac9SWojciech Drewek 
1360a27f6ac9SWojciech Drewek 			if (try_cnt == 5)
1361a27f6ac9SWojciech Drewek 				break;
1362a27f6ac9SWojciech Drewek 
1363a27f6ac9SWojciech Drewek 			msleep(20);
1364a27f6ac9SWojciech Drewek 		}
1365a27f6ac9SWojciech Drewek 
1366a27f6ac9SWojciech Drewek 		if (try_cnt)
1367a27f6ac9SWojciech Drewek 			dev_dbg(ice_hw_to_dev(hw),
1368a27f6ac9SWojciech Drewek 				"ice_aq_download_pkg number of retries: %d\n",
1369a27f6ac9SWojciech Drewek 				try_cnt);
13702ffd87d3SSergey Temerkhanov 
13712ffd87d3SSergey Temerkhanov 		/* Save AQ status from download package */
13722ffd87d3SSergey Temerkhanov 		if (status) {
13733cbdb034SDan Nowlin 			ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n",
13742ffd87d3SSergey Temerkhanov 				  status, offset, info);
13752ffd87d3SSergey Temerkhanov 			err = hw->adminq.sq_last_status;
13762ffd87d3SSergey Temerkhanov 			state = ice_map_aq_err_to_ddp_state(err);
13772ffd87d3SSergey Temerkhanov 			break;
13782ffd87d3SSergey Temerkhanov 		}
13792ffd87d3SSergey Temerkhanov 
13802ffd87d3SSergey Temerkhanov 		if (last)
13812ffd87d3SSergey Temerkhanov 			break;
13822ffd87d3SSergey Temerkhanov 	}
13832ffd87d3SSergey Temerkhanov 
13843cbdb034SDan Nowlin 	return state;
13852ffd87d3SSergey Temerkhanov }
13862ffd87d3SSergey Temerkhanov 
13873cbdb034SDan Nowlin /**
13883cbdb034SDan Nowlin  * ice_download_pkg_sig_seg - download a signature segment
13893cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
13903cbdb034SDan Nowlin  * @seg: pointer to signature segment
13913cbdb034SDan Nowlin  */
13923cbdb034SDan Nowlin static enum ice_ddp_state
13933cbdb034SDan Nowlin ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg)
13943cbdb034SDan Nowlin {
13953cbdb034SDan Nowlin 	return  ice_dwnld_cfg_bufs_no_lock(hw, seg->buf_tbl.buf_array, 0,
13963cbdb034SDan Nowlin 					   le32_to_cpu(seg->buf_tbl.buf_count),
13973cbdb034SDan Nowlin 					   false);
13983cbdb034SDan Nowlin }
13993cbdb034SDan Nowlin 
14003cbdb034SDan Nowlin /**
14013cbdb034SDan Nowlin  * ice_download_pkg_config_seg - download a config segment
14023cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
14033cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
14043cbdb034SDan Nowlin  * @idx: segment index
14053cbdb034SDan Nowlin  * @start: starting buffer
14063cbdb034SDan Nowlin  * @count: buffer count
14073cbdb034SDan Nowlin  *
14083cbdb034SDan Nowlin  * Note: idx must reference a ICE segment
14093cbdb034SDan Nowlin  */
14103cbdb034SDan Nowlin static enum ice_ddp_state
14113cbdb034SDan Nowlin ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
14123cbdb034SDan Nowlin 			    u32 idx, u32 start, u32 count)
14133cbdb034SDan Nowlin {
14143cbdb034SDan Nowlin 	struct ice_buf_table *bufs;
14153cbdb034SDan Nowlin 	struct ice_seg *seg;
14163cbdb034SDan Nowlin 	u32 buf_count;
14173cbdb034SDan Nowlin 
14183cbdb034SDan Nowlin 	seg = (struct ice_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
14193cbdb034SDan Nowlin 	if (!seg)
14203cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
14213cbdb034SDan Nowlin 
14223cbdb034SDan Nowlin 	bufs = ice_find_buf_table(seg);
14233cbdb034SDan Nowlin 	buf_count = le32_to_cpu(bufs->buf_count);
14243cbdb034SDan Nowlin 
14253cbdb034SDan Nowlin 	if (start >= buf_count || start + count > buf_count)
14263cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
14273cbdb034SDan Nowlin 
14283cbdb034SDan Nowlin 	return  ice_dwnld_cfg_bufs_no_lock(hw, bufs->buf_array, start, count,
14293cbdb034SDan Nowlin 					   true);
14303cbdb034SDan Nowlin }
14313cbdb034SDan Nowlin 
14323cbdb034SDan Nowlin /**
14333cbdb034SDan Nowlin  * ice_dwnld_sign_and_cfg_segs - download a signing segment and config segment
14343cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
14353cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
14363cbdb034SDan Nowlin  * @idx: segment index (must be a signature segment)
14373cbdb034SDan Nowlin  *
14383cbdb034SDan Nowlin  * Note: idx must reference a signature segment
14393cbdb034SDan Nowlin  */
14403cbdb034SDan Nowlin static enum ice_ddp_state
14413cbdb034SDan Nowlin ice_dwnld_sign_and_cfg_segs(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
14423cbdb034SDan Nowlin 			    u32 idx)
14433cbdb034SDan Nowlin {
14443cbdb034SDan Nowlin 	enum ice_ddp_state state;
14453cbdb034SDan Nowlin 	struct ice_sign_seg *seg;
14463cbdb034SDan Nowlin 	u32 conf_idx;
14473cbdb034SDan Nowlin 	u32 start;
14483cbdb034SDan Nowlin 	u32 count;
14493cbdb034SDan Nowlin 
14503cbdb034SDan Nowlin 	seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
14513cbdb034SDan Nowlin 	if (!seg) {
14523cbdb034SDan Nowlin 		state = ICE_DDP_PKG_ERR;
14533cbdb034SDan Nowlin 		goto exit;
14543cbdb034SDan Nowlin 	}
14553cbdb034SDan Nowlin 
14566d51d44eSDan Nowlin 	count = le32_to_cpu(seg->signed_buf_count);
14576d51d44eSDan Nowlin 	state = ice_download_pkg_sig_seg(hw, seg);
14586d51d44eSDan Nowlin 	if (state || !count)
14596d51d44eSDan Nowlin 		goto exit;
14606d51d44eSDan Nowlin 
14613cbdb034SDan Nowlin 	conf_idx = le32_to_cpu(seg->signed_seg_idx);
14623cbdb034SDan Nowlin 	start = le32_to_cpu(seg->signed_buf_start);
14633cbdb034SDan Nowlin 
14643cbdb034SDan Nowlin 	state = ice_download_pkg_config_seg(hw, pkg_hdr, conf_idx, start,
14653cbdb034SDan Nowlin 					    count);
14663cbdb034SDan Nowlin 
14673cbdb034SDan Nowlin exit:
14683cbdb034SDan Nowlin 	return state;
14693cbdb034SDan Nowlin }
14703cbdb034SDan Nowlin 
14713cbdb034SDan Nowlin /**
14723cbdb034SDan Nowlin  * ice_match_signing_seg - determine if a matching signing segment exists
14733cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
14743cbdb034SDan Nowlin  * @seg_id: segment id that is expected
14753cbdb034SDan Nowlin  * @sign_type: signing type
14763cbdb034SDan Nowlin  */
14773cbdb034SDan Nowlin static bool
14783cbdb034SDan Nowlin ice_match_signing_seg(struct ice_pkg_hdr *pkg_hdr, u32 seg_id, u32 sign_type)
14793cbdb034SDan Nowlin {
14803cbdb034SDan Nowlin 	u32 i;
14813cbdb034SDan Nowlin 
14823cbdb034SDan Nowlin 	for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) {
14833cbdb034SDan Nowlin 		if (ice_is_signing_seg_type_at_idx(pkg_hdr, i, seg_id,
14843cbdb034SDan Nowlin 						   sign_type))
14853cbdb034SDan Nowlin 			return true;
14863cbdb034SDan Nowlin 	}
14873cbdb034SDan Nowlin 
14883cbdb034SDan Nowlin 	return false;
14893cbdb034SDan Nowlin }
14903cbdb034SDan Nowlin 
14913cbdb034SDan Nowlin /**
14923cbdb034SDan Nowlin  * ice_post_dwnld_pkg_actions - perform post download package actions
14933cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
14943cbdb034SDan Nowlin  */
14953cbdb034SDan Nowlin static enum ice_ddp_state
14963cbdb034SDan Nowlin ice_post_dwnld_pkg_actions(struct ice_hw *hw)
14973cbdb034SDan Nowlin {
14983cbdb034SDan Nowlin 	int status;
14993cbdb034SDan Nowlin 
15003cbdb034SDan Nowlin 	status = ice_set_vlan_mode(hw);
15013cbdb034SDan Nowlin 	if (status) {
15023cbdb034SDan Nowlin 		ice_debug(hw, ICE_DBG_PKG, "Failed to set VLAN mode: err %d\n",
15033cbdb034SDan Nowlin 			  status);
15043cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
15053cbdb034SDan Nowlin 	}
15063cbdb034SDan Nowlin 
15073cbdb034SDan Nowlin 	return ICE_DDP_PKG_SUCCESS;
15083cbdb034SDan Nowlin }
15093cbdb034SDan Nowlin 
15103cbdb034SDan Nowlin /**
1511a778616eSDan Nowlin  * ice_download_pkg_with_sig_seg
15123cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
15133cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
15143cbdb034SDan Nowlin  *
15153cbdb034SDan Nowlin  * Handles the download of a complete package.
15163cbdb034SDan Nowlin  */
15173cbdb034SDan Nowlin static enum ice_ddp_state
1518a778616eSDan Nowlin ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
15193cbdb034SDan Nowlin {
15203cbdb034SDan Nowlin 	enum ice_aq_err aq_err = hw->adminq.sq_last_status;
15213cbdb034SDan Nowlin 	enum ice_ddp_state state = ICE_DDP_PKG_ERR;
15223cbdb034SDan Nowlin 	int status;
15233cbdb034SDan Nowlin 	u32 i;
15243cbdb034SDan Nowlin 
15253cbdb034SDan Nowlin 	ice_debug(hw, ICE_DBG_INIT, "Segment ID %d\n", hw->pkg_seg_id);
15263cbdb034SDan Nowlin 	ice_debug(hw, ICE_DBG_INIT, "Signature type %d\n", hw->pkg_sign_type);
15273cbdb034SDan Nowlin 
15283cbdb034SDan Nowlin 	status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
15293cbdb034SDan Nowlin 	if (status) {
15303cbdb034SDan Nowlin 		if (status == -EALREADY)
15313cbdb034SDan Nowlin 			state = ICE_DDP_PKG_ALREADY_LOADED;
15323cbdb034SDan Nowlin 		else
15333cbdb034SDan Nowlin 			state = ice_map_aq_err_to_ddp_state(aq_err);
15343cbdb034SDan Nowlin 		return state;
15353cbdb034SDan Nowlin 	}
15363cbdb034SDan Nowlin 
15373cbdb034SDan Nowlin 	for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) {
15383cbdb034SDan Nowlin 		if (!ice_is_signing_seg_type_at_idx(pkg_hdr, i, hw->pkg_seg_id,
15393cbdb034SDan Nowlin 						    hw->pkg_sign_type))
15403cbdb034SDan Nowlin 			continue;
15413cbdb034SDan Nowlin 
15423cbdb034SDan Nowlin 		state = ice_dwnld_sign_and_cfg_segs(hw, pkg_hdr, i);
15433cbdb034SDan Nowlin 		if (state)
15443cbdb034SDan Nowlin 			break;
15453cbdb034SDan Nowlin 	}
15463cbdb034SDan Nowlin 
15473cbdb034SDan Nowlin 	if (!state)
15483cbdb034SDan Nowlin 		state = ice_post_dwnld_pkg_actions(hw);
15493cbdb034SDan Nowlin 
15502ffd87d3SSergey Temerkhanov 	ice_release_global_cfg_lock(hw);
1551a778616eSDan Nowlin 
1552a778616eSDan Nowlin 	return state;
1553a778616eSDan Nowlin }
1554a778616eSDan Nowlin 
1555a778616eSDan Nowlin /**
1556a778616eSDan Nowlin  * ice_dwnld_cfg_bufs
1557a778616eSDan Nowlin  * @hw: pointer to the hardware structure
1558a778616eSDan Nowlin  * @bufs: pointer to an array of buffers
1559a778616eSDan Nowlin  * @count: the number of buffers in the array
1560a778616eSDan Nowlin  *
1561a778616eSDan Nowlin  * Obtains global config lock and downloads the package configuration buffers
1562a778616eSDan Nowlin  * to the firmware.
1563a778616eSDan Nowlin  */
1564a778616eSDan Nowlin static enum ice_ddp_state
1565a778616eSDan Nowlin ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
1566a778616eSDan Nowlin {
1567a778616eSDan Nowlin 	enum ice_ddp_state state;
1568a778616eSDan Nowlin 	struct ice_buf_hdr *bh;
1569a778616eSDan Nowlin 	int status;
1570a778616eSDan Nowlin 
1571a778616eSDan Nowlin 	if (!bufs || !count)
1572a778616eSDan Nowlin 		return ICE_DDP_PKG_ERR;
1573a778616eSDan Nowlin 
1574a778616eSDan Nowlin 	/* If the first buffer's first section has its metadata bit set
1575a778616eSDan Nowlin 	 * then there are no buffers to be downloaded, and the operation is
1576a778616eSDan Nowlin 	 * considered a success.
1577a778616eSDan Nowlin 	 */
1578a778616eSDan Nowlin 	bh = (struct ice_buf_hdr *)bufs;
1579a778616eSDan Nowlin 	if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF)
1580a778616eSDan Nowlin 		return ICE_DDP_PKG_SUCCESS;
1581a778616eSDan Nowlin 
1582a778616eSDan Nowlin 	status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
1583a778616eSDan Nowlin 	if (status) {
1584a778616eSDan Nowlin 		if (status == -EALREADY)
1585a778616eSDan Nowlin 			return ICE_DDP_PKG_ALREADY_LOADED;
1586a778616eSDan Nowlin 		return ice_map_aq_err_to_ddp_state(hw->adminq.sq_last_status);
1587a778616eSDan Nowlin 	}
1588a778616eSDan Nowlin 
1589a778616eSDan Nowlin 	state = ice_dwnld_cfg_bufs_no_lock(hw, bufs, 0, count, true);
1590a778616eSDan Nowlin 	if (!state)
1591a778616eSDan Nowlin 		state = ice_post_dwnld_pkg_actions(hw);
1592a778616eSDan Nowlin 
1593a778616eSDan Nowlin 	ice_release_global_cfg_lock(hw);
1594a778616eSDan Nowlin 
1595a778616eSDan Nowlin 	return state;
1596a778616eSDan Nowlin }
1597a778616eSDan Nowlin 
1598a778616eSDan Nowlin /**
1599a778616eSDan Nowlin  * ice_download_pkg_without_sig_seg
1600a778616eSDan Nowlin  * @hw: pointer to the hardware structure
1601a778616eSDan Nowlin  * @ice_seg: pointer to the segment of the package to be downloaded
1602a778616eSDan Nowlin  *
1603a778616eSDan Nowlin  * Handles the download of a complete package without signature segment.
1604a778616eSDan Nowlin  */
1605a778616eSDan Nowlin static enum ice_ddp_state
1606a778616eSDan Nowlin ice_download_pkg_without_sig_seg(struct ice_hw *hw, struct ice_seg *ice_seg)
1607a778616eSDan Nowlin {
1608a778616eSDan Nowlin 	struct ice_buf_table *ice_buf_tbl;
1609a778616eSDan Nowlin 
1610a778616eSDan Nowlin 	ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n",
1611a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.major,
1612a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.minor,
1613a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.update,
1614a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.draft);
1615a778616eSDan Nowlin 
1616a778616eSDan Nowlin 	ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n",
1617a778616eSDan Nowlin 		  le32_to_cpu(ice_seg->hdr.seg_type),
1618a778616eSDan Nowlin 		  le32_to_cpu(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id);
1619a778616eSDan Nowlin 
1620a778616eSDan Nowlin 	ice_buf_tbl = ice_find_buf_table(ice_seg);
1621a778616eSDan Nowlin 
1622a778616eSDan Nowlin 	ice_debug(hw, ICE_DBG_PKG, "Seg buf count: %d\n",
1623a778616eSDan Nowlin 		  le32_to_cpu(ice_buf_tbl->buf_count));
1624a778616eSDan Nowlin 
1625a778616eSDan Nowlin 	return ice_dwnld_cfg_bufs(hw, ice_buf_tbl->buf_array,
1626a778616eSDan Nowlin 				  le32_to_cpu(ice_buf_tbl->buf_count));
1627a778616eSDan Nowlin }
1628a778616eSDan Nowlin 
1629a778616eSDan Nowlin /**
1630a778616eSDan Nowlin  * ice_download_pkg
1631a778616eSDan Nowlin  * @hw: pointer to the hardware structure
1632a778616eSDan Nowlin  * @pkg_hdr: pointer to package header
1633a778616eSDan Nowlin  * @ice_seg: pointer to the segment of the package to be downloaded
1634a778616eSDan Nowlin  *
1635a778616eSDan Nowlin  * Handles the download of a complete package.
1636a778616eSDan Nowlin  */
1637a778616eSDan Nowlin static enum ice_ddp_state
1638a778616eSDan Nowlin ice_download_pkg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
1639a778616eSDan Nowlin 		 struct ice_seg *ice_seg)
1640a778616eSDan Nowlin {
1641a778616eSDan Nowlin 	enum ice_ddp_state state;
1642a778616eSDan Nowlin 
1643a778616eSDan Nowlin 	if (hw->pkg_has_signing_seg)
1644a778616eSDan Nowlin 		state = ice_download_pkg_with_sig_seg(hw, pkg_hdr);
1645a778616eSDan Nowlin 	else
1646a778616eSDan Nowlin 		state = ice_download_pkg_without_sig_seg(hw, ice_seg);
1647a778616eSDan Nowlin 
16483cbdb034SDan Nowlin 	ice_post_pkg_dwnld_vlan_mode_cfg(hw);
16492ffd87d3SSergey Temerkhanov 
16502ffd87d3SSergey Temerkhanov 	return state;
16512ffd87d3SSergey Temerkhanov }
16522ffd87d3SSergey Temerkhanov 
16532ffd87d3SSergey Temerkhanov /**
16542ffd87d3SSergey Temerkhanov  * ice_aq_get_pkg_info_list
16552ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
16562ffd87d3SSergey Temerkhanov  * @pkg_info: the buffer which will receive the information list
16572ffd87d3SSergey Temerkhanov  * @buf_size: the size of the pkg_info information buffer
16582ffd87d3SSergey Temerkhanov  * @cd: pointer to command details structure or NULL
16592ffd87d3SSergey Temerkhanov  *
16602ffd87d3SSergey Temerkhanov  * Get Package Info List (0x0C43)
16612ffd87d3SSergey Temerkhanov  */
16622ffd87d3SSergey Temerkhanov static int ice_aq_get_pkg_info_list(struct ice_hw *hw,
16632ffd87d3SSergey Temerkhanov 				    struct ice_aqc_get_pkg_info_resp *pkg_info,
16642ffd87d3SSergey Temerkhanov 				    u16 buf_size, struct ice_sq_cd *cd)
16652ffd87d3SSergey Temerkhanov {
16662ffd87d3SSergey Temerkhanov 	struct ice_aq_desc desc;
16672ffd87d3SSergey Temerkhanov 
16682ffd87d3SSergey Temerkhanov 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list);
16692ffd87d3SSergey Temerkhanov 
16702ffd87d3SSergey Temerkhanov 	return ice_aq_send_cmd(hw, &desc, pkg_info, buf_size, cd);
16712ffd87d3SSergey Temerkhanov }
16722ffd87d3SSergey Temerkhanov 
16732ffd87d3SSergey Temerkhanov /**
16742ffd87d3SSergey Temerkhanov  * ice_aq_update_pkg
16752ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
16762ffd87d3SSergey Temerkhanov  * @pkg_buf: the package cmd buffer
16772ffd87d3SSergey Temerkhanov  * @buf_size: the size of the package cmd buffer
16782ffd87d3SSergey Temerkhanov  * @last_buf: last buffer indicator
16792ffd87d3SSergey Temerkhanov  * @error_offset: returns error offset
16802ffd87d3SSergey Temerkhanov  * @error_info: returns error information
16812ffd87d3SSergey Temerkhanov  * @cd: pointer to command details structure or NULL
16822ffd87d3SSergey Temerkhanov  *
16832ffd87d3SSergey Temerkhanov  * Update Package (0x0C42)
16842ffd87d3SSergey Temerkhanov  */
16852ffd87d3SSergey Temerkhanov static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
16862ffd87d3SSergey Temerkhanov 			     u16 buf_size, bool last_buf, u32 *error_offset,
16872ffd87d3SSergey Temerkhanov 			     u32 *error_info, struct ice_sq_cd *cd)
16882ffd87d3SSergey Temerkhanov {
16892ffd87d3SSergey Temerkhanov 	struct ice_aqc_download_pkg *cmd;
16902ffd87d3SSergey Temerkhanov 	struct ice_aq_desc desc;
16912ffd87d3SSergey Temerkhanov 	int status;
16922ffd87d3SSergey Temerkhanov 
16932ffd87d3SSergey Temerkhanov 	if (error_offset)
16942ffd87d3SSergey Temerkhanov 		*error_offset = 0;
16952ffd87d3SSergey Temerkhanov 	if (error_info)
16962ffd87d3SSergey Temerkhanov 		*error_info = 0;
16972ffd87d3SSergey Temerkhanov 
16982ffd87d3SSergey Temerkhanov 	cmd = &desc.params.download_pkg;
16992ffd87d3SSergey Temerkhanov 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg);
17002ffd87d3SSergey Temerkhanov 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
17012ffd87d3SSergey Temerkhanov 
17022ffd87d3SSergey Temerkhanov 	if (last_buf)
17032ffd87d3SSergey Temerkhanov 		cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
17042ffd87d3SSergey Temerkhanov 
17052ffd87d3SSergey Temerkhanov 	status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
17062ffd87d3SSergey Temerkhanov 	if (status == -EIO) {
17072ffd87d3SSergey Temerkhanov 		/* Read error from buffer only when the FW returned an error */
17082ffd87d3SSergey Temerkhanov 		struct ice_aqc_download_pkg_resp *resp;
17092ffd87d3SSergey Temerkhanov 
17102ffd87d3SSergey Temerkhanov 		resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
17112ffd87d3SSergey Temerkhanov 		if (error_offset)
17122ffd87d3SSergey Temerkhanov 			*error_offset = le32_to_cpu(resp->error_offset);
17132ffd87d3SSergey Temerkhanov 		if (error_info)
17142ffd87d3SSergey Temerkhanov 			*error_info = le32_to_cpu(resp->error_info);
17152ffd87d3SSergey Temerkhanov 	}
17162ffd87d3SSergey Temerkhanov 
17172ffd87d3SSergey Temerkhanov 	return status;
17182ffd87d3SSergey Temerkhanov }
17192ffd87d3SSergey Temerkhanov 
17202ffd87d3SSergey Temerkhanov /**
1721708b352fSJan Sokolowski  * ice_aq_upload_section
1722708b352fSJan Sokolowski  * @hw: pointer to the hardware structure
1723708b352fSJan Sokolowski  * @pkg_buf: the package buffer which will receive the section
1724708b352fSJan Sokolowski  * @buf_size: the size of the package buffer
1725708b352fSJan Sokolowski  * @cd: pointer to command details structure or NULL
1726708b352fSJan Sokolowski  *
1727708b352fSJan Sokolowski  * Upload Section (0x0C41)
1728708b352fSJan Sokolowski  */
1729708b352fSJan Sokolowski int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
1730708b352fSJan Sokolowski 			  u16 buf_size, struct ice_sq_cd *cd)
1731708b352fSJan Sokolowski {
1732708b352fSJan Sokolowski 	struct ice_aq_desc desc;
1733708b352fSJan Sokolowski 
1734708b352fSJan Sokolowski 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section);
1735708b352fSJan Sokolowski 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1736708b352fSJan Sokolowski 
1737708b352fSJan Sokolowski 	return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
1738708b352fSJan Sokolowski }
1739708b352fSJan Sokolowski 
1740708b352fSJan Sokolowski /**
17412ffd87d3SSergey Temerkhanov  * ice_update_pkg_no_lock
17422ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
17432ffd87d3SSergey Temerkhanov  * @bufs: pointer to an array of buffers
17442ffd87d3SSergey Temerkhanov  * @count: the number of buffers in the array
17452ffd87d3SSergey Temerkhanov  */
17462ffd87d3SSergey Temerkhanov int ice_update_pkg_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
17472ffd87d3SSergey Temerkhanov {
17482ffd87d3SSergey Temerkhanov 	int status = 0;
17492ffd87d3SSergey Temerkhanov 	u32 i;
17502ffd87d3SSergey Temerkhanov 
17512ffd87d3SSergey Temerkhanov 	for (i = 0; i < count; i++) {
17522ffd87d3SSergey Temerkhanov 		struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i);
17532ffd87d3SSergey Temerkhanov 		bool last = ((i + 1) == count);
17542ffd87d3SSergey Temerkhanov 		u32 offset, info;
17552ffd87d3SSergey Temerkhanov 
17562ffd87d3SSergey Temerkhanov 		status = ice_aq_update_pkg(hw, bh, le16_to_cpu(bh->data_end),
17572ffd87d3SSergey Temerkhanov 					   last, &offset, &info, NULL);
17582ffd87d3SSergey Temerkhanov 
17592ffd87d3SSergey Temerkhanov 		if (status) {
17602ffd87d3SSergey Temerkhanov 			ice_debug(hw, ICE_DBG_PKG,
17612ffd87d3SSergey Temerkhanov 				  "Update pkg failed: err %d off %d inf %d\n",
17622ffd87d3SSergey Temerkhanov 				  status, offset, info);
17632ffd87d3SSergey Temerkhanov 			break;
17642ffd87d3SSergey Temerkhanov 		}
17652ffd87d3SSergey Temerkhanov 	}
17662ffd87d3SSergey Temerkhanov 
17672ffd87d3SSergey Temerkhanov 	return status;
17682ffd87d3SSergey Temerkhanov }
17692ffd87d3SSergey Temerkhanov 
17702ffd87d3SSergey Temerkhanov /**
17712ffd87d3SSergey Temerkhanov  * ice_update_pkg
17722ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
17732ffd87d3SSergey Temerkhanov  * @bufs: pointer to an array of buffers
17742ffd87d3SSergey Temerkhanov  * @count: the number of buffers in the array
17752ffd87d3SSergey Temerkhanov  *
17762ffd87d3SSergey Temerkhanov  * Obtains change lock and updates package.
17772ffd87d3SSergey Temerkhanov  */
17782ffd87d3SSergey Temerkhanov int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
17792ffd87d3SSergey Temerkhanov {
17802ffd87d3SSergey Temerkhanov 	int status;
17812ffd87d3SSergey Temerkhanov 
17822ffd87d3SSergey Temerkhanov 	status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
17832ffd87d3SSergey Temerkhanov 	if (status)
17842ffd87d3SSergey Temerkhanov 		return status;
17852ffd87d3SSergey Temerkhanov 
17862ffd87d3SSergey Temerkhanov 	status = ice_update_pkg_no_lock(hw, bufs, count);
17872ffd87d3SSergey Temerkhanov 
17882ffd87d3SSergey Temerkhanov 	ice_release_change_lock(hw);
17892ffd87d3SSergey Temerkhanov 
17902ffd87d3SSergey Temerkhanov 	return status;
17912ffd87d3SSergey Temerkhanov }
17922ffd87d3SSergey Temerkhanov 
17932ffd87d3SSergey Temerkhanov /**
17942ffd87d3SSergey Temerkhanov  * ice_find_seg_in_pkg
17952ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
17962ffd87d3SSergey Temerkhanov  * @seg_type: the segment type to search for (i.e., SEGMENT_TYPE_CPK)
17972ffd87d3SSergey Temerkhanov  * @pkg_hdr: pointer to the package header to be searched
17982ffd87d3SSergey Temerkhanov  *
17992ffd87d3SSergey Temerkhanov  * This function searches a package file for a particular segment type. On
18002ffd87d3SSergey Temerkhanov  * success it returns a pointer to the segment header, otherwise it will
18012ffd87d3SSergey Temerkhanov  * return NULL.
18022ffd87d3SSergey Temerkhanov  */
1803708b352fSJan Sokolowski static struct ice_generic_seg_hdr *
1804708b352fSJan Sokolowski ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
18052ffd87d3SSergey Temerkhanov 		    struct ice_pkg_hdr *pkg_hdr)
18062ffd87d3SSergey Temerkhanov {
18072ffd87d3SSergey Temerkhanov 	u32 i;
18082ffd87d3SSergey Temerkhanov 
18092ffd87d3SSergey Temerkhanov 	ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n",
18102ffd87d3SSergey Temerkhanov 		  pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor,
18112ffd87d3SSergey Temerkhanov 		  pkg_hdr->pkg_format_ver.update,
18122ffd87d3SSergey Temerkhanov 		  pkg_hdr->pkg_format_ver.draft);
18132ffd87d3SSergey Temerkhanov 
18142ffd87d3SSergey Temerkhanov 	/* Search all package segments for the requested segment type */
18152ffd87d3SSergey Temerkhanov 	for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) {
18162ffd87d3SSergey Temerkhanov 		struct ice_generic_seg_hdr *seg;
18172ffd87d3SSergey Temerkhanov 
18182ffd87d3SSergey Temerkhanov 		seg = (struct ice_generic_seg_hdr
18192ffd87d3SSergey Temerkhanov 			       *)((u8 *)pkg_hdr +
18202ffd87d3SSergey Temerkhanov 				  le32_to_cpu(pkg_hdr->seg_offset[i]));
18212ffd87d3SSergey Temerkhanov 
18222ffd87d3SSergey Temerkhanov 		if (le32_to_cpu(seg->seg_type) == seg_type)
18232ffd87d3SSergey Temerkhanov 			return seg;
18242ffd87d3SSergey Temerkhanov 	}
18252ffd87d3SSergey Temerkhanov 
18262ffd87d3SSergey Temerkhanov 	return NULL;
18272ffd87d3SSergey Temerkhanov }
18282ffd87d3SSergey Temerkhanov 
18292ffd87d3SSergey Temerkhanov /**
18303cbdb034SDan Nowlin  * ice_has_signing_seg - determine if package has a signing segment
18313cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
18323cbdb034SDan Nowlin  * @pkg_hdr: pointer to the driver's package hdr
18333cbdb034SDan Nowlin  */
18343cbdb034SDan Nowlin static bool ice_has_signing_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
18353cbdb034SDan Nowlin {
18363cbdb034SDan Nowlin 	struct ice_generic_seg_hdr *seg_hdr;
18373cbdb034SDan Nowlin 
18383cbdb034SDan Nowlin 	seg_hdr = (struct ice_generic_seg_hdr *)
18393cbdb034SDan Nowlin 		ice_find_seg_in_pkg(hw, SEGMENT_TYPE_SIGNING, pkg_hdr);
18403cbdb034SDan Nowlin 
18413cbdb034SDan Nowlin 	return seg_hdr ? true : false;
18423cbdb034SDan Nowlin }
18433cbdb034SDan Nowlin 
18443cbdb034SDan Nowlin /**
18453cbdb034SDan Nowlin  * ice_get_pkg_segment_id - get correct package segment id, based on device
18463cbdb034SDan Nowlin  * @mac_type: MAC type of the device
18473cbdb034SDan Nowlin  */
18483cbdb034SDan Nowlin static u32 ice_get_pkg_segment_id(enum ice_mac_type mac_type)
18493cbdb034SDan Nowlin {
18503cbdb034SDan Nowlin 	u32 seg_id;
18513cbdb034SDan Nowlin 
18523cbdb034SDan Nowlin 	switch (mac_type) {
18533cbdb034SDan Nowlin 	case ICE_MAC_E830:
18543cbdb034SDan Nowlin 		seg_id = SEGMENT_TYPE_ICE_E830;
18553cbdb034SDan Nowlin 		break;
18563cbdb034SDan Nowlin 	case ICE_MAC_GENERIC:
1857372e27deSGrzegorz Nitka 	case ICE_MAC_GENERIC_3K_E825:
18583cbdb034SDan Nowlin 	default:
18593cbdb034SDan Nowlin 		seg_id = SEGMENT_TYPE_ICE_E810;
18603cbdb034SDan Nowlin 		break;
18613cbdb034SDan Nowlin 	}
18623cbdb034SDan Nowlin 
18633cbdb034SDan Nowlin 	return seg_id;
18643cbdb034SDan Nowlin }
18653cbdb034SDan Nowlin 
18663cbdb034SDan Nowlin /**
18673cbdb034SDan Nowlin  * ice_get_pkg_sign_type - get package segment sign type, based on device
18683cbdb034SDan Nowlin  * @mac_type: MAC type of the device
18693cbdb034SDan Nowlin  */
18703cbdb034SDan Nowlin static u32 ice_get_pkg_sign_type(enum ice_mac_type mac_type)
18713cbdb034SDan Nowlin {
18723cbdb034SDan Nowlin 	u32 sign_type;
18733cbdb034SDan Nowlin 
18743cbdb034SDan Nowlin 	switch (mac_type) {
18753cbdb034SDan Nowlin 	case ICE_MAC_E830:
18763cbdb034SDan Nowlin 		sign_type = SEGMENT_SIGN_TYPE_RSA3K_SBB;
18773cbdb034SDan Nowlin 		break;
1878372e27deSGrzegorz Nitka 	case ICE_MAC_GENERIC_3K_E825:
1879372e27deSGrzegorz Nitka 		sign_type = SEGMENT_SIGN_TYPE_RSA3K_E825;
1880372e27deSGrzegorz Nitka 		break;
18813cbdb034SDan Nowlin 	case ICE_MAC_GENERIC:
18823cbdb034SDan Nowlin 	default:
18833cbdb034SDan Nowlin 		sign_type = SEGMENT_SIGN_TYPE_RSA2K;
18843cbdb034SDan Nowlin 		break;
18853cbdb034SDan Nowlin 	}
18863cbdb034SDan Nowlin 
18873cbdb034SDan Nowlin 	return sign_type;
18883cbdb034SDan Nowlin }
18893cbdb034SDan Nowlin 
18903cbdb034SDan Nowlin /**
18913cbdb034SDan Nowlin  * ice_get_signing_req - get correct package requirements, based on device
18923cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
18933cbdb034SDan Nowlin  */
18943cbdb034SDan Nowlin static void ice_get_signing_req(struct ice_hw *hw)
18953cbdb034SDan Nowlin {
18963cbdb034SDan Nowlin 	hw->pkg_seg_id = ice_get_pkg_segment_id(hw->mac_type);
18973cbdb034SDan Nowlin 	hw->pkg_sign_type = ice_get_pkg_sign_type(hw->mac_type);
18983cbdb034SDan Nowlin }
18993cbdb034SDan Nowlin 
19003cbdb034SDan Nowlin /**
19012ffd87d3SSergey Temerkhanov  * ice_init_pkg_info
19022ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
19032ffd87d3SSergey Temerkhanov  * @pkg_hdr: pointer to the driver's package hdr
19042ffd87d3SSergey Temerkhanov  *
19052ffd87d3SSergey Temerkhanov  * Saves off the package details into the HW structure.
19062ffd87d3SSergey Temerkhanov  */
19072ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_init_pkg_info(struct ice_hw *hw,
19082ffd87d3SSergey Temerkhanov 					    struct ice_pkg_hdr *pkg_hdr)
19092ffd87d3SSergey Temerkhanov {
19102ffd87d3SSergey Temerkhanov 	struct ice_generic_seg_hdr *seg_hdr;
19112ffd87d3SSergey Temerkhanov 
19122ffd87d3SSergey Temerkhanov 	if (!pkg_hdr)
19132ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
19142ffd87d3SSergey Temerkhanov 
19153cbdb034SDan Nowlin 	hw->pkg_has_signing_seg = ice_has_signing_seg(hw, pkg_hdr);
19163cbdb034SDan Nowlin 	ice_get_signing_req(hw);
19173cbdb034SDan Nowlin 
19183cbdb034SDan Nowlin 	ice_debug(hw, ICE_DBG_INIT, "Pkg using segment id: 0x%08X\n",
19193cbdb034SDan Nowlin 		  hw->pkg_seg_id);
19203cbdb034SDan Nowlin 
19213cbdb034SDan Nowlin 	seg_hdr = (struct ice_generic_seg_hdr *)
19223cbdb034SDan Nowlin 		ice_find_seg_in_pkg(hw, hw->pkg_seg_id, pkg_hdr);
19232ffd87d3SSergey Temerkhanov 	if (seg_hdr) {
19242ffd87d3SSergey Temerkhanov 		struct ice_meta_sect *meta;
19252ffd87d3SSergey Temerkhanov 		struct ice_pkg_enum state;
19262ffd87d3SSergey Temerkhanov 
19272ffd87d3SSergey Temerkhanov 		memset(&state, 0, sizeof(state));
19282ffd87d3SSergey Temerkhanov 
19292ffd87d3SSergey Temerkhanov 		/* Get package information from the Metadata Section */
19302ffd87d3SSergey Temerkhanov 		meta = ice_pkg_enum_section((struct ice_seg *)seg_hdr, &state,
19312ffd87d3SSergey Temerkhanov 					    ICE_SID_METADATA);
19322ffd87d3SSergey Temerkhanov 		if (!meta) {
19332ffd87d3SSergey Temerkhanov 			ice_debug(hw, ICE_DBG_INIT,
19342ffd87d3SSergey Temerkhanov 				  "Did not find ice metadata section in package\n");
19352ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_INVALID_FILE;
19362ffd87d3SSergey Temerkhanov 		}
19372ffd87d3SSergey Temerkhanov 
19382ffd87d3SSergey Temerkhanov 		hw->pkg_ver = meta->ver;
19392ffd87d3SSergey Temerkhanov 		memcpy(hw->pkg_name, meta->name, sizeof(meta->name));
19402ffd87d3SSergey Temerkhanov 
19412ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG, "Pkg: %d.%d.%d.%d, %s\n",
19422ffd87d3SSergey Temerkhanov 			  meta->ver.major, meta->ver.minor, meta->ver.update,
19432ffd87d3SSergey Temerkhanov 			  meta->ver.draft, meta->name);
19442ffd87d3SSergey Temerkhanov 
19452ffd87d3SSergey Temerkhanov 		hw->ice_seg_fmt_ver = seg_hdr->seg_format_ver;
19462ffd87d3SSergey Temerkhanov 		memcpy(hw->ice_seg_id, seg_hdr->seg_id, sizeof(hw->ice_seg_id));
19472ffd87d3SSergey Temerkhanov 
19482ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n",
19492ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.major,
19502ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.minor,
19512ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.update,
19522ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.draft, seg_hdr->seg_id);
19532ffd87d3SSergey Temerkhanov 	} else {
19542ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT,
19552ffd87d3SSergey Temerkhanov 			  "Did not find ice segment in driver package\n");
19562ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
19572ffd87d3SSergey Temerkhanov 	}
19582ffd87d3SSergey Temerkhanov 
19592ffd87d3SSergey Temerkhanov 	return ICE_DDP_PKG_SUCCESS;
19602ffd87d3SSergey Temerkhanov }
19612ffd87d3SSergey Temerkhanov 
19622ffd87d3SSergey Temerkhanov /**
19632ffd87d3SSergey Temerkhanov  * ice_get_pkg_info
19642ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
19652ffd87d3SSergey Temerkhanov  *
19662ffd87d3SSergey Temerkhanov  * Store details of the package currently loaded in HW into the HW structure.
19672ffd87d3SSergey Temerkhanov  */
19682ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw)
19692ffd87d3SSergey Temerkhanov {
1970d8e45f29SKees Cook 	DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg_info, pkg_info,
1971230064baSPrzemek Kitszel 			ICE_PKG_CNT);
1972230064baSPrzemek Kitszel 	u16 size = __struct_size(pkg_info);
19732ffd87d3SSergey Temerkhanov 	u32 i;
19742ffd87d3SSergey Temerkhanov 
1975230064baSPrzemek Kitszel 	if (ice_aq_get_pkg_info_list(hw, pkg_info, size, NULL))
19762ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
19772ffd87d3SSergey Temerkhanov 
19782ffd87d3SSergey Temerkhanov 	for (i = 0; i < le32_to_cpu(pkg_info->count); i++) {
19792ffd87d3SSergey Temerkhanov #define ICE_PKG_FLAG_COUNT 4
19802ffd87d3SSergey Temerkhanov 		char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 };
19812ffd87d3SSergey Temerkhanov 		u8 place = 0;
19822ffd87d3SSergey Temerkhanov 
19832ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_active) {
19842ffd87d3SSergey Temerkhanov 			flags[place++] = 'A';
19852ffd87d3SSergey Temerkhanov 			hw->active_pkg_ver = pkg_info->pkg_info[i].ver;
19862ffd87d3SSergey Temerkhanov 			hw->active_track_id =
19872ffd87d3SSergey Temerkhanov 				le32_to_cpu(pkg_info->pkg_info[i].track_id);
19882ffd87d3SSergey Temerkhanov 			memcpy(hw->active_pkg_name, pkg_info->pkg_info[i].name,
19892ffd87d3SSergey Temerkhanov 			       sizeof(pkg_info->pkg_info[i].name));
19902ffd87d3SSergey Temerkhanov 			hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm;
19912ffd87d3SSergey Temerkhanov 		}
19922ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_active_at_boot)
19932ffd87d3SSergey Temerkhanov 			flags[place++] = 'B';
19942ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_modified)
19952ffd87d3SSergey Temerkhanov 			flags[place++] = 'M';
19962ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_in_nvm)
19972ffd87d3SSergey Temerkhanov 			flags[place++] = 'N';
19982ffd87d3SSergey Temerkhanov 
19992ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG, "Pkg[%d]: %d.%d.%d.%d,%s,%s\n", i,
20002ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.major,
20012ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.minor,
20022ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.update,
20032ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.draft,
20042ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].name, flags);
20052ffd87d3SSergey Temerkhanov 	}
20062ffd87d3SSergey Temerkhanov 
2007230064baSPrzemek Kitszel 	return ICE_DDP_PKG_SUCCESS;
20082ffd87d3SSergey Temerkhanov }
20092ffd87d3SSergey Temerkhanov 
20102ffd87d3SSergey Temerkhanov /**
20112ffd87d3SSergey Temerkhanov  * ice_chk_pkg_compat
20122ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
20132ffd87d3SSergey Temerkhanov  * @ospkg: pointer to the package hdr
20142ffd87d3SSergey Temerkhanov  * @seg: pointer to the package segment hdr
20152ffd87d3SSergey Temerkhanov  *
20162ffd87d3SSergey Temerkhanov  * This function checks the package version compatibility with driver and NVM
20172ffd87d3SSergey Temerkhanov  */
20182ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_compat(struct ice_hw *hw,
20192ffd87d3SSergey Temerkhanov 					     struct ice_pkg_hdr *ospkg,
20202ffd87d3SSergey Temerkhanov 					     struct ice_seg **seg)
20212ffd87d3SSergey Temerkhanov {
2022d8e45f29SKees Cook 	DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg, pkg_info,
2023230064baSPrzemek Kitszel 			ICE_PKG_CNT);
2024230064baSPrzemek Kitszel 	u16 size = __struct_size(pkg);
20252ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state;
20262ffd87d3SSergey Temerkhanov 	u32 i;
20272ffd87d3SSergey Temerkhanov 
20282ffd87d3SSergey Temerkhanov 	/* Check package version compatibility */
20292ffd87d3SSergey Temerkhanov 	state = ice_chk_pkg_version(&hw->pkg_ver);
20302ffd87d3SSergey Temerkhanov 	if (state) {
20312ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n");
20322ffd87d3SSergey Temerkhanov 		return state;
20332ffd87d3SSergey Temerkhanov 	}
20342ffd87d3SSergey Temerkhanov 
20352ffd87d3SSergey Temerkhanov 	/* find ICE segment in given package */
20363cbdb034SDan Nowlin 	*seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, hw->pkg_seg_id,
20372ffd87d3SSergey Temerkhanov 						     ospkg);
20382ffd87d3SSergey Temerkhanov 	if (!*seg) {
20392ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n");
20402ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
20412ffd87d3SSergey Temerkhanov 	}
20422ffd87d3SSergey Temerkhanov 
20432ffd87d3SSergey Temerkhanov 	/* Check if FW is compatible with the OS package */
2044230064baSPrzemek Kitszel 	if (ice_aq_get_pkg_info_list(hw, pkg, size, NULL))
2045230064baSPrzemek Kitszel 		return ICE_DDP_PKG_LOAD_ERROR;
20462ffd87d3SSergey Temerkhanov 
20472ffd87d3SSergey Temerkhanov 	for (i = 0; i < le32_to_cpu(pkg->count); i++) {
20482ffd87d3SSergey Temerkhanov 		/* loop till we find the NVM package */
20492ffd87d3SSergey Temerkhanov 		if (!pkg->pkg_info[i].is_in_nvm)
20502ffd87d3SSergey Temerkhanov 			continue;
20512ffd87d3SSergey Temerkhanov 		if ((*seg)->hdr.seg_format_ver.major !=
20522ffd87d3SSergey Temerkhanov 			    pkg->pkg_info[i].ver.major ||
20532ffd87d3SSergey Temerkhanov 		    (*seg)->hdr.seg_format_ver.minor >
20542ffd87d3SSergey Temerkhanov 			    pkg->pkg_info[i].ver.minor) {
20552ffd87d3SSergey Temerkhanov 			state = ICE_DDP_PKG_FW_MISMATCH;
20562ffd87d3SSergey Temerkhanov 			ice_debug(hw, ICE_DBG_INIT,
20572ffd87d3SSergey Temerkhanov 				  "OS package is not compatible with NVM.\n");
20582ffd87d3SSergey Temerkhanov 		}
20592ffd87d3SSergey Temerkhanov 		/* done processing NVM package so break */
20602ffd87d3SSergey Temerkhanov 		break;
20612ffd87d3SSergey Temerkhanov 	}
2062230064baSPrzemek Kitszel 
20632ffd87d3SSergey Temerkhanov 	return state;
20642ffd87d3SSergey Temerkhanov }
20652ffd87d3SSergey Temerkhanov 
20662ffd87d3SSergey Temerkhanov /**
20672ffd87d3SSergey Temerkhanov  * ice_init_pkg_hints
20682ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
20692ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the segment of the package scan (non-NULL)
20702ffd87d3SSergey Temerkhanov  *
20712ffd87d3SSergey Temerkhanov  * This function will scan the package and save off relevant information
20722ffd87d3SSergey Temerkhanov  * (hints or metadata) for driver use. The ice_seg parameter must not be NULL
20732ffd87d3SSergey Temerkhanov  * since the first call to ice_enum_labels requires a pointer to an actual
20742ffd87d3SSergey Temerkhanov  * ice_seg structure.
20752ffd87d3SSergey Temerkhanov  */
20762ffd87d3SSergey Temerkhanov static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg)
20772ffd87d3SSergey Temerkhanov {
20782ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
20792ffd87d3SSergey Temerkhanov 	char *label_name;
20802ffd87d3SSergey Temerkhanov 	u16 val;
20812ffd87d3SSergey Temerkhanov 	int i;
20822ffd87d3SSergey Temerkhanov 
20832ffd87d3SSergey Temerkhanov 	memset(&hw->tnl, 0, sizeof(hw->tnl));
20842ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
20852ffd87d3SSergey Temerkhanov 
20862ffd87d3SSergey Temerkhanov 	if (!ice_seg)
20872ffd87d3SSergey Temerkhanov 		return;
20882ffd87d3SSergey Temerkhanov 
20892ffd87d3SSergey Temerkhanov 	label_name = ice_enum_labels(ice_seg, ICE_SID_LBL_RXPARSER_TMEM, &state,
20902ffd87d3SSergey Temerkhanov 				     &val);
20912ffd87d3SSergey Temerkhanov 
20922ffd87d3SSergey Temerkhanov 	while (label_name) {
20932ffd87d3SSergey Temerkhanov 		if (!strncmp(label_name, ICE_TNL_PRE, strlen(ICE_TNL_PRE)))
20942ffd87d3SSergey Temerkhanov 			/* check for a tunnel entry */
20952ffd87d3SSergey Temerkhanov 			ice_add_tunnel_hint(hw, label_name, val);
20962ffd87d3SSergey Temerkhanov 
20972ffd87d3SSergey Temerkhanov 		/* check for a dvm mode entry */
20982ffd87d3SSergey Temerkhanov 		else if (!strncmp(label_name, ICE_DVM_PRE, strlen(ICE_DVM_PRE)))
20992ffd87d3SSergey Temerkhanov 			ice_add_dvm_hint(hw, val, true);
21002ffd87d3SSergey Temerkhanov 
21012ffd87d3SSergey Temerkhanov 		/* check for a svm mode entry */
21022ffd87d3SSergey Temerkhanov 		else if (!strncmp(label_name, ICE_SVM_PRE, strlen(ICE_SVM_PRE)))
21032ffd87d3SSergey Temerkhanov 			ice_add_dvm_hint(hw, val, false);
21042ffd87d3SSergey Temerkhanov 
21052ffd87d3SSergey Temerkhanov 		label_name = ice_enum_labels(NULL, 0, &state, &val);
21062ffd87d3SSergey Temerkhanov 	}
21072ffd87d3SSergey Temerkhanov 
21082ffd87d3SSergey Temerkhanov 	/* Cache the appropriate boost TCAM entry pointers for tunnels */
21092ffd87d3SSergey Temerkhanov 	for (i = 0; i < hw->tnl.count; i++) {
21102ffd87d3SSergey Temerkhanov 		ice_find_boost_entry(ice_seg, hw->tnl.tbl[i].boost_addr,
21112ffd87d3SSergey Temerkhanov 				     &hw->tnl.tbl[i].boost_entry);
21122ffd87d3SSergey Temerkhanov 		if (hw->tnl.tbl[i].boost_entry) {
21132ffd87d3SSergey Temerkhanov 			hw->tnl.tbl[i].valid = true;
21142ffd87d3SSergey Temerkhanov 			if (hw->tnl.tbl[i].type < __TNL_TYPE_CNT)
21152ffd87d3SSergey Temerkhanov 				hw->tnl.valid_count[hw->tnl.tbl[i].type]++;
21162ffd87d3SSergey Temerkhanov 		}
21172ffd87d3SSergey Temerkhanov 	}
21182ffd87d3SSergey Temerkhanov 
21192ffd87d3SSergey Temerkhanov 	/* Cache the appropriate boost TCAM entry pointers for DVM and SVM */
21202ffd87d3SSergey Temerkhanov 	for (i = 0; i < hw->dvm_upd.count; i++)
21212ffd87d3SSergey Temerkhanov 		ice_find_boost_entry(ice_seg, hw->dvm_upd.tbl[i].boost_addr,
21222ffd87d3SSergey Temerkhanov 				     &hw->dvm_upd.tbl[i].boost_entry);
21232ffd87d3SSergey Temerkhanov }
21242ffd87d3SSergey Temerkhanov 
21252ffd87d3SSergey Temerkhanov /**
21262ffd87d3SSergey Temerkhanov  * ice_fill_hw_ptype - fill the enabled PTYPE bit information
21272ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
21282ffd87d3SSergey Temerkhanov  */
21292ffd87d3SSergey Temerkhanov static void ice_fill_hw_ptype(struct ice_hw *hw)
21302ffd87d3SSergey Temerkhanov {
21312ffd87d3SSergey Temerkhanov 	struct ice_marker_ptype_tcam_entry *tcam;
21322ffd87d3SSergey Temerkhanov 	struct ice_seg *seg = hw->seg;
21332ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
21342ffd87d3SSergey Temerkhanov 
21352ffd87d3SSergey Temerkhanov 	bitmap_zero(hw->hw_ptype, ICE_FLOW_PTYPE_MAX);
21362ffd87d3SSergey Temerkhanov 	if (!seg)
21372ffd87d3SSergey Temerkhanov 		return;
21382ffd87d3SSergey Temerkhanov 
21392ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
21402ffd87d3SSergey Temerkhanov 
21412ffd87d3SSergey Temerkhanov 	do {
21422ffd87d3SSergey Temerkhanov 		tcam = ice_pkg_enum_entry(seg, &state,
21432ffd87d3SSergey Temerkhanov 					  ICE_SID_RXPARSER_MARKER_PTYPE, NULL,
21442ffd87d3SSergey Temerkhanov 					  ice_marker_ptype_tcam_handler);
21452ffd87d3SSergey Temerkhanov 		if (tcam &&
21462ffd87d3SSergey Temerkhanov 		    le16_to_cpu(tcam->addr) < ICE_MARKER_PTYPE_TCAM_ADDR_MAX &&
21472ffd87d3SSergey Temerkhanov 		    le16_to_cpu(tcam->ptype) < ICE_FLOW_PTYPE_MAX)
21482ffd87d3SSergey Temerkhanov 			set_bit(le16_to_cpu(tcam->ptype), hw->hw_ptype);
21492ffd87d3SSergey Temerkhanov 
21502ffd87d3SSergey Temerkhanov 		seg = NULL;
21512ffd87d3SSergey Temerkhanov 	} while (tcam);
21522ffd87d3SSergey Temerkhanov }
21532ffd87d3SSergey Temerkhanov 
21542ffd87d3SSergey Temerkhanov /**
21552ffd87d3SSergey Temerkhanov  * ice_init_pkg - initialize/download package
21562ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
21572ffd87d3SSergey Temerkhanov  * @buf: pointer to the package buffer
21582ffd87d3SSergey Temerkhanov  * @len: size of the package buffer
21592ffd87d3SSergey Temerkhanov  *
21602ffd87d3SSergey Temerkhanov  * This function initializes a package. The package contains HW tables
21612ffd87d3SSergey Temerkhanov  * required to do packet processing. First, the function extracts package
21622ffd87d3SSergey Temerkhanov  * information such as version. Then it finds the ice configuration segment
21632ffd87d3SSergey Temerkhanov  * within the package; this function then saves a copy of the segment pointer
21642ffd87d3SSergey Temerkhanov  * within the supplied package buffer. Next, the function will cache any hints
21652ffd87d3SSergey Temerkhanov  * from the package, followed by downloading the package itself. Note, that if
21662ffd87d3SSergey Temerkhanov  * a previous PF driver has already downloaded the package successfully, then
21672ffd87d3SSergey Temerkhanov  * the current driver will not have to download the package again.
21682ffd87d3SSergey Temerkhanov  *
21692ffd87d3SSergey Temerkhanov  * The local package contents will be used to query default behavior and to
21702ffd87d3SSergey Temerkhanov  * update specific sections of the HW's version of the package (e.g. to update
21712ffd87d3SSergey Temerkhanov  * the parse graph to understand new protocols).
21722ffd87d3SSergey Temerkhanov  *
21732ffd87d3SSergey Temerkhanov  * This function stores a pointer to the package buffer memory, and it is
21742ffd87d3SSergey Temerkhanov  * expected that the supplied buffer will not be freed immediately. If the
21752ffd87d3SSergey Temerkhanov  * package buffer needs to be freed, such as when read from a file, use
21762ffd87d3SSergey Temerkhanov  * ice_copy_and_init_pkg() instead of directly calling ice_init_pkg() in this
21772ffd87d3SSergey Temerkhanov  * case.
21782ffd87d3SSergey Temerkhanov  */
21792ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len)
21802ffd87d3SSergey Temerkhanov {
21812ffd87d3SSergey Temerkhanov 	bool already_loaded = false;
21822ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state;
21832ffd87d3SSergey Temerkhanov 	struct ice_pkg_hdr *pkg;
21842ffd87d3SSergey Temerkhanov 	struct ice_seg *seg;
21852ffd87d3SSergey Temerkhanov 
21862ffd87d3SSergey Temerkhanov 	if (!buf || !len)
21872ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
21882ffd87d3SSergey Temerkhanov 
21892ffd87d3SSergey Temerkhanov 	pkg = (struct ice_pkg_hdr *)buf;
21902ffd87d3SSergey Temerkhanov 	state = ice_verify_pkg(pkg, len);
21912ffd87d3SSergey Temerkhanov 	if (state) {
21922ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n",
21932ffd87d3SSergey Temerkhanov 			  state);
21942ffd87d3SSergey Temerkhanov 		return state;
21952ffd87d3SSergey Temerkhanov 	}
21962ffd87d3SSergey Temerkhanov 
21972ffd87d3SSergey Temerkhanov 	/* initialize package info */
21982ffd87d3SSergey Temerkhanov 	state = ice_init_pkg_info(hw, pkg);
21992ffd87d3SSergey Temerkhanov 	if (state)
22002ffd87d3SSergey Temerkhanov 		return state;
22012ffd87d3SSergey Temerkhanov 
22023cbdb034SDan Nowlin 	/* must be a matching segment */
22033cbdb034SDan Nowlin 	if (hw->pkg_has_signing_seg &&
22043cbdb034SDan Nowlin 	    !ice_match_signing_seg(pkg, hw->pkg_seg_id, hw->pkg_sign_type))
22053cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
22063cbdb034SDan Nowlin 
22072ffd87d3SSergey Temerkhanov 	/* before downloading the package, check package version for
22082ffd87d3SSergey Temerkhanov 	 * compatibility with driver
22092ffd87d3SSergey Temerkhanov 	 */
22102ffd87d3SSergey Temerkhanov 	state = ice_chk_pkg_compat(hw, pkg, &seg);
22112ffd87d3SSergey Temerkhanov 	if (state)
22122ffd87d3SSergey Temerkhanov 		return state;
22132ffd87d3SSergey Temerkhanov 
22142ffd87d3SSergey Temerkhanov 	/* initialize package hints and then download package */
22152ffd87d3SSergey Temerkhanov 	ice_init_pkg_hints(hw, seg);
2216a778616eSDan Nowlin 	state = ice_download_pkg(hw, pkg, seg);
22172ffd87d3SSergey Temerkhanov 	if (state == ICE_DDP_PKG_ALREADY_LOADED) {
22182ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT,
22192ffd87d3SSergey Temerkhanov 			  "package previously loaded - no work.\n");
22202ffd87d3SSergey Temerkhanov 		already_loaded = true;
22212ffd87d3SSergey Temerkhanov 	}
22222ffd87d3SSergey Temerkhanov 
22232ffd87d3SSergey Temerkhanov 	/* Get information on the package currently loaded in HW, then make sure
22242ffd87d3SSergey Temerkhanov 	 * the driver is compatible with this version.
22252ffd87d3SSergey Temerkhanov 	 */
22262ffd87d3SSergey Temerkhanov 	if (!state || state == ICE_DDP_PKG_ALREADY_LOADED) {
22272ffd87d3SSergey Temerkhanov 		state = ice_get_pkg_info(hw);
22282ffd87d3SSergey Temerkhanov 		if (!state)
22292ffd87d3SSergey Temerkhanov 			state = ice_get_ddp_pkg_state(hw, already_loaded);
22302ffd87d3SSergey Temerkhanov 	}
22312ffd87d3SSergey Temerkhanov 
22322ffd87d3SSergey Temerkhanov 	if (ice_is_init_pkg_successful(state)) {
22332ffd87d3SSergey Temerkhanov 		hw->seg = seg;
22342ffd87d3SSergey Temerkhanov 		/* on successful package download update other required
22352ffd87d3SSergey Temerkhanov 		 * registers to support the package and fill HW tables
22362ffd87d3SSergey Temerkhanov 		 * with package content.
22372ffd87d3SSergey Temerkhanov 		 */
22382ffd87d3SSergey Temerkhanov 		ice_init_pkg_regs(hw);
22392ffd87d3SSergey Temerkhanov 		ice_fill_blk_tbls(hw);
22402ffd87d3SSergey Temerkhanov 		ice_fill_hw_ptype(hw);
22412ffd87d3SSergey Temerkhanov 		ice_get_prof_index_max(hw);
22422ffd87d3SSergey Temerkhanov 	} else {
22432ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n", state);
22442ffd87d3SSergey Temerkhanov 	}
22452ffd87d3SSergey Temerkhanov 
22462ffd87d3SSergey Temerkhanov 	return state;
22472ffd87d3SSergey Temerkhanov }
22482ffd87d3SSergey Temerkhanov 
22492ffd87d3SSergey Temerkhanov /**
22502ffd87d3SSergey Temerkhanov  * ice_copy_and_init_pkg - initialize/download a copy of the package
22512ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
22522ffd87d3SSergey Temerkhanov  * @buf: pointer to the package buffer
22532ffd87d3SSergey Temerkhanov  * @len: size of the package buffer
22542ffd87d3SSergey Temerkhanov  *
22552ffd87d3SSergey Temerkhanov  * This function copies the package buffer, and then calls ice_init_pkg() to
22562ffd87d3SSergey Temerkhanov  * initialize the copied package contents.
22572ffd87d3SSergey Temerkhanov  *
22582ffd87d3SSergey Temerkhanov  * The copying is necessary if the package buffer supplied is constant, or if
22592ffd87d3SSergey Temerkhanov  * the memory may disappear shortly after calling this function.
22602ffd87d3SSergey Temerkhanov  *
22612ffd87d3SSergey Temerkhanov  * If the package buffer resides in the data segment and can be modified, the
22622ffd87d3SSergey Temerkhanov  * caller is free to use ice_init_pkg() instead of ice_copy_and_init_pkg().
22632ffd87d3SSergey Temerkhanov  *
22642ffd87d3SSergey Temerkhanov  * However, if the package buffer needs to be copied first, such as when being
22652ffd87d3SSergey Temerkhanov  * read from a file, the caller should use ice_copy_and_init_pkg().
22662ffd87d3SSergey Temerkhanov  *
22672ffd87d3SSergey Temerkhanov  * This function will first copy the package buffer, before calling
22682ffd87d3SSergey Temerkhanov  * ice_init_pkg(). The caller is free to immediately destroy the original
22692ffd87d3SSergey Temerkhanov  * package buffer, as the new copy will be managed by this function and
22702ffd87d3SSergey Temerkhanov  * related routines.
22712ffd87d3SSergey Temerkhanov  */
22722ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf,
22732ffd87d3SSergey Temerkhanov 					 u32 len)
22742ffd87d3SSergey Temerkhanov {
22752ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state;
22762ffd87d3SSergey Temerkhanov 	u8 *buf_copy;
22772ffd87d3SSergey Temerkhanov 
22782ffd87d3SSergey Temerkhanov 	if (!buf || !len)
22792ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
22802ffd87d3SSergey Temerkhanov 
22812ffd87d3SSergey Temerkhanov 	buf_copy = devm_kmemdup(ice_hw_to_dev(hw), buf, len, GFP_KERNEL);
22822ffd87d3SSergey Temerkhanov 
22832ffd87d3SSergey Temerkhanov 	state = ice_init_pkg(hw, buf_copy, len);
22842ffd87d3SSergey Temerkhanov 	if (!ice_is_init_pkg_successful(state)) {
22852ffd87d3SSergey Temerkhanov 		/* Free the copy, since we failed to initialize the package */
22862ffd87d3SSergey Temerkhanov 		devm_kfree(ice_hw_to_dev(hw), buf_copy);
22872ffd87d3SSergey Temerkhanov 	} else {
22882ffd87d3SSergey Temerkhanov 		/* Track the copied pkg so we can free it later */
22892ffd87d3SSergey Temerkhanov 		hw->pkg_copy = buf_copy;
22902ffd87d3SSergey Temerkhanov 		hw->pkg_size = len;
22912ffd87d3SSergey Temerkhanov 	}
22922ffd87d3SSergey Temerkhanov 
22932ffd87d3SSergey Temerkhanov 	return state;
22942ffd87d3SSergey Temerkhanov }
229591427e6dSRaj Victor 
229691427e6dSRaj Victor /**
229791427e6dSRaj Victor  * ice_get_set_tx_topo - get or set Tx topology
229891427e6dSRaj Victor  * @hw: pointer to the HW struct
229991427e6dSRaj Victor  * @buf: pointer to Tx topology buffer
230091427e6dSRaj Victor  * @buf_size: buffer size
230191427e6dSRaj Victor  * @cd: pointer to command details structure or NULL
230291427e6dSRaj Victor  * @flags: pointer to descriptor flags
230391427e6dSRaj Victor  * @set: 0-get, 1-set topology
230491427e6dSRaj Victor  *
230591427e6dSRaj Victor  * The function will get or set Tx topology
230691427e6dSRaj Victor  *
230791427e6dSRaj Victor  * Return: zero when set was successful, negative values otherwise.
230891427e6dSRaj Victor  */
230991427e6dSRaj Victor static int
231091427e6dSRaj Victor ice_get_set_tx_topo(struct ice_hw *hw, u8 *buf, u16 buf_size,
231191427e6dSRaj Victor 		    struct ice_sq_cd *cd, u8 *flags, bool set)
231291427e6dSRaj Victor {
231391427e6dSRaj Victor 	struct ice_aqc_get_set_tx_topo *cmd;
231491427e6dSRaj Victor 	struct ice_aq_desc desc;
231591427e6dSRaj Victor 	int status;
231691427e6dSRaj Victor 
231791427e6dSRaj Victor 	cmd = &desc.params.get_set_tx_topo;
231891427e6dSRaj Victor 	if (set) {
231991427e6dSRaj Victor 		ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_tx_topo);
232091427e6dSRaj Victor 		cmd->set_flags = ICE_AQC_TX_TOPO_FLAGS_ISSUED;
232191427e6dSRaj Victor 		/* requested to update a new topology, not a default topology */
232291427e6dSRaj Victor 		if (buf)
232391427e6dSRaj Victor 			cmd->set_flags |= ICE_AQC_TX_TOPO_FLAGS_SRC_RAM |
232491427e6dSRaj Victor 					  ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW;
232591427e6dSRaj Victor 
232691427e6dSRaj Victor 		if (ice_is_e825c(hw))
232791427e6dSRaj Victor 			desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
232891427e6dSRaj Victor 	} else {
232991427e6dSRaj Victor 		ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_tx_topo);
233091427e6dSRaj Victor 		cmd->get_flags = ICE_AQC_TX_TOPO_GET_RAM;
233191427e6dSRaj Victor 	}
233291427e6dSRaj Victor 
233391427e6dSRaj Victor 	if (!ice_is_e825c(hw))
233491427e6dSRaj Victor 		desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
233591427e6dSRaj Victor 
233691427e6dSRaj Victor 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
233791427e6dSRaj Victor 	if (status)
233891427e6dSRaj Victor 		return status;
233991427e6dSRaj Victor 	/* read the return flag values (first byte) for get operation */
234091427e6dSRaj Victor 	if (!set && flags)
234191427e6dSRaj Victor 		*flags = desc.params.get_set_tx_topo.set_flags;
234291427e6dSRaj Victor 
234391427e6dSRaj Victor 	return 0;
234491427e6dSRaj Victor }
234591427e6dSRaj Victor 
234691427e6dSRaj Victor /**
234791427e6dSRaj Victor  * ice_cfg_tx_topo - Initialize new Tx topology if available
234891427e6dSRaj Victor  * @hw: pointer to the HW struct
234991427e6dSRaj Victor  * @buf: pointer to Tx topology buffer
235091427e6dSRaj Victor  * @len: buffer size
235191427e6dSRaj Victor  *
235291427e6dSRaj Victor  * The function will apply the new Tx topology from the package buffer
235391427e6dSRaj Victor  * if available.
235491427e6dSRaj Victor  *
235591427e6dSRaj Victor  * Return: zero when update was successful, negative values otherwise.
235691427e6dSRaj Victor  */
235791427e6dSRaj Victor int ice_cfg_tx_topo(struct ice_hw *hw, u8 *buf, u32 len)
235891427e6dSRaj Victor {
235991427e6dSRaj Victor 	u8 *current_topo, *new_topo = NULL;
236091427e6dSRaj Victor 	struct ice_run_time_cfg_seg *seg;
236191427e6dSRaj Victor 	struct ice_buf_hdr *section;
236291427e6dSRaj Victor 	struct ice_pkg_hdr *pkg_hdr;
236391427e6dSRaj Victor 	enum ice_ddp_state state;
236491427e6dSRaj Victor 	u16 offset, size = 0;
236591427e6dSRaj Victor 	u32 reg = 0;
236691427e6dSRaj Victor 	int status;
236791427e6dSRaj Victor 	u8 flags;
236891427e6dSRaj Victor 
236991427e6dSRaj Victor 	if (!buf || !len)
237091427e6dSRaj Victor 		return -EINVAL;
237191427e6dSRaj Victor 
237291427e6dSRaj Victor 	/* Does FW support new Tx topology mode ? */
237391427e6dSRaj Victor 	if (!hw->func_caps.common_cap.tx_sched_topo_comp_mode_en) {
237491427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "FW doesn't support compatibility mode\n");
237591427e6dSRaj Victor 		return -EOPNOTSUPP;
237691427e6dSRaj Victor 	}
237791427e6dSRaj Victor 
237891427e6dSRaj Victor 	current_topo = kzalloc(ICE_AQ_MAX_BUF_LEN, GFP_KERNEL);
237991427e6dSRaj Victor 	if (!current_topo)
238091427e6dSRaj Victor 		return -ENOMEM;
238191427e6dSRaj Victor 
238291427e6dSRaj Victor 	/* Get the current Tx topology */
238391427e6dSRaj Victor 	status = ice_get_set_tx_topo(hw, current_topo, ICE_AQ_MAX_BUF_LEN, NULL,
238491427e6dSRaj Victor 				     &flags, false);
238591427e6dSRaj Victor 
238691427e6dSRaj Victor 	kfree(current_topo);
238791427e6dSRaj Victor 
238891427e6dSRaj Victor 	if (status) {
238991427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "Get current topology is failed\n");
239091427e6dSRaj Victor 		return status;
239191427e6dSRaj Victor 	}
239291427e6dSRaj Victor 
239391427e6dSRaj Victor 	/* Is default topology already applied ? */
239491427e6dSRaj Victor 	if (!(flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) &&
239591427e6dSRaj Victor 	    hw->num_tx_sched_layers == ICE_SCHED_9_LAYERS) {
239691427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "Default topology already applied\n");
239791427e6dSRaj Victor 		return -EEXIST;
239891427e6dSRaj Victor 	}
239991427e6dSRaj Victor 
240091427e6dSRaj Victor 	/* Is new topology already applied ? */
240191427e6dSRaj Victor 	if ((flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) &&
240291427e6dSRaj Victor 	    hw->num_tx_sched_layers == ICE_SCHED_5_LAYERS) {
240391427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "New topology already applied\n");
240491427e6dSRaj Victor 		return -EEXIST;
240591427e6dSRaj Victor 	}
240691427e6dSRaj Victor 
240791427e6dSRaj Victor 	/* Setting topology already issued? */
240891427e6dSRaj Victor 	if (flags & ICE_AQC_TX_TOPO_FLAGS_ISSUED) {
240991427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "Update Tx topology was done by another PF\n");
241091427e6dSRaj Victor 		/* Add a small delay before exiting */
241191427e6dSRaj Victor 		msleep(2000);
241291427e6dSRaj Victor 		return -EEXIST;
241391427e6dSRaj Victor 	}
241491427e6dSRaj Victor 
241591427e6dSRaj Victor 	/* Change the topology from new to default (5 to 9) */
241691427e6dSRaj Victor 	if (!(flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) &&
241791427e6dSRaj Victor 	    hw->num_tx_sched_layers == ICE_SCHED_5_LAYERS) {
241891427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "Change topology from 5 to 9 layers\n");
241991427e6dSRaj Victor 		goto update_topo;
242091427e6dSRaj Victor 	}
242191427e6dSRaj Victor 
242291427e6dSRaj Victor 	pkg_hdr = (struct ice_pkg_hdr *)buf;
242391427e6dSRaj Victor 	state = ice_verify_pkg(pkg_hdr, len);
242491427e6dSRaj Victor 	if (state) {
242591427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "Failed to verify pkg (err: %d)\n",
242691427e6dSRaj Victor 			  state);
242791427e6dSRaj Victor 		return -EIO;
242891427e6dSRaj Victor 	}
242991427e6dSRaj Victor 
243091427e6dSRaj Victor 	/* Find runtime configuration segment */
243191427e6dSRaj Victor 	seg = (struct ice_run_time_cfg_seg *)
243291427e6dSRaj Victor 	      ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE_RUN_TIME_CFG, pkg_hdr);
243391427e6dSRaj Victor 	if (!seg) {
243491427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "5 layer topology segment is missing\n");
243591427e6dSRaj Victor 		return -EIO;
243691427e6dSRaj Victor 	}
243791427e6dSRaj Victor 
243891427e6dSRaj Victor 	if (le32_to_cpu(seg->buf_table.buf_count) < ICE_MIN_S_COUNT) {
243991427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "5 layer topology segment count(%d) is wrong\n",
244091427e6dSRaj Victor 			  seg->buf_table.buf_count);
244191427e6dSRaj Victor 		return -EIO;
244291427e6dSRaj Victor 	}
244391427e6dSRaj Victor 
244491427e6dSRaj Victor 	section = ice_pkg_val_buf(seg->buf_table.buf_array);
244591427e6dSRaj Victor 	if (!section || le32_to_cpu(section->section_entry[0].type) !=
244691427e6dSRaj Victor 		ICE_SID_TX_5_LAYER_TOPO) {
244791427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "5 layer topology section type is wrong\n");
244891427e6dSRaj Victor 		return -EIO;
244991427e6dSRaj Victor 	}
245091427e6dSRaj Victor 
245191427e6dSRaj Victor 	size = le16_to_cpu(section->section_entry[0].size);
245291427e6dSRaj Victor 	offset = le16_to_cpu(section->section_entry[0].offset);
245391427e6dSRaj Victor 	if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ) {
245491427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "5 layer topology section size is wrong\n");
245591427e6dSRaj Victor 		return -EIO;
245691427e6dSRaj Victor 	}
245791427e6dSRaj Victor 
245891427e6dSRaj Victor 	/* Make sure the section fits in the buffer */
245991427e6dSRaj Victor 	if (offset + size > ICE_PKG_BUF_SIZE) {
246091427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "5 layer topology buffer > 4K\n");
246191427e6dSRaj Victor 		return -EIO;
246291427e6dSRaj Victor 	}
246391427e6dSRaj Victor 
246491427e6dSRaj Victor 	/* Get the new topology buffer */
246591427e6dSRaj Victor 	new_topo = ((u8 *)section) + offset;
246691427e6dSRaj Victor 
246791427e6dSRaj Victor update_topo:
246891427e6dSRaj Victor 	/* Acquire global lock to make sure that set topology issued
246991427e6dSRaj Victor 	 * by one PF.
247091427e6dSRaj Victor 	 */
247191427e6dSRaj Victor 	status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, ICE_RES_WRITE,
247291427e6dSRaj Victor 				 ICE_GLOBAL_CFG_LOCK_TIMEOUT);
247391427e6dSRaj Victor 	if (status) {
247491427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "Failed to acquire global lock\n");
247591427e6dSRaj Victor 		return status;
247691427e6dSRaj Victor 	}
247791427e6dSRaj Victor 
247891427e6dSRaj Victor 	/* Check if reset was triggered already. */
247991427e6dSRaj Victor 	reg = rd32(hw, GLGEN_RSTAT);
248091427e6dSRaj Victor 	if (reg & GLGEN_RSTAT_DEVSTATE_M) {
248191427e6dSRaj Victor 		/* Reset is in progress, re-init the HW again */
248291427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "Reset is in progress. Layer topology might be applied already\n");
248391427e6dSRaj Victor 		ice_check_reset(hw);
248491427e6dSRaj Victor 		return 0;
248591427e6dSRaj Victor 	}
248691427e6dSRaj Victor 
248791427e6dSRaj Victor 	/* Set new topology */
248891427e6dSRaj Victor 	status = ice_get_set_tx_topo(hw, new_topo, size, NULL, NULL, true);
248991427e6dSRaj Victor 	if (status) {
249091427e6dSRaj Victor 		ice_debug(hw, ICE_DBG_INIT, "Failed setting Tx topology\n");
249191427e6dSRaj Victor 		return status;
249291427e6dSRaj Victor 	}
249391427e6dSRaj Victor 
249491427e6dSRaj Victor 	/* New topology is updated, delay 1 second before issuing the CORER */
249591427e6dSRaj Victor 	msleep(1000);
249691427e6dSRaj Victor 	ice_reset(hw, ICE_RESET_CORER);
249791427e6dSRaj Victor 	/* CORER will clear the global lock, so no explicit call
249891427e6dSRaj Victor 	 * required for release.
249991427e6dSRaj Victor 	 */
250091427e6dSRaj Victor 
250191427e6dSRaj Victor 	return 0;
250291427e6dSRaj Victor }
2503