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