xref: /linux/drivers/net/ethernet/intel/ice/ice_ddp.c (revision 784feaa65dfd2695f837842bcd151db0add4cb17)
12ffd87d3SSergey Temerkhanov // SPDX-License-Identifier: GPL-2.0
22ffd87d3SSergey Temerkhanov /* Copyright (c) 2022, Intel Corporation. */
32ffd87d3SSergey Temerkhanov 
42ffd87d3SSergey Temerkhanov #include "ice_common.h"
52ffd87d3SSergey Temerkhanov #include "ice.h"
62ffd87d3SSergey Temerkhanov #include "ice_ddp.h"
72ffd87d3SSergey Temerkhanov 
82ffd87d3SSergey Temerkhanov /* For supporting double VLAN mode, it is necessary to enable or disable certain
92ffd87d3SSergey Temerkhanov  * boost tcam entries. The metadata labels names that match the following
102ffd87d3SSergey Temerkhanov  * prefixes will be saved to allow enabling double VLAN mode.
112ffd87d3SSergey Temerkhanov  */
122ffd87d3SSergey Temerkhanov #define ICE_DVM_PRE "BOOST_MAC_VLAN_DVM" /* enable these entries */
132ffd87d3SSergey Temerkhanov #define ICE_SVM_PRE "BOOST_MAC_VLAN_SVM" /* disable these entries */
142ffd87d3SSergey Temerkhanov 
152ffd87d3SSergey Temerkhanov /* To support tunneling entries by PF, the package will append the PF number to
162ffd87d3SSergey Temerkhanov  * the label; for example TNL_VXLAN_PF0, TNL_VXLAN_PF1, TNL_VXLAN_PF2, etc.
172ffd87d3SSergey Temerkhanov  */
182ffd87d3SSergey Temerkhanov #define ICE_TNL_PRE "TNL_"
192ffd87d3SSergey Temerkhanov static const struct ice_tunnel_type_scan tnls[] = {
202ffd87d3SSergey Temerkhanov 	{ TNL_VXLAN, "TNL_VXLAN_PF" },
212ffd87d3SSergey Temerkhanov 	{ TNL_GENEVE, "TNL_GENEVE_PF" },
222ffd87d3SSergey Temerkhanov 	{ TNL_LAST, "" }
232ffd87d3SSergey Temerkhanov };
242ffd87d3SSergey Temerkhanov 
252ffd87d3SSergey Temerkhanov /**
262ffd87d3SSergey Temerkhanov  * ice_verify_pkg - verify package
272ffd87d3SSergey Temerkhanov  * @pkg: pointer to the package buffer
282ffd87d3SSergey Temerkhanov  * @len: size of the package buffer
292ffd87d3SSergey Temerkhanov  *
302ffd87d3SSergey Temerkhanov  * Verifies various attributes of the package file, including length, format
312ffd87d3SSergey Temerkhanov  * version, and the requirement of at least one segment.
322ffd87d3SSergey Temerkhanov  */
33708b352fSJan Sokolowski static enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
342ffd87d3SSergey Temerkhanov {
352ffd87d3SSergey Temerkhanov 	u32 seg_count;
362ffd87d3SSergey Temerkhanov 	u32 i;
372ffd87d3SSergey Temerkhanov 
382ffd87d3SSergey Temerkhanov 	if (len < struct_size(pkg, seg_offset, 1))
392ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
402ffd87d3SSergey Temerkhanov 
412ffd87d3SSergey Temerkhanov 	if (pkg->pkg_format_ver.major != ICE_PKG_FMT_VER_MAJ ||
422ffd87d3SSergey Temerkhanov 	    pkg->pkg_format_ver.minor != ICE_PKG_FMT_VER_MNR ||
432ffd87d3SSergey Temerkhanov 	    pkg->pkg_format_ver.update != ICE_PKG_FMT_VER_UPD ||
442ffd87d3SSergey Temerkhanov 	    pkg->pkg_format_ver.draft != ICE_PKG_FMT_VER_DFT)
452ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
462ffd87d3SSergey Temerkhanov 
472ffd87d3SSergey Temerkhanov 	/* pkg must have at least one segment */
482ffd87d3SSergey Temerkhanov 	seg_count = le32_to_cpu(pkg->seg_count);
492ffd87d3SSergey Temerkhanov 	if (seg_count < 1)
502ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
512ffd87d3SSergey Temerkhanov 
522ffd87d3SSergey Temerkhanov 	/* make sure segment array fits in package length */
532ffd87d3SSergey Temerkhanov 	if (len < struct_size(pkg, seg_offset, seg_count))
542ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
552ffd87d3SSergey Temerkhanov 
562ffd87d3SSergey Temerkhanov 	/* all segments must fit within length */
572ffd87d3SSergey Temerkhanov 	for (i = 0; i < seg_count; i++) {
582ffd87d3SSergey Temerkhanov 		u32 off = le32_to_cpu(pkg->seg_offset[i]);
592ffd87d3SSergey Temerkhanov 		struct ice_generic_seg_hdr *seg;
602ffd87d3SSergey Temerkhanov 
612ffd87d3SSergey Temerkhanov 		/* segment header must fit */
622ffd87d3SSergey Temerkhanov 		if (len < off + sizeof(*seg))
632ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_INVALID_FILE;
642ffd87d3SSergey Temerkhanov 
652ffd87d3SSergey Temerkhanov 		seg = (struct ice_generic_seg_hdr *)((u8 *)pkg + off);
662ffd87d3SSergey Temerkhanov 
672ffd87d3SSergey Temerkhanov 		/* segment body must fit */
682ffd87d3SSergey Temerkhanov 		if (len < off + le32_to_cpu(seg->seg_size))
692ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_INVALID_FILE;
702ffd87d3SSergey Temerkhanov 	}
712ffd87d3SSergey Temerkhanov 
722ffd87d3SSergey Temerkhanov 	return ICE_DDP_PKG_SUCCESS;
732ffd87d3SSergey Temerkhanov }
742ffd87d3SSergey Temerkhanov 
752ffd87d3SSergey Temerkhanov /**
762ffd87d3SSergey Temerkhanov  * ice_free_seg - free package segment pointer
772ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
782ffd87d3SSergey Temerkhanov  *
792ffd87d3SSergey Temerkhanov  * Frees the package segment pointer in the proper manner, depending on if the
802ffd87d3SSergey Temerkhanov  * segment was allocated or just the passed in pointer was stored.
812ffd87d3SSergey Temerkhanov  */
822ffd87d3SSergey Temerkhanov void ice_free_seg(struct ice_hw *hw)
832ffd87d3SSergey Temerkhanov {
842ffd87d3SSergey Temerkhanov 	if (hw->pkg_copy) {
852ffd87d3SSergey Temerkhanov 		devm_kfree(ice_hw_to_dev(hw), hw->pkg_copy);
862ffd87d3SSergey Temerkhanov 		hw->pkg_copy = NULL;
872ffd87d3SSergey Temerkhanov 		hw->pkg_size = 0;
882ffd87d3SSergey Temerkhanov 	}
892ffd87d3SSergey Temerkhanov 	hw->seg = NULL;
902ffd87d3SSergey Temerkhanov }
912ffd87d3SSergey Temerkhanov 
922ffd87d3SSergey Temerkhanov /**
932ffd87d3SSergey Temerkhanov  * ice_chk_pkg_version - check package version for compatibility with driver
942ffd87d3SSergey Temerkhanov  * @pkg_ver: pointer to a version structure to check
952ffd87d3SSergey Temerkhanov  *
962ffd87d3SSergey Temerkhanov  * Check to make sure that the package about to be downloaded is compatible with
972ffd87d3SSergey Temerkhanov  * the driver. To be compatible, the major and minor components of the package
982ffd87d3SSergey Temerkhanov  * version must match our ICE_PKG_SUPP_VER_MAJ and ICE_PKG_SUPP_VER_MNR
992ffd87d3SSergey Temerkhanov  * definitions.
1002ffd87d3SSergey Temerkhanov  */
1012ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver)
1022ffd87d3SSergey Temerkhanov {
1032ffd87d3SSergey Temerkhanov 	if (pkg_ver->major > ICE_PKG_SUPP_VER_MAJ ||
1042ffd87d3SSergey Temerkhanov 	    (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ &&
1052ffd87d3SSergey Temerkhanov 	     pkg_ver->minor > ICE_PKG_SUPP_VER_MNR))
1062ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_FILE_VERSION_TOO_HIGH;
1072ffd87d3SSergey Temerkhanov 	else if (pkg_ver->major < ICE_PKG_SUPP_VER_MAJ ||
1082ffd87d3SSergey Temerkhanov 		 (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ &&
1092ffd87d3SSergey Temerkhanov 		  pkg_ver->minor < ICE_PKG_SUPP_VER_MNR))
1102ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_FILE_VERSION_TOO_LOW;
1112ffd87d3SSergey Temerkhanov 
1122ffd87d3SSergey Temerkhanov 	return ICE_DDP_PKG_SUCCESS;
1132ffd87d3SSergey Temerkhanov }
1142ffd87d3SSergey Temerkhanov 
1152ffd87d3SSergey Temerkhanov /**
1162ffd87d3SSergey Temerkhanov  * ice_pkg_val_buf
1172ffd87d3SSergey Temerkhanov  * @buf: pointer to the ice buffer
1182ffd87d3SSergey Temerkhanov  *
1192ffd87d3SSergey Temerkhanov  * This helper function validates a buffer's header.
1202ffd87d3SSergey Temerkhanov  */
121708b352fSJan Sokolowski static struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf)
1222ffd87d3SSergey Temerkhanov {
1232ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *hdr;
1242ffd87d3SSergey Temerkhanov 	u16 section_count;
1252ffd87d3SSergey Temerkhanov 	u16 data_end;
1262ffd87d3SSergey Temerkhanov 
1272ffd87d3SSergey Temerkhanov 	hdr = (struct ice_buf_hdr *)buf->buf;
1282ffd87d3SSergey Temerkhanov 	/* verify data */
1292ffd87d3SSergey Temerkhanov 	section_count = le16_to_cpu(hdr->section_count);
1302ffd87d3SSergey Temerkhanov 	if (section_count < ICE_MIN_S_COUNT || section_count > ICE_MAX_S_COUNT)
1312ffd87d3SSergey Temerkhanov 		return NULL;
1322ffd87d3SSergey Temerkhanov 
1332ffd87d3SSergey Temerkhanov 	data_end = le16_to_cpu(hdr->data_end);
1342ffd87d3SSergey Temerkhanov 	if (data_end < ICE_MIN_S_DATA_END || data_end > ICE_MAX_S_DATA_END)
1352ffd87d3SSergey Temerkhanov 		return NULL;
1362ffd87d3SSergey Temerkhanov 
1372ffd87d3SSergey Temerkhanov 	return hdr;
1382ffd87d3SSergey Temerkhanov }
1392ffd87d3SSergey Temerkhanov 
1402ffd87d3SSergey Temerkhanov /**
1412ffd87d3SSergey Temerkhanov  * ice_find_buf_table
1422ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment
1432ffd87d3SSergey Temerkhanov  *
1442ffd87d3SSergey Temerkhanov  * Returns the address of the buffer table within the ice segment.
1452ffd87d3SSergey Temerkhanov  */
1462ffd87d3SSergey Temerkhanov static struct ice_buf_table *ice_find_buf_table(struct ice_seg *ice_seg)
1472ffd87d3SSergey Temerkhanov {
1482ffd87d3SSergey Temerkhanov 	struct ice_nvm_table *nvms = (struct ice_nvm_table *)
1492ffd87d3SSergey Temerkhanov 		(ice_seg->device_table + le32_to_cpu(ice_seg->device_table_count));
1502ffd87d3SSergey Temerkhanov 
1512ffd87d3SSergey Temerkhanov 	return (__force struct ice_buf_table *)(nvms->vers +
1522ffd87d3SSergey Temerkhanov 						le32_to_cpu(nvms->table_count));
1532ffd87d3SSergey Temerkhanov }
1542ffd87d3SSergey Temerkhanov 
1552ffd87d3SSergey Temerkhanov /**
1562ffd87d3SSergey Temerkhanov  * ice_pkg_enum_buf
1572ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
1582ffd87d3SSergey Temerkhanov  * @state: pointer to the enum state
1592ffd87d3SSergey Temerkhanov  *
1602ffd87d3SSergey Temerkhanov  * This function will enumerate all the buffers in the ice segment. The first
1612ffd87d3SSergey Temerkhanov  * call is made with the ice_seg parameter non-NULL; on subsequent calls,
1622ffd87d3SSergey Temerkhanov  * ice_seg is set to NULL which continues the enumeration. When the function
1632ffd87d3SSergey Temerkhanov  * returns a NULL pointer, then the end of the buffers has been reached, or an
1642ffd87d3SSergey Temerkhanov  * unexpected value has been detected (for example an invalid section count or
1652ffd87d3SSergey Temerkhanov  * an invalid buffer end value).
1662ffd87d3SSergey Temerkhanov  */
1672ffd87d3SSergey Temerkhanov static struct ice_buf_hdr *ice_pkg_enum_buf(struct ice_seg *ice_seg,
1682ffd87d3SSergey Temerkhanov 					    struct ice_pkg_enum *state)
1692ffd87d3SSergey Temerkhanov {
1702ffd87d3SSergey Temerkhanov 	if (ice_seg) {
1712ffd87d3SSergey Temerkhanov 		state->buf_table = ice_find_buf_table(ice_seg);
1722ffd87d3SSergey Temerkhanov 		if (!state->buf_table)
1732ffd87d3SSergey Temerkhanov 			return NULL;
1742ffd87d3SSergey Temerkhanov 
1752ffd87d3SSergey Temerkhanov 		state->buf_idx = 0;
1762ffd87d3SSergey Temerkhanov 		return ice_pkg_val_buf(state->buf_table->buf_array);
1772ffd87d3SSergey Temerkhanov 	}
1782ffd87d3SSergey Temerkhanov 
1792ffd87d3SSergey Temerkhanov 	if (++state->buf_idx < le32_to_cpu(state->buf_table->buf_count))
1802ffd87d3SSergey Temerkhanov 		return ice_pkg_val_buf(state->buf_table->buf_array +
1812ffd87d3SSergey Temerkhanov 				       state->buf_idx);
1822ffd87d3SSergey Temerkhanov 	else
1832ffd87d3SSergey Temerkhanov 		return NULL;
1842ffd87d3SSergey Temerkhanov }
1852ffd87d3SSergey Temerkhanov 
1862ffd87d3SSergey Temerkhanov /**
1872ffd87d3SSergey Temerkhanov  * ice_pkg_advance_sect
1882ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
1892ffd87d3SSergey Temerkhanov  * @state: pointer to the enum state
1902ffd87d3SSergey Temerkhanov  *
1912ffd87d3SSergey Temerkhanov  * This helper function will advance the section within the ice segment,
1922ffd87d3SSergey Temerkhanov  * also advancing the buffer if needed.
1932ffd87d3SSergey Temerkhanov  */
1942ffd87d3SSergey Temerkhanov static bool ice_pkg_advance_sect(struct ice_seg *ice_seg,
1952ffd87d3SSergey Temerkhanov 				 struct ice_pkg_enum *state)
1962ffd87d3SSergey Temerkhanov {
1972ffd87d3SSergey Temerkhanov 	if (!ice_seg && !state->buf)
1982ffd87d3SSergey Temerkhanov 		return false;
1992ffd87d3SSergey Temerkhanov 
2002ffd87d3SSergey Temerkhanov 	if (!ice_seg && state->buf)
2012ffd87d3SSergey Temerkhanov 		if (++state->sect_idx < le16_to_cpu(state->buf->section_count))
2022ffd87d3SSergey Temerkhanov 			return true;
2032ffd87d3SSergey Temerkhanov 
2042ffd87d3SSergey Temerkhanov 	state->buf = ice_pkg_enum_buf(ice_seg, state);
2052ffd87d3SSergey Temerkhanov 	if (!state->buf)
2062ffd87d3SSergey Temerkhanov 		return false;
2072ffd87d3SSergey Temerkhanov 
2082ffd87d3SSergey Temerkhanov 	/* start of new buffer, reset section index */
2092ffd87d3SSergey Temerkhanov 	state->sect_idx = 0;
2102ffd87d3SSergey Temerkhanov 	return true;
2112ffd87d3SSergey Temerkhanov }
2122ffd87d3SSergey Temerkhanov 
2132ffd87d3SSergey Temerkhanov /**
2142ffd87d3SSergey Temerkhanov  * ice_pkg_enum_section
2152ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
2162ffd87d3SSergey Temerkhanov  * @state: pointer to the enum state
2172ffd87d3SSergey Temerkhanov  * @sect_type: section type to enumerate
2182ffd87d3SSergey Temerkhanov  *
2192ffd87d3SSergey Temerkhanov  * This function will enumerate all the sections of a particular type in the
2202ffd87d3SSergey Temerkhanov  * ice segment. The first call is made with the ice_seg parameter non-NULL;
2212ffd87d3SSergey Temerkhanov  * on subsequent calls, ice_seg is set to NULL which continues the enumeration.
2222ffd87d3SSergey Temerkhanov  * When the function returns a NULL pointer, then the end of the matching
2232ffd87d3SSergey Temerkhanov  * sections has been reached.
2242ffd87d3SSergey Temerkhanov  */
2252ffd87d3SSergey Temerkhanov void *ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
2262ffd87d3SSergey Temerkhanov 			   u32 sect_type)
2272ffd87d3SSergey Temerkhanov {
2282ffd87d3SSergey Temerkhanov 	u16 offset, size;
2292ffd87d3SSergey Temerkhanov 
2302ffd87d3SSergey Temerkhanov 	if (ice_seg)
2312ffd87d3SSergey Temerkhanov 		state->type = sect_type;
2322ffd87d3SSergey Temerkhanov 
2332ffd87d3SSergey Temerkhanov 	if (!ice_pkg_advance_sect(ice_seg, state))
2342ffd87d3SSergey Temerkhanov 		return NULL;
2352ffd87d3SSergey Temerkhanov 
2362ffd87d3SSergey Temerkhanov 	/* scan for next matching section */
2372ffd87d3SSergey Temerkhanov 	while (state->buf->section_entry[state->sect_idx].type !=
2382ffd87d3SSergey Temerkhanov 	       cpu_to_le32(state->type))
2392ffd87d3SSergey Temerkhanov 		if (!ice_pkg_advance_sect(NULL, state))
2402ffd87d3SSergey Temerkhanov 			return NULL;
2412ffd87d3SSergey Temerkhanov 
2422ffd87d3SSergey Temerkhanov 	/* validate section */
2432ffd87d3SSergey Temerkhanov 	offset = le16_to_cpu(state->buf->section_entry[state->sect_idx].offset);
2442ffd87d3SSergey Temerkhanov 	if (offset < ICE_MIN_S_OFF || offset > ICE_MAX_S_OFF)
2452ffd87d3SSergey Temerkhanov 		return NULL;
2462ffd87d3SSergey Temerkhanov 
2472ffd87d3SSergey Temerkhanov 	size = le16_to_cpu(state->buf->section_entry[state->sect_idx].size);
2482ffd87d3SSergey Temerkhanov 	if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ)
2492ffd87d3SSergey Temerkhanov 		return NULL;
2502ffd87d3SSergey Temerkhanov 
2512ffd87d3SSergey Temerkhanov 	/* make sure the section fits in the buffer */
2522ffd87d3SSergey Temerkhanov 	if (offset + size > ICE_PKG_BUF_SIZE)
2532ffd87d3SSergey Temerkhanov 		return NULL;
2542ffd87d3SSergey Temerkhanov 
2552ffd87d3SSergey Temerkhanov 	state->sect_type =
2562ffd87d3SSergey Temerkhanov 		le32_to_cpu(state->buf->section_entry[state->sect_idx].type);
2572ffd87d3SSergey Temerkhanov 
2582ffd87d3SSergey Temerkhanov 	/* calc pointer to this section */
2592ffd87d3SSergey Temerkhanov 	state->sect =
2602ffd87d3SSergey Temerkhanov 		((u8 *)state->buf) +
2612ffd87d3SSergey Temerkhanov 		le16_to_cpu(state->buf->section_entry[state->sect_idx].offset);
2622ffd87d3SSergey Temerkhanov 
2632ffd87d3SSergey Temerkhanov 	return state->sect;
2642ffd87d3SSergey Temerkhanov }
2652ffd87d3SSergey Temerkhanov 
2662ffd87d3SSergey Temerkhanov /**
2672ffd87d3SSergey Temerkhanov  * ice_pkg_enum_entry
2682ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
2692ffd87d3SSergey Temerkhanov  * @state: pointer to the enum state
2702ffd87d3SSergey Temerkhanov  * @sect_type: section type to enumerate
2712ffd87d3SSergey Temerkhanov  * @offset: pointer to variable that receives the offset in the table (optional)
2722ffd87d3SSergey Temerkhanov  * @handler: function that handles access to the entries into the section type
2732ffd87d3SSergey Temerkhanov  *
2742ffd87d3SSergey Temerkhanov  * This function will enumerate all the entries in particular section type in
2752ffd87d3SSergey Temerkhanov  * the ice segment. The first call is made with the ice_seg parameter non-NULL;
2762ffd87d3SSergey Temerkhanov  * on subsequent calls, ice_seg is set to NULL which continues the enumeration.
2772ffd87d3SSergey Temerkhanov  * When the function returns a NULL pointer, then the end of the entries has
2782ffd87d3SSergey Temerkhanov  * been reached.
2792ffd87d3SSergey Temerkhanov  *
2802ffd87d3SSergey Temerkhanov  * Since each section may have a different header and entry size, the handler
2812ffd87d3SSergey Temerkhanov  * function is needed to determine the number and location entries in each
2822ffd87d3SSergey Temerkhanov  * section.
2832ffd87d3SSergey Temerkhanov  *
2842ffd87d3SSergey Temerkhanov  * The offset parameter is optional, but should be used for sections that
2852ffd87d3SSergey Temerkhanov  * contain an offset for each section table. For such cases, the section handler
2862ffd87d3SSergey Temerkhanov  * function must return the appropriate offset + index to give the absolution
2872ffd87d3SSergey Temerkhanov  * offset for each entry. For example, if the base for a section's header
2882ffd87d3SSergey Temerkhanov  * indicates a base offset of 10, and the index for the entry is 2, then
2892ffd87d3SSergey Temerkhanov  * section handler function should set the offset to 10 + 2 = 12.
2902ffd87d3SSergey Temerkhanov  */
2912ffd87d3SSergey Temerkhanov static void *ice_pkg_enum_entry(struct ice_seg *ice_seg,
2922ffd87d3SSergey Temerkhanov 				struct ice_pkg_enum *state, u32 sect_type,
2932ffd87d3SSergey Temerkhanov 				u32 *offset,
2942ffd87d3SSergey Temerkhanov 				void *(*handler)(u32 sect_type, void *section,
2952ffd87d3SSergey Temerkhanov 						 u32 index, u32 *offset))
2962ffd87d3SSergey Temerkhanov {
2972ffd87d3SSergey Temerkhanov 	void *entry;
2982ffd87d3SSergey Temerkhanov 
2992ffd87d3SSergey Temerkhanov 	if (ice_seg) {
3002ffd87d3SSergey Temerkhanov 		if (!handler)
3012ffd87d3SSergey Temerkhanov 			return NULL;
3022ffd87d3SSergey Temerkhanov 
3032ffd87d3SSergey Temerkhanov 		if (!ice_pkg_enum_section(ice_seg, state, sect_type))
3042ffd87d3SSergey Temerkhanov 			return NULL;
3052ffd87d3SSergey Temerkhanov 
3062ffd87d3SSergey Temerkhanov 		state->entry_idx = 0;
3072ffd87d3SSergey Temerkhanov 		state->handler = handler;
3082ffd87d3SSergey Temerkhanov 	} else {
3092ffd87d3SSergey Temerkhanov 		state->entry_idx++;
3102ffd87d3SSergey Temerkhanov 	}
3112ffd87d3SSergey Temerkhanov 
3122ffd87d3SSergey Temerkhanov 	if (!state->handler)
3132ffd87d3SSergey Temerkhanov 		return NULL;
3142ffd87d3SSergey Temerkhanov 
3152ffd87d3SSergey Temerkhanov 	/* get entry */
3162ffd87d3SSergey Temerkhanov 	entry = state->handler(state->sect_type, state->sect, state->entry_idx,
3172ffd87d3SSergey Temerkhanov 			       offset);
3182ffd87d3SSergey Temerkhanov 	if (!entry) {
3192ffd87d3SSergey Temerkhanov 		/* end of a section, look for another section of this type */
3202ffd87d3SSergey Temerkhanov 		if (!ice_pkg_enum_section(NULL, state, 0))
3212ffd87d3SSergey Temerkhanov 			return NULL;
3222ffd87d3SSergey Temerkhanov 
3232ffd87d3SSergey Temerkhanov 		state->entry_idx = 0;
3242ffd87d3SSergey Temerkhanov 		entry = state->handler(state->sect_type, state->sect,
3252ffd87d3SSergey Temerkhanov 				       state->entry_idx, offset);
3262ffd87d3SSergey Temerkhanov 	}
3272ffd87d3SSergey Temerkhanov 
3282ffd87d3SSergey Temerkhanov 	return entry;
3292ffd87d3SSergey Temerkhanov }
3302ffd87d3SSergey Temerkhanov 
3312ffd87d3SSergey Temerkhanov /**
3322ffd87d3SSergey Temerkhanov  * ice_sw_fv_handler
3332ffd87d3SSergey Temerkhanov  * @sect_type: section type
3342ffd87d3SSergey Temerkhanov  * @section: pointer to section
3352ffd87d3SSergey Temerkhanov  * @index: index of the field vector entry to be returned
3362ffd87d3SSergey Temerkhanov  * @offset: ptr to variable that receives the offset in the field vector table
3372ffd87d3SSergey Temerkhanov  *
3382ffd87d3SSergey Temerkhanov  * This is a callback function that can be passed to ice_pkg_enum_entry.
3392ffd87d3SSergey Temerkhanov  * This function treats the given section as of type ice_sw_fv_section and
3402ffd87d3SSergey Temerkhanov  * enumerates offset field. "offset" is an index into the field vector table.
3412ffd87d3SSergey Temerkhanov  */
3422ffd87d3SSergey Temerkhanov static void *ice_sw_fv_handler(u32 sect_type, void *section, u32 index,
3432ffd87d3SSergey Temerkhanov 			       u32 *offset)
3442ffd87d3SSergey Temerkhanov {
3452ffd87d3SSergey Temerkhanov 	struct ice_sw_fv_section *fv_section = section;
3462ffd87d3SSergey Temerkhanov 
3472ffd87d3SSergey Temerkhanov 	if (!section || sect_type != ICE_SID_FLD_VEC_SW)
3482ffd87d3SSergey Temerkhanov 		return NULL;
3492ffd87d3SSergey Temerkhanov 	if (index >= le16_to_cpu(fv_section->count))
3502ffd87d3SSergey Temerkhanov 		return NULL;
3512ffd87d3SSergey Temerkhanov 	if (offset)
3522ffd87d3SSergey Temerkhanov 		/* "index" passed in to this function is relative to a given
3532ffd87d3SSergey Temerkhanov 		 * 4k block. To get to the true index into the field vector
3542ffd87d3SSergey Temerkhanov 		 * table need to add the relative index to the base_offset
3552ffd87d3SSergey Temerkhanov 		 * field of this section
3562ffd87d3SSergey Temerkhanov 		 */
3572ffd87d3SSergey Temerkhanov 		*offset = le16_to_cpu(fv_section->base_offset) + index;
3582ffd87d3SSergey Temerkhanov 	return fv_section->fv + index;
3592ffd87d3SSergey Temerkhanov }
3602ffd87d3SSergey Temerkhanov 
3612ffd87d3SSergey Temerkhanov /**
3622ffd87d3SSergey Temerkhanov  * ice_get_prof_index_max - get the max profile index for used profile
3632ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW struct
3642ffd87d3SSergey Temerkhanov  *
3652ffd87d3SSergey Temerkhanov  * Calling this function will get the max profile index for used profile
3662ffd87d3SSergey Temerkhanov  * and store the index number in struct ice_switch_info *switch_info
3672ffd87d3SSergey Temerkhanov  * in HW for following use.
3682ffd87d3SSergey Temerkhanov  */
3692ffd87d3SSergey Temerkhanov static int ice_get_prof_index_max(struct ice_hw *hw)
3702ffd87d3SSergey Temerkhanov {
3712ffd87d3SSergey Temerkhanov 	u16 prof_index = 0, j, max_prof_index = 0;
3722ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
3732ffd87d3SSergey Temerkhanov 	struct ice_seg *ice_seg;
3742ffd87d3SSergey Temerkhanov 	bool flag = false;
3752ffd87d3SSergey Temerkhanov 	struct ice_fv *fv;
3762ffd87d3SSergey Temerkhanov 	u32 offset;
3772ffd87d3SSergey Temerkhanov 
3782ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
3792ffd87d3SSergey Temerkhanov 
3802ffd87d3SSergey Temerkhanov 	if (!hw->seg)
3812ffd87d3SSergey Temerkhanov 		return -EINVAL;
3822ffd87d3SSergey Temerkhanov 
3832ffd87d3SSergey Temerkhanov 	ice_seg = hw->seg;
3842ffd87d3SSergey Temerkhanov 
3852ffd87d3SSergey Temerkhanov 	do {
3862ffd87d3SSergey Temerkhanov 		fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
3872ffd87d3SSergey Temerkhanov 					&offset, ice_sw_fv_handler);
3882ffd87d3SSergey Temerkhanov 		if (!fv)
3892ffd87d3SSergey Temerkhanov 			break;
3902ffd87d3SSergey Temerkhanov 		ice_seg = NULL;
3912ffd87d3SSergey Temerkhanov 
3922ffd87d3SSergey Temerkhanov 		/* in the profile that not be used, the prot_id is set to 0xff
3932ffd87d3SSergey Temerkhanov 		 * and the off is set to 0x1ff for all the field vectors.
3942ffd87d3SSergey Temerkhanov 		 */
3952ffd87d3SSergey Temerkhanov 		for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
3962ffd87d3SSergey Temerkhanov 			if (fv->ew[j].prot_id != ICE_PROT_INVALID ||
3972ffd87d3SSergey Temerkhanov 			    fv->ew[j].off != ICE_FV_OFFSET_INVAL)
3982ffd87d3SSergey Temerkhanov 				flag = true;
3992ffd87d3SSergey Temerkhanov 		if (flag && prof_index > max_prof_index)
4002ffd87d3SSergey Temerkhanov 			max_prof_index = prof_index;
4012ffd87d3SSergey Temerkhanov 
4022ffd87d3SSergey Temerkhanov 		prof_index++;
4032ffd87d3SSergey Temerkhanov 		flag = false;
4042ffd87d3SSergey Temerkhanov 	} while (fv);
4052ffd87d3SSergey Temerkhanov 
4062ffd87d3SSergey Temerkhanov 	hw->switch_info->max_used_prof_index = max_prof_index;
4072ffd87d3SSergey Temerkhanov 
4082ffd87d3SSergey Temerkhanov 	return 0;
4092ffd87d3SSergey Temerkhanov }
4102ffd87d3SSergey Temerkhanov 
4112ffd87d3SSergey Temerkhanov /**
4122ffd87d3SSergey Temerkhanov  * ice_get_ddp_pkg_state - get DDP pkg state after download
4132ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW struct
4142ffd87d3SSergey Temerkhanov  * @already_loaded: indicates if pkg was already loaded onto the device
4152ffd87d3SSergey Temerkhanov  */
4162ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_ddp_pkg_state(struct ice_hw *hw,
4172ffd87d3SSergey Temerkhanov 						bool already_loaded)
4182ffd87d3SSergey Temerkhanov {
4192ffd87d3SSergey Temerkhanov 	if (hw->pkg_ver.major == hw->active_pkg_ver.major &&
4202ffd87d3SSergey Temerkhanov 	    hw->pkg_ver.minor == hw->active_pkg_ver.minor &&
4212ffd87d3SSergey Temerkhanov 	    hw->pkg_ver.update == hw->active_pkg_ver.update &&
4222ffd87d3SSergey Temerkhanov 	    hw->pkg_ver.draft == hw->active_pkg_ver.draft &&
4232ffd87d3SSergey Temerkhanov 	    !memcmp(hw->pkg_name, hw->active_pkg_name, sizeof(hw->pkg_name))) {
4242ffd87d3SSergey Temerkhanov 		if (already_loaded)
4252ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED;
4262ffd87d3SSergey Temerkhanov 		else
4272ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_SUCCESS;
4282ffd87d3SSergey Temerkhanov 	} else if (hw->active_pkg_ver.major != ICE_PKG_SUPP_VER_MAJ ||
4292ffd87d3SSergey Temerkhanov 		   hw->active_pkg_ver.minor != ICE_PKG_SUPP_VER_MNR) {
4302ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ALREADY_LOADED_NOT_SUPPORTED;
4312ffd87d3SSergey Temerkhanov 	} else if (hw->active_pkg_ver.major == ICE_PKG_SUPP_VER_MAJ &&
4322ffd87d3SSergey Temerkhanov 		   hw->active_pkg_ver.minor == ICE_PKG_SUPP_VER_MNR) {
4332ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED;
4342ffd87d3SSergey Temerkhanov 	} else {
4352ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
4362ffd87d3SSergey Temerkhanov 	}
4372ffd87d3SSergey Temerkhanov }
4382ffd87d3SSergey Temerkhanov 
4392ffd87d3SSergey Temerkhanov /**
4402ffd87d3SSergey Temerkhanov  * ice_init_pkg_regs - initialize additional package registers
4412ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
4422ffd87d3SSergey Temerkhanov  */
4432ffd87d3SSergey Temerkhanov static void ice_init_pkg_regs(struct ice_hw *hw)
4442ffd87d3SSergey Temerkhanov {
4452ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_INP_MASK_L 0xFFFFFFFF
4462ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_INP_MASK_H 0x0000FFFF
4472ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_IDX 0
4482ffd87d3SSergey Temerkhanov 
4492ffd87d3SSergey Temerkhanov 	/* setup Switch block input mask, which is 48-bits in two parts */
4502ffd87d3SSergey Temerkhanov 	wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L);
4512ffd87d3SSergey Temerkhanov 	wr32(hw, GL_PREEXT_L2_PMASK1(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_H);
4522ffd87d3SSergey Temerkhanov }
4532ffd87d3SSergey Temerkhanov 
4542ffd87d3SSergey Temerkhanov /**
4552ffd87d3SSergey Temerkhanov  * ice_marker_ptype_tcam_handler
4562ffd87d3SSergey Temerkhanov  * @sect_type: section type
4572ffd87d3SSergey Temerkhanov  * @section: pointer to section
4582ffd87d3SSergey Temerkhanov  * @index: index of the Marker PType TCAM entry to be returned
4592ffd87d3SSergey Temerkhanov  * @offset: pointer to receive absolute offset, always 0 for ptype TCAM sections
4602ffd87d3SSergey Temerkhanov  *
4612ffd87d3SSergey Temerkhanov  * This is a callback function that can be passed to ice_pkg_enum_entry.
4622ffd87d3SSergey Temerkhanov  * Handles enumeration of individual Marker PType TCAM entries.
4632ffd87d3SSergey Temerkhanov  */
4642ffd87d3SSergey Temerkhanov static void *ice_marker_ptype_tcam_handler(u32 sect_type, void *section,
4652ffd87d3SSergey Temerkhanov 					   u32 index, u32 *offset)
4662ffd87d3SSergey Temerkhanov {
4672ffd87d3SSergey Temerkhanov 	struct ice_marker_ptype_tcam_section *marker_ptype;
4682ffd87d3SSergey Temerkhanov 
4692ffd87d3SSergey Temerkhanov 	if (sect_type != ICE_SID_RXPARSER_MARKER_PTYPE)
4702ffd87d3SSergey Temerkhanov 		return NULL;
4712ffd87d3SSergey Temerkhanov 
4722ffd87d3SSergey Temerkhanov 	if (index > ICE_MAX_MARKER_PTYPE_TCAMS_IN_BUF)
4732ffd87d3SSergey Temerkhanov 		return NULL;
4742ffd87d3SSergey Temerkhanov 
4752ffd87d3SSergey Temerkhanov 	if (offset)
4762ffd87d3SSergey Temerkhanov 		*offset = 0;
4772ffd87d3SSergey Temerkhanov 
4782ffd87d3SSergey Temerkhanov 	marker_ptype = section;
4792ffd87d3SSergey Temerkhanov 	if (index >= le16_to_cpu(marker_ptype->count))
4802ffd87d3SSergey Temerkhanov 		return NULL;
4812ffd87d3SSergey Temerkhanov 
4822ffd87d3SSergey Temerkhanov 	return marker_ptype->tcam + index;
4832ffd87d3SSergey Temerkhanov }
4842ffd87d3SSergey Temerkhanov 
4852ffd87d3SSergey Temerkhanov /**
4862ffd87d3SSergey Temerkhanov  * ice_add_dvm_hint
4872ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
4882ffd87d3SSergey Temerkhanov  * @val: value of the boost entry
4892ffd87d3SSergey Temerkhanov  * @enable: true if entry needs to be enabled, or false if needs to be disabled
4902ffd87d3SSergey Temerkhanov  */
4912ffd87d3SSergey Temerkhanov static void ice_add_dvm_hint(struct ice_hw *hw, u16 val, bool enable)
4922ffd87d3SSergey Temerkhanov {
4932ffd87d3SSergey Temerkhanov 	if (hw->dvm_upd.count < ICE_DVM_MAX_ENTRIES) {
4942ffd87d3SSergey Temerkhanov 		hw->dvm_upd.tbl[hw->dvm_upd.count].boost_addr = val;
4952ffd87d3SSergey Temerkhanov 		hw->dvm_upd.tbl[hw->dvm_upd.count].enable = enable;
4962ffd87d3SSergey Temerkhanov 		hw->dvm_upd.count++;
4972ffd87d3SSergey Temerkhanov 	}
4982ffd87d3SSergey Temerkhanov }
4992ffd87d3SSergey Temerkhanov 
5002ffd87d3SSergey Temerkhanov /**
5012ffd87d3SSergey Temerkhanov  * ice_add_tunnel_hint
5022ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
5032ffd87d3SSergey Temerkhanov  * @label_name: label text
5042ffd87d3SSergey Temerkhanov  * @val: value of the tunnel port boost entry
5052ffd87d3SSergey Temerkhanov  */
5062ffd87d3SSergey Temerkhanov static void ice_add_tunnel_hint(struct ice_hw *hw, char *label_name, u16 val)
5072ffd87d3SSergey Temerkhanov {
5082ffd87d3SSergey Temerkhanov 	if (hw->tnl.count < ICE_TUNNEL_MAX_ENTRIES) {
5092ffd87d3SSergey Temerkhanov 		u16 i;
5102ffd87d3SSergey Temerkhanov 
5112ffd87d3SSergey Temerkhanov 		for (i = 0; tnls[i].type != TNL_LAST; i++) {
5122ffd87d3SSergey Temerkhanov 			size_t len = strlen(tnls[i].label_prefix);
5132ffd87d3SSergey Temerkhanov 
5142ffd87d3SSergey Temerkhanov 			/* Look for matching label start, before continuing */
5152ffd87d3SSergey Temerkhanov 			if (strncmp(label_name, tnls[i].label_prefix, len))
5162ffd87d3SSergey Temerkhanov 				continue;
5172ffd87d3SSergey Temerkhanov 
5182ffd87d3SSergey Temerkhanov 			/* Make sure this label matches our PF. Note that the PF
5192ffd87d3SSergey Temerkhanov 			 * character ('0' - '7') will be located where our
5202ffd87d3SSergey Temerkhanov 			 * prefix string's null terminator is located.
5212ffd87d3SSergey Temerkhanov 			 */
5222ffd87d3SSergey Temerkhanov 			if ((label_name[len] - '0') == hw->pf_id) {
5232ffd87d3SSergey Temerkhanov 				hw->tnl.tbl[hw->tnl.count].type = tnls[i].type;
5242ffd87d3SSergey Temerkhanov 				hw->tnl.tbl[hw->tnl.count].valid = false;
5252ffd87d3SSergey Temerkhanov 				hw->tnl.tbl[hw->tnl.count].boost_addr = val;
5262ffd87d3SSergey Temerkhanov 				hw->tnl.tbl[hw->tnl.count].port = 0;
5272ffd87d3SSergey Temerkhanov 				hw->tnl.count++;
5282ffd87d3SSergey Temerkhanov 				break;
5292ffd87d3SSergey Temerkhanov 			}
5302ffd87d3SSergey Temerkhanov 		}
5312ffd87d3SSergey Temerkhanov 	}
5322ffd87d3SSergey Temerkhanov }
5332ffd87d3SSergey Temerkhanov 
5342ffd87d3SSergey Temerkhanov /**
5352ffd87d3SSergey Temerkhanov  * ice_label_enum_handler
5362ffd87d3SSergey Temerkhanov  * @sect_type: section type
5372ffd87d3SSergey Temerkhanov  * @section: pointer to section
5382ffd87d3SSergey Temerkhanov  * @index: index of the label entry to be returned
5392ffd87d3SSergey Temerkhanov  * @offset: pointer to receive absolute offset, always zero for label sections
5402ffd87d3SSergey Temerkhanov  *
5412ffd87d3SSergey Temerkhanov  * This is a callback function that can be passed to ice_pkg_enum_entry.
5422ffd87d3SSergey Temerkhanov  * Handles enumeration of individual label entries.
5432ffd87d3SSergey Temerkhanov  */
5442ffd87d3SSergey Temerkhanov static void *ice_label_enum_handler(u32 __always_unused sect_type,
5452ffd87d3SSergey Temerkhanov 				    void *section, u32 index, u32 *offset)
5462ffd87d3SSergey Temerkhanov {
5472ffd87d3SSergey Temerkhanov 	struct ice_label_section *labels;
5482ffd87d3SSergey Temerkhanov 
5492ffd87d3SSergey Temerkhanov 	if (!section)
5502ffd87d3SSergey Temerkhanov 		return NULL;
5512ffd87d3SSergey Temerkhanov 
5522ffd87d3SSergey Temerkhanov 	if (index > ICE_MAX_LABELS_IN_BUF)
5532ffd87d3SSergey Temerkhanov 		return NULL;
5542ffd87d3SSergey Temerkhanov 
5552ffd87d3SSergey Temerkhanov 	if (offset)
5562ffd87d3SSergey Temerkhanov 		*offset = 0;
5572ffd87d3SSergey Temerkhanov 
5582ffd87d3SSergey Temerkhanov 	labels = section;
5592ffd87d3SSergey Temerkhanov 	if (index >= le16_to_cpu(labels->count))
5602ffd87d3SSergey Temerkhanov 		return NULL;
5612ffd87d3SSergey Temerkhanov 
5622ffd87d3SSergey Temerkhanov 	return labels->label + index;
5632ffd87d3SSergey Temerkhanov }
5642ffd87d3SSergey Temerkhanov 
5652ffd87d3SSergey Temerkhanov /**
5662ffd87d3SSergey Temerkhanov  * ice_enum_labels
5672ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (NULL on subsequent calls)
5682ffd87d3SSergey Temerkhanov  * @type: the section type that will contain the label (0 on subsequent calls)
5692ffd87d3SSergey Temerkhanov  * @state: ice_pkg_enum structure that will hold the state of the enumeration
5702ffd87d3SSergey Temerkhanov  * @value: pointer to a value that will return the label's value if found
5712ffd87d3SSergey Temerkhanov  *
5722ffd87d3SSergey Temerkhanov  * Enumerates a list of labels in the package. The caller will call
5732ffd87d3SSergey Temerkhanov  * ice_enum_labels(ice_seg, type, ...) to start the enumeration, then call
5742ffd87d3SSergey Temerkhanov  * ice_enum_labels(NULL, 0, ...) to continue. When the function returns a NULL
5752ffd87d3SSergey Temerkhanov  * the end of the list has been reached.
5762ffd87d3SSergey Temerkhanov  */
5772ffd87d3SSergey Temerkhanov static char *ice_enum_labels(struct ice_seg *ice_seg, u32 type,
5782ffd87d3SSergey Temerkhanov 			     struct ice_pkg_enum *state, u16 *value)
5792ffd87d3SSergey Temerkhanov {
5802ffd87d3SSergey Temerkhanov 	struct ice_label *label;
5812ffd87d3SSergey Temerkhanov 
5822ffd87d3SSergey Temerkhanov 	/* Check for valid label section on first call */
5832ffd87d3SSergey Temerkhanov 	if (type && !(type >= ICE_SID_LBL_FIRST && type <= ICE_SID_LBL_LAST))
5842ffd87d3SSergey Temerkhanov 		return NULL;
5852ffd87d3SSergey Temerkhanov 
5862ffd87d3SSergey Temerkhanov 	label = ice_pkg_enum_entry(ice_seg, state, type, NULL,
5872ffd87d3SSergey Temerkhanov 				   ice_label_enum_handler);
5882ffd87d3SSergey Temerkhanov 	if (!label)
5892ffd87d3SSergey Temerkhanov 		return NULL;
5902ffd87d3SSergey Temerkhanov 
5912ffd87d3SSergey Temerkhanov 	*value = le16_to_cpu(label->value);
5922ffd87d3SSergey Temerkhanov 	return label->name;
5932ffd87d3SSergey Temerkhanov }
5942ffd87d3SSergey Temerkhanov 
5952ffd87d3SSergey Temerkhanov /**
5962ffd87d3SSergey Temerkhanov  * ice_boost_tcam_handler
5972ffd87d3SSergey Temerkhanov  * @sect_type: section type
5982ffd87d3SSergey Temerkhanov  * @section: pointer to section
5992ffd87d3SSergey Temerkhanov  * @index: index of the boost TCAM entry to be returned
6002ffd87d3SSergey Temerkhanov  * @offset: pointer to receive absolute offset, always 0 for boost TCAM sections
6012ffd87d3SSergey Temerkhanov  *
6022ffd87d3SSergey Temerkhanov  * This is a callback function that can be passed to ice_pkg_enum_entry.
6032ffd87d3SSergey Temerkhanov  * Handles enumeration of individual boost TCAM entries.
6042ffd87d3SSergey Temerkhanov  */
6052ffd87d3SSergey Temerkhanov static void *ice_boost_tcam_handler(u32 sect_type, void *section, u32 index,
6062ffd87d3SSergey Temerkhanov 				    u32 *offset)
6072ffd87d3SSergey Temerkhanov {
6082ffd87d3SSergey Temerkhanov 	struct ice_boost_tcam_section *boost;
6092ffd87d3SSergey Temerkhanov 
6102ffd87d3SSergey Temerkhanov 	if (!section)
6112ffd87d3SSergey Temerkhanov 		return NULL;
6122ffd87d3SSergey Temerkhanov 
6132ffd87d3SSergey Temerkhanov 	if (sect_type != ICE_SID_RXPARSER_BOOST_TCAM)
6142ffd87d3SSergey Temerkhanov 		return NULL;
6152ffd87d3SSergey Temerkhanov 
6162ffd87d3SSergey Temerkhanov 	if (index > ICE_MAX_BST_TCAMS_IN_BUF)
6172ffd87d3SSergey Temerkhanov 		return NULL;
6182ffd87d3SSergey Temerkhanov 
6192ffd87d3SSergey Temerkhanov 	if (offset)
6202ffd87d3SSergey Temerkhanov 		*offset = 0;
6212ffd87d3SSergey Temerkhanov 
6222ffd87d3SSergey Temerkhanov 	boost = section;
6232ffd87d3SSergey Temerkhanov 	if (index >= le16_to_cpu(boost->count))
6242ffd87d3SSergey Temerkhanov 		return NULL;
6252ffd87d3SSergey Temerkhanov 
6262ffd87d3SSergey Temerkhanov 	return boost->tcam + index;
6272ffd87d3SSergey Temerkhanov }
6282ffd87d3SSergey Temerkhanov 
6292ffd87d3SSergey Temerkhanov /**
6302ffd87d3SSergey Temerkhanov  * ice_find_boost_entry
6312ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the ice segment (non-NULL)
6322ffd87d3SSergey Temerkhanov  * @addr: Boost TCAM address of entry to search for
6332ffd87d3SSergey Temerkhanov  * @entry: returns pointer to the entry
6342ffd87d3SSergey Temerkhanov  *
6352ffd87d3SSergey Temerkhanov  * Finds a particular Boost TCAM entry and returns a pointer to that entry
6362ffd87d3SSergey Temerkhanov  * if it is found. The ice_seg parameter must not be NULL since the first call
6372ffd87d3SSergey Temerkhanov  * to ice_pkg_enum_entry requires a pointer to an actual ice_segment structure.
6382ffd87d3SSergey Temerkhanov  */
6392ffd87d3SSergey Temerkhanov static int ice_find_boost_entry(struct ice_seg *ice_seg, u16 addr,
6402ffd87d3SSergey Temerkhanov 				struct ice_boost_tcam_entry **entry)
6412ffd87d3SSergey Temerkhanov {
6422ffd87d3SSergey Temerkhanov 	struct ice_boost_tcam_entry *tcam;
6432ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
6442ffd87d3SSergey Temerkhanov 
6452ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
6462ffd87d3SSergey Temerkhanov 
6472ffd87d3SSergey Temerkhanov 	if (!ice_seg)
6482ffd87d3SSergey Temerkhanov 		return -EINVAL;
6492ffd87d3SSergey Temerkhanov 
6502ffd87d3SSergey Temerkhanov 	do {
6512ffd87d3SSergey Temerkhanov 		tcam = ice_pkg_enum_entry(ice_seg, &state,
6522ffd87d3SSergey Temerkhanov 					  ICE_SID_RXPARSER_BOOST_TCAM, NULL,
6532ffd87d3SSergey Temerkhanov 					  ice_boost_tcam_handler);
6542ffd87d3SSergey Temerkhanov 		if (tcam && le16_to_cpu(tcam->addr) == addr) {
6552ffd87d3SSergey Temerkhanov 			*entry = tcam;
6562ffd87d3SSergey Temerkhanov 			return 0;
6572ffd87d3SSergey Temerkhanov 		}
6582ffd87d3SSergey Temerkhanov 
6592ffd87d3SSergey Temerkhanov 		ice_seg = NULL;
6602ffd87d3SSergey Temerkhanov 	} while (tcam);
6612ffd87d3SSergey Temerkhanov 
6622ffd87d3SSergey Temerkhanov 	*entry = NULL;
6632ffd87d3SSergey Temerkhanov 	return -EIO;
6642ffd87d3SSergey Temerkhanov }
6652ffd87d3SSergey Temerkhanov 
6662ffd87d3SSergey Temerkhanov /**
6672ffd87d3SSergey Temerkhanov  * ice_is_init_pkg_successful - check if DDP init was successful
6682ffd87d3SSergey Temerkhanov  * @state: state of the DDP pkg after download
6692ffd87d3SSergey Temerkhanov  */
6702ffd87d3SSergey Temerkhanov bool ice_is_init_pkg_successful(enum ice_ddp_state state)
6712ffd87d3SSergey Temerkhanov {
6722ffd87d3SSergey Temerkhanov 	switch (state) {
6732ffd87d3SSergey Temerkhanov 	case ICE_DDP_PKG_SUCCESS:
6742ffd87d3SSergey Temerkhanov 	case ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED:
6752ffd87d3SSergey Temerkhanov 	case ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED:
6762ffd87d3SSergey Temerkhanov 		return true;
6772ffd87d3SSergey Temerkhanov 	default:
6782ffd87d3SSergey Temerkhanov 		return false;
6792ffd87d3SSergey Temerkhanov 	}
6802ffd87d3SSergey Temerkhanov }
6812ffd87d3SSergey Temerkhanov 
6822ffd87d3SSergey Temerkhanov /**
6832ffd87d3SSergey Temerkhanov  * ice_pkg_buf_alloc
6842ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
6852ffd87d3SSergey Temerkhanov  *
6862ffd87d3SSergey Temerkhanov  * Allocates a package buffer and returns a pointer to the buffer header.
6872ffd87d3SSergey Temerkhanov  * Note: all package contents must be in Little Endian form.
6882ffd87d3SSergey Temerkhanov  */
6892ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
6902ffd87d3SSergey Temerkhanov {
6912ffd87d3SSergey Temerkhanov 	struct ice_buf_build *bld;
6922ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *buf;
6932ffd87d3SSergey Temerkhanov 
6942ffd87d3SSergey Temerkhanov 	bld = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*bld), GFP_KERNEL);
6952ffd87d3SSergey Temerkhanov 	if (!bld)
6962ffd87d3SSergey Temerkhanov 		return NULL;
6972ffd87d3SSergey Temerkhanov 
6982ffd87d3SSergey Temerkhanov 	buf = (struct ice_buf_hdr *)bld;
6992ffd87d3SSergey Temerkhanov 	buf->data_end =
7002ffd87d3SSergey Temerkhanov 		cpu_to_le16(offsetof(struct ice_buf_hdr, section_entry));
7012ffd87d3SSergey Temerkhanov 	return bld;
7022ffd87d3SSergey Temerkhanov }
7032ffd87d3SSergey Temerkhanov 
7042ffd87d3SSergey Temerkhanov static bool ice_is_gtp_u_profile(u16 prof_idx)
7052ffd87d3SSergey Temerkhanov {
7062ffd87d3SSergey Temerkhanov 	return (prof_idx >= ICE_PROFID_IPV6_GTPU_TEID &&
7072ffd87d3SSergey Temerkhanov 		prof_idx <= ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER) ||
7082ffd87d3SSergey Temerkhanov 	       prof_idx == ICE_PROFID_IPV4_GTPU_TEID;
7092ffd87d3SSergey Temerkhanov }
7102ffd87d3SSergey Temerkhanov 
7112ffd87d3SSergey Temerkhanov static bool ice_is_gtp_c_profile(u16 prof_idx)
7122ffd87d3SSergey Temerkhanov {
7132ffd87d3SSergey Temerkhanov 	switch (prof_idx) {
7142ffd87d3SSergey Temerkhanov 	case ICE_PROFID_IPV4_GTPC_TEID:
7152ffd87d3SSergey Temerkhanov 	case ICE_PROFID_IPV4_GTPC_NO_TEID:
7162ffd87d3SSergey Temerkhanov 	case ICE_PROFID_IPV6_GTPC_TEID:
7172ffd87d3SSergey Temerkhanov 	case ICE_PROFID_IPV6_GTPC_NO_TEID:
7182ffd87d3SSergey Temerkhanov 		return true;
7192ffd87d3SSergey Temerkhanov 	default:
7202ffd87d3SSergey Temerkhanov 		return false;
7212ffd87d3SSergey Temerkhanov 	}
7222ffd87d3SSergey Temerkhanov }
7232ffd87d3SSergey Temerkhanov 
724*784feaa6SMarcin Szycik static bool ice_is_pfcp_profile(u16 prof_idx)
725*784feaa6SMarcin Szycik {
726*784feaa6SMarcin Szycik 	return prof_idx >= ICE_PROFID_IPV4_PFCP_NODE &&
727*784feaa6SMarcin Szycik 	       prof_idx <= ICE_PROFID_IPV6_PFCP_SESSION;
728*784feaa6SMarcin Szycik }
729*784feaa6SMarcin Szycik 
7302ffd87d3SSergey Temerkhanov /**
7312ffd87d3SSergey Temerkhanov  * ice_get_sw_prof_type - determine switch profile type
7322ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
7332ffd87d3SSergey Temerkhanov  * @fv: pointer to the switch field vector
7342ffd87d3SSergey Temerkhanov  * @prof_idx: profile index to check
7352ffd87d3SSergey Temerkhanov  */
7362ffd87d3SSergey Temerkhanov static enum ice_prof_type ice_get_sw_prof_type(struct ice_hw *hw,
7372ffd87d3SSergey Temerkhanov 					       struct ice_fv *fv, u32 prof_idx)
7382ffd87d3SSergey Temerkhanov {
7392ffd87d3SSergey Temerkhanov 	u16 i;
7402ffd87d3SSergey Temerkhanov 
7412ffd87d3SSergey Temerkhanov 	if (ice_is_gtp_c_profile(prof_idx))
7422ffd87d3SSergey Temerkhanov 		return ICE_PROF_TUN_GTPC;
7432ffd87d3SSergey Temerkhanov 
7442ffd87d3SSergey Temerkhanov 	if (ice_is_gtp_u_profile(prof_idx))
7452ffd87d3SSergey Temerkhanov 		return ICE_PROF_TUN_GTPU;
7462ffd87d3SSergey Temerkhanov 
747*784feaa6SMarcin Szycik 	if (ice_is_pfcp_profile(prof_idx))
748*784feaa6SMarcin Szycik 		return ICE_PROF_TUN_PFCP;
749*784feaa6SMarcin Szycik 
7502ffd87d3SSergey Temerkhanov 	for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) {
7512ffd87d3SSergey Temerkhanov 		/* UDP tunnel will have UDP_OF protocol ID and VNI offset */
7522ffd87d3SSergey Temerkhanov 		if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF &&
7532ffd87d3SSergey Temerkhanov 		    fv->ew[i].off == ICE_VNI_OFFSET)
7542ffd87d3SSergey Temerkhanov 			return ICE_PROF_TUN_UDP;
7552ffd87d3SSergey Temerkhanov 
7562ffd87d3SSergey Temerkhanov 		/* GRE tunnel will have GRE protocol */
7572ffd87d3SSergey Temerkhanov 		if (fv->ew[i].prot_id == (u8)ICE_PROT_GRE_OF)
7582ffd87d3SSergey Temerkhanov 			return ICE_PROF_TUN_GRE;
7592ffd87d3SSergey Temerkhanov 	}
7602ffd87d3SSergey Temerkhanov 
7612ffd87d3SSergey Temerkhanov 	return ICE_PROF_NON_TUN;
7622ffd87d3SSergey Temerkhanov }
7632ffd87d3SSergey Temerkhanov 
7642ffd87d3SSergey Temerkhanov /**
7652ffd87d3SSergey Temerkhanov  * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type
7662ffd87d3SSergey Temerkhanov  * @hw: pointer to hardware structure
7672ffd87d3SSergey Temerkhanov  * @req_profs: type of profiles requested
7682ffd87d3SSergey Temerkhanov  * @bm: pointer to memory for returning the bitmap of field vectors
7692ffd87d3SSergey Temerkhanov  */
7702ffd87d3SSergey Temerkhanov void ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
7712ffd87d3SSergey Temerkhanov 			  unsigned long *bm)
7722ffd87d3SSergey Temerkhanov {
7732ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
7742ffd87d3SSergey Temerkhanov 	struct ice_seg *ice_seg;
7752ffd87d3SSergey Temerkhanov 	struct ice_fv *fv;
7762ffd87d3SSergey Temerkhanov 
7772ffd87d3SSergey Temerkhanov 	if (req_profs == ICE_PROF_ALL) {
7782ffd87d3SSergey Temerkhanov 		bitmap_set(bm, 0, ICE_MAX_NUM_PROFILES);
7792ffd87d3SSergey Temerkhanov 		return;
7802ffd87d3SSergey Temerkhanov 	}
7812ffd87d3SSergey Temerkhanov 
7822ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
7832ffd87d3SSergey Temerkhanov 	bitmap_zero(bm, ICE_MAX_NUM_PROFILES);
7842ffd87d3SSergey Temerkhanov 	ice_seg = hw->seg;
7852ffd87d3SSergey Temerkhanov 	do {
7862ffd87d3SSergey Temerkhanov 		enum ice_prof_type prof_type;
7872ffd87d3SSergey Temerkhanov 		u32 offset;
7882ffd87d3SSergey Temerkhanov 
7892ffd87d3SSergey Temerkhanov 		fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
7902ffd87d3SSergey Temerkhanov 					&offset, ice_sw_fv_handler);
7912ffd87d3SSergey Temerkhanov 		ice_seg = NULL;
7922ffd87d3SSergey Temerkhanov 
7932ffd87d3SSergey Temerkhanov 		if (fv) {
7942ffd87d3SSergey Temerkhanov 			/* Determine field vector type */
7952ffd87d3SSergey Temerkhanov 			prof_type = ice_get_sw_prof_type(hw, fv, offset);
7962ffd87d3SSergey Temerkhanov 
7972ffd87d3SSergey Temerkhanov 			if (req_profs & prof_type)
7982ffd87d3SSergey Temerkhanov 				set_bit((u16)offset, bm);
7992ffd87d3SSergey Temerkhanov 		}
8002ffd87d3SSergey Temerkhanov 	} while (fv);
8012ffd87d3SSergey Temerkhanov }
8022ffd87d3SSergey Temerkhanov 
8032ffd87d3SSergey Temerkhanov /**
8042ffd87d3SSergey Temerkhanov  * ice_get_sw_fv_list
8052ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
8062ffd87d3SSergey Temerkhanov  * @lkups: list of protocol types
8072ffd87d3SSergey Temerkhanov  * @bm: bitmap of field vectors to consider
8082ffd87d3SSergey Temerkhanov  * @fv_list: Head of a list
8092ffd87d3SSergey Temerkhanov  *
8102ffd87d3SSergey Temerkhanov  * Finds all the field vector entries from switch block that contain
8112ffd87d3SSergey Temerkhanov  * a given protocol ID and offset and returns a list of structures of type
8122ffd87d3SSergey Temerkhanov  * "ice_sw_fv_list_entry". Every structure in the list has a field vector
8132ffd87d3SSergey Temerkhanov  * definition and profile ID information
8142ffd87d3SSergey Temerkhanov  * NOTE: The caller of the function is responsible for freeing the memory
8152ffd87d3SSergey Temerkhanov  * allocated for every list entry.
8162ffd87d3SSergey Temerkhanov  */
8172ffd87d3SSergey Temerkhanov int ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups,
8182ffd87d3SSergey Temerkhanov 		       unsigned long *bm, struct list_head *fv_list)
8192ffd87d3SSergey Temerkhanov {
8202ffd87d3SSergey Temerkhanov 	struct ice_sw_fv_list_entry *fvl;
8212ffd87d3SSergey Temerkhanov 	struct ice_sw_fv_list_entry *tmp;
8222ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
8232ffd87d3SSergey Temerkhanov 	struct ice_seg *ice_seg;
8242ffd87d3SSergey Temerkhanov 	struct ice_fv *fv;
8252ffd87d3SSergey Temerkhanov 	u32 offset;
8262ffd87d3SSergey Temerkhanov 
8272ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
8282ffd87d3SSergey Temerkhanov 
8292ffd87d3SSergey Temerkhanov 	if (!lkups->n_val_words || !hw->seg)
8302ffd87d3SSergey Temerkhanov 		return -EINVAL;
8312ffd87d3SSergey Temerkhanov 
8322ffd87d3SSergey Temerkhanov 	ice_seg = hw->seg;
8332ffd87d3SSergey Temerkhanov 	do {
8342ffd87d3SSergey Temerkhanov 		u16 i;
8352ffd87d3SSergey Temerkhanov 
8362ffd87d3SSergey Temerkhanov 		fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
8372ffd87d3SSergey Temerkhanov 					&offset, ice_sw_fv_handler);
8382ffd87d3SSergey Temerkhanov 		if (!fv)
8392ffd87d3SSergey Temerkhanov 			break;
8402ffd87d3SSergey Temerkhanov 		ice_seg = NULL;
8412ffd87d3SSergey Temerkhanov 
8422ffd87d3SSergey Temerkhanov 		/* If field vector is not in the bitmap list, then skip this
8432ffd87d3SSergey Temerkhanov 		 * profile.
8442ffd87d3SSergey Temerkhanov 		 */
8452ffd87d3SSergey Temerkhanov 		if (!test_bit((u16)offset, bm))
8462ffd87d3SSergey Temerkhanov 			continue;
8472ffd87d3SSergey Temerkhanov 
8482ffd87d3SSergey Temerkhanov 		for (i = 0; i < lkups->n_val_words; i++) {
8492ffd87d3SSergey Temerkhanov 			int j;
8502ffd87d3SSergey Temerkhanov 
8512ffd87d3SSergey Temerkhanov 			for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
8522ffd87d3SSergey Temerkhanov 				if (fv->ew[j].prot_id ==
8532ffd87d3SSergey Temerkhanov 					    lkups->fv_words[i].prot_id &&
8542ffd87d3SSergey Temerkhanov 				    fv->ew[j].off == lkups->fv_words[i].off)
8552ffd87d3SSergey Temerkhanov 					break;
8562ffd87d3SSergey Temerkhanov 			if (j >= hw->blk[ICE_BLK_SW].es.fvw)
8572ffd87d3SSergey Temerkhanov 				break;
8582ffd87d3SSergey Temerkhanov 			if (i + 1 == lkups->n_val_words) {
8592ffd87d3SSergey Temerkhanov 				fvl = devm_kzalloc(ice_hw_to_dev(hw),
8602ffd87d3SSergey Temerkhanov 						   sizeof(*fvl), GFP_KERNEL);
8612ffd87d3SSergey Temerkhanov 				if (!fvl)
8622ffd87d3SSergey Temerkhanov 					goto err;
8632ffd87d3SSergey Temerkhanov 				fvl->fv_ptr = fv;
8642ffd87d3SSergey Temerkhanov 				fvl->profile_id = offset;
8652ffd87d3SSergey Temerkhanov 				list_add(&fvl->list_entry, fv_list);
8662ffd87d3SSergey Temerkhanov 				break;
8672ffd87d3SSergey Temerkhanov 			}
8682ffd87d3SSergey Temerkhanov 		}
8692ffd87d3SSergey Temerkhanov 	} while (fv);
8702ffd87d3SSergey Temerkhanov 	if (list_empty(fv_list)) {
8712ffd87d3SSergey Temerkhanov 		dev_warn(ice_hw_to_dev(hw),
8722ffd87d3SSergey Temerkhanov 			 "Required profiles not found in currently loaded DDP package");
8732ffd87d3SSergey Temerkhanov 		return -EIO;
8742ffd87d3SSergey Temerkhanov 	}
8752ffd87d3SSergey Temerkhanov 
8762ffd87d3SSergey Temerkhanov 	return 0;
8772ffd87d3SSergey Temerkhanov 
8782ffd87d3SSergey Temerkhanov err:
8792ffd87d3SSergey Temerkhanov 	list_for_each_entry_safe(fvl, tmp, fv_list, list_entry) {
8802ffd87d3SSergey Temerkhanov 		list_del(&fvl->list_entry);
8812ffd87d3SSergey Temerkhanov 		devm_kfree(ice_hw_to_dev(hw), fvl);
8822ffd87d3SSergey Temerkhanov 	}
8832ffd87d3SSergey Temerkhanov 
8842ffd87d3SSergey Temerkhanov 	return -ENOMEM;
8852ffd87d3SSergey Temerkhanov }
8862ffd87d3SSergey Temerkhanov 
8872ffd87d3SSergey Temerkhanov /**
8882ffd87d3SSergey Temerkhanov  * ice_init_prof_result_bm - Initialize the profile result index bitmap
8892ffd87d3SSergey Temerkhanov  * @hw: pointer to hardware structure
8902ffd87d3SSergey Temerkhanov  */
8912ffd87d3SSergey Temerkhanov void ice_init_prof_result_bm(struct ice_hw *hw)
8922ffd87d3SSergey Temerkhanov {
8932ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
8942ffd87d3SSergey Temerkhanov 	struct ice_seg *ice_seg;
8952ffd87d3SSergey Temerkhanov 	struct ice_fv *fv;
8962ffd87d3SSergey Temerkhanov 
8972ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
8982ffd87d3SSergey Temerkhanov 
8992ffd87d3SSergey Temerkhanov 	if (!hw->seg)
9002ffd87d3SSergey Temerkhanov 		return;
9012ffd87d3SSergey Temerkhanov 
9022ffd87d3SSergey Temerkhanov 	ice_seg = hw->seg;
9032ffd87d3SSergey Temerkhanov 	do {
9042ffd87d3SSergey Temerkhanov 		u32 off;
9052ffd87d3SSergey Temerkhanov 		u16 i;
9062ffd87d3SSergey Temerkhanov 
9072ffd87d3SSergey Temerkhanov 		fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
9082ffd87d3SSergey Temerkhanov 					&off, ice_sw_fv_handler);
9092ffd87d3SSergey Temerkhanov 		ice_seg = NULL;
9102ffd87d3SSergey Temerkhanov 		if (!fv)
9112ffd87d3SSergey Temerkhanov 			break;
9122ffd87d3SSergey Temerkhanov 
9132ffd87d3SSergey Temerkhanov 		bitmap_zero(hw->switch_info->prof_res_bm[off],
9142ffd87d3SSergey Temerkhanov 			    ICE_MAX_FV_WORDS);
9152ffd87d3SSergey Temerkhanov 
9162ffd87d3SSergey Temerkhanov 		/* Determine empty field vector indices, these can be
9172ffd87d3SSergey Temerkhanov 		 * used for recipe results. Skip index 0, since it is
9182ffd87d3SSergey Temerkhanov 		 * always used for Switch ID.
9192ffd87d3SSergey Temerkhanov 		 */
9202ffd87d3SSergey Temerkhanov 		for (i = 1; i < ICE_MAX_FV_WORDS; i++)
9212ffd87d3SSergey Temerkhanov 			if (fv->ew[i].prot_id == ICE_PROT_INVALID &&
9222ffd87d3SSergey Temerkhanov 			    fv->ew[i].off == ICE_FV_OFFSET_INVAL)
9232ffd87d3SSergey Temerkhanov 				set_bit(i, hw->switch_info->prof_res_bm[off]);
9242ffd87d3SSergey Temerkhanov 	} while (fv);
9252ffd87d3SSergey Temerkhanov }
9262ffd87d3SSergey Temerkhanov 
9272ffd87d3SSergey Temerkhanov /**
9282ffd87d3SSergey Temerkhanov  * ice_pkg_buf_free
9292ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
9302ffd87d3SSergey Temerkhanov  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
9312ffd87d3SSergey Temerkhanov  *
9322ffd87d3SSergey Temerkhanov  * Frees a package buffer
9332ffd87d3SSergey Temerkhanov  */
9342ffd87d3SSergey Temerkhanov void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld)
9352ffd87d3SSergey Temerkhanov {
9362ffd87d3SSergey Temerkhanov 	devm_kfree(ice_hw_to_dev(hw), bld);
9372ffd87d3SSergey Temerkhanov }
9382ffd87d3SSergey Temerkhanov 
9392ffd87d3SSergey Temerkhanov /**
9402ffd87d3SSergey Temerkhanov  * ice_pkg_buf_reserve_section
9412ffd87d3SSergey Temerkhanov  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
9422ffd87d3SSergey Temerkhanov  * @count: the number of sections to reserve
9432ffd87d3SSergey Temerkhanov  *
9442ffd87d3SSergey Temerkhanov  * Reserves one or more section table entries in a package buffer. This routine
9452ffd87d3SSergey Temerkhanov  * can be called multiple times as long as they are made before calling
9462ffd87d3SSergey Temerkhanov  * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section()
9472ffd87d3SSergey Temerkhanov  * is called once, the number of sections that can be allocated will not be able
9482ffd87d3SSergey Temerkhanov  * to be increased; not using all reserved sections is fine, but this will
9492ffd87d3SSergey Temerkhanov  * result in some wasted space in the buffer.
9502ffd87d3SSergey Temerkhanov  * Note: all package contents must be in Little Endian form.
9512ffd87d3SSergey Temerkhanov  */
9522ffd87d3SSergey Temerkhanov int ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count)
9532ffd87d3SSergey Temerkhanov {
9542ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *buf;
9552ffd87d3SSergey Temerkhanov 	u16 section_count;
9562ffd87d3SSergey Temerkhanov 	u16 data_end;
9572ffd87d3SSergey Temerkhanov 
9582ffd87d3SSergey Temerkhanov 	if (!bld)
9592ffd87d3SSergey Temerkhanov 		return -EINVAL;
9602ffd87d3SSergey Temerkhanov 
9612ffd87d3SSergey Temerkhanov 	buf = (struct ice_buf_hdr *)&bld->buf;
9622ffd87d3SSergey Temerkhanov 
9632ffd87d3SSergey Temerkhanov 	/* already an active section, can't increase table size */
9642ffd87d3SSergey Temerkhanov 	section_count = le16_to_cpu(buf->section_count);
9652ffd87d3SSergey Temerkhanov 	if (section_count > 0)
9662ffd87d3SSergey Temerkhanov 		return -EIO;
9672ffd87d3SSergey Temerkhanov 
9682ffd87d3SSergey Temerkhanov 	if (bld->reserved_section_table_entries + count > ICE_MAX_S_COUNT)
9692ffd87d3SSergey Temerkhanov 		return -EIO;
9702ffd87d3SSergey Temerkhanov 	bld->reserved_section_table_entries += count;
9712ffd87d3SSergey Temerkhanov 
9722ffd87d3SSergey Temerkhanov 	data_end = le16_to_cpu(buf->data_end) +
9732ffd87d3SSergey Temerkhanov 		   flex_array_size(buf, section_entry, count);
9742ffd87d3SSergey Temerkhanov 	buf->data_end = cpu_to_le16(data_end);
9752ffd87d3SSergey Temerkhanov 
9762ffd87d3SSergey Temerkhanov 	return 0;
9772ffd87d3SSergey Temerkhanov }
9782ffd87d3SSergey Temerkhanov 
9792ffd87d3SSergey Temerkhanov /**
9802ffd87d3SSergey Temerkhanov  * ice_pkg_buf_alloc_section
9812ffd87d3SSergey Temerkhanov  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
9822ffd87d3SSergey Temerkhanov  * @type: the section type value
9832ffd87d3SSergey Temerkhanov  * @size: the size of the section to reserve (in bytes)
9842ffd87d3SSergey Temerkhanov  *
9852ffd87d3SSergey Temerkhanov  * Reserves memory in the buffer for a section's content and updates the
9862ffd87d3SSergey Temerkhanov  * buffers' status accordingly. This routine returns a pointer to the first
9872ffd87d3SSergey Temerkhanov  * byte of the section start within the buffer, which is used to fill in the
9882ffd87d3SSergey Temerkhanov  * section contents.
9892ffd87d3SSergey Temerkhanov  * Note: all package contents must be in Little Endian form.
9902ffd87d3SSergey Temerkhanov  */
9912ffd87d3SSergey Temerkhanov void *ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size)
9922ffd87d3SSergey Temerkhanov {
9932ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *buf;
9942ffd87d3SSergey Temerkhanov 	u16 sect_count;
9952ffd87d3SSergey Temerkhanov 	u16 data_end;
9962ffd87d3SSergey Temerkhanov 
9972ffd87d3SSergey Temerkhanov 	if (!bld || !type || !size)
9982ffd87d3SSergey Temerkhanov 		return NULL;
9992ffd87d3SSergey Temerkhanov 
10002ffd87d3SSergey Temerkhanov 	buf = (struct ice_buf_hdr *)&bld->buf;
10012ffd87d3SSergey Temerkhanov 
10022ffd87d3SSergey Temerkhanov 	/* check for enough space left in buffer */
10032ffd87d3SSergey Temerkhanov 	data_end = le16_to_cpu(buf->data_end);
10042ffd87d3SSergey Temerkhanov 
10052ffd87d3SSergey Temerkhanov 	/* section start must align on 4 byte boundary */
10062ffd87d3SSergey Temerkhanov 	data_end = ALIGN(data_end, 4);
10072ffd87d3SSergey Temerkhanov 
10082ffd87d3SSergey Temerkhanov 	if ((data_end + size) > ICE_MAX_S_DATA_END)
10092ffd87d3SSergey Temerkhanov 		return NULL;
10102ffd87d3SSergey Temerkhanov 
10112ffd87d3SSergey Temerkhanov 	/* check for more available section table entries */
10122ffd87d3SSergey Temerkhanov 	sect_count = le16_to_cpu(buf->section_count);
10132ffd87d3SSergey Temerkhanov 	if (sect_count < bld->reserved_section_table_entries) {
10142ffd87d3SSergey Temerkhanov 		void *section_ptr = ((u8 *)buf) + data_end;
10152ffd87d3SSergey Temerkhanov 
10162ffd87d3SSergey Temerkhanov 		buf->section_entry[sect_count].offset = cpu_to_le16(data_end);
10172ffd87d3SSergey Temerkhanov 		buf->section_entry[sect_count].size = cpu_to_le16(size);
10182ffd87d3SSergey Temerkhanov 		buf->section_entry[sect_count].type = cpu_to_le32(type);
10192ffd87d3SSergey Temerkhanov 
10202ffd87d3SSergey Temerkhanov 		data_end += size;
10212ffd87d3SSergey Temerkhanov 		buf->data_end = cpu_to_le16(data_end);
10222ffd87d3SSergey Temerkhanov 
10232ffd87d3SSergey Temerkhanov 		buf->section_count = cpu_to_le16(sect_count + 1);
10242ffd87d3SSergey Temerkhanov 		return section_ptr;
10252ffd87d3SSergey Temerkhanov 	}
10262ffd87d3SSergey Temerkhanov 
10272ffd87d3SSergey Temerkhanov 	/* no free section table entries */
10282ffd87d3SSergey Temerkhanov 	return NULL;
10292ffd87d3SSergey Temerkhanov }
10302ffd87d3SSergey Temerkhanov 
10312ffd87d3SSergey Temerkhanov /**
10322ffd87d3SSergey Temerkhanov  * ice_pkg_buf_alloc_single_section
10332ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
10342ffd87d3SSergey Temerkhanov  * @type: the section type value
10352ffd87d3SSergey Temerkhanov  * @size: the size of the section to reserve (in bytes)
10362ffd87d3SSergey Temerkhanov  * @section: returns pointer to the section
10372ffd87d3SSergey Temerkhanov  *
10382ffd87d3SSergey Temerkhanov  * Allocates a package buffer with a single section.
10392ffd87d3SSergey Temerkhanov  * Note: all package contents must be in Little Endian form.
10402ffd87d3SSergey Temerkhanov  */
10412ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc_single_section(struct ice_hw *hw,
10422ffd87d3SSergey Temerkhanov 						       u32 type, u16 size,
10432ffd87d3SSergey Temerkhanov 						       void **section)
10442ffd87d3SSergey Temerkhanov {
10452ffd87d3SSergey Temerkhanov 	struct ice_buf_build *buf;
10462ffd87d3SSergey Temerkhanov 
10472ffd87d3SSergey Temerkhanov 	if (!section)
10482ffd87d3SSergey Temerkhanov 		return NULL;
10492ffd87d3SSergey Temerkhanov 
10502ffd87d3SSergey Temerkhanov 	buf = ice_pkg_buf_alloc(hw);
10512ffd87d3SSergey Temerkhanov 	if (!buf)
10522ffd87d3SSergey Temerkhanov 		return NULL;
10532ffd87d3SSergey Temerkhanov 
10542ffd87d3SSergey Temerkhanov 	if (ice_pkg_buf_reserve_section(buf, 1))
10552ffd87d3SSergey Temerkhanov 		goto ice_pkg_buf_alloc_single_section_err;
10562ffd87d3SSergey Temerkhanov 
10572ffd87d3SSergey Temerkhanov 	*section = ice_pkg_buf_alloc_section(buf, type, size);
10582ffd87d3SSergey Temerkhanov 	if (!*section)
10592ffd87d3SSergey Temerkhanov 		goto ice_pkg_buf_alloc_single_section_err;
10602ffd87d3SSergey Temerkhanov 
10612ffd87d3SSergey Temerkhanov 	return buf;
10622ffd87d3SSergey Temerkhanov 
10632ffd87d3SSergey Temerkhanov ice_pkg_buf_alloc_single_section_err:
10642ffd87d3SSergey Temerkhanov 	ice_pkg_buf_free(hw, buf);
10652ffd87d3SSergey Temerkhanov 	return NULL;
10662ffd87d3SSergey Temerkhanov }
10672ffd87d3SSergey Temerkhanov 
10682ffd87d3SSergey Temerkhanov /**
10692ffd87d3SSergey Temerkhanov  * ice_pkg_buf_get_active_sections
10702ffd87d3SSergey Temerkhanov  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
10712ffd87d3SSergey Temerkhanov  *
10722ffd87d3SSergey Temerkhanov  * Returns the number of active sections. Before using the package buffer
10732ffd87d3SSergey Temerkhanov  * in an update package command, the caller should make sure that there is at
10742ffd87d3SSergey Temerkhanov  * least one active section - otherwise, the buffer is not legal and should
10752ffd87d3SSergey Temerkhanov  * not be used.
10762ffd87d3SSergey Temerkhanov  * Note: all package contents must be in Little Endian form.
10772ffd87d3SSergey Temerkhanov  */
10782ffd87d3SSergey Temerkhanov u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld)
10792ffd87d3SSergey Temerkhanov {
10802ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *buf;
10812ffd87d3SSergey Temerkhanov 
10822ffd87d3SSergey Temerkhanov 	if (!bld)
10832ffd87d3SSergey Temerkhanov 		return 0;
10842ffd87d3SSergey Temerkhanov 
10852ffd87d3SSergey Temerkhanov 	buf = (struct ice_buf_hdr *)&bld->buf;
10862ffd87d3SSergey Temerkhanov 	return le16_to_cpu(buf->section_count);
10872ffd87d3SSergey Temerkhanov }
10882ffd87d3SSergey Temerkhanov 
10892ffd87d3SSergey Temerkhanov /**
10902ffd87d3SSergey Temerkhanov  * ice_pkg_buf
10912ffd87d3SSergey Temerkhanov  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
10922ffd87d3SSergey Temerkhanov  *
10932ffd87d3SSergey Temerkhanov  * Return a pointer to the buffer's header
10942ffd87d3SSergey Temerkhanov  */
10952ffd87d3SSergey Temerkhanov struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
10962ffd87d3SSergey Temerkhanov {
10972ffd87d3SSergey Temerkhanov 	if (!bld)
10982ffd87d3SSergey Temerkhanov 		return NULL;
10992ffd87d3SSergey Temerkhanov 
11002ffd87d3SSergey Temerkhanov 	return &bld->buf;
11012ffd87d3SSergey Temerkhanov }
11022ffd87d3SSergey Temerkhanov 
11032ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_map_aq_err_to_ddp_state(enum ice_aq_err aq_err)
11042ffd87d3SSergey Temerkhanov {
11052ffd87d3SSergey Temerkhanov 	switch (aq_err) {
11062ffd87d3SSergey Temerkhanov 	case ICE_AQ_RC_ENOSEC:
11072ffd87d3SSergey Temerkhanov 	case ICE_AQ_RC_EBADSIG:
11082ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_FILE_SIGNATURE_INVALID;
11092ffd87d3SSergey Temerkhanov 	case ICE_AQ_RC_ESVN:
11102ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_FILE_REVISION_TOO_LOW;
11112ffd87d3SSergey Temerkhanov 	case ICE_AQ_RC_EBADMAN:
11122ffd87d3SSergey Temerkhanov 	case ICE_AQ_RC_EBADBUF:
11132ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_LOAD_ERROR;
11142ffd87d3SSergey Temerkhanov 	default:
11152ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
11162ffd87d3SSergey Temerkhanov 	}
11172ffd87d3SSergey Temerkhanov }
11182ffd87d3SSergey Temerkhanov 
11192ffd87d3SSergey Temerkhanov /**
11202ffd87d3SSergey Temerkhanov  * ice_acquire_global_cfg_lock
11212ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
11222ffd87d3SSergey Temerkhanov  * @access: access type (read or write)
11232ffd87d3SSergey Temerkhanov  *
11242ffd87d3SSergey Temerkhanov  * This function will request ownership of the global config lock for reading
11252ffd87d3SSergey Temerkhanov  * or writing of the package. When attempting to obtain write access, the
11262ffd87d3SSergey Temerkhanov  * caller must check for the following two return values:
11272ffd87d3SSergey Temerkhanov  *
11282ffd87d3SSergey Temerkhanov  * 0         -  Means the caller has acquired the global config lock
11292ffd87d3SSergey Temerkhanov  *              and can perform writing of the package.
11302ffd87d3SSergey Temerkhanov  * -EALREADY - Indicates another driver has already written the
11312ffd87d3SSergey Temerkhanov  *             package or has found that no update was necessary; in
11322ffd87d3SSergey Temerkhanov  *             this case, the caller can just skip performing any
11332ffd87d3SSergey Temerkhanov  *             update of the package.
11342ffd87d3SSergey Temerkhanov  */
11352ffd87d3SSergey Temerkhanov static int ice_acquire_global_cfg_lock(struct ice_hw *hw,
11362ffd87d3SSergey Temerkhanov 				       enum ice_aq_res_access_type access)
11372ffd87d3SSergey Temerkhanov {
11382ffd87d3SSergey Temerkhanov 	int status;
11392ffd87d3SSergey Temerkhanov 
11402ffd87d3SSergey Temerkhanov 	status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, access,
11412ffd87d3SSergey Temerkhanov 				 ICE_GLOBAL_CFG_LOCK_TIMEOUT);
11422ffd87d3SSergey Temerkhanov 
11432ffd87d3SSergey Temerkhanov 	if (!status)
11442ffd87d3SSergey Temerkhanov 		mutex_lock(&ice_global_cfg_lock_sw);
11452ffd87d3SSergey Temerkhanov 	else if (status == -EALREADY)
11462ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG,
11472ffd87d3SSergey Temerkhanov 			  "Global config lock: No work to do\n");
11482ffd87d3SSergey Temerkhanov 
11492ffd87d3SSergey Temerkhanov 	return status;
11502ffd87d3SSergey Temerkhanov }
11512ffd87d3SSergey Temerkhanov 
11522ffd87d3SSergey Temerkhanov /**
11532ffd87d3SSergey Temerkhanov  * ice_release_global_cfg_lock
11542ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
11552ffd87d3SSergey Temerkhanov  *
11562ffd87d3SSergey Temerkhanov  * This function will release the global config lock.
11572ffd87d3SSergey Temerkhanov  */
11582ffd87d3SSergey Temerkhanov static void ice_release_global_cfg_lock(struct ice_hw *hw)
11592ffd87d3SSergey Temerkhanov {
11602ffd87d3SSergey Temerkhanov 	mutex_unlock(&ice_global_cfg_lock_sw);
11612ffd87d3SSergey Temerkhanov 	ice_release_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID);
11622ffd87d3SSergey Temerkhanov }
11632ffd87d3SSergey Temerkhanov 
11642ffd87d3SSergey Temerkhanov /**
1165708b352fSJan Sokolowski  * ice_aq_download_pkg
1166708b352fSJan Sokolowski  * @hw: pointer to the hardware structure
1167708b352fSJan Sokolowski  * @pkg_buf: the package buffer to transfer
1168708b352fSJan Sokolowski  * @buf_size: the size of the package buffer
1169708b352fSJan Sokolowski  * @last_buf: last buffer indicator
1170708b352fSJan Sokolowski  * @error_offset: returns error offset
1171708b352fSJan Sokolowski  * @error_info: returns error information
1172708b352fSJan Sokolowski  * @cd: pointer to command details structure or NULL
1173708b352fSJan Sokolowski  *
1174708b352fSJan Sokolowski  * Download Package (0x0C40)
1175708b352fSJan Sokolowski  */
1176708b352fSJan Sokolowski static int
1177708b352fSJan Sokolowski ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
1178708b352fSJan Sokolowski 		    u16 buf_size, bool last_buf, u32 *error_offset,
1179708b352fSJan Sokolowski 		    u32 *error_info, struct ice_sq_cd *cd)
1180708b352fSJan Sokolowski {
1181708b352fSJan Sokolowski 	struct ice_aqc_download_pkg *cmd;
1182708b352fSJan Sokolowski 	struct ice_aq_desc desc;
1183708b352fSJan Sokolowski 	int status;
1184708b352fSJan Sokolowski 
1185708b352fSJan Sokolowski 	if (error_offset)
1186708b352fSJan Sokolowski 		*error_offset = 0;
1187708b352fSJan Sokolowski 	if (error_info)
1188708b352fSJan Sokolowski 		*error_info = 0;
1189708b352fSJan Sokolowski 
1190708b352fSJan Sokolowski 	cmd = &desc.params.download_pkg;
1191708b352fSJan Sokolowski 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg);
1192708b352fSJan Sokolowski 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1193708b352fSJan Sokolowski 
1194708b352fSJan Sokolowski 	if (last_buf)
1195708b352fSJan Sokolowski 		cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
1196708b352fSJan Sokolowski 
1197708b352fSJan Sokolowski 	status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
1198708b352fSJan Sokolowski 	if (status == -EIO) {
1199708b352fSJan Sokolowski 		/* Read error from buffer only when the FW returned an error */
1200708b352fSJan Sokolowski 		struct ice_aqc_download_pkg_resp *resp;
1201708b352fSJan Sokolowski 
1202708b352fSJan Sokolowski 		resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
1203708b352fSJan Sokolowski 		if (error_offset)
1204708b352fSJan Sokolowski 			*error_offset = le32_to_cpu(resp->error_offset);
1205708b352fSJan Sokolowski 		if (error_info)
1206708b352fSJan Sokolowski 			*error_info = le32_to_cpu(resp->error_info);
1207708b352fSJan Sokolowski 	}
1208708b352fSJan Sokolowski 
1209708b352fSJan Sokolowski 	return status;
1210708b352fSJan Sokolowski }
1211708b352fSJan Sokolowski 
1212708b352fSJan Sokolowski /**
12133cbdb034SDan Nowlin  * ice_get_pkg_seg_by_idx
12143cbdb034SDan Nowlin  * @pkg_hdr: pointer to the package header to be searched
12153cbdb034SDan Nowlin  * @idx: index of segment
12163cbdb034SDan Nowlin  */
12173cbdb034SDan Nowlin static struct ice_generic_seg_hdr *
12183cbdb034SDan Nowlin ice_get_pkg_seg_by_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx)
12193cbdb034SDan Nowlin {
12203cbdb034SDan Nowlin 	if (idx < le32_to_cpu(pkg_hdr->seg_count))
12213cbdb034SDan Nowlin 		return (struct ice_generic_seg_hdr *)
12223cbdb034SDan Nowlin 			((u8 *)pkg_hdr +
12233cbdb034SDan Nowlin 			 le32_to_cpu(pkg_hdr->seg_offset[idx]));
12243cbdb034SDan Nowlin 
12253cbdb034SDan Nowlin 	return NULL;
12263cbdb034SDan Nowlin }
12273cbdb034SDan Nowlin 
12283cbdb034SDan Nowlin /**
12293cbdb034SDan Nowlin  * ice_is_signing_seg_at_idx - determine if segment is a signing segment
12303cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
12313cbdb034SDan Nowlin  * @idx: segment index
12323cbdb034SDan Nowlin  */
12333cbdb034SDan Nowlin static bool ice_is_signing_seg_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx)
12343cbdb034SDan Nowlin {
12353cbdb034SDan Nowlin 	struct ice_generic_seg_hdr *seg;
12363cbdb034SDan Nowlin 
12373cbdb034SDan Nowlin 	seg = ice_get_pkg_seg_by_idx(pkg_hdr, idx);
12383cbdb034SDan Nowlin 	if (!seg)
12393cbdb034SDan Nowlin 		return false;
12403cbdb034SDan Nowlin 
12413cbdb034SDan Nowlin 	return le32_to_cpu(seg->seg_type) == SEGMENT_TYPE_SIGNING;
12423cbdb034SDan Nowlin }
12433cbdb034SDan Nowlin 
12443cbdb034SDan Nowlin /**
12453cbdb034SDan Nowlin  * ice_is_signing_seg_type_at_idx
12463cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
12473cbdb034SDan Nowlin  * @idx: segment index
12483cbdb034SDan Nowlin  * @seg_id: segment id that is expected
12493cbdb034SDan Nowlin  * @sign_type: signing type
12503cbdb034SDan Nowlin  *
12513cbdb034SDan Nowlin  * Determine if a segment is a signing segment of the correct type
12523cbdb034SDan Nowlin  */
12533cbdb034SDan Nowlin static bool
12543cbdb034SDan Nowlin ice_is_signing_seg_type_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx,
12553cbdb034SDan Nowlin 			       u32 seg_id, u32 sign_type)
12563cbdb034SDan Nowlin {
12573cbdb034SDan Nowlin 	struct ice_sign_seg *seg;
12583cbdb034SDan Nowlin 
12593cbdb034SDan Nowlin 	if (!ice_is_signing_seg_at_idx(pkg_hdr, idx))
12603cbdb034SDan Nowlin 		return false;
12613cbdb034SDan Nowlin 
12623cbdb034SDan Nowlin 	seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
12633cbdb034SDan Nowlin 
12643cbdb034SDan Nowlin 	if (seg && le32_to_cpu(seg->seg_id) == seg_id &&
12653cbdb034SDan Nowlin 	    le32_to_cpu(seg->sign_type) == sign_type)
12663cbdb034SDan Nowlin 		return true;
12673cbdb034SDan Nowlin 
12683cbdb034SDan Nowlin 	return false;
12693cbdb034SDan Nowlin }
12703cbdb034SDan Nowlin 
12713cbdb034SDan Nowlin /**
12723cbdb034SDan Nowlin  * ice_is_buffer_metadata - determine if package buffer is a metadata buffer
12733cbdb034SDan Nowlin  * @buf: pointer to buffer header
12743cbdb034SDan Nowlin  */
12753cbdb034SDan Nowlin static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf)
12763cbdb034SDan Nowlin {
12773cbdb034SDan Nowlin 	if (le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF)
12783cbdb034SDan Nowlin 		return true;
12793cbdb034SDan Nowlin 
12803cbdb034SDan Nowlin 	return false;
12813cbdb034SDan Nowlin }
12823cbdb034SDan Nowlin 
12833cbdb034SDan Nowlin /**
12843cbdb034SDan Nowlin  * ice_is_last_download_buffer
12853cbdb034SDan Nowlin  * @buf: pointer to current buffer header
12863cbdb034SDan Nowlin  * @idx: index of the buffer in the current sequence
12873cbdb034SDan Nowlin  * @count: the buffer count in the current sequence
12883cbdb034SDan Nowlin  *
12893cbdb034SDan Nowlin  * Note: this routine should only be called if the buffer is not the last buffer
12903cbdb034SDan Nowlin  */
12913cbdb034SDan Nowlin static bool
12923cbdb034SDan Nowlin ice_is_last_download_buffer(struct ice_buf_hdr *buf, u32 idx, u32 count)
12933cbdb034SDan Nowlin {
12943cbdb034SDan Nowlin 	struct ice_buf *next_buf;
12953cbdb034SDan Nowlin 
12963cbdb034SDan Nowlin 	if ((idx + 1) == count)
12973cbdb034SDan Nowlin 		return true;
12983cbdb034SDan Nowlin 
12993cbdb034SDan Nowlin 	/* A set metadata flag in the next buffer will signal that the current
13003cbdb034SDan Nowlin 	 * buffer will be the last buffer downloaded
13013cbdb034SDan Nowlin 	 */
13023cbdb034SDan Nowlin 	next_buf = ((struct ice_buf *)buf) + 1;
13033cbdb034SDan Nowlin 
13043cbdb034SDan Nowlin 	return ice_is_buffer_metadata((struct ice_buf_hdr *)next_buf);
13053cbdb034SDan Nowlin }
13063cbdb034SDan Nowlin 
13073cbdb034SDan Nowlin /**
13083cbdb034SDan Nowlin  * ice_dwnld_cfg_bufs_no_lock
13092ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
13102ffd87d3SSergey Temerkhanov  * @bufs: pointer to an array of buffers
13113cbdb034SDan Nowlin  * @start: buffer index of first buffer to download
13123cbdb034SDan Nowlin  * @count: the number of buffers to download
13133cbdb034SDan Nowlin  * @indicate_last: if true, then set last buffer flag on last buffer download
13142ffd87d3SSergey Temerkhanov  *
13153cbdb034SDan Nowlin  * Downloads package configuration buffers to the firmware. Metadata buffers
13163cbdb034SDan Nowlin  * are skipped, and the first metadata buffer found indicates that the rest
13173cbdb034SDan Nowlin  * of the buffers are all metadata buffers.
13182ffd87d3SSergey Temerkhanov  */
13193cbdb034SDan Nowlin static enum ice_ddp_state
13203cbdb034SDan Nowlin ice_dwnld_cfg_bufs_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 start,
13213cbdb034SDan Nowlin 			   u32 count, bool indicate_last)
13222ffd87d3SSergey Temerkhanov {
13232ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS;
13242ffd87d3SSergey Temerkhanov 	struct ice_buf_hdr *bh;
13252ffd87d3SSergey Temerkhanov 	enum ice_aq_err err;
13262ffd87d3SSergey Temerkhanov 	u32 offset, info, i;
13272ffd87d3SSergey Temerkhanov 
13282ffd87d3SSergey Temerkhanov 	if (!bufs || !count)
13292ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
13302ffd87d3SSergey Temerkhanov 
13312ffd87d3SSergey Temerkhanov 	/* If the first buffer's first section has its metadata bit set
13322ffd87d3SSergey Temerkhanov 	 * then there are no buffers to be downloaded, and the operation is
13332ffd87d3SSergey Temerkhanov 	 * considered a success.
13342ffd87d3SSergey Temerkhanov 	 */
13353cbdb034SDan Nowlin 	bh = (struct ice_buf_hdr *)(bufs + start);
13362ffd87d3SSergey Temerkhanov 	if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF)
13372ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_SUCCESS;
13382ffd87d3SSergey Temerkhanov 
13392ffd87d3SSergey Temerkhanov 	for (i = 0; i < count; i++) {
13403cbdb034SDan Nowlin 		bool last = false;
13413cbdb034SDan Nowlin 		int status;
13422ffd87d3SSergey Temerkhanov 
13433cbdb034SDan Nowlin 		bh = (struct ice_buf_hdr *)(bufs + start + i);
13442ffd87d3SSergey Temerkhanov 
13453cbdb034SDan Nowlin 		if (indicate_last)
13463cbdb034SDan Nowlin 			last = ice_is_last_download_buffer(bh, i, count);
13472ffd87d3SSergey Temerkhanov 
13482ffd87d3SSergey Temerkhanov 		status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE, last,
13492ffd87d3SSergey Temerkhanov 					     &offset, &info, NULL);
13502ffd87d3SSergey Temerkhanov 
13512ffd87d3SSergey Temerkhanov 		/* Save AQ status from download package */
13522ffd87d3SSergey Temerkhanov 		if (status) {
13533cbdb034SDan Nowlin 			ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n",
13542ffd87d3SSergey Temerkhanov 				  status, offset, info);
13552ffd87d3SSergey Temerkhanov 			err = hw->adminq.sq_last_status;
13562ffd87d3SSergey Temerkhanov 			state = ice_map_aq_err_to_ddp_state(err);
13572ffd87d3SSergey Temerkhanov 			break;
13582ffd87d3SSergey Temerkhanov 		}
13592ffd87d3SSergey Temerkhanov 
13602ffd87d3SSergey Temerkhanov 		if (last)
13612ffd87d3SSergey Temerkhanov 			break;
13622ffd87d3SSergey Temerkhanov 	}
13632ffd87d3SSergey Temerkhanov 
13643cbdb034SDan Nowlin 	return state;
13652ffd87d3SSergey Temerkhanov }
13662ffd87d3SSergey Temerkhanov 
13673cbdb034SDan Nowlin /**
13683cbdb034SDan Nowlin  * ice_download_pkg_sig_seg - download a signature segment
13693cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
13703cbdb034SDan Nowlin  * @seg: pointer to signature segment
13713cbdb034SDan Nowlin  */
13723cbdb034SDan Nowlin static enum ice_ddp_state
13733cbdb034SDan Nowlin ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg)
13743cbdb034SDan Nowlin {
13753cbdb034SDan Nowlin 	return  ice_dwnld_cfg_bufs_no_lock(hw, seg->buf_tbl.buf_array, 0,
13763cbdb034SDan Nowlin 					   le32_to_cpu(seg->buf_tbl.buf_count),
13773cbdb034SDan Nowlin 					   false);
13783cbdb034SDan Nowlin }
13793cbdb034SDan Nowlin 
13803cbdb034SDan Nowlin /**
13813cbdb034SDan Nowlin  * ice_download_pkg_config_seg - download a config segment
13823cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
13833cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
13843cbdb034SDan Nowlin  * @idx: segment index
13853cbdb034SDan Nowlin  * @start: starting buffer
13863cbdb034SDan Nowlin  * @count: buffer count
13873cbdb034SDan Nowlin  *
13883cbdb034SDan Nowlin  * Note: idx must reference a ICE segment
13893cbdb034SDan Nowlin  */
13903cbdb034SDan Nowlin static enum ice_ddp_state
13913cbdb034SDan Nowlin ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
13923cbdb034SDan Nowlin 			    u32 idx, u32 start, u32 count)
13933cbdb034SDan Nowlin {
13943cbdb034SDan Nowlin 	struct ice_buf_table *bufs;
13953cbdb034SDan Nowlin 	struct ice_seg *seg;
13963cbdb034SDan Nowlin 	u32 buf_count;
13973cbdb034SDan Nowlin 
13983cbdb034SDan Nowlin 	seg = (struct ice_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
13993cbdb034SDan Nowlin 	if (!seg)
14003cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
14013cbdb034SDan Nowlin 
14023cbdb034SDan Nowlin 	bufs = ice_find_buf_table(seg);
14033cbdb034SDan Nowlin 	buf_count = le32_to_cpu(bufs->buf_count);
14043cbdb034SDan Nowlin 
14053cbdb034SDan Nowlin 	if (start >= buf_count || start + count > buf_count)
14063cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
14073cbdb034SDan Nowlin 
14083cbdb034SDan Nowlin 	return  ice_dwnld_cfg_bufs_no_lock(hw, bufs->buf_array, start, count,
14093cbdb034SDan Nowlin 					   true);
14103cbdb034SDan Nowlin }
14113cbdb034SDan Nowlin 
14123cbdb034SDan Nowlin /**
14133cbdb034SDan Nowlin  * ice_dwnld_sign_and_cfg_segs - download a signing segment and config segment
14143cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
14153cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
14163cbdb034SDan Nowlin  * @idx: segment index (must be a signature segment)
14173cbdb034SDan Nowlin  *
14183cbdb034SDan Nowlin  * Note: idx must reference a signature segment
14193cbdb034SDan Nowlin  */
14203cbdb034SDan Nowlin static enum ice_ddp_state
14213cbdb034SDan Nowlin ice_dwnld_sign_and_cfg_segs(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
14223cbdb034SDan Nowlin 			    u32 idx)
14233cbdb034SDan Nowlin {
14243cbdb034SDan Nowlin 	enum ice_ddp_state state;
14253cbdb034SDan Nowlin 	struct ice_sign_seg *seg;
14263cbdb034SDan Nowlin 	u32 conf_idx;
14273cbdb034SDan Nowlin 	u32 start;
14283cbdb034SDan Nowlin 	u32 count;
14293cbdb034SDan Nowlin 
14303cbdb034SDan Nowlin 	seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
14313cbdb034SDan Nowlin 	if (!seg) {
14323cbdb034SDan Nowlin 		state = ICE_DDP_PKG_ERR;
14333cbdb034SDan Nowlin 		goto exit;
14343cbdb034SDan Nowlin 	}
14353cbdb034SDan Nowlin 
14363cbdb034SDan Nowlin 	conf_idx = le32_to_cpu(seg->signed_seg_idx);
14373cbdb034SDan Nowlin 	start = le32_to_cpu(seg->signed_buf_start);
14383cbdb034SDan Nowlin 	count = le32_to_cpu(seg->signed_buf_count);
14393cbdb034SDan Nowlin 
14403cbdb034SDan Nowlin 	state = ice_download_pkg_sig_seg(hw, seg);
14413cbdb034SDan Nowlin 	if (state)
14423cbdb034SDan Nowlin 		goto exit;
14433cbdb034SDan Nowlin 
14443cbdb034SDan Nowlin 	state = ice_download_pkg_config_seg(hw, pkg_hdr, conf_idx, start,
14453cbdb034SDan Nowlin 					    count);
14463cbdb034SDan Nowlin 
14473cbdb034SDan Nowlin exit:
14483cbdb034SDan Nowlin 	return state;
14493cbdb034SDan Nowlin }
14503cbdb034SDan Nowlin 
14513cbdb034SDan Nowlin /**
14523cbdb034SDan Nowlin  * ice_match_signing_seg - determine if a matching signing segment exists
14533cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
14543cbdb034SDan Nowlin  * @seg_id: segment id that is expected
14553cbdb034SDan Nowlin  * @sign_type: signing type
14563cbdb034SDan Nowlin  */
14573cbdb034SDan Nowlin static bool
14583cbdb034SDan Nowlin ice_match_signing_seg(struct ice_pkg_hdr *pkg_hdr, u32 seg_id, u32 sign_type)
14593cbdb034SDan Nowlin {
14603cbdb034SDan Nowlin 	u32 i;
14613cbdb034SDan Nowlin 
14623cbdb034SDan Nowlin 	for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) {
14633cbdb034SDan Nowlin 		if (ice_is_signing_seg_type_at_idx(pkg_hdr, i, seg_id,
14643cbdb034SDan Nowlin 						   sign_type))
14653cbdb034SDan Nowlin 			return true;
14663cbdb034SDan Nowlin 	}
14673cbdb034SDan Nowlin 
14683cbdb034SDan Nowlin 	return false;
14693cbdb034SDan Nowlin }
14703cbdb034SDan Nowlin 
14713cbdb034SDan Nowlin /**
14723cbdb034SDan Nowlin  * ice_post_dwnld_pkg_actions - perform post download package actions
14733cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
14743cbdb034SDan Nowlin  */
14753cbdb034SDan Nowlin static enum ice_ddp_state
14763cbdb034SDan Nowlin ice_post_dwnld_pkg_actions(struct ice_hw *hw)
14773cbdb034SDan Nowlin {
14783cbdb034SDan Nowlin 	int status;
14793cbdb034SDan Nowlin 
14803cbdb034SDan Nowlin 	status = ice_set_vlan_mode(hw);
14813cbdb034SDan Nowlin 	if (status) {
14823cbdb034SDan Nowlin 		ice_debug(hw, ICE_DBG_PKG, "Failed to set VLAN mode: err %d\n",
14833cbdb034SDan Nowlin 			  status);
14843cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
14853cbdb034SDan Nowlin 	}
14863cbdb034SDan Nowlin 
14873cbdb034SDan Nowlin 	return ICE_DDP_PKG_SUCCESS;
14883cbdb034SDan Nowlin }
14893cbdb034SDan Nowlin 
14903cbdb034SDan Nowlin /**
1491a778616eSDan Nowlin  * ice_download_pkg_with_sig_seg
14923cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
14933cbdb034SDan Nowlin  * @pkg_hdr: pointer to package header
14943cbdb034SDan Nowlin  *
14953cbdb034SDan Nowlin  * Handles the download of a complete package.
14963cbdb034SDan Nowlin  */
14973cbdb034SDan Nowlin static enum ice_ddp_state
1498a778616eSDan Nowlin ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
14993cbdb034SDan Nowlin {
15003cbdb034SDan Nowlin 	enum ice_aq_err aq_err = hw->adminq.sq_last_status;
15013cbdb034SDan Nowlin 	enum ice_ddp_state state = ICE_DDP_PKG_ERR;
15023cbdb034SDan Nowlin 	int status;
15033cbdb034SDan Nowlin 	u32 i;
15043cbdb034SDan Nowlin 
15053cbdb034SDan Nowlin 	ice_debug(hw, ICE_DBG_INIT, "Segment ID %d\n", hw->pkg_seg_id);
15063cbdb034SDan Nowlin 	ice_debug(hw, ICE_DBG_INIT, "Signature type %d\n", hw->pkg_sign_type);
15073cbdb034SDan Nowlin 
15083cbdb034SDan Nowlin 	status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
15093cbdb034SDan Nowlin 	if (status) {
15103cbdb034SDan Nowlin 		if (status == -EALREADY)
15113cbdb034SDan Nowlin 			state = ICE_DDP_PKG_ALREADY_LOADED;
15123cbdb034SDan Nowlin 		else
15133cbdb034SDan Nowlin 			state = ice_map_aq_err_to_ddp_state(aq_err);
15143cbdb034SDan Nowlin 		return state;
15153cbdb034SDan Nowlin 	}
15163cbdb034SDan Nowlin 
15173cbdb034SDan Nowlin 	for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) {
15183cbdb034SDan Nowlin 		if (!ice_is_signing_seg_type_at_idx(pkg_hdr, i, hw->pkg_seg_id,
15193cbdb034SDan Nowlin 						    hw->pkg_sign_type))
15203cbdb034SDan Nowlin 			continue;
15213cbdb034SDan Nowlin 
15223cbdb034SDan Nowlin 		state = ice_dwnld_sign_and_cfg_segs(hw, pkg_hdr, i);
15233cbdb034SDan Nowlin 		if (state)
15243cbdb034SDan Nowlin 			break;
15253cbdb034SDan Nowlin 	}
15263cbdb034SDan Nowlin 
15273cbdb034SDan Nowlin 	if (!state)
15283cbdb034SDan Nowlin 		state = ice_post_dwnld_pkg_actions(hw);
15293cbdb034SDan Nowlin 
15302ffd87d3SSergey Temerkhanov 	ice_release_global_cfg_lock(hw);
1531a778616eSDan Nowlin 
1532a778616eSDan Nowlin 	return state;
1533a778616eSDan Nowlin }
1534a778616eSDan Nowlin 
1535a778616eSDan Nowlin /**
1536a778616eSDan Nowlin  * ice_dwnld_cfg_bufs
1537a778616eSDan Nowlin  * @hw: pointer to the hardware structure
1538a778616eSDan Nowlin  * @bufs: pointer to an array of buffers
1539a778616eSDan Nowlin  * @count: the number of buffers in the array
1540a778616eSDan Nowlin  *
1541a778616eSDan Nowlin  * Obtains global config lock and downloads the package configuration buffers
1542a778616eSDan Nowlin  * to the firmware.
1543a778616eSDan Nowlin  */
1544a778616eSDan Nowlin static enum ice_ddp_state
1545a778616eSDan Nowlin ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
1546a778616eSDan Nowlin {
1547a778616eSDan Nowlin 	enum ice_ddp_state state;
1548a778616eSDan Nowlin 	struct ice_buf_hdr *bh;
1549a778616eSDan Nowlin 	int status;
1550a778616eSDan Nowlin 
1551a778616eSDan Nowlin 	if (!bufs || !count)
1552a778616eSDan Nowlin 		return ICE_DDP_PKG_ERR;
1553a778616eSDan Nowlin 
1554a778616eSDan Nowlin 	/* If the first buffer's first section has its metadata bit set
1555a778616eSDan Nowlin 	 * then there are no buffers to be downloaded, and the operation is
1556a778616eSDan Nowlin 	 * considered a success.
1557a778616eSDan Nowlin 	 */
1558a778616eSDan Nowlin 	bh = (struct ice_buf_hdr *)bufs;
1559a778616eSDan Nowlin 	if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF)
1560a778616eSDan Nowlin 		return ICE_DDP_PKG_SUCCESS;
1561a778616eSDan Nowlin 
1562a778616eSDan Nowlin 	status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
1563a778616eSDan Nowlin 	if (status) {
1564a778616eSDan Nowlin 		if (status == -EALREADY)
1565a778616eSDan Nowlin 			return ICE_DDP_PKG_ALREADY_LOADED;
1566a778616eSDan Nowlin 		return ice_map_aq_err_to_ddp_state(hw->adminq.sq_last_status);
1567a778616eSDan Nowlin 	}
1568a778616eSDan Nowlin 
1569a778616eSDan Nowlin 	state = ice_dwnld_cfg_bufs_no_lock(hw, bufs, 0, count, true);
1570a778616eSDan Nowlin 	if (!state)
1571a778616eSDan Nowlin 		state = ice_post_dwnld_pkg_actions(hw);
1572a778616eSDan Nowlin 
1573a778616eSDan Nowlin 	ice_release_global_cfg_lock(hw);
1574a778616eSDan Nowlin 
1575a778616eSDan Nowlin 	return state;
1576a778616eSDan Nowlin }
1577a778616eSDan Nowlin 
1578a778616eSDan Nowlin /**
1579a778616eSDan Nowlin  * ice_download_pkg_without_sig_seg
1580a778616eSDan Nowlin  * @hw: pointer to the hardware structure
1581a778616eSDan Nowlin  * @ice_seg: pointer to the segment of the package to be downloaded
1582a778616eSDan Nowlin  *
1583a778616eSDan Nowlin  * Handles the download of a complete package without signature segment.
1584a778616eSDan Nowlin  */
1585a778616eSDan Nowlin static enum ice_ddp_state
1586a778616eSDan Nowlin ice_download_pkg_without_sig_seg(struct ice_hw *hw, struct ice_seg *ice_seg)
1587a778616eSDan Nowlin {
1588a778616eSDan Nowlin 	struct ice_buf_table *ice_buf_tbl;
1589a778616eSDan Nowlin 
1590a778616eSDan Nowlin 	ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n",
1591a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.major,
1592a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.minor,
1593a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.update,
1594a778616eSDan Nowlin 		  ice_seg->hdr.seg_format_ver.draft);
1595a778616eSDan Nowlin 
1596a778616eSDan Nowlin 	ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n",
1597a778616eSDan Nowlin 		  le32_to_cpu(ice_seg->hdr.seg_type),
1598a778616eSDan Nowlin 		  le32_to_cpu(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id);
1599a778616eSDan Nowlin 
1600a778616eSDan Nowlin 	ice_buf_tbl = ice_find_buf_table(ice_seg);
1601a778616eSDan Nowlin 
1602a778616eSDan Nowlin 	ice_debug(hw, ICE_DBG_PKG, "Seg buf count: %d\n",
1603a778616eSDan Nowlin 		  le32_to_cpu(ice_buf_tbl->buf_count));
1604a778616eSDan Nowlin 
1605a778616eSDan Nowlin 	return ice_dwnld_cfg_bufs(hw, ice_buf_tbl->buf_array,
1606a778616eSDan Nowlin 				  le32_to_cpu(ice_buf_tbl->buf_count));
1607a778616eSDan Nowlin }
1608a778616eSDan Nowlin 
1609a778616eSDan Nowlin /**
1610a778616eSDan Nowlin  * ice_download_pkg
1611a778616eSDan Nowlin  * @hw: pointer to the hardware structure
1612a778616eSDan Nowlin  * @pkg_hdr: pointer to package header
1613a778616eSDan Nowlin  * @ice_seg: pointer to the segment of the package to be downloaded
1614a778616eSDan Nowlin  *
1615a778616eSDan Nowlin  * Handles the download of a complete package.
1616a778616eSDan Nowlin  */
1617a778616eSDan Nowlin static enum ice_ddp_state
1618a778616eSDan Nowlin ice_download_pkg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
1619a778616eSDan Nowlin 		 struct ice_seg *ice_seg)
1620a778616eSDan Nowlin {
1621a778616eSDan Nowlin 	enum ice_ddp_state state;
1622a778616eSDan Nowlin 
1623a778616eSDan Nowlin 	if (hw->pkg_has_signing_seg)
1624a778616eSDan Nowlin 		state = ice_download_pkg_with_sig_seg(hw, pkg_hdr);
1625a778616eSDan Nowlin 	else
1626a778616eSDan Nowlin 		state = ice_download_pkg_without_sig_seg(hw, ice_seg);
1627a778616eSDan Nowlin 
16283cbdb034SDan Nowlin 	ice_post_pkg_dwnld_vlan_mode_cfg(hw);
16292ffd87d3SSergey Temerkhanov 
16302ffd87d3SSergey Temerkhanov 	return state;
16312ffd87d3SSergey Temerkhanov }
16322ffd87d3SSergey Temerkhanov 
16332ffd87d3SSergey Temerkhanov /**
16342ffd87d3SSergey Temerkhanov  * ice_aq_get_pkg_info_list
16352ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
16362ffd87d3SSergey Temerkhanov  * @pkg_info: the buffer which will receive the information list
16372ffd87d3SSergey Temerkhanov  * @buf_size: the size of the pkg_info information buffer
16382ffd87d3SSergey Temerkhanov  * @cd: pointer to command details structure or NULL
16392ffd87d3SSergey Temerkhanov  *
16402ffd87d3SSergey Temerkhanov  * Get Package Info List (0x0C43)
16412ffd87d3SSergey Temerkhanov  */
16422ffd87d3SSergey Temerkhanov static int ice_aq_get_pkg_info_list(struct ice_hw *hw,
16432ffd87d3SSergey Temerkhanov 				    struct ice_aqc_get_pkg_info_resp *pkg_info,
16442ffd87d3SSergey Temerkhanov 				    u16 buf_size, struct ice_sq_cd *cd)
16452ffd87d3SSergey Temerkhanov {
16462ffd87d3SSergey Temerkhanov 	struct ice_aq_desc desc;
16472ffd87d3SSergey Temerkhanov 
16482ffd87d3SSergey Temerkhanov 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list);
16492ffd87d3SSergey Temerkhanov 
16502ffd87d3SSergey Temerkhanov 	return ice_aq_send_cmd(hw, &desc, pkg_info, buf_size, cd);
16512ffd87d3SSergey Temerkhanov }
16522ffd87d3SSergey Temerkhanov 
16532ffd87d3SSergey Temerkhanov /**
16542ffd87d3SSergey Temerkhanov  * ice_aq_update_pkg
16552ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
16562ffd87d3SSergey Temerkhanov  * @pkg_buf: the package cmd buffer
16572ffd87d3SSergey Temerkhanov  * @buf_size: the size of the package cmd buffer
16582ffd87d3SSergey Temerkhanov  * @last_buf: last buffer indicator
16592ffd87d3SSergey Temerkhanov  * @error_offset: returns error offset
16602ffd87d3SSergey Temerkhanov  * @error_info: returns error information
16612ffd87d3SSergey Temerkhanov  * @cd: pointer to command details structure or NULL
16622ffd87d3SSergey Temerkhanov  *
16632ffd87d3SSergey Temerkhanov  * Update Package (0x0C42)
16642ffd87d3SSergey Temerkhanov  */
16652ffd87d3SSergey Temerkhanov static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
16662ffd87d3SSergey Temerkhanov 			     u16 buf_size, bool last_buf, u32 *error_offset,
16672ffd87d3SSergey Temerkhanov 			     u32 *error_info, struct ice_sq_cd *cd)
16682ffd87d3SSergey Temerkhanov {
16692ffd87d3SSergey Temerkhanov 	struct ice_aqc_download_pkg *cmd;
16702ffd87d3SSergey Temerkhanov 	struct ice_aq_desc desc;
16712ffd87d3SSergey Temerkhanov 	int status;
16722ffd87d3SSergey Temerkhanov 
16732ffd87d3SSergey Temerkhanov 	if (error_offset)
16742ffd87d3SSergey Temerkhanov 		*error_offset = 0;
16752ffd87d3SSergey Temerkhanov 	if (error_info)
16762ffd87d3SSergey Temerkhanov 		*error_info = 0;
16772ffd87d3SSergey Temerkhanov 
16782ffd87d3SSergey Temerkhanov 	cmd = &desc.params.download_pkg;
16792ffd87d3SSergey Temerkhanov 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg);
16802ffd87d3SSergey Temerkhanov 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
16812ffd87d3SSergey Temerkhanov 
16822ffd87d3SSergey Temerkhanov 	if (last_buf)
16832ffd87d3SSergey Temerkhanov 		cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
16842ffd87d3SSergey Temerkhanov 
16852ffd87d3SSergey Temerkhanov 	status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
16862ffd87d3SSergey Temerkhanov 	if (status == -EIO) {
16872ffd87d3SSergey Temerkhanov 		/* Read error from buffer only when the FW returned an error */
16882ffd87d3SSergey Temerkhanov 		struct ice_aqc_download_pkg_resp *resp;
16892ffd87d3SSergey Temerkhanov 
16902ffd87d3SSergey Temerkhanov 		resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
16912ffd87d3SSergey Temerkhanov 		if (error_offset)
16922ffd87d3SSergey Temerkhanov 			*error_offset = le32_to_cpu(resp->error_offset);
16932ffd87d3SSergey Temerkhanov 		if (error_info)
16942ffd87d3SSergey Temerkhanov 			*error_info = le32_to_cpu(resp->error_info);
16952ffd87d3SSergey Temerkhanov 	}
16962ffd87d3SSergey Temerkhanov 
16972ffd87d3SSergey Temerkhanov 	return status;
16982ffd87d3SSergey Temerkhanov }
16992ffd87d3SSergey Temerkhanov 
17002ffd87d3SSergey Temerkhanov /**
1701708b352fSJan Sokolowski  * ice_aq_upload_section
1702708b352fSJan Sokolowski  * @hw: pointer to the hardware structure
1703708b352fSJan Sokolowski  * @pkg_buf: the package buffer which will receive the section
1704708b352fSJan Sokolowski  * @buf_size: the size of the package buffer
1705708b352fSJan Sokolowski  * @cd: pointer to command details structure or NULL
1706708b352fSJan Sokolowski  *
1707708b352fSJan Sokolowski  * Upload Section (0x0C41)
1708708b352fSJan Sokolowski  */
1709708b352fSJan Sokolowski int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
1710708b352fSJan Sokolowski 			  u16 buf_size, struct ice_sq_cd *cd)
1711708b352fSJan Sokolowski {
1712708b352fSJan Sokolowski 	struct ice_aq_desc desc;
1713708b352fSJan Sokolowski 
1714708b352fSJan Sokolowski 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section);
1715708b352fSJan Sokolowski 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1716708b352fSJan Sokolowski 
1717708b352fSJan Sokolowski 	return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
1718708b352fSJan Sokolowski }
1719708b352fSJan Sokolowski 
1720708b352fSJan Sokolowski /**
17212ffd87d3SSergey Temerkhanov  * ice_update_pkg_no_lock
17222ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
17232ffd87d3SSergey Temerkhanov  * @bufs: pointer to an array of buffers
17242ffd87d3SSergey Temerkhanov  * @count: the number of buffers in the array
17252ffd87d3SSergey Temerkhanov  */
17262ffd87d3SSergey Temerkhanov int ice_update_pkg_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
17272ffd87d3SSergey Temerkhanov {
17282ffd87d3SSergey Temerkhanov 	int status = 0;
17292ffd87d3SSergey Temerkhanov 	u32 i;
17302ffd87d3SSergey Temerkhanov 
17312ffd87d3SSergey Temerkhanov 	for (i = 0; i < count; i++) {
17322ffd87d3SSergey Temerkhanov 		struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i);
17332ffd87d3SSergey Temerkhanov 		bool last = ((i + 1) == count);
17342ffd87d3SSergey Temerkhanov 		u32 offset, info;
17352ffd87d3SSergey Temerkhanov 
17362ffd87d3SSergey Temerkhanov 		status = ice_aq_update_pkg(hw, bh, le16_to_cpu(bh->data_end),
17372ffd87d3SSergey Temerkhanov 					   last, &offset, &info, NULL);
17382ffd87d3SSergey Temerkhanov 
17392ffd87d3SSergey Temerkhanov 		if (status) {
17402ffd87d3SSergey Temerkhanov 			ice_debug(hw, ICE_DBG_PKG,
17412ffd87d3SSergey Temerkhanov 				  "Update pkg failed: err %d off %d inf %d\n",
17422ffd87d3SSergey Temerkhanov 				  status, offset, info);
17432ffd87d3SSergey Temerkhanov 			break;
17442ffd87d3SSergey Temerkhanov 		}
17452ffd87d3SSergey Temerkhanov 	}
17462ffd87d3SSergey Temerkhanov 
17472ffd87d3SSergey Temerkhanov 	return status;
17482ffd87d3SSergey Temerkhanov }
17492ffd87d3SSergey Temerkhanov 
17502ffd87d3SSergey Temerkhanov /**
17512ffd87d3SSergey Temerkhanov  * ice_update_pkg
17522ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
17532ffd87d3SSergey Temerkhanov  * @bufs: pointer to an array of buffers
17542ffd87d3SSergey Temerkhanov  * @count: the number of buffers in the array
17552ffd87d3SSergey Temerkhanov  *
17562ffd87d3SSergey Temerkhanov  * Obtains change lock and updates package.
17572ffd87d3SSergey Temerkhanov  */
17582ffd87d3SSergey Temerkhanov int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
17592ffd87d3SSergey Temerkhanov {
17602ffd87d3SSergey Temerkhanov 	int status;
17612ffd87d3SSergey Temerkhanov 
17622ffd87d3SSergey Temerkhanov 	status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
17632ffd87d3SSergey Temerkhanov 	if (status)
17642ffd87d3SSergey Temerkhanov 		return status;
17652ffd87d3SSergey Temerkhanov 
17662ffd87d3SSergey Temerkhanov 	status = ice_update_pkg_no_lock(hw, bufs, count);
17672ffd87d3SSergey Temerkhanov 
17682ffd87d3SSergey Temerkhanov 	ice_release_change_lock(hw);
17692ffd87d3SSergey Temerkhanov 
17702ffd87d3SSergey Temerkhanov 	return status;
17712ffd87d3SSergey Temerkhanov }
17722ffd87d3SSergey Temerkhanov 
17732ffd87d3SSergey Temerkhanov /**
17742ffd87d3SSergey Temerkhanov  * ice_find_seg_in_pkg
17752ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
17762ffd87d3SSergey Temerkhanov  * @seg_type: the segment type to search for (i.e., SEGMENT_TYPE_CPK)
17772ffd87d3SSergey Temerkhanov  * @pkg_hdr: pointer to the package header to be searched
17782ffd87d3SSergey Temerkhanov  *
17792ffd87d3SSergey Temerkhanov  * This function searches a package file for a particular segment type. On
17802ffd87d3SSergey Temerkhanov  * success it returns a pointer to the segment header, otherwise it will
17812ffd87d3SSergey Temerkhanov  * return NULL.
17822ffd87d3SSergey Temerkhanov  */
1783708b352fSJan Sokolowski static struct ice_generic_seg_hdr *
1784708b352fSJan Sokolowski ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
17852ffd87d3SSergey Temerkhanov 		    struct ice_pkg_hdr *pkg_hdr)
17862ffd87d3SSergey Temerkhanov {
17872ffd87d3SSergey Temerkhanov 	u32 i;
17882ffd87d3SSergey Temerkhanov 
17892ffd87d3SSergey Temerkhanov 	ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n",
17902ffd87d3SSergey Temerkhanov 		  pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor,
17912ffd87d3SSergey Temerkhanov 		  pkg_hdr->pkg_format_ver.update,
17922ffd87d3SSergey Temerkhanov 		  pkg_hdr->pkg_format_ver.draft);
17932ffd87d3SSergey Temerkhanov 
17942ffd87d3SSergey Temerkhanov 	/* Search all package segments for the requested segment type */
17952ffd87d3SSergey Temerkhanov 	for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) {
17962ffd87d3SSergey Temerkhanov 		struct ice_generic_seg_hdr *seg;
17972ffd87d3SSergey Temerkhanov 
17982ffd87d3SSergey Temerkhanov 		seg = (struct ice_generic_seg_hdr
17992ffd87d3SSergey Temerkhanov 			       *)((u8 *)pkg_hdr +
18002ffd87d3SSergey Temerkhanov 				  le32_to_cpu(pkg_hdr->seg_offset[i]));
18012ffd87d3SSergey Temerkhanov 
18022ffd87d3SSergey Temerkhanov 		if (le32_to_cpu(seg->seg_type) == seg_type)
18032ffd87d3SSergey Temerkhanov 			return seg;
18042ffd87d3SSergey Temerkhanov 	}
18052ffd87d3SSergey Temerkhanov 
18062ffd87d3SSergey Temerkhanov 	return NULL;
18072ffd87d3SSergey Temerkhanov }
18082ffd87d3SSergey Temerkhanov 
18092ffd87d3SSergey Temerkhanov /**
18103cbdb034SDan Nowlin  * ice_has_signing_seg - determine if package has a signing segment
18113cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
18123cbdb034SDan Nowlin  * @pkg_hdr: pointer to the driver's package hdr
18133cbdb034SDan Nowlin  */
18143cbdb034SDan Nowlin static bool ice_has_signing_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
18153cbdb034SDan Nowlin {
18163cbdb034SDan Nowlin 	struct ice_generic_seg_hdr *seg_hdr;
18173cbdb034SDan Nowlin 
18183cbdb034SDan Nowlin 	seg_hdr = (struct ice_generic_seg_hdr *)
18193cbdb034SDan Nowlin 		ice_find_seg_in_pkg(hw, SEGMENT_TYPE_SIGNING, pkg_hdr);
18203cbdb034SDan Nowlin 
18213cbdb034SDan Nowlin 	return seg_hdr ? true : false;
18223cbdb034SDan Nowlin }
18233cbdb034SDan Nowlin 
18243cbdb034SDan Nowlin /**
18253cbdb034SDan Nowlin  * ice_get_pkg_segment_id - get correct package segment id, based on device
18263cbdb034SDan Nowlin  * @mac_type: MAC type of the device
18273cbdb034SDan Nowlin  */
18283cbdb034SDan Nowlin static u32 ice_get_pkg_segment_id(enum ice_mac_type mac_type)
18293cbdb034SDan Nowlin {
18303cbdb034SDan Nowlin 	u32 seg_id;
18313cbdb034SDan Nowlin 
18323cbdb034SDan Nowlin 	switch (mac_type) {
18333cbdb034SDan Nowlin 	case ICE_MAC_E830:
18343cbdb034SDan Nowlin 		seg_id = SEGMENT_TYPE_ICE_E830;
18353cbdb034SDan Nowlin 		break;
18363cbdb034SDan Nowlin 	case ICE_MAC_GENERIC:
1837372e27deSGrzegorz Nitka 	case ICE_MAC_GENERIC_3K_E825:
18383cbdb034SDan Nowlin 	default:
18393cbdb034SDan Nowlin 		seg_id = SEGMENT_TYPE_ICE_E810;
18403cbdb034SDan Nowlin 		break;
18413cbdb034SDan Nowlin 	}
18423cbdb034SDan Nowlin 
18433cbdb034SDan Nowlin 	return seg_id;
18443cbdb034SDan Nowlin }
18453cbdb034SDan Nowlin 
18463cbdb034SDan Nowlin /**
18473cbdb034SDan Nowlin  * ice_get_pkg_sign_type - get package segment sign type, based on device
18483cbdb034SDan Nowlin  * @mac_type: MAC type of the device
18493cbdb034SDan Nowlin  */
18503cbdb034SDan Nowlin static u32 ice_get_pkg_sign_type(enum ice_mac_type mac_type)
18513cbdb034SDan Nowlin {
18523cbdb034SDan Nowlin 	u32 sign_type;
18533cbdb034SDan Nowlin 
18543cbdb034SDan Nowlin 	switch (mac_type) {
18553cbdb034SDan Nowlin 	case ICE_MAC_E830:
18563cbdb034SDan Nowlin 		sign_type = SEGMENT_SIGN_TYPE_RSA3K_SBB;
18573cbdb034SDan Nowlin 		break;
1858372e27deSGrzegorz Nitka 	case ICE_MAC_GENERIC_3K_E825:
1859372e27deSGrzegorz Nitka 		sign_type = SEGMENT_SIGN_TYPE_RSA3K_E825;
1860372e27deSGrzegorz Nitka 		break;
18613cbdb034SDan Nowlin 	case ICE_MAC_GENERIC:
18623cbdb034SDan Nowlin 	default:
18633cbdb034SDan Nowlin 		sign_type = SEGMENT_SIGN_TYPE_RSA2K;
18643cbdb034SDan Nowlin 		break;
18653cbdb034SDan Nowlin 	}
18663cbdb034SDan Nowlin 
18673cbdb034SDan Nowlin 	return sign_type;
18683cbdb034SDan Nowlin }
18693cbdb034SDan Nowlin 
18703cbdb034SDan Nowlin /**
18713cbdb034SDan Nowlin  * ice_get_signing_req - get correct package requirements, based on device
18723cbdb034SDan Nowlin  * @hw: pointer to the hardware structure
18733cbdb034SDan Nowlin  */
18743cbdb034SDan Nowlin static void ice_get_signing_req(struct ice_hw *hw)
18753cbdb034SDan Nowlin {
18763cbdb034SDan Nowlin 	hw->pkg_seg_id = ice_get_pkg_segment_id(hw->mac_type);
18773cbdb034SDan Nowlin 	hw->pkg_sign_type = ice_get_pkg_sign_type(hw->mac_type);
18783cbdb034SDan Nowlin }
18793cbdb034SDan Nowlin 
18803cbdb034SDan Nowlin /**
18812ffd87d3SSergey Temerkhanov  * ice_init_pkg_info
18822ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
18832ffd87d3SSergey Temerkhanov  * @pkg_hdr: pointer to the driver's package hdr
18842ffd87d3SSergey Temerkhanov  *
18852ffd87d3SSergey Temerkhanov  * Saves off the package details into the HW structure.
18862ffd87d3SSergey Temerkhanov  */
18872ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_init_pkg_info(struct ice_hw *hw,
18882ffd87d3SSergey Temerkhanov 					    struct ice_pkg_hdr *pkg_hdr)
18892ffd87d3SSergey Temerkhanov {
18902ffd87d3SSergey Temerkhanov 	struct ice_generic_seg_hdr *seg_hdr;
18912ffd87d3SSergey Temerkhanov 
18922ffd87d3SSergey Temerkhanov 	if (!pkg_hdr)
18932ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
18942ffd87d3SSergey Temerkhanov 
18953cbdb034SDan Nowlin 	hw->pkg_has_signing_seg = ice_has_signing_seg(hw, pkg_hdr);
18963cbdb034SDan Nowlin 	ice_get_signing_req(hw);
18973cbdb034SDan Nowlin 
18983cbdb034SDan Nowlin 	ice_debug(hw, ICE_DBG_INIT, "Pkg using segment id: 0x%08X\n",
18993cbdb034SDan Nowlin 		  hw->pkg_seg_id);
19003cbdb034SDan Nowlin 
19013cbdb034SDan Nowlin 	seg_hdr = (struct ice_generic_seg_hdr *)
19023cbdb034SDan Nowlin 		ice_find_seg_in_pkg(hw, hw->pkg_seg_id, pkg_hdr);
19032ffd87d3SSergey Temerkhanov 	if (seg_hdr) {
19042ffd87d3SSergey Temerkhanov 		struct ice_meta_sect *meta;
19052ffd87d3SSergey Temerkhanov 		struct ice_pkg_enum state;
19062ffd87d3SSergey Temerkhanov 
19072ffd87d3SSergey Temerkhanov 		memset(&state, 0, sizeof(state));
19082ffd87d3SSergey Temerkhanov 
19092ffd87d3SSergey Temerkhanov 		/* Get package information from the Metadata Section */
19102ffd87d3SSergey Temerkhanov 		meta = ice_pkg_enum_section((struct ice_seg *)seg_hdr, &state,
19112ffd87d3SSergey Temerkhanov 					    ICE_SID_METADATA);
19122ffd87d3SSergey Temerkhanov 		if (!meta) {
19132ffd87d3SSergey Temerkhanov 			ice_debug(hw, ICE_DBG_INIT,
19142ffd87d3SSergey Temerkhanov 				  "Did not find ice metadata section in package\n");
19152ffd87d3SSergey Temerkhanov 			return ICE_DDP_PKG_INVALID_FILE;
19162ffd87d3SSergey Temerkhanov 		}
19172ffd87d3SSergey Temerkhanov 
19182ffd87d3SSergey Temerkhanov 		hw->pkg_ver = meta->ver;
19192ffd87d3SSergey Temerkhanov 		memcpy(hw->pkg_name, meta->name, sizeof(meta->name));
19202ffd87d3SSergey Temerkhanov 
19212ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG, "Pkg: %d.%d.%d.%d, %s\n",
19222ffd87d3SSergey Temerkhanov 			  meta->ver.major, meta->ver.minor, meta->ver.update,
19232ffd87d3SSergey Temerkhanov 			  meta->ver.draft, meta->name);
19242ffd87d3SSergey Temerkhanov 
19252ffd87d3SSergey Temerkhanov 		hw->ice_seg_fmt_ver = seg_hdr->seg_format_ver;
19262ffd87d3SSergey Temerkhanov 		memcpy(hw->ice_seg_id, seg_hdr->seg_id, sizeof(hw->ice_seg_id));
19272ffd87d3SSergey Temerkhanov 
19282ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n",
19292ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.major,
19302ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.minor,
19312ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.update,
19322ffd87d3SSergey Temerkhanov 			  seg_hdr->seg_format_ver.draft, seg_hdr->seg_id);
19332ffd87d3SSergey Temerkhanov 	} else {
19342ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT,
19352ffd87d3SSergey Temerkhanov 			  "Did not find ice segment in driver package\n");
19362ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
19372ffd87d3SSergey Temerkhanov 	}
19382ffd87d3SSergey Temerkhanov 
19392ffd87d3SSergey Temerkhanov 	return ICE_DDP_PKG_SUCCESS;
19402ffd87d3SSergey Temerkhanov }
19412ffd87d3SSergey Temerkhanov 
19422ffd87d3SSergey Temerkhanov /**
19432ffd87d3SSergey Temerkhanov  * ice_get_pkg_info
19442ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
19452ffd87d3SSergey Temerkhanov  *
19462ffd87d3SSergey Temerkhanov  * Store details of the package currently loaded in HW into the HW structure.
19472ffd87d3SSergey Temerkhanov  */
19482ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw)
19492ffd87d3SSergey Temerkhanov {
1950d8e45f29SKees Cook 	DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg_info, pkg_info,
1951230064baSPrzemek Kitszel 			ICE_PKG_CNT);
1952230064baSPrzemek Kitszel 	u16 size = __struct_size(pkg_info);
19532ffd87d3SSergey Temerkhanov 	u32 i;
19542ffd87d3SSergey Temerkhanov 
1955230064baSPrzemek Kitszel 	if (ice_aq_get_pkg_info_list(hw, pkg_info, size, NULL))
19562ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
19572ffd87d3SSergey Temerkhanov 
19582ffd87d3SSergey Temerkhanov 	for (i = 0; i < le32_to_cpu(pkg_info->count); i++) {
19592ffd87d3SSergey Temerkhanov #define ICE_PKG_FLAG_COUNT 4
19602ffd87d3SSergey Temerkhanov 		char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 };
19612ffd87d3SSergey Temerkhanov 		u8 place = 0;
19622ffd87d3SSergey Temerkhanov 
19632ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_active) {
19642ffd87d3SSergey Temerkhanov 			flags[place++] = 'A';
19652ffd87d3SSergey Temerkhanov 			hw->active_pkg_ver = pkg_info->pkg_info[i].ver;
19662ffd87d3SSergey Temerkhanov 			hw->active_track_id =
19672ffd87d3SSergey Temerkhanov 				le32_to_cpu(pkg_info->pkg_info[i].track_id);
19682ffd87d3SSergey Temerkhanov 			memcpy(hw->active_pkg_name, pkg_info->pkg_info[i].name,
19692ffd87d3SSergey Temerkhanov 			       sizeof(pkg_info->pkg_info[i].name));
19702ffd87d3SSergey Temerkhanov 			hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm;
19712ffd87d3SSergey Temerkhanov 		}
19722ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_active_at_boot)
19732ffd87d3SSergey Temerkhanov 			flags[place++] = 'B';
19742ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_modified)
19752ffd87d3SSergey Temerkhanov 			flags[place++] = 'M';
19762ffd87d3SSergey Temerkhanov 		if (pkg_info->pkg_info[i].is_in_nvm)
19772ffd87d3SSergey Temerkhanov 			flags[place++] = 'N';
19782ffd87d3SSergey Temerkhanov 
19792ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_PKG, "Pkg[%d]: %d.%d.%d.%d,%s,%s\n", i,
19802ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.major,
19812ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.minor,
19822ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.update,
19832ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].ver.draft,
19842ffd87d3SSergey Temerkhanov 			  pkg_info->pkg_info[i].name, flags);
19852ffd87d3SSergey Temerkhanov 	}
19862ffd87d3SSergey Temerkhanov 
1987230064baSPrzemek Kitszel 	return ICE_DDP_PKG_SUCCESS;
19882ffd87d3SSergey Temerkhanov }
19892ffd87d3SSergey Temerkhanov 
19902ffd87d3SSergey Temerkhanov /**
19912ffd87d3SSergey Temerkhanov  * ice_chk_pkg_compat
19922ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
19932ffd87d3SSergey Temerkhanov  * @ospkg: pointer to the package hdr
19942ffd87d3SSergey Temerkhanov  * @seg: pointer to the package segment hdr
19952ffd87d3SSergey Temerkhanov  *
19962ffd87d3SSergey Temerkhanov  * This function checks the package version compatibility with driver and NVM
19972ffd87d3SSergey Temerkhanov  */
19982ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_compat(struct ice_hw *hw,
19992ffd87d3SSergey Temerkhanov 					     struct ice_pkg_hdr *ospkg,
20002ffd87d3SSergey Temerkhanov 					     struct ice_seg **seg)
20012ffd87d3SSergey Temerkhanov {
2002d8e45f29SKees Cook 	DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg, pkg_info,
2003230064baSPrzemek Kitszel 			ICE_PKG_CNT);
2004230064baSPrzemek Kitszel 	u16 size = __struct_size(pkg);
20052ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state;
20062ffd87d3SSergey Temerkhanov 	u32 i;
20072ffd87d3SSergey Temerkhanov 
20082ffd87d3SSergey Temerkhanov 	/* Check package version compatibility */
20092ffd87d3SSergey Temerkhanov 	state = ice_chk_pkg_version(&hw->pkg_ver);
20102ffd87d3SSergey Temerkhanov 	if (state) {
20112ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n");
20122ffd87d3SSergey Temerkhanov 		return state;
20132ffd87d3SSergey Temerkhanov 	}
20142ffd87d3SSergey Temerkhanov 
20152ffd87d3SSergey Temerkhanov 	/* find ICE segment in given package */
20163cbdb034SDan Nowlin 	*seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, hw->pkg_seg_id,
20172ffd87d3SSergey Temerkhanov 						     ospkg);
20182ffd87d3SSergey Temerkhanov 	if (!*seg) {
20192ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n");
20202ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_INVALID_FILE;
20212ffd87d3SSergey Temerkhanov 	}
20222ffd87d3SSergey Temerkhanov 
20232ffd87d3SSergey Temerkhanov 	/* Check if FW is compatible with the OS package */
2024230064baSPrzemek Kitszel 	if (ice_aq_get_pkg_info_list(hw, pkg, size, NULL))
2025230064baSPrzemek Kitszel 		return ICE_DDP_PKG_LOAD_ERROR;
20262ffd87d3SSergey Temerkhanov 
20272ffd87d3SSergey Temerkhanov 	for (i = 0; i < le32_to_cpu(pkg->count); i++) {
20282ffd87d3SSergey Temerkhanov 		/* loop till we find the NVM package */
20292ffd87d3SSergey Temerkhanov 		if (!pkg->pkg_info[i].is_in_nvm)
20302ffd87d3SSergey Temerkhanov 			continue;
20312ffd87d3SSergey Temerkhanov 		if ((*seg)->hdr.seg_format_ver.major !=
20322ffd87d3SSergey Temerkhanov 			    pkg->pkg_info[i].ver.major ||
20332ffd87d3SSergey Temerkhanov 		    (*seg)->hdr.seg_format_ver.minor >
20342ffd87d3SSergey Temerkhanov 			    pkg->pkg_info[i].ver.minor) {
20352ffd87d3SSergey Temerkhanov 			state = ICE_DDP_PKG_FW_MISMATCH;
20362ffd87d3SSergey Temerkhanov 			ice_debug(hw, ICE_DBG_INIT,
20372ffd87d3SSergey Temerkhanov 				  "OS package is not compatible with NVM.\n");
20382ffd87d3SSergey Temerkhanov 		}
20392ffd87d3SSergey Temerkhanov 		/* done processing NVM package so break */
20402ffd87d3SSergey Temerkhanov 		break;
20412ffd87d3SSergey Temerkhanov 	}
2042230064baSPrzemek Kitszel 
20432ffd87d3SSergey Temerkhanov 	return state;
20442ffd87d3SSergey Temerkhanov }
20452ffd87d3SSergey Temerkhanov 
20462ffd87d3SSergey Temerkhanov /**
20472ffd87d3SSergey Temerkhanov  * ice_init_pkg_hints
20482ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
20492ffd87d3SSergey Temerkhanov  * @ice_seg: pointer to the segment of the package scan (non-NULL)
20502ffd87d3SSergey Temerkhanov  *
20512ffd87d3SSergey Temerkhanov  * This function will scan the package and save off relevant information
20522ffd87d3SSergey Temerkhanov  * (hints or metadata) for driver use. The ice_seg parameter must not be NULL
20532ffd87d3SSergey Temerkhanov  * since the first call to ice_enum_labels requires a pointer to an actual
20542ffd87d3SSergey Temerkhanov  * ice_seg structure.
20552ffd87d3SSergey Temerkhanov  */
20562ffd87d3SSergey Temerkhanov static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg)
20572ffd87d3SSergey Temerkhanov {
20582ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
20592ffd87d3SSergey Temerkhanov 	char *label_name;
20602ffd87d3SSergey Temerkhanov 	u16 val;
20612ffd87d3SSergey Temerkhanov 	int i;
20622ffd87d3SSergey Temerkhanov 
20632ffd87d3SSergey Temerkhanov 	memset(&hw->tnl, 0, sizeof(hw->tnl));
20642ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
20652ffd87d3SSergey Temerkhanov 
20662ffd87d3SSergey Temerkhanov 	if (!ice_seg)
20672ffd87d3SSergey Temerkhanov 		return;
20682ffd87d3SSergey Temerkhanov 
20692ffd87d3SSergey Temerkhanov 	label_name = ice_enum_labels(ice_seg, ICE_SID_LBL_RXPARSER_TMEM, &state,
20702ffd87d3SSergey Temerkhanov 				     &val);
20712ffd87d3SSergey Temerkhanov 
20722ffd87d3SSergey Temerkhanov 	while (label_name) {
20732ffd87d3SSergey Temerkhanov 		if (!strncmp(label_name, ICE_TNL_PRE, strlen(ICE_TNL_PRE)))
20742ffd87d3SSergey Temerkhanov 			/* check for a tunnel entry */
20752ffd87d3SSergey Temerkhanov 			ice_add_tunnel_hint(hw, label_name, val);
20762ffd87d3SSergey Temerkhanov 
20772ffd87d3SSergey Temerkhanov 		/* check for a dvm mode entry */
20782ffd87d3SSergey Temerkhanov 		else if (!strncmp(label_name, ICE_DVM_PRE, strlen(ICE_DVM_PRE)))
20792ffd87d3SSergey Temerkhanov 			ice_add_dvm_hint(hw, val, true);
20802ffd87d3SSergey Temerkhanov 
20812ffd87d3SSergey Temerkhanov 		/* check for a svm mode entry */
20822ffd87d3SSergey Temerkhanov 		else if (!strncmp(label_name, ICE_SVM_PRE, strlen(ICE_SVM_PRE)))
20832ffd87d3SSergey Temerkhanov 			ice_add_dvm_hint(hw, val, false);
20842ffd87d3SSergey Temerkhanov 
20852ffd87d3SSergey Temerkhanov 		label_name = ice_enum_labels(NULL, 0, &state, &val);
20862ffd87d3SSergey Temerkhanov 	}
20872ffd87d3SSergey Temerkhanov 
20882ffd87d3SSergey Temerkhanov 	/* Cache the appropriate boost TCAM entry pointers for tunnels */
20892ffd87d3SSergey Temerkhanov 	for (i = 0; i < hw->tnl.count; i++) {
20902ffd87d3SSergey Temerkhanov 		ice_find_boost_entry(ice_seg, hw->tnl.tbl[i].boost_addr,
20912ffd87d3SSergey Temerkhanov 				     &hw->tnl.tbl[i].boost_entry);
20922ffd87d3SSergey Temerkhanov 		if (hw->tnl.tbl[i].boost_entry) {
20932ffd87d3SSergey Temerkhanov 			hw->tnl.tbl[i].valid = true;
20942ffd87d3SSergey Temerkhanov 			if (hw->tnl.tbl[i].type < __TNL_TYPE_CNT)
20952ffd87d3SSergey Temerkhanov 				hw->tnl.valid_count[hw->tnl.tbl[i].type]++;
20962ffd87d3SSergey Temerkhanov 		}
20972ffd87d3SSergey Temerkhanov 	}
20982ffd87d3SSergey Temerkhanov 
20992ffd87d3SSergey Temerkhanov 	/* Cache the appropriate boost TCAM entry pointers for DVM and SVM */
21002ffd87d3SSergey Temerkhanov 	for (i = 0; i < hw->dvm_upd.count; i++)
21012ffd87d3SSergey Temerkhanov 		ice_find_boost_entry(ice_seg, hw->dvm_upd.tbl[i].boost_addr,
21022ffd87d3SSergey Temerkhanov 				     &hw->dvm_upd.tbl[i].boost_entry);
21032ffd87d3SSergey Temerkhanov }
21042ffd87d3SSergey Temerkhanov 
21052ffd87d3SSergey Temerkhanov /**
21062ffd87d3SSergey Temerkhanov  * ice_fill_hw_ptype - fill the enabled PTYPE bit information
21072ffd87d3SSergey Temerkhanov  * @hw: pointer to the HW structure
21082ffd87d3SSergey Temerkhanov  */
21092ffd87d3SSergey Temerkhanov static void ice_fill_hw_ptype(struct ice_hw *hw)
21102ffd87d3SSergey Temerkhanov {
21112ffd87d3SSergey Temerkhanov 	struct ice_marker_ptype_tcam_entry *tcam;
21122ffd87d3SSergey Temerkhanov 	struct ice_seg *seg = hw->seg;
21132ffd87d3SSergey Temerkhanov 	struct ice_pkg_enum state;
21142ffd87d3SSergey Temerkhanov 
21152ffd87d3SSergey Temerkhanov 	bitmap_zero(hw->hw_ptype, ICE_FLOW_PTYPE_MAX);
21162ffd87d3SSergey Temerkhanov 	if (!seg)
21172ffd87d3SSergey Temerkhanov 		return;
21182ffd87d3SSergey Temerkhanov 
21192ffd87d3SSergey Temerkhanov 	memset(&state, 0, sizeof(state));
21202ffd87d3SSergey Temerkhanov 
21212ffd87d3SSergey Temerkhanov 	do {
21222ffd87d3SSergey Temerkhanov 		tcam = ice_pkg_enum_entry(seg, &state,
21232ffd87d3SSergey Temerkhanov 					  ICE_SID_RXPARSER_MARKER_PTYPE, NULL,
21242ffd87d3SSergey Temerkhanov 					  ice_marker_ptype_tcam_handler);
21252ffd87d3SSergey Temerkhanov 		if (tcam &&
21262ffd87d3SSergey Temerkhanov 		    le16_to_cpu(tcam->addr) < ICE_MARKER_PTYPE_TCAM_ADDR_MAX &&
21272ffd87d3SSergey Temerkhanov 		    le16_to_cpu(tcam->ptype) < ICE_FLOW_PTYPE_MAX)
21282ffd87d3SSergey Temerkhanov 			set_bit(le16_to_cpu(tcam->ptype), hw->hw_ptype);
21292ffd87d3SSergey Temerkhanov 
21302ffd87d3SSergey Temerkhanov 		seg = NULL;
21312ffd87d3SSergey Temerkhanov 	} while (tcam);
21322ffd87d3SSergey Temerkhanov }
21332ffd87d3SSergey Temerkhanov 
21342ffd87d3SSergey Temerkhanov /**
21352ffd87d3SSergey Temerkhanov  * ice_init_pkg - initialize/download package
21362ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
21372ffd87d3SSergey Temerkhanov  * @buf: pointer to the package buffer
21382ffd87d3SSergey Temerkhanov  * @len: size of the package buffer
21392ffd87d3SSergey Temerkhanov  *
21402ffd87d3SSergey Temerkhanov  * This function initializes a package. The package contains HW tables
21412ffd87d3SSergey Temerkhanov  * required to do packet processing. First, the function extracts package
21422ffd87d3SSergey Temerkhanov  * information such as version. Then it finds the ice configuration segment
21432ffd87d3SSergey Temerkhanov  * within the package; this function then saves a copy of the segment pointer
21442ffd87d3SSergey Temerkhanov  * within the supplied package buffer. Next, the function will cache any hints
21452ffd87d3SSergey Temerkhanov  * from the package, followed by downloading the package itself. Note, that if
21462ffd87d3SSergey Temerkhanov  * a previous PF driver has already downloaded the package successfully, then
21472ffd87d3SSergey Temerkhanov  * the current driver will not have to download the package again.
21482ffd87d3SSergey Temerkhanov  *
21492ffd87d3SSergey Temerkhanov  * The local package contents will be used to query default behavior and to
21502ffd87d3SSergey Temerkhanov  * update specific sections of the HW's version of the package (e.g. to update
21512ffd87d3SSergey Temerkhanov  * the parse graph to understand new protocols).
21522ffd87d3SSergey Temerkhanov  *
21532ffd87d3SSergey Temerkhanov  * This function stores a pointer to the package buffer memory, and it is
21542ffd87d3SSergey Temerkhanov  * expected that the supplied buffer will not be freed immediately. If the
21552ffd87d3SSergey Temerkhanov  * package buffer needs to be freed, such as when read from a file, use
21562ffd87d3SSergey Temerkhanov  * ice_copy_and_init_pkg() instead of directly calling ice_init_pkg() in this
21572ffd87d3SSergey Temerkhanov  * case.
21582ffd87d3SSergey Temerkhanov  */
21592ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len)
21602ffd87d3SSergey Temerkhanov {
21612ffd87d3SSergey Temerkhanov 	bool already_loaded = false;
21622ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state;
21632ffd87d3SSergey Temerkhanov 	struct ice_pkg_hdr *pkg;
21642ffd87d3SSergey Temerkhanov 	struct ice_seg *seg;
21652ffd87d3SSergey Temerkhanov 
21662ffd87d3SSergey Temerkhanov 	if (!buf || !len)
21672ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
21682ffd87d3SSergey Temerkhanov 
21692ffd87d3SSergey Temerkhanov 	pkg = (struct ice_pkg_hdr *)buf;
21702ffd87d3SSergey Temerkhanov 	state = ice_verify_pkg(pkg, len);
21712ffd87d3SSergey Temerkhanov 	if (state) {
21722ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n",
21732ffd87d3SSergey Temerkhanov 			  state);
21742ffd87d3SSergey Temerkhanov 		return state;
21752ffd87d3SSergey Temerkhanov 	}
21762ffd87d3SSergey Temerkhanov 
21772ffd87d3SSergey Temerkhanov 	/* initialize package info */
21782ffd87d3SSergey Temerkhanov 	state = ice_init_pkg_info(hw, pkg);
21792ffd87d3SSergey Temerkhanov 	if (state)
21802ffd87d3SSergey Temerkhanov 		return state;
21812ffd87d3SSergey Temerkhanov 
21823cbdb034SDan Nowlin 	/* must be a matching segment */
21833cbdb034SDan Nowlin 	if (hw->pkg_has_signing_seg &&
21843cbdb034SDan Nowlin 	    !ice_match_signing_seg(pkg, hw->pkg_seg_id, hw->pkg_sign_type))
21853cbdb034SDan Nowlin 		return ICE_DDP_PKG_ERR;
21863cbdb034SDan Nowlin 
21872ffd87d3SSergey Temerkhanov 	/* before downloading the package, check package version for
21882ffd87d3SSergey Temerkhanov 	 * compatibility with driver
21892ffd87d3SSergey Temerkhanov 	 */
21902ffd87d3SSergey Temerkhanov 	state = ice_chk_pkg_compat(hw, pkg, &seg);
21912ffd87d3SSergey Temerkhanov 	if (state)
21922ffd87d3SSergey Temerkhanov 		return state;
21932ffd87d3SSergey Temerkhanov 
21942ffd87d3SSergey Temerkhanov 	/* initialize package hints and then download package */
21952ffd87d3SSergey Temerkhanov 	ice_init_pkg_hints(hw, seg);
2196a778616eSDan Nowlin 	state = ice_download_pkg(hw, pkg, seg);
21972ffd87d3SSergey Temerkhanov 	if (state == ICE_DDP_PKG_ALREADY_LOADED) {
21982ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT,
21992ffd87d3SSergey Temerkhanov 			  "package previously loaded - no work.\n");
22002ffd87d3SSergey Temerkhanov 		already_loaded = true;
22012ffd87d3SSergey Temerkhanov 	}
22022ffd87d3SSergey Temerkhanov 
22032ffd87d3SSergey Temerkhanov 	/* Get information on the package currently loaded in HW, then make sure
22042ffd87d3SSergey Temerkhanov 	 * the driver is compatible with this version.
22052ffd87d3SSergey Temerkhanov 	 */
22062ffd87d3SSergey Temerkhanov 	if (!state || state == ICE_DDP_PKG_ALREADY_LOADED) {
22072ffd87d3SSergey Temerkhanov 		state = ice_get_pkg_info(hw);
22082ffd87d3SSergey Temerkhanov 		if (!state)
22092ffd87d3SSergey Temerkhanov 			state = ice_get_ddp_pkg_state(hw, already_loaded);
22102ffd87d3SSergey Temerkhanov 	}
22112ffd87d3SSergey Temerkhanov 
22122ffd87d3SSergey Temerkhanov 	if (ice_is_init_pkg_successful(state)) {
22132ffd87d3SSergey Temerkhanov 		hw->seg = seg;
22142ffd87d3SSergey Temerkhanov 		/* on successful package download update other required
22152ffd87d3SSergey Temerkhanov 		 * registers to support the package and fill HW tables
22162ffd87d3SSergey Temerkhanov 		 * with package content.
22172ffd87d3SSergey Temerkhanov 		 */
22182ffd87d3SSergey Temerkhanov 		ice_init_pkg_regs(hw);
22192ffd87d3SSergey Temerkhanov 		ice_fill_blk_tbls(hw);
22202ffd87d3SSergey Temerkhanov 		ice_fill_hw_ptype(hw);
22212ffd87d3SSergey Temerkhanov 		ice_get_prof_index_max(hw);
22222ffd87d3SSergey Temerkhanov 	} else {
22232ffd87d3SSergey Temerkhanov 		ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n", state);
22242ffd87d3SSergey Temerkhanov 	}
22252ffd87d3SSergey Temerkhanov 
22262ffd87d3SSergey Temerkhanov 	return state;
22272ffd87d3SSergey Temerkhanov }
22282ffd87d3SSergey Temerkhanov 
22292ffd87d3SSergey Temerkhanov /**
22302ffd87d3SSergey Temerkhanov  * ice_copy_and_init_pkg - initialize/download a copy of the package
22312ffd87d3SSergey Temerkhanov  * @hw: pointer to the hardware structure
22322ffd87d3SSergey Temerkhanov  * @buf: pointer to the package buffer
22332ffd87d3SSergey Temerkhanov  * @len: size of the package buffer
22342ffd87d3SSergey Temerkhanov  *
22352ffd87d3SSergey Temerkhanov  * This function copies the package buffer, and then calls ice_init_pkg() to
22362ffd87d3SSergey Temerkhanov  * initialize the copied package contents.
22372ffd87d3SSergey Temerkhanov  *
22382ffd87d3SSergey Temerkhanov  * The copying is necessary if the package buffer supplied is constant, or if
22392ffd87d3SSergey Temerkhanov  * the memory may disappear shortly after calling this function.
22402ffd87d3SSergey Temerkhanov  *
22412ffd87d3SSergey Temerkhanov  * If the package buffer resides in the data segment and can be modified, the
22422ffd87d3SSergey Temerkhanov  * caller is free to use ice_init_pkg() instead of ice_copy_and_init_pkg().
22432ffd87d3SSergey Temerkhanov  *
22442ffd87d3SSergey Temerkhanov  * However, if the package buffer needs to be copied first, such as when being
22452ffd87d3SSergey Temerkhanov  * read from a file, the caller should use ice_copy_and_init_pkg().
22462ffd87d3SSergey Temerkhanov  *
22472ffd87d3SSergey Temerkhanov  * This function will first copy the package buffer, before calling
22482ffd87d3SSergey Temerkhanov  * ice_init_pkg(). The caller is free to immediately destroy the original
22492ffd87d3SSergey Temerkhanov  * package buffer, as the new copy will be managed by this function and
22502ffd87d3SSergey Temerkhanov  * related routines.
22512ffd87d3SSergey Temerkhanov  */
22522ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf,
22532ffd87d3SSergey Temerkhanov 					 u32 len)
22542ffd87d3SSergey Temerkhanov {
22552ffd87d3SSergey Temerkhanov 	enum ice_ddp_state state;
22562ffd87d3SSergey Temerkhanov 	u8 *buf_copy;
22572ffd87d3SSergey Temerkhanov 
22582ffd87d3SSergey Temerkhanov 	if (!buf || !len)
22592ffd87d3SSergey Temerkhanov 		return ICE_DDP_PKG_ERR;
22602ffd87d3SSergey Temerkhanov 
22612ffd87d3SSergey Temerkhanov 	buf_copy = devm_kmemdup(ice_hw_to_dev(hw), buf, len, GFP_KERNEL);
22622ffd87d3SSergey Temerkhanov 
22632ffd87d3SSergey Temerkhanov 	state = ice_init_pkg(hw, buf_copy, len);
22642ffd87d3SSergey Temerkhanov 	if (!ice_is_init_pkg_successful(state)) {
22652ffd87d3SSergey Temerkhanov 		/* Free the copy, since we failed to initialize the package */
22662ffd87d3SSergey Temerkhanov 		devm_kfree(ice_hw_to_dev(hw), buf_copy);
22672ffd87d3SSergey Temerkhanov 	} else {
22682ffd87d3SSergey Temerkhanov 		/* Track the copied pkg so we can free it later */
22692ffd87d3SSergey Temerkhanov 		hw->pkg_copy = buf_copy;
22702ffd87d3SSergey Temerkhanov 		hw->pkg_size = len;
22712ffd87d3SSergey Temerkhanov 	}
22722ffd87d3SSergey Temerkhanov 
22732ffd87d3SSergey Temerkhanov 	return state;
22742ffd87d3SSergey Temerkhanov }
2275