xref: /freebsd/sys/dev/ice/ice_ddp_common.c (revision 9dc2f6e26fc24b88f9046667708a5555c63fb461)
18923de59SPiotr Kubaj /* SPDX-License-Identifier: BSD-3-Clause */
2*9dc2f6e2SEric Joyner /*  Copyright (c) 2023, Intel Corporation
38923de59SPiotr Kubaj  *  All rights reserved.
48923de59SPiotr Kubaj  *
58923de59SPiotr Kubaj  *  Redistribution and use in source and binary forms, with or without
68923de59SPiotr Kubaj  *  modification, are permitted provided that the following conditions are met:
78923de59SPiotr Kubaj  *
88923de59SPiotr Kubaj  *   1. Redistributions of source code must retain the above copyright notice,
98923de59SPiotr Kubaj  *      this list of conditions and the following disclaimer.
108923de59SPiotr Kubaj  *
118923de59SPiotr Kubaj  *   2. Redistributions in binary form must reproduce the above copyright
128923de59SPiotr Kubaj  *      notice, this list of conditions and the following disclaimer in the
138923de59SPiotr Kubaj  *      documentation and/or other materials provided with the distribution.
148923de59SPiotr Kubaj  *
158923de59SPiotr Kubaj  *   3. Neither the name of the Intel Corporation nor the names of its
168923de59SPiotr Kubaj  *      contributors may be used to endorse or promote products derived from
178923de59SPiotr Kubaj  *      this software without specific prior written permission.
188923de59SPiotr Kubaj  *
198923de59SPiotr Kubaj  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
208923de59SPiotr Kubaj  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218923de59SPiotr Kubaj  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228923de59SPiotr Kubaj  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
238923de59SPiotr Kubaj  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
248923de59SPiotr Kubaj  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
258923de59SPiotr Kubaj  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
268923de59SPiotr Kubaj  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
278923de59SPiotr Kubaj  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
288923de59SPiotr Kubaj  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
298923de59SPiotr Kubaj  *  POSSIBILITY OF SUCH DAMAGE.
308923de59SPiotr Kubaj  */
318923de59SPiotr Kubaj /*$FreeBSD$*/
328923de59SPiotr Kubaj 
338923de59SPiotr Kubaj #include "ice_ddp_common.h"
348923de59SPiotr Kubaj #include "ice_type.h"
358923de59SPiotr Kubaj #include "ice_common.h"
368923de59SPiotr Kubaj #include "ice_sched.h"
378923de59SPiotr Kubaj 
388923de59SPiotr Kubaj /**
398923de59SPiotr Kubaj  * ice_aq_download_pkg
408923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
418923de59SPiotr Kubaj  * @pkg_buf: the package buffer to transfer
428923de59SPiotr Kubaj  * @buf_size: the size of the package buffer
438923de59SPiotr Kubaj  * @last_buf: last buffer indicator
448923de59SPiotr Kubaj  * @error_offset: returns error offset
458923de59SPiotr Kubaj  * @error_info: returns error information
468923de59SPiotr Kubaj  * @cd: pointer to command details structure or NULL
478923de59SPiotr Kubaj  *
488923de59SPiotr Kubaj  * Download Package (0x0C40)
498923de59SPiotr Kubaj  */
508923de59SPiotr Kubaj static enum ice_status
518923de59SPiotr Kubaj ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
528923de59SPiotr Kubaj 		    u16 buf_size, bool last_buf, u32 *error_offset,
538923de59SPiotr Kubaj 		    u32 *error_info, struct ice_sq_cd *cd)
548923de59SPiotr Kubaj {
558923de59SPiotr Kubaj 	struct ice_aqc_download_pkg *cmd;
568923de59SPiotr Kubaj 	struct ice_aq_desc desc;
578923de59SPiotr Kubaj 	enum ice_status status;
588923de59SPiotr Kubaj 
598923de59SPiotr Kubaj 	if (error_offset)
608923de59SPiotr Kubaj 		*error_offset = 0;
618923de59SPiotr Kubaj 	if (error_info)
628923de59SPiotr Kubaj 		*error_info = 0;
638923de59SPiotr Kubaj 
648923de59SPiotr Kubaj 	cmd = &desc.params.download_pkg;
658923de59SPiotr Kubaj 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg);
668923de59SPiotr Kubaj 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
678923de59SPiotr Kubaj 
688923de59SPiotr Kubaj 	if (last_buf)
698923de59SPiotr Kubaj 		cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
708923de59SPiotr Kubaj 
718923de59SPiotr Kubaj 	status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
728923de59SPiotr Kubaj 	if (status == ICE_ERR_AQ_ERROR) {
738923de59SPiotr Kubaj 		/* Read error from buffer only when the FW returned an error */
748923de59SPiotr Kubaj 		struct ice_aqc_download_pkg_resp *resp;
758923de59SPiotr Kubaj 
768923de59SPiotr Kubaj 		resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
778923de59SPiotr Kubaj 		if (error_offset)
788923de59SPiotr Kubaj 			*error_offset = LE32_TO_CPU(resp->error_offset);
798923de59SPiotr Kubaj 		if (error_info)
808923de59SPiotr Kubaj 			*error_info = LE32_TO_CPU(resp->error_info);
818923de59SPiotr Kubaj 	}
828923de59SPiotr Kubaj 
838923de59SPiotr Kubaj 	return status;
848923de59SPiotr Kubaj }
858923de59SPiotr Kubaj 
868923de59SPiotr Kubaj /**
878923de59SPiotr Kubaj  * ice_aq_upload_section
888923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
898923de59SPiotr Kubaj  * @pkg_buf: the package buffer which will receive the section
908923de59SPiotr Kubaj  * @buf_size: the size of the package buffer
918923de59SPiotr Kubaj  * @cd: pointer to command details structure or NULL
928923de59SPiotr Kubaj  *
938923de59SPiotr Kubaj  * Upload Section (0x0C41)
948923de59SPiotr Kubaj  */
958923de59SPiotr Kubaj enum ice_status
968923de59SPiotr Kubaj ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
978923de59SPiotr Kubaj 		      u16 buf_size, struct ice_sq_cd *cd)
988923de59SPiotr Kubaj {
998923de59SPiotr Kubaj 	struct ice_aq_desc desc;
1008923de59SPiotr Kubaj 
1018923de59SPiotr Kubaj 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section);
1028923de59SPiotr Kubaj 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
1038923de59SPiotr Kubaj 
1048923de59SPiotr Kubaj 	return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
1058923de59SPiotr Kubaj }
1068923de59SPiotr Kubaj 
1078923de59SPiotr Kubaj /**
1088923de59SPiotr Kubaj  * ice_aq_update_pkg
1098923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
1108923de59SPiotr Kubaj  * @pkg_buf: the package cmd buffer
1118923de59SPiotr Kubaj  * @buf_size: the size of the package cmd buffer
1128923de59SPiotr Kubaj  * @last_buf: last buffer indicator
1138923de59SPiotr Kubaj  * @error_offset: returns error offset
1148923de59SPiotr Kubaj  * @error_info: returns error information
1158923de59SPiotr Kubaj  * @cd: pointer to command details structure or NULL
1168923de59SPiotr Kubaj  *
1178923de59SPiotr Kubaj  * Update Package (0x0C42)
1188923de59SPiotr Kubaj  */
1198923de59SPiotr Kubaj static enum ice_status
1208923de59SPiotr Kubaj ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, u16 buf_size,
1218923de59SPiotr Kubaj 		  bool last_buf, u32 *error_offset, u32 *error_info,
1228923de59SPiotr Kubaj 		  struct ice_sq_cd *cd)
1238923de59SPiotr Kubaj {
1248923de59SPiotr Kubaj 	struct ice_aqc_download_pkg *cmd;
1258923de59SPiotr Kubaj 	struct ice_aq_desc desc;
1268923de59SPiotr Kubaj 	enum ice_status status;
1278923de59SPiotr Kubaj 
1288923de59SPiotr Kubaj 	if (error_offset)
1298923de59SPiotr Kubaj 		*error_offset = 0;
1308923de59SPiotr Kubaj 	if (error_info)
1318923de59SPiotr Kubaj 		*error_info = 0;
1328923de59SPiotr Kubaj 
1338923de59SPiotr Kubaj 	cmd = &desc.params.download_pkg;
1348923de59SPiotr Kubaj 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg);
1358923de59SPiotr Kubaj 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
1368923de59SPiotr Kubaj 
1378923de59SPiotr Kubaj 	if (last_buf)
1388923de59SPiotr Kubaj 		cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
1398923de59SPiotr Kubaj 
1408923de59SPiotr Kubaj 	status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
1418923de59SPiotr Kubaj 	if (status == ICE_ERR_AQ_ERROR) {
1428923de59SPiotr Kubaj 		/* Read error from buffer only when the FW returned an error */
1438923de59SPiotr Kubaj 		struct ice_aqc_download_pkg_resp *resp;
1448923de59SPiotr Kubaj 
1458923de59SPiotr Kubaj 		resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
1468923de59SPiotr Kubaj 		if (error_offset)
1478923de59SPiotr Kubaj 			*error_offset = LE32_TO_CPU(resp->error_offset);
1488923de59SPiotr Kubaj 		if (error_info)
1498923de59SPiotr Kubaj 			*error_info = LE32_TO_CPU(resp->error_info);
1508923de59SPiotr Kubaj 	}
1518923de59SPiotr Kubaj 
1528923de59SPiotr Kubaj 	return status;
1538923de59SPiotr Kubaj }
1548923de59SPiotr Kubaj 
1558923de59SPiotr Kubaj /**
1568923de59SPiotr Kubaj  * ice_find_seg_in_pkg
1578923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
1588923de59SPiotr Kubaj  * @seg_type: the segment type to search for (i.e., SEGMENT_TYPE_CPK)
1598923de59SPiotr Kubaj  * @pkg_hdr: pointer to the package header to be searched
1608923de59SPiotr Kubaj  *
1618923de59SPiotr Kubaj  * This function searches a package file for a particular segment type. On
1628923de59SPiotr Kubaj  * success it returns a pointer to the segment header, otherwise it will
1638923de59SPiotr Kubaj  * return NULL.
1648923de59SPiotr Kubaj  */
1658923de59SPiotr Kubaj struct ice_generic_seg_hdr *
1668923de59SPiotr Kubaj ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
1678923de59SPiotr Kubaj 		    struct ice_pkg_hdr *pkg_hdr)
1688923de59SPiotr Kubaj {
1698923de59SPiotr Kubaj 	u32 i;
1708923de59SPiotr Kubaj 
1718923de59SPiotr Kubaj 	ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n",
1728923de59SPiotr Kubaj 		  pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor,
1738923de59SPiotr Kubaj 		  pkg_hdr->pkg_format_ver.update,
1748923de59SPiotr Kubaj 		  pkg_hdr->pkg_format_ver.draft);
1758923de59SPiotr Kubaj 
1768923de59SPiotr Kubaj 	/* Search all package segments for the requested segment type */
1778923de59SPiotr Kubaj 	for (i = 0; i < LE32_TO_CPU(pkg_hdr->seg_count); i++) {
1788923de59SPiotr Kubaj 		struct ice_generic_seg_hdr *seg;
1798923de59SPiotr Kubaj 
1808923de59SPiotr Kubaj 		seg = (struct ice_generic_seg_hdr *)
1818923de59SPiotr Kubaj 			((u8 *)pkg_hdr + LE32_TO_CPU(pkg_hdr->seg_offset[i]));
1828923de59SPiotr Kubaj 
1838923de59SPiotr Kubaj 		if (LE32_TO_CPU(seg->seg_type) == seg_type)
1848923de59SPiotr Kubaj 			return seg;
1858923de59SPiotr Kubaj 	}
1868923de59SPiotr Kubaj 
1878923de59SPiotr Kubaj 	return NULL;
1888923de59SPiotr Kubaj }
1898923de59SPiotr Kubaj 
1908923de59SPiotr Kubaj /**
1918923de59SPiotr Kubaj  * ice_get_pkg_seg_by_idx
1928923de59SPiotr Kubaj  * @pkg_hdr: pointer to the package header to be searched
1938923de59SPiotr Kubaj  * @idx: index of segment
1948923de59SPiotr Kubaj  */
1958923de59SPiotr Kubaj static struct ice_generic_seg_hdr *
1968923de59SPiotr Kubaj ice_get_pkg_seg_by_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx)
1978923de59SPiotr Kubaj {
1988923de59SPiotr Kubaj 	struct ice_generic_seg_hdr *seg = NULL;
1998923de59SPiotr Kubaj 
2008923de59SPiotr Kubaj 	if (idx < LE32_TO_CPU(pkg_hdr->seg_count))
2018923de59SPiotr Kubaj 		seg = (struct ice_generic_seg_hdr *)
2028923de59SPiotr Kubaj 			((u8 *)pkg_hdr +
2038923de59SPiotr Kubaj 			 LE32_TO_CPU(pkg_hdr->seg_offset[idx]));
2048923de59SPiotr Kubaj 
2058923de59SPiotr Kubaj 	return seg;
2068923de59SPiotr Kubaj }
2078923de59SPiotr Kubaj 
2088923de59SPiotr Kubaj /**
2098923de59SPiotr Kubaj  * ice_is_signing_seg_at_idx - determine if segment is a signing segment
2108923de59SPiotr Kubaj  * @pkg_hdr: pointer to package header
2118923de59SPiotr Kubaj  * @idx: segment index
2128923de59SPiotr Kubaj  */
2138923de59SPiotr Kubaj static bool ice_is_signing_seg_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx)
2148923de59SPiotr Kubaj {
2158923de59SPiotr Kubaj 	struct ice_generic_seg_hdr *seg;
2168923de59SPiotr Kubaj 	bool retval = false;
2178923de59SPiotr Kubaj 
2188923de59SPiotr Kubaj 	seg = ice_get_pkg_seg_by_idx(pkg_hdr, idx);
2198923de59SPiotr Kubaj 	if (seg)
2208923de59SPiotr Kubaj 		retval = LE32_TO_CPU(seg->seg_type) == SEGMENT_TYPE_SIGNING;
2218923de59SPiotr Kubaj 
2228923de59SPiotr Kubaj 	return retval;
2238923de59SPiotr Kubaj }
2248923de59SPiotr Kubaj 
2258923de59SPiotr Kubaj /**
2268923de59SPiotr Kubaj  * ice_is_signing_seg_type_at_idx
2278923de59SPiotr Kubaj  * @pkg_hdr: pointer to package header
2288923de59SPiotr Kubaj  * @idx: segment index
2298923de59SPiotr Kubaj  * @seg_id: segment id that is expected
2308923de59SPiotr Kubaj  * @sign_type: signing type
2318923de59SPiotr Kubaj  *
2328923de59SPiotr Kubaj  * Determine if a segment is a signing segment of the correct type
2338923de59SPiotr Kubaj  */
2348923de59SPiotr Kubaj static bool
2358923de59SPiotr Kubaj ice_is_signing_seg_type_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx,
2368923de59SPiotr Kubaj 			       u32 seg_id, u32 sign_type)
2378923de59SPiotr Kubaj {
2388923de59SPiotr Kubaj 	bool result = false;
2398923de59SPiotr Kubaj 
2408923de59SPiotr Kubaj 	if (ice_is_signing_seg_at_idx(pkg_hdr, idx)) {
2418923de59SPiotr Kubaj 		struct ice_sign_seg *seg;
2428923de59SPiotr Kubaj 
2438923de59SPiotr Kubaj 		seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr,
2448923de59SPiotr Kubaj 								    idx);
2458923de59SPiotr Kubaj 		if (seg && LE32_TO_CPU(seg->seg_id) == seg_id &&
2468923de59SPiotr Kubaj 		    LE32_TO_CPU(seg->sign_type) == sign_type)
2478923de59SPiotr Kubaj 			result = true;
2488923de59SPiotr Kubaj 	}
2498923de59SPiotr Kubaj 
2508923de59SPiotr Kubaj 	return result;
2518923de59SPiotr Kubaj }
2528923de59SPiotr Kubaj 
2538923de59SPiotr Kubaj /**
2548923de59SPiotr Kubaj  * ice_update_pkg_no_lock
2558923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
2568923de59SPiotr Kubaj  * @bufs: pointer to an array of buffers
2578923de59SPiotr Kubaj  * @count: the number of buffers in the array
2588923de59SPiotr Kubaj  */
2598923de59SPiotr Kubaj enum ice_status
2608923de59SPiotr Kubaj ice_update_pkg_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
2618923de59SPiotr Kubaj {
2628923de59SPiotr Kubaj 	enum ice_status status = ICE_SUCCESS;
2638923de59SPiotr Kubaj 	u32 i;
2648923de59SPiotr Kubaj 
2658923de59SPiotr Kubaj 	for (i = 0; i < count; i++) {
2668923de59SPiotr Kubaj 		struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i);
2678923de59SPiotr Kubaj 		bool last = ((i + 1) == count);
2688923de59SPiotr Kubaj 		u32 offset, info;
2698923de59SPiotr Kubaj 
2708923de59SPiotr Kubaj 		status = ice_aq_update_pkg(hw, bh, LE16_TO_CPU(bh->data_end),
2718923de59SPiotr Kubaj 					   last, &offset, &info, NULL);
2728923de59SPiotr Kubaj 
2738923de59SPiotr Kubaj 		if (status) {
2748923de59SPiotr Kubaj 			ice_debug(hw, ICE_DBG_PKG, "Update pkg failed: err %d off %d inf %d\n",
2758923de59SPiotr Kubaj 				  status, offset, info);
2768923de59SPiotr Kubaj 			break;
2778923de59SPiotr Kubaj 		}
2788923de59SPiotr Kubaj 	}
2798923de59SPiotr Kubaj 
2808923de59SPiotr Kubaj 	return status;
2818923de59SPiotr Kubaj }
2828923de59SPiotr Kubaj 
2838923de59SPiotr Kubaj /**
2848923de59SPiotr Kubaj  * ice_update_pkg
2858923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
2868923de59SPiotr Kubaj  * @bufs: pointer to an array of buffers
2878923de59SPiotr Kubaj  * @count: the number of buffers in the array
2888923de59SPiotr Kubaj  *
2898923de59SPiotr Kubaj  * Obtains change lock and updates package.
2908923de59SPiotr Kubaj  */
2918923de59SPiotr Kubaj enum ice_status
2928923de59SPiotr Kubaj ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
2938923de59SPiotr Kubaj {
2948923de59SPiotr Kubaj 	enum ice_status status;
2958923de59SPiotr Kubaj 
2968923de59SPiotr Kubaj 	status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
2978923de59SPiotr Kubaj 	if (status)
2988923de59SPiotr Kubaj 		return status;
2998923de59SPiotr Kubaj 
3008923de59SPiotr Kubaj 	status = ice_update_pkg_no_lock(hw, bufs, count);
3018923de59SPiotr Kubaj 
3028923de59SPiotr Kubaj 	ice_release_change_lock(hw);
3038923de59SPiotr Kubaj 
3048923de59SPiotr Kubaj 	return status;
3058923de59SPiotr Kubaj }
3068923de59SPiotr Kubaj 
3078923de59SPiotr Kubaj static enum ice_ddp_state
3088923de59SPiotr Kubaj ice_map_aq_err_to_ddp_state(enum ice_aq_err aq_err)
3098923de59SPiotr Kubaj {
3108923de59SPiotr Kubaj 	switch (aq_err) {
3118923de59SPiotr Kubaj 	case ICE_AQ_RC_ENOSEC:
3128923de59SPiotr Kubaj 		return ICE_DDP_PKG_NO_SEC_MANIFEST;
3138923de59SPiotr Kubaj 	case ICE_AQ_RC_EBADSIG:
3148923de59SPiotr Kubaj 		return ICE_DDP_PKG_FILE_SIGNATURE_INVALID;
3158923de59SPiotr Kubaj 	case ICE_AQ_RC_ESVN:
3168923de59SPiotr Kubaj 		return ICE_DDP_PKG_SECURE_VERSION_NBR_TOO_LOW;
3178923de59SPiotr Kubaj 	case ICE_AQ_RC_EBADMAN:
3188923de59SPiotr Kubaj 		return ICE_DDP_PKG_MANIFEST_INVALID;
3198923de59SPiotr Kubaj 	case ICE_AQ_RC_EBADBUF:
3208923de59SPiotr Kubaj 		return ICE_DDP_PKG_BUFFER_INVALID;
3218923de59SPiotr Kubaj 	default:
3228923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
3238923de59SPiotr Kubaj 	}
3248923de59SPiotr Kubaj }
3258923de59SPiotr Kubaj 
3268923de59SPiotr Kubaj /**
3278923de59SPiotr Kubaj  * ice_is_buffer_metadata - determine if package buffer is a metadata buffer
3288923de59SPiotr Kubaj  * @buf: pointer to buffer header
3298923de59SPiotr Kubaj  */
3308923de59SPiotr Kubaj static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf)
3318923de59SPiotr Kubaj {
3328923de59SPiotr Kubaj 	bool metadata = false;
3338923de59SPiotr Kubaj 
3348923de59SPiotr Kubaj 	if (LE32_TO_CPU(buf->section_entry[0].type) & ICE_METADATA_BUF)
3358923de59SPiotr Kubaj 		metadata = true;
3368923de59SPiotr Kubaj 
3378923de59SPiotr Kubaj 	return metadata;
3388923de59SPiotr Kubaj }
3398923de59SPiotr Kubaj 
3408923de59SPiotr Kubaj /**
3418923de59SPiotr Kubaj  * ice_is_last_download_buffer
3428923de59SPiotr Kubaj  * @buf: pointer to current buffer header
3438923de59SPiotr Kubaj  * @idx: index of the buffer in the current sequence
3448923de59SPiotr Kubaj  * @count: the buffer count in the current sequence
3458923de59SPiotr Kubaj  *
3468923de59SPiotr Kubaj  * Note: this routine should only be called if the buffer is not the last buffer
3478923de59SPiotr Kubaj  */
3488923de59SPiotr Kubaj static bool
3498923de59SPiotr Kubaj ice_is_last_download_buffer(struct ice_buf_hdr *buf, u32 idx, u32 count)
3508923de59SPiotr Kubaj {
3518923de59SPiotr Kubaj 	bool last = ((idx + 1) == count);
3528923de59SPiotr Kubaj 
3538923de59SPiotr Kubaj 	/* A set metadata flag in the next buffer will signal that the current
3548923de59SPiotr Kubaj 	 * buffer will be the last buffer downloaded
3558923de59SPiotr Kubaj 	 */
3568923de59SPiotr Kubaj 	if (!last) {
3578923de59SPiotr Kubaj 		struct ice_buf *next_buf = ((struct ice_buf *)buf) + 1;
3588923de59SPiotr Kubaj 
3598923de59SPiotr Kubaj 		last = ice_is_buffer_metadata((struct ice_buf_hdr *)next_buf);
3608923de59SPiotr Kubaj 	}
3618923de59SPiotr Kubaj 
3628923de59SPiotr Kubaj 	return last;
3638923de59SPiotr Kubaj }
3648923de59SPiotr Kubaj 
3658923de59SPiotr Kubaj /**
3668923de59SPiotr Kubaj  * ice_dwnld_cfg_bufs_no_lock
3678923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
3688923de59SPiotr Kubaj  * @bufs: pointer to an array of buffers
3698923de59SPiotr Kubaj  * @start: buffer index of first buffer to download
3708923de59SPiotr Kubaj  * @count: the number of buffers to download
3718923de59SPiotr Kubaj  * @indicate_last: if true, then set last buffer flag on last buffer download
3728923de59SPiotr Kubaj  *
3738923de59SPiotr Kubaj  * Downloads package configuration buffers to the firmware. Metadata buffers
3748923de59SPiotr Kubaj  * are skipped, and the first metadata buffer found indicates that the rest
3758923de59SPiotr Kubaj  * of the buffers are all metadata buffers.
3768923de59SPiotr Kubaj  */
3778923de59SPiotr Kubaj static enum ice_ddp_state
3788923de59SPiotr Kubaj ice_dwnld_cfg_bufs_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 start,
3798923de59SPiotr Kubaj 			   u32 count, bool indicate_last)
3808923de59SPiotr Kubaj {
3818923de59SPiotr Kubaj 	enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS;
3828923de59SPiotr Kubaj 	struct ice_buf_hdr *bh;
3838923de59SPiotr Kubaj 	enum ice_aq_err err;
3848923de59SPiotr Kubaj 	u32 offset, info, i;
3858923de59SPiotr Kubaj 
3868923de59SPiotr Kubaj 	if (!bufs || !count)
3878923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
3888923de59SPiotr Kubaj 
3898923de59SPiotr Kubaj 	/* If the first buffer's first section has its metadata bit set
3908923de59SPiotr Kubaj 	 * then there are no buffers to be downloaded, and the operation is
3918923de59SPiotr Kubaj 	 * considered a success.
3928923de59SPiotr Kubaj 	 */
3938923de59SPiotr Kubaj 	bh = (struct ice_buf_hdr *)(bufs + start);
3948923de59SPiotr Kubaj 	if (LE32_TO_CPU(bh->section_entry[0].type) & ICE_METADATA_BUF)
3958923de59SPiotr Kubaj 		return ICE_DDP_PKG_SUCCESS;
3968923de59SPiotr Kubaj 
3978923de59SPiotr Kubaj 	for (i = 0; i < count; i++) {
3988923de59SPiotr Kubaj 		enum ice_status status;
3998923de59SPiotr Kubaj 		bool last = false;
4008923de59SPiotr Kubaj 
4018923de59SPiotr Kubaj 		bh = (struct ice_buf_hdr *)(bufs + start + i);
4028923de59SPiotr Kubaj 
4038923de59SPiotr Kubaj 		if (indicate_last)
4048923de59SPiotr Kubaj 			last = ice_is_last_download_buffer(bh, i, count);
4058923de59SPiotr Kubaj 
4068923de59SPiotr Kubaj 		status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE, last,
4078923de59SPiotr Kubaj 					     &offset, &info, NULL);
4088923de59SPiotr Kubaj 
4098923de59SPiotr Kubaj 		/* Save AQ status from download package */
4108923de59SPiotr Kubaj 		if (status) {
4118923de59SPiotr Kubaj 			ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n",
4128923de59SPiotr Kubaj 				  status, offset, info);
4138923de59SPiotr Kubaj 			err = hw->adminq.sq_last_status;
4148923de59SPiotr Kubaj 			state = ice_map_aq_err_to_ddp_state(err);
4158923de59SPiotr Kubaj 			break;
4168923de59SPiotr Kubaj 		}
4178923de59SPiotr Kubaj 
4188923de59SPiotr Kubaj 		if (last)
4198923de59SPiotr Kubaj 			break;
4208923de59SPiotr Kubaj 	}
4218923de59SPiotr Kubaj 
4228923de59SPiotr Kubaj 	return state;
4238923de59SPiotr Kubaj }
4248923de59SPiotr Kubaj 
4258923de59SPiotr Kubaj /**
4268923de59SPiotr Kubaj  * ice_aq_get_pkg_info_list
4278923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
4288923de59SPiotr Kubaj  * @pkg_info: the buffer which will receive the information list
4298923de59SPiotr Kubaj  * @buf_size: the size of the pkg_info information buffer
4308923de59SPiotr Kubaj  * @cd: pointer to command details structure or NULL
4318923de59SPiotr Kubaj  *
4328923de59SPiotr Kubaj  * Get Package Info List (0x0C43)
4338923de59SPiotr Kubaj  */
4348923de59SPiotr Kubaj static enum ice_status
4358923de59SPiotr Kubaj ice_aq_get_pkg_info_list(struct ice_hw *hw,
4368923de59SPiotr Kubaj 			 struct ice_aqc_get_pkg_info_resp *pkg_info,
4378923de59SPiotr Kubaj 			 u16 buf_size, struct ice_sq_cd *cd)
4388923de59SPiotr Kubaj {
4398923de59SPiotr Kubaj 	struct ice_aq_desc desc;
4408923de59SPiotr Kubaj 
4418923de59SPiotr Kubaj 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list);
4428923de59SPiotr Kubaj 
4438923de59SPiotr Kubaj 	return ice_aq_send_cmd(hw, &desc, pkg_info, buf_size, cd);
4448923de59SPiotr Kubaj }
4458923de59SPiotr Kubaj 
4468923de59SPiotr Kubaj /**
4478923de59SPiotr Kubaj  * ice_has_signing_seg - determine if package has a signing segment
4488923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
4498923de59SPiotr Kubaj  * @pkg_hdr: pointer to the driver's package hdr
4508923de59SPiotr Kubaj  */
4518923de59SPiotr Kubaj static bool ice_has_signing_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
4528923de59SPiotr Kubaj {
4538923de59SPiotr Kubaj 	struct ice_generic_seg_hdr *seg_hdr;
4548923de59SPiotr Kubaj 
4558923de59SPiotr Kubaj 	seg_hdr = (struct ice_generic_seg_hdr *)
4568923de59SPiotr Kubaj 		ice_find_seg_in_pkg(hw, SEGMENT_TYPE_SIGNING, pkg_hdr);
4578923de59SPiotr Kubaj 
4588923de59SPiotr Kubaj 	return seg_hdr ? true : false;
4598923de59SPiotr Kubaj }
4608923de59SPiotr Kubaj 
4618923de59SPiotr Kubaj /**
4628923de59SPiotr Kubaj  * ice_get_pkg_segment_id - get correct package segment id, based on device
4638923de59SPiotr Kubaj  * @mac_type: MAC type of the device
4648923de59SPiotr Kubaj  */
4658923de59SPiotr Kubaj static u32 ice_get_pkg_segment_id(enum ice_mac_type mac_type)
4668923de59SPiotr Kubaj {
4678923de59SPiotr Kubaj 	u32 seg_id;
4688923de59SPiotr Kubaj 
4698923de59SPiotr Kubaj 	switch (mac_type) {
4708923de59SPiotr Kubaj 	case ICE_MAC_GENERIC:
4718923de59SPiotr Kubaj 	case ICE_MAC_GENERIC_3K:
4728923de59SPiotr Kubaj 	default:
4738923de59SPiotr Kubaj 		seg_id = SEGMENT_TYPE_ICE_E810;
4748923de59SPiotr Kubaj 		break;
4758923de59SPiotr Kubaj 	}
4768923de59SPiotr Kubaj 
4778923de59SPiotr Kubaj 	return seg_id;
4788923de59SPiotr Kubaj }
4798923de59SPiotr Kubaj 
4808923de59SPiotr Kubaj /**
4818923de59SPiotr Kubaj  * ice_get_pkg_sign_type - get package segment sign type, based on device
4828923de59SPiotr Kubaj  * @mac_type: MAC type of the device
4838923de59SPiotr Kubaj  */
4848923de59SPiotr Kubaj static u32 ice_get_pkg_sign_type(enum ice_mac_type mac_type)
4858923de59SPiotr Kubaj {
4868923de59SPiotr Kubaj 	u32 sign_type;
4878923de59SPiotr Kubaj 
4888923de59SPiotr Kubaj 	switch (mac_type) {
4898923de59SPiotr Kubaj 	case ICE_MAC_GENERIC_3K:
4908923de59SPiotr Kubaj 		sign_type = SEGMENT_SIGN_TYPE_RSA3K;
4918923de59SPiotr Kubaj 		break;
4928923de59SPiotr Kubaj 	case ICE_MAC_GENERIC:
4938923de59SPiotr Kubaj 	default:
4948923de59SPiotr Kubaj 		sign_type = SEGMENT_SIGN_TYPE_RSA2K;
4958923de59SPiotr Kubaj 		break;
4968923de59SPiotr Kubaj 	}
4978923de59SPiotr Kubaj 
4988923de59SPiotr Kubaj 	return sign_type;
4998923de59SPiotr Kubaj }
5008923de59SPiotr Kubaj 
5018923de59SPiotr Kubaj /**
5028923de59SPiotr Kubaj  * ice_get_signing_req - get correct package requirements, based on device
5038923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
5048923de59SPiotr Kubaj  */
5058923de59SPiotr Kubaj static void ice_get_signing_req(struct ice_hw *hw)
5068923de59SPiotr Kubaj {
5078923de59SPiotr Kubaj 	hw->pkg_seg_id = ice_get_pkg_segment_id(hw->mac_type);
5088923de59SPiotr Kubaj 	hw->pkg_sign_type = ice_get_pkg_sign_type(hw->mac_type);
5098923de59SPiotr Kubaj }
5108923de59SPiotr Kubaj 
5118923de59SPiotr Kubaj /**
5128923de59SPiotr Kubaj  * ice_download_pkg_sig_seg - download a signature segment
5138923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
5148923de59SPiotr Kubaj  * @seg: pointer to signature segment
5158923de59SPiotr Kubaj  */
5168923de59SPiotr Kubaj static enum ice_ddp_state
5178923de59SPiotr Kubaj ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg)
5188923de59SPiotr Kubaj {
5198923de59SPiotr Kubaj 	enum ice_ddp_state state;
5208923de59SPiotr Kubaj 
5218923de59SPiotr Kubaj 	state = ice_dwnld_cfg_bufs_no_lock(hw, seg->buf_tbl.buf_array, 0,
5228923de59SPiotr Kubaj 					   LE32_TO_CPU(seg->buf_tbl.buf_count),
5238923de59SPiotr Kubaj 					   false);
5248923de59SPiotr Kubaj 
5258923de59SPiotr Kubaj 	return state;
5268923de59SPiotr Kubaj }
5278923de59SPiotr Kubaj 
5288923de59SPiotr Kubaj /**
5298923de59SPiotr Kubaj  * ice_download_pkg_config_seg - download a config segment
5308923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
5318923de59SPiotr Kubaj  * @pkg_hdr: pointer to package header
5328923de59SPiotr Kubaj  * @idx: segment index
5338923de59SPiotr Kubaj  * @start: starting buffer
5348923de59SPiotr Kubaj  * @count: buffer count
5358923de59SPiotr Kubaj  *
5368923de59SPiotr Kubaj  * Note: idx must reference a ICE segment
5378923de59SPiotr Kubaj  */
5388923de59SPiotr Kubaj static enum ice_ddp_state
5398923de59SPiotr Kubaj ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
5408923de59SPiotr Kubaj 			    u32 idx, u32 start, u32 count)
5418923de59SPiotr Kubaj {
5428923de59SPiotr Kubaj 	struct ice_buf_table *bufs;
5438923de59SPiotr Kubaj 	enum ice_ddp_state state;
5448923de59SPiotr Kubaj 	struct ice_seg *seg;
5458923de59SPiotr Kubaj 	u32 buf_count;
5468923de59SPiotr Kubaj 
5478923de59SPiotr Kubaj 	seg = (struct ice_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
5488923de59SPiotr Kubaj 	if (!seg)
5498923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
5508923de59SPiotr Kubaj 
5518923de59SPiotr Kubaj 	bufs = ice_find_buf_table(seg);
5528923de59SPiotr Kubaj 	buf_count = LE32_TO_CPU(bufs->buf_count);
5538923de59SPiotr Kubaj 
5548923de59SPiotr Kubaj 	if (start >= buf_count || start + count > buf_count)
5558923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
5568923de59SPiotr Kubaj 
5578923de59SPiotr Kubaj 	state = ice_dwnld_cfg_bufs_no_lock(hw, bufs->buf_array, start, count,
5588923de59SPiotr Kubaj 					   true);
5598923de59SPiotr Kubaj 
5608923de59SPiotr Kubaj 	return state;
5618923de59SPiotr Kubaj }
5628923de59SPiotr Kubaj 
5638923de59SPiotr Kubaj /**
5648923de59SPiotr Kubaj  * ice_dwnld_sign_and_cfg_segs - download a signing segment and config segment
5658923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
5668923de59SPiotr Kubaj  * @pkg_hdr: pointer to package header
5678923de59SPiotr Kubaj  * @idx: segment index (must be a signature segment)
5688923de59SPiotr Kubaj  *
5698923de59SPiotr Kubaj  * Note: idx must reference a signature segment
5708923de59SPiotr Kubaj  */
5718923de59SPiotr Kubaj static enum ice_ddp_state
5728923de59SPiotr Kubaj ice_dwnld_sign_and_cfg_segs(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
5738923de59SPiotr Kubaj 			    u32 idx)
5748923de59SPiotr Kubaj {
5758923de59SPiotr Kubaj 	enum ice_ddp_state state;
5768923de59SPiotr Kubaj 	struct ice_sign_seg *seg;
5778923de59SPiotr Kubaj 	u32 conf_idx;
5788923de59SPiotr Kubaj 	u32 start;
5798923de59SPiotr Kubaj 	u32 count;
5808923de59SPiotr Kubaj 
5818923de59SPiotr Kubaj 	seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
5828923de59SPiotr Kubaj 	if (!seg) {
5838923de59SPiotr Kubaj 		state = ICE_DDP_PKG_ERR;
5848923de59SPiotr Kubaj 		goto exit;
5858923de59SPiotr Kubaj 	}
5868923de59SPiotr Kubaj 
5878923de59SPiotr Kubaj 	conf_idx = LE32_TO_CPU(seg->signed_seg_idx);
5888923de59SPiotr Kubaj 	start = LE32_TO_CPU(seg->signed_buf_start);
5898923de59SPiotr Kubaj 	count = LE32_TO_CPU(seg->signed_buf_count);
5908923de59SPiotr Kubaj 
5918923de59SPiotr Kubaj 	state = ice_download_pkg_sig_seg(hw, seg);
5928923de59SPiotr Kubaj 	if (state)
5938923de59SPiotr Kubaj 		goto exit;
5948923de59SPiotr Kubaj 
5958923de59SPiotr Kubaj 	state = ice_download_pkg_config_seg(hw, pkg_hdr, conf_idx, start,
5968923de59SPiotr Kubaj 					    count);
5978923de59SPiotr Kubaj 
5988923de59SPiotr Kubaj exit:
5998923de59SPiotr Kubaj 	return state;
6008923de59SPiotr Kubaj }
6018923de59SPiotr Kubaj 
6028923de59SPiotr Kubaj /**
6038923de59SPiotr Kubaj  * ice_match_signing_seg - determine if a matching signing segment exists
6048923de59SPiotr Kubaj  * @pkg_hdr: pointer to package header
6058923de59SPiotr Kubaj  * @seg_id: segment id that is expected
6068923de59SPiotr Kubaj  * @sign_type: signing type
6078923de59SPiotr Kubaj  */
6088923de59SPiotr Kubaj static bool
6098923de59SPiotr Kubaj ice_match_signing_seg(struct ice_pkg_hdr *pkg_hdr, u32 seg_id, u32 sign_type)
6108923de59SPiotr Kubaj {
6118923de59SPiotr Kubaj 	bool match = false;
6128923de59SPiotr Kubaj 	u32 i;
6138923de59SPiotr Kubaj 
6148923de59SPiotr Kubaj 	for (i = 0; i < LE32_TO_CPU(pkg_hdr->seg_count); i++) {
6158923de59SPiotr Kubaj 		if (ice_is_signing_seg_type_at_idx(pkg_hdr, i, seg_id,
6168923de59SPiotr Kubaj 						   sign_type)) {
6178923de59SPiotr Kubaj 			match = true;
6188923de59SPiotr Kubaj 			break;
6198923de59SPiotr Kubaj 		}
6208923de59SPiotr Kubaj 	}
6218923de59SPiotr Kubaj 
6228923de59SPiotr Kubaj 	return match;
6238923de59SPiotr Kubaj }
6248923de59SPiotr Kubaj 
6258923de59SPiotr Kubaj /**
6268923de59SPiotr Kubaj  * ice_post_dwnld_pkg_actions - perform post download package actions
6278923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
6288923de59SPiotr Kubaj  */
6298923de59SPiotr Kubaj static enum ice_ddp_state
6308923de59SPiotr Kubaj ice_post_dwnld_pkg_actions(struct ice_hw *hw)
6318923de59SPiotr Kubaj {
6328923de59SPiotr Kubaj 	enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS;
6338923de59SPiotr Kubaj 	enum ice_status status;
6348923de59SPiotr Kubaj 
6358923de59SPiotr Kubaj 	status = ice_set_vlan_mode(hw);
6368923de59SPiotr Kubaj 	if (status) {
6378923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_PKG, "Failed to set VLAN mode: err %d\n",
6388923de59SPiotr Kubaj 			  status);
6398923de59SPiotr Kubaj 		state = ICE_DDP_PKG_ERR;
6408923de59SPiotr Kubaj 	}
6418923de59SPiotr Kubaj 
6428923de59SPiotr Kubaj 	return state;
6438923de59SPiotr Kubaj }
6448923de59SPiotr Kubaj 
6458923de59SPiotr Kubaj /**
6468923de59SPiotr Kubaj  * ice_download_pkg_with_sig_seg - download package using signature segments
6478923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
6488923de59SPiotr Kubaj  * @pkg_hdr: pointer to package header
6498923de59SPiotr Kubaj  */
6508923de59SPiotr Kubaj static enum ice_ddp_state
6518923de59SPiotr Kubaj ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
6528923de59SPiotr Kubaj {
6538923de59SPiotr Kubaj 	enum ice_aq_err aq_err = hw->adminq.sq_last_status;
6548923de59SPiotr Kubaj 	enum ice_ddp_state state = ICE_DDP_PKG_ERR;
6558923de59SPiotr Kubaj 	enum ice_status status;
6568923de59SPiotr Kubaj 	u32 i;
6578923de59SPiotr Kubaj 
6588923de59SPiotr Kubaj 	ice_debug(hw, ICE_DBG_INIT, "Segment ID %d\n", hw->pkg_seg_id);
6598923de59SPiotr Kubaj 	ice_debug(hw, ICE_DBG_INIT, "Signature type %d\n", hw->pkg_sign_type);
6608923de59SPiotr Kubaj 
6618923de59SPiotr Kubaj 	status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
6628923de59SPiotr Kubaj 	if (status) {
6638923de59SPiotr Kubaj 		if (status == ICE_ERR_AQ_NO_WORK)
6648923de59SPiotr Kubaj 			state = ICE_DDP_PKG_ALREADY_LOADED;
6658923de59SPiotr Kubaj 		else
6668923de59SPiotr Kubaj 			state = ice_map_aq_err_to_ddp_state(aq_err);
6678923de59SPiotr Kubaj 		return state;
6688923de59SPiotr Kubaj 	}
6698923de59SPiotr Kubaj 
6708923de59SPiotr Kubaj 	for (i = 0; i < LE32_TO_CPU(pkg_hdr->seg_count); i++) {
6718923de59SPiotr Kubaj 		if (!ice_is_signing_seg_type_at_idx(pkg_hdr, i, hw->pkg_seg_id,
6728923de59SPiotr Kubaj 						    hw->pkg_sign_type))
6738923de59SPiotr Kubaj 			continue;
6748923de59SPiotr Kubaj 
6758923de59SPiotr Kubaj 		state = ice_dwnld_sign_and_cfg_segs(hw, pkg_hdr, i);
6768923de59SPiotr Kubaj 		if (state)
6778923de59SPiotr Kubaj 			break;
6788923de59SPiotr Kubaj 	}
6798923de59SPiotr Kubaj 
6808923de59SPiotr Kubaj 	if (!state)
6818923de59SPiotr Kubaj 		state = ice_post_dwnld_pkg_actions(hw);
6828923de59SPiotr Kubaj 
6838923de59SPiotr Kubaj 	ice_release_global_cfg_lock(hw);
6848923de59SPiotr Kubaj 
6858923de59SPiotr Kubaj 	return state;
6868923de59SPiotr Kubaj }
6878923de59SPiotr Kubaj 
6888923de59SPiotr Kubaj /**
6898923de59SPiotr Kubaj  * ice_dwnld_cfg_bufs
6908923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
6918923de59SPiotr Kubaj  * @bufs: pointer to an array of buffers
6928923de59SPiotr Kubaj  * @count: the number of buffers in the array
6938923de59SPiotr Kubaj  *
6948923de59SPiotr Kubaj  * Obtains global config lock and downloads the package configuration buffers
6958923de59SPiotr Kubaj  * to the firmware.
6968923de59SPiotr Kubaj  */
6978923de59SPiotr Kubaj static enum ice_ddp_state
6988923de59SPiotr Kubaj ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
6998923de59SPiotr Kubaj {
7008923de59SPiotr Kubaj 	enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS;
7018923de59SPiotr Kubaj 	enum ice_status status;
7028923de59SPiotr Kubaj 	struct ice_buf_hdr *bh;
7038923de59SPiotr Kubaj 
7048923de59SPiotr Kubaj 	if (!bufs || !count)
7058923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
7068923de59SPiotr Kubaj 
7078923de59SPiotr Kubaj 	/* If the first buffer's first section has its metadata bit set
7088923de59SPiotr Kubaj 	 * then there are no buffers to be downloaded, and the operation is
7098923de59SPiotr Kubaj 	 * considered a success.
7108923de59SPiotr Kubaj 	 */
7118923de59SPiotr Kubaj 	bh = (struct ice_buf_hdr *)bufs;
7128923de59SPiotr Kubaj 	if (LE32_TO_CPU(bh->section_entry[0].type) & ICE_METADATA_BUF)
7138923de59SPiotr Kubaj 		return ICE_DDP_PKG_SUCCESS;
7148923de59SPiotr Kubaj 
7158923de59SPiotr Kubaj 	status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
7168923de59SPiotr Kubaj 	if (status) {
7178923de59SPiotr Kubaj 		if (status == ICE_ERR_AQ_NO_WORK)
7188923de59SPiotr Kubaj 			return ICE_DDP_PKG_ALREADY_LOADED;
7198923de59SPiotr Kubaj 		return ice_map_aq_err_to_ddp_state(hw->adminq.sq_last_status);
7208923de59SPiotr Kubaj 	}
7218923de59SPiotr Kubaj 
7228923de59SPiotr Kubaj 	state = ice_dwnld_cfg_bufs_no_lock(hw, bufs, 0, count, true);
7238923de59SPiotr Kubaj 	if (!state)
7248923de59SPiotr Kubaj 		state = ice_post_dwnld_pkg_actions(hw);
7258923de59SPiotr Kubaj 
7268923de59SPiotr Kubaj 	ice_release_global_cfg_lock(hw);
7278923de59SPiotr Kubaj 
7288923de59SPiotr Kubaj 	return state;
7298923de59SPiotr Kubaj }
7308923de59SPiotr Kubaj 
7318923de59SPiotr Kubaj /**
7328923de59SPiotr Kubaj  * ice_download_pkg_without_sig_seg
7338923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
7348923de59SPiotr Kubaj  * @ice_seg: pointer to the segment of the package to be downloaded
7358923de59SPiotr Kubaj  *
7368923de59SPiotr Kubaj  * Handles the download of a complete package without signature segment.
7378923de59SPiotr Kubaj  */
7388923de59SPiotr Kubaj static enum ice_ddp_state
7398923de59SPiotr Kubaj ice_download_pkg_without_sig_seg(struct ice_hw *hw, struct ice_seg *ice_seg)
7408923de59SPiotr Kubaj {
7418923de59SPiotr Kubaj 	struct ice_buf_table *ice_buf_tbl;
7428923de59SPiotr Kubaj 	enum ice_ddp_state state;
7438923de59SPiotr Kubaj 
7448923de59SPiotr Kubaj 	ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n",
7458923de59SPiotr Kubaj 		  ice_seg->hdr.seg_format_ver.major,
7468923de59SPiotr Kubaj 		  ice_seg->hdr.seg_format_ver.minor,
7478923de59SPiotr Kubaj 		  ice_seg->hdr.seg_format_ver.update,
7488923de59SPiotr Kubaj 		  ice_seg->hdr.seg_format_ver.draft);
7498923de59SPiotr Kubaj 
7508923de59SPiotr Kubaj 	ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n",
7518923de59SPiotr Kubaj 		  LE32_TO_CPU(ice_seg->hdr.seg_type),
7528923de59SPiotr Kubaj 		  LE32_TO_CPU(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id);
7538923de59SPiotr Kubaj 
7548923de59SPiotr Kubaj 	ice_buf_tbl = ice_find_buf_table(ice_seg);
7558923de59SPiotr Kubaj 
7568923de59SPiotr Kubaj 	ice_debug(hw, ICE_DBG_PKG, "Seg buf count: %d\n",
7578923de59SPiotr Kubaj 		  LE32_TO_CPU(ice_buf_tbl->buf_count));
7588923de59SPiotr Kubaj 
7598923de59SPiotr Kubaj 	state = ice_dwnld_cfg_bufs(hw, ice_buf_tbl->buf_array,
7608923de59SPiotr Kubaj 				   LE32_TO_CPU(ice_buf_tbl->buf_count));
7618923de59SPiotr Kubaj 
7628923de59SPiotr Kubaj 	return state;
7638923de59SPiotr Kubaj }
7648923de59SPiotr Kubaj 
7658923de59SPiotr Kubaj /**
7668923de59SPiotr Kubaj  * ice_download_pkg
7678923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
7688923de59SPiotr Kubaj  * @pkg_hdr: pointer to package header
7698923de59SPiotr Kubaj  * @ice_seg: pointer to the segment of the package to be downloaded
7708923de59SPiotr Kubaj  *
7718923de59SPiotr Kubaj  * Handles the download of a complete package.
7728923de59SPiotr Kubaj  */
7738923de59SPiotr Kubaj static enum ice_ddp_state
7748923de59SPiotr Kubaj ice_download_pkg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
7758923de59SPiotr Kubaj 		 struct ice_seg *ice_seg)
7768923de59SPiotr Kubaj {
7778923de59SPiotr Kubaj 	enum ice_ddp_state state;
7788923de59SPiotr Kubaj 
7798923de59SPiotr Kubaj 	if (hw->pkg_has_signing_seg)
7808923de59SPiotr Kubaj 		state = ice_download_pkg_with_sig_seg(hw, pkg_hdr);
7818923de59SPiotr Kubaj 	else
7828923de59SPiotr Kubaj 		state = ice_download_pkg_without_sig_seg(hw, ice_seg);
7838923de59SPiotr Kubaj 
7848923de59SPiotr Kubaj 	ice_post_pkg_dwnld_vlan_mode_cfg(hw);
7858923de59SPiotr Kubaj 
7868923de59SPiotr Kubaj 	return state;
7878923de59SPiotr Kubaj }
7888923de59SPiotr Kubaj 
7898923de59SPiotr Kubaj /**
7908923de59SPiotr Kubaj  * ice_init_pkg_info
7918923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
7928923de59SPiotr Kubaj  * @pkg_hdr: pointer to the driver's package hdr
7938923de59SPiotr Kubaj  *
7948923de59SPiotr Kubaj  * Saves off the package details into the HW structure.
7958923de59SPiotr Kubaj  */
7968923de59SPiotr Kubaj static enum ice_ddp_state
7978923de59SPiotr Kubaj ice_init_pkg_info(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
7988923de59SPiotr Kubaj {
7998923de59SPiotr Kubaj 	struct ice_generic_seg_hdr *seg_hdr;
8008923de59SPiotr Kubaj 
8018923de59SPiotr Kubaj 	if (!pkg_hdr)
8028923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
8038923de59SPiotr Kubaj 
8048923de59SPiotr Kubaj 	hw->pkg_has_signing_seg = ice_has_signing_seg(hw, pkg_hdr);
8058923de59SPiotr Kubaj 	ice_get_signing_req(hw);
8068923de59SPiotr Kubaj 
8078923de59SPiotr Kubaj 	ice_debug(hw, ICE_DBG_INIT, "Pkg using segment id: 0x%08X\n",
8088923de59SPiotr Kubaj 		  hw->pkg_seg_id);
8098923de59SPiotr Kubaj 
8108923de59SPiotr Kubaj 	seg_hdr = (struct ice_generic_seg_hdr *)
8118923de59SPiotr Kubaj 		ice_find_seg_in_pkg(hw, hw->pkg_seg_id, pkg_hdr);
8128923de59SPiotr Kubaj 	if (seg_hdr) {
8138923de59SPiotr Kubaj 		struct ice_meta_sect *meta;
8148923de59SPiotr Kubaj 		struct ice_pkg_enum state;
8158923de59SPiotr Kubaj 
8168923de59SPiotr Kubaj 		ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
8178923de59SPiotr Kubaj 
8188923de59SPiotr Kubaj 		/* Get package information from the Metadata Section */
8198923de59SPiotr Kubaj 		meta = (struct ice_meta_sect *)
8208923de59SPiotr Kubaj 			ice_pkg_enum_section((struct ice_seg *)seg_hdr, &state,
8218923de59SPiotr Kubaj 					     ICE_SID_METADATA);
8228923de59SPiotr Kubaj 		if (!meta) {
8238923de59SPiotr Kubaj 			ice_debug(hw, ICE_DBG_INIT, "Did not find ice metadata section in package\n");
8248923de59SPiotr Kubaj 			return ICE_DDP_PKG_INVALID_FILE;
8258923de59SPiotr Kubaj 		}
8268923de59SPiotr Kubaj 
8278923de59SPiotr Kubaj 		hw->pkg_ver = meta->ver;
8288923de59SPiotr Kubaj 		ice_memcpy(hw->pkg_name, meta->name, sizeof(meta->name),
8298923de59SPiotr Kubaj 			   ICE_NONDMA_TO_NONDMA);
8308923de59SPiotr Kubaj 
8318923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_PKG, "Pkg: %d.%d.%d.%d, %s\n",
8328923de59SPiotr Kubaj 			  meta->ver.major, meta->ver.minor, meta->ver.update,
8338923de59SPiotr Kubaj 			  meta->ver.draft, meta->name);
8348923de59SPiotr Kubaj 
8358923de59SPiotr Kubaj 		hw->ice_seg_fmt_ver = seg_hdr->seg_format_ver;
8368923de59SPiotr Kubaj 		ice_memcpy(hw->ice_seg_id, seg_hdr->seg_id,
8378923de59SPiotr Kubaj 			   sizeof(hw->ice_seg_id), ICE_NONDMA_TO_NONDMA);
8388923de59SPiotr Kubaj 
8398923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n",
8408923de59SPiotr Kubaj 			  seg_hdr->seg_format_ver.major,
8418923de59SPiotr Kubaj 			  seg_hdr->seg_format_ver.minor,
8428923de59SPiotr Kubaj 			  seg_hdr->seg_format_ver.update,
8438923de59SPiotr Kubaj 			  seg_hdr->seg_format_ver.draft,
8448923de59SPiotr Kubaj 			  seg_hdr->seg_id);
8458923de59SPiotr Kubaj 	} else {
8468923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "Did not find ice segment in driver package\n");
8478923de59SPiotr Kubaj 		return ICE_DDP_PKG_INVALID_FILE;
8488923de59SPiotr Kubaj 	}
8498923de59SPiotr Kubaj 
8508923de59SPiotr Kubaj 	return ICE_DDP_PKG_SUCCESS;
8518923de59SPiotr Kubaj }
8528923de59SPiotr Kubaj 
8538923de59SPiotr Kubaj /**
8548923de59SPiotr Kubaj  * ice_get_pkg_info
8558923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
8568923de59SPiotr Kubaj  *
8578923de59SPiotr Kubaj  * Store details of the package currently loaded in HW into the HW structure.
8588923de59SPiotr Kubaj  */
8598923de59SPiotr Kubaj enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw)
8608923de59SPiotr Kubaj {
8618923de59SPiotr Kubaj 	enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS;
8628923de59SPiotr Kubaj 	struct ice_aqc_get_pkg_info_resp *pkg_info;
8638923de59SPiotr Kubaj 	u16 size;
8648923de59SPiotr Kubaj 	u32 i;
8658923de59SPiotr Kubaj 
8668923de59SPiotr Kubaj 	size = ice_struct_size(pkg_info, pkg_info, ICE_PKG_CNT);
8678923de59SPiotr Kubaj 	pkg_info = (struct ice_aqc_get_pkg_info_resp *)ice_malloc(hw, size);
8688923de59SPiotr Kubaj 	if (!pkg_info)
8698923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
8708923de59SPiotr Kubaj 
8718923de59SPiotr Kubaj 	if (ice_aq_get_pkg_info_list(hw, pkg_info, size, NULL)) {
8728923de59SPiotr Kubaj 		state = ICE_DDP_PKG_ERR;
8738923de59SPiotr Kubaj 		goto init_pkg_free_alloc;
8748923de59SPiotr Kubaj 	}
8758923de59SPiotr Kubaj 
8768923de59SPiotr Kubaj 	for (i = 0; i < LE32_TO_CPU(pkg_info->count); i++) {
8778923de59SPiotr Kubaj #define ICE_PKG_FLAG_COUNT	4
8788923de59SPiotr Kubaj 		char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 };
8798923de59SPiotr Kubaj 		u8 place = 0;
8808923de59SPiotr Kubaj 
8818923de59SPiotr Kubaj 		if (pkg_info->pkg_info[i].is_active) {
8828923de59SPiotr Kubaj 			flags[place++] = 'A';
8838923de59SPiotr Kubaj 			hw->active_pkg_ver = pkg_info->pkg_info[i].ver;
8848923de59SPiotr Kubaj 			hw->active_track_id =
8858923de59SPiotr Kubaj 				LE32_TO_CPU(pkg_info->pkg_info[i].track_id);
8868923de59SPiotr Kubaj 			ice_memcpy(hw->active_pkg_name,
8878923de59SPiotr Kubaj 				   pkg_info->pkg_info[i].name,
8888923de59SPiotr Kubaj 				   sizeof(pkg_info->pkg_info[i].name),
8898923de59SPiotr Kubaj 				   ICE_NONDMA_TO_NONDMA);
8908923de59SPiotr Kubaj 			hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm;
8918923de59SPiotr Kubaj 		}
8928923de59SPiotr Kubaj 		if (pkg_info->pkg_info[i].is_active_at_boot)
8938923de59SPiotr Kubaj 			flags[place++] = 'B';
8948923de59SPiotr Kubaj 		if (pkg_info->pkg_info[i].is_modified)
8958923de59SPiotr Kubaj 			flags[place++] = 'M';
8968923de59SPiotr Kubaj 		if (pkg_info->pkg_info[i].is_in_nvm)
8978923de59SPiotr Kubaj 			flags[place++] = 'N';
8988923de59SPiotr Kubaj 
8998923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_PKG, "Pkg[%d]: %d.%d.%d.%d,%s,%s\n",
9008923de59SPiotr Kubaj 			  i, pkg_info->pkg_info[i].ver.major,
9018923de59SPiotr Kubaj 			  pkg_info->pkg_info[i].ver.minor,
9028923de59SPiotr Kubaj 			  pkg_info->pkg_info[i].ver.update,
9038923de59SPiotr Kubaj 			  pkg_info->pkg_info[i].ver.draft,
9048923de59SPiotr Kubaj 			  pkg_info->pkg_info[i].name, flags);
9058923de59SPiotr Kubaj 	}
9068923de59SPiotr Kubaj 
9078923de59SPiotr Kubaj init_pkg_free_alloc:
9088923de59SPiotr Kubaj 	ice_free(hw, pkg_info);
9098923de59SPiotr Kubaj 
9108923de59SPiotr Kubaj 	return state;
9118923de59SPiotr Kubaj }
9128923de59SPiotr Kubaj 
9138923de59SPiotr Kubaj /**
9148923de59SPiotr Kubaj  * ice_label_enum_handler
9158923de59SPiotr Kubaj  * @sect_type: section type
9168923de59SPiotr Kubaj  * @section: pointer to section
9178923de59SPiotr Kubaj  * @index: index of the label entry to be returned
9188923de59SPiotr Kubaj  * @offset: pointer to receive absolute offset, always zero for label sections
9198923de59SPiotr Kubaj  *
9208923de59SPiotr Kubaj  * This is a callback function that can be passed to ice_pkg_enum_entry.
9218923de59SPiotr Kubaj  * Handles enumeration of individual label entries.
9228923de59SPiotr Kubaj  */
9238923de59SPiotr Kubaj static void *
9248923de59SPiotr Kubaj ice_label_enum_handler(u32 __ALWAYS_UNUSED sect_type, void *section, u32 index,
9258923de59SPiotr Kubaj 		       u32 *offset)
9268923de59SPiotr Kubaj {
9278923de59SPiotr Kubaj 	struct ice_label_section *labels;
9288923de59SPiotr Kubaj 
9298923de59SPiotr Kubaj 	if (!section)
9308923de59SPiotr Kubaj 		return NULL;
9318923de59SPiotr Kubaj 
9328923de59SPiotr Kubaj 	if (index > ICE_MAX_LABELS_IN_BUF)
9338923de59SPiotr Kubaj 		return NULL;
9348923de59SPiotr Kubaj 
9358923de59SPiotr Kubaj 	if (offset)
9368923de59SPiotr Kubaj 		*offset = 0;
9378923de59SPiotr Kubaj 
9388923de59SPiotr Kubaj 	labels = (struct ice_label_section *)section;
9398923de59SPiotr Kubaj 	if (index >= LE16_TO_CPU(labels->count))
9408923de59SPiotr Kubaj 		return NULL;
9418923de59SPiotr Kubaj 
9428923de59SPiotr Kubaj 	return labels->label + index;
9438923de59SPiotr Kubaj }
9448923de59SPiotr Kubaj 
9458923de59SPiotr Kubaj /**
9468923de59SPiotr Kubaj  * ice_enum_labels
9478923de59SPiotr Kubaj  * @ice_seg: pointer to the ice segment (NULL on subsequent calls)
9488923de59SPiotr Kubaj  * @type: the section type that will contain the label (0 on subsequent calls)
9498923de59SPiotr Kubaj  * @state: ice_pkg_enum structure that will hold the state of the enumeration
9508923de59SPiotr Kubaj  * @value: pointer to a value that will return the label's value if found
9518923de59SPiotr Kubaj  *
9528923de59SPiotr Kubaj  * Enumerates a list of labels in the package. The caller will call
9538923de59SPiotr Kubaj  * ice_enum_labels(ice_seg, type, ...) to start the enumeration, then call
9548923de59SPiotr Kubaj  * ice_enum_labels(NULL, 0, ...) to continue. When the function returns a NULL
9558923de59SPiotr Kubaj  * the end of the list has been reached.
9568923de59SPiotr Kubaj  */
9578923de59SPiotr Kubaj static char *
9588923de59SPiotr Kubaj ice_enum_labels(struct ice_seg *ice_seg, u32 type, struct ice_pkg_enum *state,
9598923de59SPiotr Kubaj 		u16 *value)
9608923de59SPiotr Kubaj {
9618923de59SPiotr Kubaj 	struct ice_label *label;
9628923de59SPiotr Kubaj 
9638923de59SPiotr Kubaj 	/* Check for valid label section on first call */
9648923de59SPiotr Kubaj 	if (type && !(type >= ICE_SID_LBL_FIRST && type <= ICE_SID_LBL_LAST))
9658923de59SPiotr Kubaj 		return NULL;
9668923de59SPiotr Kubaj 
9678923de59SPiotr Kubaj 	label = (struct ice_label *)ice_pkg_enum_entry(ice_seg, state, type,
9688923de59SPiotr Kubaj 						       NULL,
9698923de59SPiotr Kubaj 						       ice_label_enum_handler);
9708923de59SPiotr Kubaj 	if (!label)
9718923de59SPiotr Kubaj 		return NULL;
9728923de59SPiotr Kubaj 
9738923de59SPiotr Kubaj 	*value = LE16_TO_CPU(label->value);
9748923de59SPiotr Kubaj 	return label->name;
9758923de59SPiotr Kubaj }
9768923de59SPiotr Kubaj 
9778923de59SPiotr Kubaj /**
9788923de59SPiotr Kubaj  * ice_find_label_value
9798923de59SPiotr Kubaj  * @ice_seg: pointer to the ice segment (non-NULL)
9808923de59SPiotr Kubaj  * @name: name of the label to search for
9818923de59SPiotr Kubaj  * @type: the section type that will contain the label
9828923de59SPiotr Kubaj  * @value: pointer to a value that will return the label's value if found
9838923de59SPiotr Kubaj  *
9848923de59SPiotr Kubaj  * Finds a label's value given the label name and the section type to search.
9858923de59SPiotr Kubaj  * The ice_seg parameter must not be NULL since the first call to
9868923de59SPiotr Kubaj  * ice_enum_labels requires a pointer to an actual ice_seg structure.
9878923de59SPiotr Kubaj  */
9888923de59SPiotr Kubaj enum ice_status
9898923de59SPiotr Kubaj ice_find_label_value(struct ice_seg *ice_seg, char const *name, u32 type,
9908923de59SPiotr Kubaj 		     u16 *value)
9918923de59SPiotr Kubaj {
9928923de59SPiotr Kubaj 	struct ice_pkg_enum state;
9938923de59SPiotr Kubaj 	char *label_name;
9948923de59SPiotr Kubaj 	u16 val;
9958923de59SPiotr Kubaj 
9968923de59SPiotr Kubaj 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
9978923de59SPiotr Kubaj 
9988923de59SPiotr Kubaj 	if (!ice_seg)
9998923de59SPiotr Kubaj 		return ICE_ERR_PARAM;
10008923de59SPiotr Kubaj 
10018923de59SPiotr Kubaj 	do {
10028923de59SPiotr Kubaj 		label_name = ice_enum_labels(ice_seg, type, &state, &val);
10038923de59SPiotr Kubaj 		if (label_name && !strcmp(label_name, name)) {
10048923de59SPiotr Kubaj 			*value = val;
10058923de59SPiotr Kubaj 			return ICE_SUCCESS;
10068923de59SPiotr Kubaj 		}
10078923de59SPiotr Kubaj 
10088923de59SPiotr Kubaj 		ice_seg = NULL;
10098923de59SPiotr Kubaj 	} while (label_name);
10108923de59SPiotr Kubaj 
10118923de59SPiotr Kubaj 	return ICE_ERR_CFG;
10128923de59SPiotr Kubaj }
10138923de59SPiotr Kubaj 
10148923de59SPiotr Kubaj /**
10158923de59SPiotr Kubaj  * ice_verify_pkg - verify package
10168923de59SPiotr Kubaj  * @pkg: pointer to the package buffer
10178923de59SPiotr Kubaj  * @len: size of the package buffer
10188923de59SPiotr Kubaj  *
10198923de59SPiotr Kubaj  * Verifies various attributes of the package file, including length, format
10208923de59SPiotr Kubaj  * version, and the requirement of at least one segment.
10218923de59SPiotr Kubaj  */
10228923de59SPiotr Kubaj enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
10238923de59SPiotr Kubaj {
10248923de59SPiotr Kubaj 	u32 seg_count;
10258923de59SPiotr Kubaj 	u32 i;
10268923de59SPiotr Kubaj 
10278923de59SPiotr Kubaj 	if (len < ice_struct_size(pkg, seg_offset, 1))
10288923de59SPiotr Kubaj 		return ICE_DDP_PKG_INVALID_FILE;
10298923de59SPiotr Kubaj 
10308923de59SPiotr Kubaj 	if (pkg->pkg_format_ver.major != ICE_PKG_FMT_VER_MAJ ||
10318923de59SPiotr Kubaj 	    pkg->pkg_format_ver.minor != ICE_PKG_FMT_VER_MNR ||
10328923de59SPiotr Kubaj 	    pkg->pkg_format_ver.update != ICE_PKG_FMT_VER_UPD ||
10338923de59SPiotr Kubaj 	    pkg->pkg_format_ver.draft != ICE_PKG_FMT_VER_DFT)
10348923de59SPiotr Kubaj 		return ICE_DDP_PKG_INVALID_FILE;
10358923de59SPiotr Kubaj 
10368923de59SPiotr Kubaj 	/* pkg must have at least one segment */
10378923de59SPiotr Kubaj 	seg_count = LE32_TO_CPU(pkg->seg_count);
10388923de59SPiotr Kubaj 	if (seg_count < 1)
10398923de59SPiotr Kubaj 		return ICE_DDP_PKG_INVALID_FILE;
10408923de59SPiotr Kubaj 
10418923de59SPiotr Kubaj 	/* make sure segment array fits in package length */
10428923de59SPiotr Kubaj 	if (len < ice_struct_size(pkg, seg_offset, seg_count))
10438923de59SPiotr Kubaj 		return ICE_DDP_PKG_INVALID_FILE;
10448923de59SPiotr Kubaj 
10458923de59SPiotr Kubaj 	/* all segments must fit within length */
10468923de59SPiotr Kubaj 	for (i = 0; i < seg_count; i++) {
10478923de59SPiotr Kubaj 		u32 off = LE32_TO_CPU(pkg->seg_offset[i]);
10488923de59SPiotr Kubaj 		struct ice_generic_seg_hdr *seg;
10498923de59SPiotr Kubaj 
10508923de59SPiotr Kubaj 		/* segment header must fit */
10518923de59SPiotr Kubaj 		if (len < off + sizeof(*seg))
10528923de59SPiotr Kubaj 			return ICE_DDP_PKG_INVALID_FILE;
10538923de59SPiotr Kubaj 
10548923de59SPiotr Kubaj 		seg = (struct ice_generic_seg_hdr *)((u8 *)pkg + off);
10558923de59SPiotr Kubaj 
10568923de59SPiotr Kubaj 		/* segment body must fit */
10578923de59SPiotr Kubaj 		if (len < off + LE32_TO_CPU(seg->seg_size))
10588923de59SPiotr Kubaj 			return ICE_DDP_PKG_INVALID_FILE;
10598923de59SPiotr Kubaj 	}
10608923de59SPiotr Kubaj 
10618923de59SPiotr Kubaj 	return ICE_DDP_PKG_SUCCESS;
10628923de59SPiotr Kubaj }
10638923de59SPiotr Kubaj 
10648923de59SPiotr Kubaj /**
10658923de59SPiotr Kubaj  * ice_free_seg - free package segment pointer
10668923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
10678923de59SPiotr Kubaj  *
10688923de59SPiotr Kubaj  * Frees the package segment pointer in the proper manner, depending on if the
10698923de59SPiotr Kubaj  * segment was allocated or just the passed in pointer was stored.
10708923de59SPiotr Kubaj  */
10718923de59SPiotr Kubaj void ice_free_seg(struct ice_hw *hw)
10728923de59SPiotr Kubaj {
10738923de59SPiotr Kubaj 	if (hw->pkg_copy) {
10748923de59SPiotr Kubaj 		ice_free(hw, hw->pkg_copy);
10758923de59SPiotr Kubaj 		hw->pkg_copy = NULL;
10768923de59SPiotr Kubaj 		hw->pkg_size = 0;
10778923de59SPiotr Kubaj 	}
10788923de59SPiotr Kubaj 	hw->seg = NULL;
10798923de59SPiotr Kubaj }
10808923de59SPiotr Kubaj 
10818923de59SPiotr Kubaj /**
10828923de59SPiotr Kubaj  * ice_chk_pkg_version - check package version for compatibility with driver
10838923de59SPiotr Kubaj  * @pkg_ver: pointer to a version structure to check
10848923de59SPiotr Kubaj  *
10858923de59SPiotr Kubaj  * Check to make sure that the package about to be downloaded is compatible with
10868923de59SPiotr Kubaj  * the driver. To be compatible, the major and minor components of the package
10878923de59SPiotr Kubaj  * version must match our ICE_PKG_SUPP_VER_MAJ and ICE_PKG_SUPP_VER_MNR
10888923de59SPiotr Kubaj  * definitions.
10898923de59SPiotr Kubaj  */
10908923de59SPiotr Kubaj static enum ice_ddp_state ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver)
10918923de59SPiotr Kubaj {
10928923de59SPiotr Kubaj 	if (pkg_ver->major > ICE_PKG_SUPP_VER_MAJ ||
10938923de59SPiotr Kubaj 	    (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ &&
10948923de59SPiotr Kubaj 	     pkg_ver->minor > ICE_PKG_SUPP_VER_MNR))
10958923de59SPiotr Kubaj 		return ICE_DDP_PKG_FILE_VERSION_TOO_HIGH;
10968923de59SPiotr Kubaj 	else if (pkg_ver->major < ICE_PKG_SUPP_VER_MAJ ||
10978923de59SPiotr Kubaj 		 (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ &&
10988923de59SPiotr Kubaj 		  pkg_ver->minor < ICE_PKG_SUPP_VER_MNR))
10998923de59SPiotr Kubaj 		return ICE_DDP_PKG_FILE_VERSION_TOO_LOW;
11008923de59SPiotr Kubaj 
11018923de59SPiotr Kubaj 	return ICE_DDP_PKG_SUCCESS;
11028923de59SPiotr Kubaj }
11038923de59SPiotr Kubaj 
11048923de59SPiotr Kubaj /**
11058923de59SPiotr Kubaj  * ice_chk_pkg_compat
11068923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
11078923de59SPiotr Kubaj  * @ospkg: pointer to the package hdr
11088923de59SPiotr Kubaj  * @seg: pointer to the package segment hdr
11098923de59SPiotr Kubaj  *
11108923de59SPiotr Kubaj  * This function checks the package version compatibility with driver and NVM
11118923de59SPiotr Kubaj  */
11128923de59SPiotr Kubaj static enum ice_ddp_state
11138923de59SPiotr Kubaj ice_chk_pkg_compat(struct ice_hw *hw, struct ice_pkg_hdr *ospkg,
11148923de59SPiotr Kubaj 		   struct ice_seg **seg)
11158923de59SPiotr Kubaj {
11168923de59SPiotr Kubaj 	struct ice_aqc_get_pkg_info_resp *pkg;
11178923de59SPiotr Kubaj 	enum ice_ddp_state state;
11188923de59SPiotr Kubaj 	u16 size;
11198923de59SPiotr Kubaj 	u32 i;
11208923de59SPiotr Kubaj 
11218923de59SPiotr Kubaj 	/* Check package version compatibility */
11228923de59SPiotr Kubaj 	state = ice_chk_pkg_version(&hw->pkg_ver);
11238923de59SPiotr Kubaj 	if (state) {
11248923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n");
11258923de59SPiotr Kubaj 		return state;
11268923de59SPiotr Kubaj 	}
11278923de59SPiotr Kubaj 
11288923de59SPiotr Kubaj 	/* find ICE segment in given package */
11298923de59SPiotr Kubaj 	*seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, hw->pkg_seg_id,
11308923de59SPiotr Kubaj 						     ospkg);
11318923de59SPiotr Kubaj 	if (!*seg) {
11328923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n");
11338923de59SPiotr Kubaj 		return ICE_DDP_PKG_INVALID_FILE;
11348923de59SPiotr Kubaj 	}
11358923de59SPiotr Kubaj 
11368923de59SPiotr Kubaj 	/* Check if FW is compatible with the OS package */
11378923de59SPiotr Kubaj 	size = ice_struct_size(pkg, pkg_info, ICE_PKG_CNT);
11388923de59SPiotr Kubaj 	pkg = (struct ice_aqc_get_pkg_info_resp *)ice_malloc(hw, size);
11398923de59SPiotr Kubaj 	if (!pkg)
11408923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
11418923de59SPiotr Kubaj 
11428923de59SPiotr Kubaj 	if (ice_aq_get_pkg_info_list(hw, pkg, size, NULL)) {
11438923de59SPiotr Kubaj 		state = ICE_DDP_PKG_ERR;
11448923de59SPiotr Kubaj 		goto fw_ddp_compat_free_alloc;
11458923de59SPiotr Kubaj 	}
11468923de59SPiotr Kubaj 
11478923de59SPiotr Kubaj 	for (i = 0; i < LE32_TO_CPU(pkg->count); i++) {
11488923de59SPiotr Kubaj 		/* loop till we find the NVM package */
11498923de59SPiotr Kubaj 		if (!pkg->pkg_info[i].is_in_nvm)
11508923de59SPiotr Kubaj 			continue;
11518923de59SPiotr Kubaj 		if ((*seg)->hdr.seg_format_ver.major !=
11528923de59SPiotr Kubaj 			pkg->pkg_info[i].ver.major ||
11538923de59SPiotr Kubaj 		    (*seg)->hdr.seg_format_ver.minor >
11548923de59SPiotr Kubaj 			pkg->pkg_info[i].ver.minor) {
11558923de59SPiotr Kubaj 			state = ICE_DDP_PKG_FW_MISMATCH;
11568923de59SPiotr Kubaj 			ice_debug(hw, ICE_DBG_INIT, "OS package is not compatible with NVM.\n");
11578923de59SPiotr Kubaj 		}
11588923de59SPiotr Kubaj 		/* done processing NVM package so break */
11598923de59SPiotr Kubaj 		break;
11608923de59SPiotr Kubaj 	}
11618923de59SPiotr Kubaj fw_ddp_compat_free_alloc:
11628923de59SPiotr Kubaj 	ice_free(hw, pkg);
11638923de59SPiotr Kubaj 	return state;
11648923de59SPiotr Kubaj }
11658923de59SPiotr Kubaj 
11668923de59SPiotr Kubaj /**
11678923de59SPiotr Kubaj  * ice_sw_fv_handler
11688923de59SPiotr Kubaj  * @sect_type: section type
11698923de59SPiotr Kubaj  * @section: pointer to section
11708923de59SPiotr Kubaj  * @index: index of the field vector entry to be returned
11718923de59SPiotr Kubaj  * @offset: ptr to variable that receives the offset in the field vector table
11728923de59SPiotr Kubaj  *
11738923de59SPiotr Kubaj  * This is a callback function that can be passed to ice_pkg_enum_entry.
11748923de59SPiotr Kubaj  * This function treats the given section as of type ice_sw_fv_section and
11758923de59SPiotr Kubaj  * enumerates offset field. "offset" is an index into the field vector table.
11768923de59SPiotr Kubaj  */
11778923de59SPiotr Kubaj static void *
11788923de59SPiotr Kubaj ice_sw_fv_handler(u32 sect_type, void *section, u32 index, u32 *offset)
11798923de59SPiotr Kubaj {
11808923de59SPiotr Kubaj 	struct ice_sw_fv_section *fv_section =
11818923de59SPiotr Kubaj 		(struct ice_sw_fv_section *)section;
11828923de59SPiotr Kubaj 
11838923de59SPiotr Kubaj 	if (!section || sect_type != ICE_SID_FLD_VEC_SW)
11848923de59SPiotr Kubaj 		return NULL;
11858923de59SPiotr Kubaj 	if (index >= LE16_TO_CPU(fv_section->count))
11868923de59SPiotr Kubaj 		return NULL;
11878923de59SPiotr Kubaj 	if (offset)
11888923de59SPiotr Kubaj 		/* "index" passed in to this function is relative to a given
11898923de59SPiotr Kubaj 		 * 4k block. To get to the true index into the field vector
11908923de59SPiotr Kubaj 		 * table need to add the relative index to the base_offset
11918923de59SPiotr Kubaj 		 * field of this section
11928923de59SPiotr Kubaj 		 */
11938923de59SPiotr Kubaj 		*offset = LE16_TO_CPU(fv_section->base_offset) + index;
11948923de59SPiotr Kubaj 	return fv_section->fv + index;
11958923de59SPiotr Kubaj }
11968923de59SPiotr Kubaj 
11978923de59SPiotr Kubaj /**
11988923de59SPiotr Kubaj  * ice_get_prof_index_max - get the max profile index for used profile
11998923de59SPiotr Kubaj  * @hw: pointer to the HW struct
12008923de59SPiotr Kubaj  *
12018923de59SPiotr Kubaj  * Calling this function will get the max profile index for used profile
12028923de59SPiotr Kubaj  * and store the index number in struct ice_switch_info *switch_info
12038923de59SPiotr Kubaj  * in hw for following use.
12048923de59SPiotr Kubaj  */
12058923de59SPiotr Kubaj static int ice_get_prof_index_max(struct ice_hw *hw)
12068923de59SPiotr Kubaj {
12078923de59SPiotr Kubaj 	u16 prof_index = 0, j, max_prof_index = 0;
12088923de59SPiotr Kubaj 	struct ice_pkg_enum state;
12098923de59SPiotr Kubaj 	struct ice_seg *ice_seg;
12108923de59SPiotr Kubaj 	bool flag = false;
12118923de59SPiotr Kubaj 	struct ice_fv *fv;
12128923de59SPiotr Kubaj 	u32 offset;
12138923de59SPiotr Kubaj 
12148923de59SPiotr Kubaj 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
12158923de59SPiotr Kubaj 
12168923de59SPiotr Kubaj 	if (!hw->seg)
12178923de59SPiotr Kubaj 		return ICE_ERR_PARAM;
12188923de59SPiotr Kubaj 
12198923de59SPiotr Kubaj 	ice_seg = hw->seg;
12208923de59SPiotr Kubaj 
12218923de59SPiotr Kubaj 	do {
12228923de59SPiotr Kubaj 		fv = (struct ice_fv *)
12238923de59SPiotr Kubaj 			ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
12248923de59SPiotr Kubaj 					   &offset, ice_sw_fv_handler);
12258923de59SPiotr Kubaj 		if (!fv)
12268923de59SPiotr Kubaj 			break;
12278923de59SPiotr Kubaj 		ice_seg = NULL;
12288923de59SPiotr Kubaj 
12298923de59SPiotr Kubaj 		/* in the profile that not be used, the prot_id is set to 0xff
12308923de59SPiotr Kubaj 		 * and the off is set to 0x1ff for all the field vectors.
12318923de59SPiotr Kubaj 		 */
12328923de59SPiotr Kubaj 		for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
12338923de59SPiotr Kubaj 			if (fv->ew[j].prot_id != ICE_PROT_INVALID ||
12348923de59SPiotr Kubaj 			    fv->ew[j].off != ICE_FV_OFFSET_INVAL)
12358923de59SPiotr Kubaj 				flag = true;
12368923de59SPiotr Kubaj 		if (flag && prof_index > max_prof_index)
12378923de59SPiotr Kubaj 			max_prof_index = prof_index;
12388923de59SPiotr Kubaj 
12398923de59SPiotr Kubaj 		prof_index++;
12408923de59SPiotr Kubaj 		flag = false;
12418923de59SPiotr Kubaj 	} while (fv);
12428923de59SPiotr Kubaj 
12438923de59SPiotr Kubaj 	hw->switch_info->max_used_prof_index = max_prof_index;
12448923de59SPiotr Kubaj 
12458923de59SPiotr Kubaj 	return ICE_SUCCESS;
12468923de59SPiotr Kubaj }
12478923de59SPiotr Kubaj 
12488923de59SPiotr Kubaj /**
12498923de59SPiotr Kubaj  * ice_get_ddp_pkg_state - get DDP pkg state after download
12508923de59SPiotr Kubaj  * @hw: pointer to the HW struct
12518923de59SPiotr Kubaj  * @already_loaded: indicates if pkg was already loaded onto the device
12528923de59SPiotr Kubaj  *
12538923de59SPiotr Kubaj  */
12548923de59SPiotr Kubaj static enum ice_ddp_state
12558923de59SPiotr Kubaj ice_get_ddp_pkg_state(struct ice_hw *hw, bool already_loaded)
12568923de59SPiotr Kubaj {
12578923de59SPiotr Kubaj 	if (hw->pkg_ver.major == hw->active_pkg_ver.major &&
12588923de59SPiotr Kubaj 	    hw->pkg_ver.minor == hw->active_pkg_ver.minor &&
12598923de59SPiotr Kubaj 	    hw->pkg_ver.update == hw->active_pkg_ver.update &&
12608923de59SPiotr Kubaj 	    hw->pkg_ver.draft == hw->active_pkg_ver.draft &&
12618923de59SPiotr Kubaj 	    !memcmp(hw->pkg_name, hw->active_pkg_name, sizeof(hw->pkg_name))) {
12628923de59SPiotr Kubaj 		if (already_loaded)
12638923de59SPiotr Kubaj 			return ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED;
12648923de59SPiotr Kubaj 		else
12658923de59SPiotr Kubaj 			return ICE_DDP_PKG_SUCCESS;
12668923de59SPiotr Kubaj 	} else if (hw->active_pkg_ver.major != ICE_PKG_SUPP_VER_MAJ ||
12678923de59SPiotr Kubaj 		   hw->active_pkg_ver.minor != ICE_PKG_SUPP_VER_MNR) {
12688923de59SPiotr Kubaj 		return ICE_DDP_PKG_ALREADY_LOADED_NOT_SUPPORTED;
12698923de59SPiotr Kubaj 	} else if (hw->active_pkg_ver.major == ICE_PKG_SUPP_VER_MAJ &&
12708923de59SPiotr Kubaj 		   hw->active_pkg_ver.minor == ICE_PKG_SUPP_VER_MNR) {
12718923de59SPiotr Kubaj 		return ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED;
12728923de59SPiotr Kubaj 	} else {
12738923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
12748923de59SPiotr Kubaj 	}
12758923de59SPiotr Kubaj }
12768923de59SPiotr Kubaj 
12778923de59SPiotr Kubaj /**
12788923de59SPiotr Kubaj  * ice_init_pkg_regs - initialize additional package registers
12798923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
12808923de59SPiotr Kubaj  */
12818923de59SPiotr Kubaj static void ice_init_pkg_regs(struct ice_hw *hw)
12828923de59SPiotr Kubaj {
12838923de59SPiotr Kubaj #define ICE_SW_BLK_INP_MASK_L 0xFFFFFFFF
12848923de59SPiotr Kubaj #define ICE_SW_BLK_INP_MASK_H 0x0000FFFF
12858923de59SPiotr Kubaj #define ICE_SW_BLK_IDX	0
12868923de59SPiotr Kubaj 
12878923de59SPiotr Kubaj 	/* setup Switch block input mask, which is 48-bits in two parts */
12888923de59SPiotr Kubaj 	wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L);
12898923de59SPiotr Kubaj 	wr32(hw, GL_PREEXT_L2_PMASK1(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_H);
12908923de59SPiotr Kubaj }
12918923de59SPiotr Kubaj 
12928923de59SPiotr Kubaj /**
12938923de59SPiotr Kubaj  * ice_init_pkg - initialize/download package
12948923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
12958923de59SPiotr Kubaj  * @buf: pointer to the package buffer
12968923de59SPiotr Kubaj  * @len: size of the package buffer
12978923de59SPiotr Kubaj  *
12988923de59SPiotr Kubaj  * This function initializes a package. The package contains HW tables
12998923de59SPiotr Kubaj  * required to do packet processing. First, the function extracts package
13008923de59SPiotr Kubaj  * information such as version. Then it finds the ice configuration segment
13018923de59SPiotr Kubaj  * within the package; this function then saves a copy of the segment pointer
13028923de59SPiotr Kubaj  * within the supplied package buffer. Next, the function will cache any hints
13038923de59SPiotr Kubaj  * from the package, followed by downloading the package itself. Note, that if
13048923de59SPiotr Kubaj  * a previous PF driver has already downloaded the package successfully, then
13058923de59SPiotr Kubaj  * the current driver will not have to download the package again.
13068923de59SPiotr Kubaj  *
13078923de59SPiotr Kubaj  * The local package contents will be used to query default behavior and to
13088923de59SPiotr Kubaj  * update specific sections of the HW's version of the package (e.g. to update
13098923de59SPiotr Kubaj  * the parse graph to understand new protocols).
13108923de59SPiotr Kubaj  *
13118923de59SPiotr Kubaj  * This function stores a pointer to the package buffer memory, and it is
13128923de59SPiotr Kubaj  * expected that the supplied buffer will not be freed immediately. If the
13138923de59SPiotr Kubaj  * package buffer needs to be freed, such as when read from a file, use
13148923de59SPiotr Kubaj  * ice_copy_and_init_pkg() instead of directly calling ice_init_pkg() in this
13158923de59SPiotr Kubaj  * case.
13168923de59SPiotr Kubaj  */
13178923de59SPiotr Kubaj enum ice_ddp_state ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len)
13188923de59SPiotr Kubaj {
13198923de59SPiotr Kubaj 	bool already_loaded = false;
13208923de59SPiotr Kubaj 	enum ice_ddp_state state;
13218923de59SPiotr Kubaj 	struct ice_pkg_hdr *pkg;
13228923de59SPiotr Kubaj 	struct ice_seg *seg;
13238923de59SPiotr Kubaj 
13248923de59SPiotr Kubaj 	if (!buf || !len)
13258923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
13268923de59SPiotr Kubaj 
13278923de59SPiotr Kubaj 	pkg = (struct ice_pkg_hdr *)buf;
13288923de59SPiotr Kubaj 	state = ice_verify_pkg(pkg, len);
13298923de59SPiotr Kubaj 	if (state) {
13308923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n",
13318923de59SPiotr Kubaj 			  state);
13328923de59SPiotr Kubaj 		return state;
13338923de59SPiotr Kubaj 	}
13348923de59SPiotr Kubaj 
13358923de59SPiotr Kubaj 	/* initialize package info */
13368923de59SPiotr Kubaj 	state = ice_init_pkg_info(hw, pkg);
13378923de59SPiotr Kubaj 	if (state)
13388923de59SPiotr Kubaj 		return state;
13398923de59SPiotr Kubaj 
13408923de59SPiotr Kubaj 	/* For packages with signing segments, must be a matching segment */
13418923de59SPiotr Kubaj 	if (hw->pkg_has_signing_seg)
13428923de59SPiotr Kubaj 		if (!ice_match_signing_seg(pkg, hw->pkg_seg_id,
13438923de59SPiotr Kubaj 					   hw->pkg_sign_type))
13448923de59SPiotr Kubaj 			return ICE_DDP_PKG_ERR;
13458923de59SPiotr Kubaj 
13468923de59SPiotr Kubaj 	/* before downloading the package, check package version for
13478923de59SPiotr Kubaj 	 * compatibility with driver
13488923de59SPiotr Kubaj 	 */
13498923de59SPiotr Kubaj 	state = ice_chk_pkg_compat(hw, pkg, &seg);
13508923de59SPiotr Kubaj 	if (state)
13518923de59SPiotr Kubaj 		return state;
13528923de59SPiotr Kubaj 
13538923de59SPiotr Kubaj 	/* initialize package hints and then download package */
13548923de59SPiotr Kubaj 	ice_init_pkg_hints(hw, seg);
13558923de59SPiotr Kubaj 	state = ice_download_pkg(hw, pkg, seg);
13568923de59SPiotr Kubaj 
13578923de59SPiotr Kubaj 	if (state == ICE_DDP_PKG_ALREADY_LOADED) {
13588923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "package previously loaded - no work.\n");
13598923de59SPiotr Kubaj 		already_loaded = true;
13608923de59SPiotr Kubaj 	}
13618923de59SPiotr Kubaj 
13628923de59SPiotr Kubaj 	/* Get information on the package currently loaded in HW, then make sure
13638923de59SPiotr Kubaj 	 * the driver is compatible with this version.
13648923de59SPiotr Kubaj 	 */
13658923de59SPiotr Kubaj 	if (!state || state == ICE_DDP_PKG_ALREADY_LOADED) {
13668923de59SPiotr Kubaj 		state = ice_get_pkg_info(hw);
13678923de59SPiotr Kubaj 		if (!state)
13688923de59SPiotr Kubaj 			state = ice_get_ddp_pkg_state(hw, already_loaded);
13698923de59SPiotr Kubaj 	}
13708923de59SPiotr Kubaj 
13718923de59SPiotr Kubaj 	if (ice_is_init_pkg_successful(state)) {
13728923de59SPiotr Kubaj 		hw->seg = seg;
13738923de59SPiotr Kubaj 		/* on successful package download update other required
13748923de59SPiotr Kubaj 		 * registers to support the package and fill HW tables
13758923de59SPiotr Kubaj 		 * with package content.
13768923de59SPiotr Kubaj 		 */
13778923de59SPiotr Kubaj 		ice_init_pkg_regs(hw);
13788923de59SPiotr Kubaj 		ice_fill_blk_tbls(hw);
13798923de59SPiotr Kubaj 		ice_get_prof_index_max(hw);
13808923de59SPiotr Kubaj 	} else {
13818923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n",
13828923de59SPiotr Kubaj 			  state);
13838923de59SPiotr Kubaj 	}
13848923de59SPiotr Kubaj 
13858923de59SPiotr Kubaj 	return state;
13868923de59SPiotr Kubaj }
13878923de59SPiotr Kubaj 
13888923de59SPiotr Kubaj /**
13898923de59SPiotr Kubaj  * ice_copy_and_init_pkg - initialize/download a copy of the package
13908923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
13918923de59SPiotr Kubaj  * @buf: pointer to the package buffer
13928923de59SPiotr Kubaj  * @len: size of the package buffer
13938923de59SPiotr Kubaj  *
13948923de59SPiotr Kubaj  * This function copies the package buffer, and then calls ice_init_pkg() to
13958923de59SPiotr Kubaj  * initialize the copied package contents.
13968923de59SPiotr Kubaj  *
13978923de59SPiotr Kubaj  * The copying is necessary if the package buffer supplied is constant, or if
13988923de59SPiotr Kubaj  * the memory may disappear shortly after calling this function.
13998923de59SPiotr Kubaj  *
14008923de59SPiotr Kubaj  * If the package buffer resides in the data segment and can be modified, the
14018923de59SPiotr Kubaj  * caller is free to use ice_init_pkg() instead of ice_copy_and_init_pkg().
14028923de59SPiotr Kubaj  *
14038923de59SPiotr Kubaj  * However, if the package buffer needs to be copied first, such as when being
14048923de59SPiotr Kubaj  * read from a file, the caller should use ice_copy_and_init_pkg().
14058923de59SPiotr Kubaj  *
14068923de59SPiotr Kubaj  * This function will first copy the package buffer, before calling
14078923de59SPiotr Kubaj  * ice_init_pkg(). The caller is free to immediately destroy the original
14088923de59SPiotr Kubaj  * package buffer, as the new copy will be managed by this function and
14098923de59SPiotr Kubaj  * related routines.
14108923de59SPiotr Kubaj  */
14118923de59SPiotr Kubaj enum ice_ddp_state
14128923de59SPiotr Kubaj ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, u32 len)
14138923de59SPiotr Kubaj {
14148923de59SPiotr Kubaj 	enum ice_ddp_state state;
14158923de59SPiotr Kubaj 	u8 *buf_copy;
14168923de59SPiotr Kubaj 
14178923de59SPiotr Kubaj 	if (!buf || !len)
14188923de59SPiotr Kubaj 		return ICE_DDP_PKG_ERR;
14198923de59SPiotr Kubaj 
14208923de59SPiotr Kubaj 	buf_copy = (u8 *)ice_memdup(hw, buf, len, ICE_NONDMA_TO_NONDMA);
14218923de59SPiotr Kubaj 
14228923de59SPiotr Kubaj 	state = ice_init_pkg(hw, buf_copy, len);
14238923de59SPiotr Kubaj 	if (!ice_is_init_pkg_successful(state)) {
14248923de59SPiotr Kubaj 		/* Free the copy, since we failed to initialize the package */
14258923de59SPiotr Kubaj 		ice_free(hw, buf_copy);
14268923de59SPiotr Kubaj 	} else {
14278923de59SPiotr Kubaj 		/* Track the copied pkg so we can free it later */
14288923de59SPiotr Kubaj 		hw->pkg_copy = buf_copy;
14298923de59SPiotr Kubaj 		hw->pkg_size = len;
14308923de59SPiotr Kubaj 	}
14318923de59SPiotr Kubaj 
14328923de59SPiotr Kubaj 	return state;
14338923de59SPiotr Kubaj }
14348923de59SPiotr Kubaj 
14358923de59SPiotr Kubaj /**
14368923de59SPiotr Kubaj  * ice_is_init_pkg_successful - check if DDP init was successful
14378923de59SPiotr Kubaj  * @state: state of the DDP pkg after download
14388923de59SPiotr Kubaj  */
14398923de59SPiotr Kubaj bool ice_is_init_pkg_successful(enum ice_ddp_state state)
14408923de59SPiotr Kubaj {
14418923de59SPiotr Kubaj 	switch (state) {
14428923de59SPiotr Kubaj 	case ICE_DDP_PKG_SUCCESS:
14438923de59SPiotr Kubaj 	case ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED:
14448923de59SPiotr Kubaj 	case ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED:
14458923de59SPiotr Kubaj 		return true;
14468923de59SPiotr Kubaj 	default:
14478923de59SPiotr Kubaj 		return false;
14488923de59SPiotr Kubaj 	}
14498923de59SPiotr Kubaj }
14508923de59SPiotr Kubaj 
14518923de59SPiotr Kubaj /**
14528923de59SPiotr Kubaj  * ice_pkg_buf_alloc
14538923de59SPiotr Kubaj  * @hw: pointer to the HW structure
14548923de59SPiotr Kubaj  *
14558923de59SPiotr Kubaj  * Allocates a package buffer and returns a pointer to the buffer header.
14568923de59SPiotr Kubaj  * Note: all package contents must be in Little Endian form.
14578923de59SPiotr Kubaj  */
14588923de59SPiotr Kubaj struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
14598923de59SPiotr Kubaj {
14608923de59SPiotr Kubaj 	struct ice_buf_build *bld;
14618923de59SPiotr Kubaj 	struct ice_buf_hdr *buf;
14628923de59SPiotr Kubaj 
14638923de59SPiotr Kubaj 	bld = (struct ice_buf_build *)ice_malloc(hw, sizeof(*bld));
14648923de59SPiotr Kubaj 	if (!bld)
14658923de59SPiotr Kubaj 		return NULL;
14668923de59SPiotr Kubaj 
14678923de59SPiotr Kubaj 	buf = (struct ice_buf_hdr *)bld;
14688923de59SPiotr Kubaj 	buf->data_end = CPU_TO_LE16(offsetof(struct ice_buf_hdr,
14698923de59SPiotr Kubaj 					     section_entry));
14708923de59SPiotr Kubaj 	return bld;
14718923de59SPiotr Kubaj }
14728923de59SPiotr Kubaj 
1473*9dc2f6e2SEric Joyner static bool ice_is_gtp_u_profile(u32 prof_idx)
14748923de59SPiotr Kubaj {
14758923de59SPiotr Kubaj 	return (prof_idx >= ICE_PROFID_IPV6_GTPU_TEID &&
14768923de59SPiotr Kubaj 		prof_idx <= ICE_PROFID_IPV6_GTPU_IPV6_TCP) ||
14778923de59SPiotr Kubaj 	       prof_idx == ICE_PROFID_IPV4_GTPU_TEID;
14788923de59SPiotr Kubaj }
14798923de59SPiotr Kubaj 
1480*9dc2f6e2SEric Joyner static bool ice_is_gtp_c_profile(u32 prof_idx)
14818923de59SPiotr Kubaj {
14828923de59SPiotr Kubaj 	switch (prof_idx) {
14838923de59SPiotr Kubaj 	case ICE_PROFID_IPV4_GTPC_TEID:
14848923de59SPiotr Kubaj 	case ICE_PROFID_IPV4_GTPC_NO_TEID:
14858923de59SPiotr Kubaj 	case ICE_PROFID_IPV6_GTPC_TEID:
14868923de59SPiotr Kubaj 	case ICE_PROFID_IPV6_GTPC_NO_TEID:
14878923de59SPiotr Kubaj 		return true;
14888923de59SPiotr Kubaj 	default:
14898923de59SPiotr Kubaj 		return false;
14908923de59SPiotr Kubaj 	}
14918923de59SPiotr Kubaj }
14928923de59SPiotr Kubaj 
14938923de59SPiotr Kubaj /**
14948923de59SPiotr Kubaj  * ice_get_sw_prof_type - determine switch profile type
14958923de59SPiotr Kubaj  * @hw: pointer to the HW structure
14968923de59SPiotr Kubaj  * @fv: pointer to the switch field vector
14978923de59SPiotr Kubaj  * @prof_idx: profile index to check
14988923de59SPiotr Kubaj  */
14998923de59SPiotr Kubaj static enum ice_prof_type
15008923de59SPiotr Kubaj ice_get_sw_prof_type(struct ice_hw *hw, struct ice_fv *fv, u32 prof_idx)
15018923de59SPiotr Kubaj {
15028923de59SPiotr Kubaj 	bool valid_prof = false;
15038923de59SPiotr Kubaj 	u16 i;
15048923de59SPiotr Kubaj 
15058923de59SPiotr Kubaj 	if (ice_is_gtp_c_profile(prof_idx))
15068923de59SPiotr Kubaj 		return ICE_PROF_TUN_GTPC;
15078923de59SPiotr Kubaj 
15088923de59SPiotr Kubaj 	if (ice_is_gtp_u_profile(prof_idx))
15098923de59SPiotr Kubaj 		return ICE_PROF_TUN_GTPU;
15108923de59SPiotr Kubaj 
15118923de59SPiotr Kubaj 	for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) {
15128923de59SPiotr Kubaj 		if (fv->ew[i].off != ICE_NAN_OFFSET)
15138923de59SPiotr Kubaj 			valid_prof = true;
15148923de59SPiotr Kubaj 
15158923de59SPiotr Kubaj 		/* UDP tunnel will have UDP_OF protocol ID and VNI offset */
15168923de59SPiotr Kubaj 		if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF &&
15178923de59SPiotr Kubaj 		    fv->ew[i].off == ICE_VNI_OFFSET)
15188923de59SPiotr Kubaj 			return ICE_PROF_TUN_UDP;
15198923de59SPiotr Kubaj 
15208923de59SPiotr Kubaj 		/* GRE tunnel will have GRE protocol */
15218923de59SPiotr Kubaj 		if (fv->ew[i].prot_id == (u8)ICE_PROT_GRE_OF)
15228923de59SPiotr Kubaj 			return ICE_PROF_TUN_GRE;
15238923de59SPiotr Kubaj 	}
15248923de59SPiotr Kubaj 
15258923de59SPiotr Kubaj 	return valid_prof ? ICE_PROF_NON_TUN : ICE_PROF_INVALID;
15268923de59SPiotr Kubaj }
15278923de59SPiotr Kubaj 
15288923de59SPiotr Kubaj /**
15298923de59SPiotr Kubaj  * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type
15308923de59SPiotr Kubaj  * @hw: pointer to hardware structure
15318923de59SPiotr Kubaj  * @req_profs: type of profiles requested
15328923de59SPiotr Kubaj  * @bm: pointer to memory for returning the bitmap of field vectors
15338923de59SPiotr Kubaj  */
15348923de59SPiotr Kubaj void
15358923de59SPiotr Kubaj ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
15368923de59SPiotr Kubaj 		     ice_bitmap_t *bm)
15378923de59SPiotr Kubaj {
15388923de59SPiotr Kubaj 	struct ice_pkg_enum state;
15398923de59SPiotr Kubaj 	struct ice_seg *ice_seg;
15408923de59SPiotr Kubaj 	struct ice_fv *fv;
15418923de59SPiotr Kubaj 
15428923de59SPiotr Kubaj 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
15438923de59SPiotr Kubaj 	ice_zero_bitmap(bm, ICE_MAX_NUM_PROFILES);
15448923de59SPiotr Kubaj 	ice_seg = hw->seg;
15458923de59SPiotr Kubaj 	do {
15468923de59SPiotr Kubaj 		enum ice_prof_type prof_type;
15478923de59SPiotr Kubaj 		u32 offset;
15488923de59SPiotr Kubaj 
15498923de59SPiotr Kubaj 		fv = (struct ice_fv *)
15508923de59SPiotr Kubaj 			ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
15518923de59SPiotr Kubaj 					   &offset, ice_sw_fv_handler);
15528923de59SPiotr Kubaj 		ice_seg = NULL;
15538923de59SPiotr Kubaj 
15548923de59SPiotr Kubaj 		if (fv) {
15558923de59SPiotr Kubaj 			/* Determine field vector type */
15568923de59SPiotr Kubaj 			prof_type = ice_get_sw_prof_type(hw, fv, offset);
15578923de59SPiotr Kubaj 
15588923de59SPiotr Kubaj 			if (req_profs & prof_type)
15598923de59SPiotr Kubaj 				ice_set_bit((u16)offset, bm);
15608923de59SPiotr Kubaj 		}
15618923de59SPiotr Kubaj 	} while (fv);
15628923de59SPiotr Kubaj }
15638923de59SPiotr Kubaj 
15648923de59SPiotr Kubaj /**
15658923de59SPiotr Kubaj  * ice_get_sw_fv_list
15668923de59SPiotr Kubaj  * @hw: pointer to the HW structure
15678923de59SPiotr Kubaj  * @lkups: lookup elements or match criteria for the advanced recipe, one
15688923de59SPiotr Kubaj  *	   structure per protocol header
15698923de59SPiotr Kubaj  * @bm: bitmap of field vectors to consider
15708923de59SPiotr Kubaj  * @fv_list: Head of a list
15718923de59SPiotr Kubaj  *
15728923de59SPiotr Kubaj  * Finds all the field vector entries from switch block that contain
15738923de59SPiotr Kubaj  * a given protocol ID and offset and returns a list of structures of type
15748923de59SPiotr Kubaj  * "ice_sw_fv_list_entry". Every structure in the list has a field vector
15758923de59SPiotr Kubaj  * definition and profile ID information
15768923de59SPiotr Kubaj  * NOTE: The caller of the function is responsible for freeing the memory
15778923de59SPiotr Kubaj  * allocated for every list entry.
15788923de59SPiotr Kubaj  */
15798923de59SPiotr Kubaj enum ice_status
15808923de59SPiotr Kubaj ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups,
15818923de59SPiotr Kubaj 		   ice_bitmap_t *bm, struct LIST_HEAD_TYPE *fv_list)
15828923de59SPiotr Kubaj {
15838923de59SPiotr Kubaj 	struct ice_sw_fv_list_entry *fvl;
15848923de59SPiotr Kubaj 	struct ice_sw_fv_list_entry *tmp;
15858923de59SPiotr Kubaj 	struct ice_pkg_enum state;
15868923de59SPiotr Kubaj 	struct ice_seg *ice_seg;
15878923de59SPiotr Kubaj 	struct ice_fv *fv;
15888923de59SPiotr Kubaj 	u32 offset;
15898923de59SPiotr Kubaj 
15908923de59SPiotr Kubaj 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
15918923de59SPiotr Kubaj 
15928923de59SPiotr Kubaj 	if (!lkups->n_val_words || !hw->seg)
15938923de59SPiotr Kubaj 		return ICE_ERR_PARAM;
15948923de59SPiotr Kubaj 
15958923de59SPiotr Kubaj 	ice_seg = hw->seg;
15968923de59SPiotr Kubaj 	do {
15978923de59SPiotr Kubaj 		u16 i;
15988923de59SPiotr Kubaj 
15998923de59SPiotr Kubaj 		fv = (struct ice_fv *)
16008923de59SPiotr Kubaj 			ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
16018923de59SPiotr Kubaj 					   &offset, ice_sw_fv_handler);
16028923de59SPiotr Kubaj 		if (!fv)
16038923de59SPiotr Kubaj 			break;
16048923de59SPiotr Kubaj 		ice_seg = NULL;
16058923de59SPiotr Kubaj 
16068923de59SPiotr Kubaj 		/* If field vector is not in the bitmap list, then skip this
16078923de59SPiotr Kubaj 		 * profile.
16088923de59SPiotr Kubaj 		 */
16098923de59SPiotr Kubaj 		if (!ice_is_bit_set(bm, (u16)offset))
16108923de59SPiotr Kubaj 			continue;
16118923de59SPiotr Kubaj 
16128923de59SPiotr Kubaj 		for (i = 0; i < lkups->n_val_words; i++) {
16138923de59SPiotr Kubaj 			int j;
16148923de59SPiotr Kubaj 
16158923de59SPiotr Kubaj 			for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
16168923de59SPiotr Kubaj 				if (fv->ew[j].prot_id ==
16178923de59SPiotr Kubaj 				    lkups->fv_words[i].prot_id &&
16188923de59SPiotr Kubaj 				    fv->ew[j].off == lkups->fv_words[i].off)
16198923de59SPiotr Kubaj 					break;
16208923de59SPiotr Kubaj 			if (j >= hw->blk[ICE_BLK_SW].es.fvw)
16218923de59SPiotr Kubaj 				break;
16228923de59SPiotr Kubaj 			if (i + 1 == lkups->n_val_words) {
16238923de59SPiotr Kubaj 				fvl = (struct ice_sw_fv_list_entry *)
16248923de59SPiotr Kubaj 					ice_malloc(hw, sizeof(*fvl));
16258923de59SPiotr Kubaj 				if (!fvl)
16268923de59SPiotr Kubaj 					goto err;
16278923de59SPiotr Kubaj 				fvl->fv_ptr = fv;
16288923de59SPiotr Kubaj 				fvl->profile_id = offset;
16298923de59SPiotr Kubaj 				LIST_ADD(&fvl->list_entry, fv_list);
16308923de59SPiotr Kubaj 				break;
16318923de59SPiotr Kubaj 			}
16328923de59SPiotr Kubaj 		}
16338923de59SPiotr Kubaj 	} while (fv);
16348923de59SPiotr Kubaj 	if (LIST_EMPTY(fv_list)) {
16358923de59SPiotr Kubaj 		ice_warn(hw, "Required profiles not found in currently loaded DDP package");
16368923de59SPiotr Kubaj 		return ICE_ERR_CFG;
16378923de59SPiotr Kubaj 	}
16388923de59SPiotr Kubaj 	return ICE_SUCCESS;
16398923de59SPiotr Kubaj 
16408923de59SPiotr Kubaj err:
16418923de59SPiotr Kubaj 	LIST_FOR_EACH_ENTRY_SAFE(fvl, tmp, fv_list, ice_sw_fv_list_entry,
16428923de59SPiotr Kubaj 				 list_entry) {
16438923de59SPiotr Kubaj 		LIST_DEL(&fvl->list_entry);
16448923de59SPiotr Kubaj 		ice_free(hw, fvl);
16458923de59SPiotr Kubaj 	}
16468923de59SPiotr Kubaj 
16478923de59SPiotr Kubaj 	return ICE_ERR_NO_MEMORY;
16488923de59SPiotr Kubaj }
16498923de59SPiotr Kubaj 
16508923de59SPiotr Kubaj /**
16518923de59SPiotr Kubaj  * ice_init_prof_result_bm - Initialize the profile result index bitmap
16528923de59SPiotr Kubaj  * @hw: pointer to hardware structure
16538923de59SPiotr Kubaj  */
16548923de59SPiotr Kubaj void ice_init_prof_result_bm(struct ice_hw *hw)
16558923de59SPiotr Kubaj {
16568923de59SPiotr Kubaj 	struct ice_pkg_enum state;
16578923de59SPiotr Kubaj 	struct ice_seg *ice_seg;
16588923de59SPiotr Kubaj 	struct ice_fv *fv;
16598923de59SPiotr Kubaj 
16608923de59SPiotr Kubaj 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
16618923de59SPiotr Kubaj 
16628923de59SPiotr Kubaj 	if (!hw->seg)
16638923de59SPiotr Kubaj 		return;
16648923de59SPiotr Kubaj 
16658923de59SPiotr Kubaj 	ice_seg = hw->seg;
16668923de59SPiotr Kubaj 	do {
16678923de59SPiotr Kubaj 		u32 off;
16688923de59SPiotr Kubaj 		u16 i;
16698923de59SPiotr Kubaj 
16708923de59SPiotr Kubaj 		fv = (struct ice_fv *)
16718923de59SPiotr Kubaj 			ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
16728923de59SPiotr Kubaj 					   &off, ice_sw_fv_handler);
16738923de59SPiotr Kubaj 		ice_seg = NULL;
16748923de59SPiotr Kubaj 		if (!fv)
16758923de59SPiotr Kubaj 			break;
16768923de59SPiotr Kubaj 
16778923de59SPiotr Kubaj 		ice_zero_bitmap(hw->switch_info->prof_res_bm[off],
16788923de59SPiotr Kubaj 				ICE_MAX_FV_WORDS);
16798923de59SPiotr Kubaj 
16808923de59SPiotr Kubaj 		/* Determine empty field vector indices, these can be
16818923de59SPiotr Kubaj 		 * used for recipe results. Skip index 0, since it is
16828923de59SPiotr Kubaj 		 * always used for Switch ID.
16838923de59SPiotr Kubaj 		 */
16848923de59SPiotr Kubaj 		for (i = 1; i < ICE_MAX_FV_WORDS; i++)
16858923de59SPiotr Kubaj 			if (fv->ew[i].prot_id == ICE_PROT_INVALID &&
16868923de59SPiotr Kubaj 			    fv->ew[i].off == ICE_FV_OFFSET_INVAL)
16878923de59SPiotr Kubaj 				ice_set_bit(i,
16888923de59SPiotr Kubaj 					    hw->switch_info->prof_res_bm[off]);
16898923de59SPiotr Kubaj 	} while (fv);
16908923de59SPiotr Kubaj }
16918923de59SPiotr Kubaj 
16928923de59SPiotr Kubaj /**
16938923de59SPiotr Kubaj  * ice_pkg_buf_free
16948923de59SPiotr Kubaj  * @hw: pointer to the HW structure
16958923de59SPiotr Kubaj  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
16968923de59SPiotr Kubaj  *
16978923de59SPiotr Kubaj  * Frees a package buffer
16988923de59SPiotr Kubaj  */
16998923de59SPiotr Kubaj void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld)
17008923de59SPiotr Kubaj {
17018923de59SPiotr Kubaj 	ice_free(hw, bld);
17028923de59SPiotr Kubaj }
17038923de59SPiotr Kubaj 
17048923de59SPiotr Kubaj /**
17058923de59SPiotr Kubaj  * ice_pkg_buf_reserve_section
17068923de59SPiotr Kubaj  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
17078923de59SPiotr Kubaj  * @count: the number of sections to reserve
17088923de59SPiotr Kubaj  *
17098923de59SPiotr Kubaj  * Reserves one or more section table entries in a package buffer. This routine
17108923de59SPiotr Kubaj  * can be called multiple times as long as they are made before calling
17118923de59SPiotr Kubaj  * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section()
17128923de59SPiotr Kubaj  * is called once, the number of sections that can be allocated will not be able
17138923de59SPiotr Kubaj  * to be increased; not using all reserved sections is fine, but this will
17148923de59SPiotr Kubaj  * result in some wasted space in the buffer.
17158923de59SPiotr Kubaj  * Note: all package contents must be in Little Endian form.
17168923de59SPiotr Kubaj  */
17178923de59SPiotr Kubaj enum ice_status
17188923de59SPiotr Kubaj ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count)
17198923de59SPiotr Kubaj {
17208923de59SPiotr Kubaj 	struct ice_buf_hdr *buf;
17218923de59SPiotr Kubaj 	u16 section_count;
17228923de59SPiotr Kubaj 	u16 data_end;
17238923de59SPiotr Kubaj 
17248923de59SPiotr Kubaj 	if (!bld)
17258923de59SPiotr Kubaj 		return ICE_ERR_PARAM;
17268923de59SPiotr Kubaj 
17278923de59SPiotr Kubaj 	buf = (struct ice_buf_hdr *)&bld->buf;
17288923de59SPiotr Kubaj 
17298923de59SPiotr Kubaj 	/* already an active section, can't increase table size */
17308923de59SPiotr Kubaj 	section_count = LE16_TO_CPU(buf->section_count);
17318923de59SPiotr Kubaj 	if (section_count > 0)
17328923de59SPiotr Kubaj 		return ICE_ERR_CFG;
17338923de59SPiotr Kubaj 
17348923de59SPiotr Kubaj 	if (bld->reserved_section_table_entries + count > ICE_MAX_S_COUNT)
17358923de59SPiotr Kubaj 		return ICE_ERR_CFG;
17368923de59SPiotr Kubaj 	bld->reserved_section_table_entries += count;
17378923de59SPiotr Kubaj 
17388923de59SPiotr Kubaj 	data_end = LE16_TO_CPU(buf->data_end) +
17398923de59SPiotr Kubaj 		FLEX_ARRAY_SIZE(buf, section_entry, count);
17408923de59SPiotr Kubaj 	buf->data_end = CPU_TO_LE16(data_end);
17418923de59SPiotr Kubaj 
17428923de59SPiotr Kubaj 	return ICE_SUCCESS;
17438923de59SPiotr Kubaj }
17448923de59SPiotr Kubaj 
17458923de59SPiotr Kubaj /**
17468923de59SPiotr Kubaj  * ice_pkg_buf_alloc_section
17478923de59SPiotr Kubaj  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
17488923de59SPiotr Kubaj  * @type: the section type value
17498923de59SPiotr Kubaj  * @size: the size of the section to reserve (in bytes)
17508923de59SPiotr Kubaj  *
17518923de59SPiotr Kubaj  * Reserves memory in the buffer for a section's content and updates the
17528923de59SPiotr Kubaj  * buffers' status accordingly. This routine returns a pointer to the first
17538923de59SPiotr Kubaj  * byte of the section start within the buffer, which is used to fill in the
17548923de59SPiotr Kubaj  * section contents.
17558923de59SPiotr Kubaj  * Note: all package contents must be in Little Endian form.
17568923de59SPiotr Kubaj  */
17578923de59SPiotr Kubaj void *
17588923de59SPiotr Kubaj ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size)
17598923de59SPiotr Kubaj {
17608923de59SPiotr Kubaj 	struct ice_buf_hdr *buf;
17618923de59SPiotr Kubaj 	u16 sect_count;
17628923de59SPiotr Kubaj 	u16 data_end;
17638923de59SPiotr Kubaj 
17648923de59SPiotr Kubaj 	if (!bld || !type || !size)
17658923de59SPiotr Kubaj 		return NULL;
17668923de59SPiotr Kubaj 
17678923de59SPiotr Kubaj 	buf = (struct ice_buf_hdr *)&bld->buf;
17688923de59SPiotr Kubaj 
17698923de59SPiotr Kubaj 	/* check for enough space left in buffer */
17708923de59SPiotr Kubaj 	data_end = LE16_TO_CPU(buf->data_end);
17718923de59SPiotr Kubaj 
17728923de59SPiotr Kubaj 	/* section start must align on 4 byte boundary */
17738923de59SPiotr Kubaj 	data_end = ICE_ALIGN(data_end, 4);
17748923de59SPiotr Kubaj 
17758923de59SPiotr Kubaj 	if ((data_end + size) > ICE_MAX_S_DATA_END)
17768923de59SPiotr Kubaj 		return NULL;
17778923de59SPiotr Kubaj 
17788923de59SPiotr Kubaj 	/* check for more available section table entries */
17798923de59SPiotr Kubaj 	sect_count = LE16_TO_CPU(buf->section_count);
17808923de59SPiotr Kubaj 	if (sect_count < bld->reserved_section_table_entries) {
17818923de59SPiotr Kubaj 		void *section_ptr = ((u8 *)buf) + data_end;
17828923de59SPiotr Kubaj 
17838923de59SPiotr Kubaj 		buf->section_entry[sect_count].offset = CPU_TO_LE16(data_end);
17848923de59SPiotr Kubaj 		buf->section_entry[sect_count].size = CPU_TO_LE16(size);
17858923de59SPiotr Kubaj 		buf->section_entry[sect_count].type = CPU_TO_LE32(type);
17868923de59SPiotr Kubaj 
17878923de59SPiotr Kubaj 		data_end += size;
17888923de59SPiotr Kubaj 		buf->data_end = CPU_TO_LE16(data_end);
17898923de59SPiotr Kubaj 
17908923de59SPiotr Kubaj 		buf->section_count = CPU_TO_LE16(sect_count + 1);
17918923de59SPiotr Kubaj 		return section_ptr;
17928923de59SPiotr Kubaj 	}
17938923de59SPiotr Kubaj 
17948923de59SPiotr Kubaj 	/* no free section table entries */
17958923de59SPiotr Kubaj 	return NULL;
17968923de59SPiotr Kubaj }
17978923de59SPiotr Kubaj 
17988923de59SPiotr Kubaj /**
17998923de59SPiotr Kubaj  * ice_pkg_buf_alloc_single_section
18008923de59SPiotr Kubaj  * @hw: pointer to the HW structure
18018923de59SPiotr Kubaj  * @type: the section type value
18028923de59SPiotr Kubaj  * @size: the size of the section to reserve (in bytes)
18038923de59SPiotr Kubaj  * @section: returns pointer to the section
18048923de59SPiotr Kubaj  *
18058923de59SPiotr Kubaj  * Allocates a package buffer with a single section.
18068923de59SPiotr Kubaj  * Note: all package contents must be in Little Endian form.
18078923de59SPiotr Kubaj  */
18088923de59SPiotr Kubaj struct ice_buf_build *
18098923de59SPiotr Kubaj ice_pkg_buf_alloc_single_section(struct ice_hw *hw, u32 type, u16 size,
18108923de59SPiotr Kubaj 				 void **section)
18118923de59SPiotr Kubaj {
18128923de59SPiotr Kubaj 	struct ice_buf_build *buf;
18138923de59SPiotr Kubaj 
18148923de59SPiotr Kubaj 	if (!section)
18158923de59SPiotr Kubaj 		return NULL;
18168923de59SPiotr Kubaj 
18178923de59SPiotr Kubaj 	buf = ice_pkg_buf_alloc(hw);
18188923de59SPiotr Kubaj 	if (!buf)
18198923de59SPiotr Kubaj 		return NULL;
18208923de59SPiotr Kubaj 
18218923de59SPiotr Kubaj 	if (ice_pkg_buf_reserve_section(buf, 1))
18228923de59SPiotr Kubaj 		goto ice_pkg_buf_alloc_single_section_err;
18238923de59SPiotr Kubaj 
18248923de59SPiotr Kubaj 	*section = ice_pkg_buf_alloc_section(buf, type, size);
18258923de59SPiotr Kubaj 	if (!*section)
18268923de59SPiotr Kubaj 		goto ice_pkg_buf_alloc_single_section_err;
18278923de59SPiotr Kubaj 
18288923de59SPiotr Kubaj 	return buf;
18298923de59SPiotr Kubaj 
18308923de59SPiotr Kubaj ice_pkg_buf_alloc_single_section_err:
18318923de59SPiotr Kubaj 	ice_pkg_buf_free(hw, buf);
18328923de59SPiotr Kubaj 	return NULL;
18338923de59SPiotr Kubaj }
18348923de59SPiotr Kubaj 
18358923de59SPiotr Kubaj /**
18368923de59SPiotr Kubaj  * ice_pkg_buf_unreserve_section
18378923de59SPiotr Kubaj  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
18388923de59SPiotr Kubaj  * @count: the number of sections to unreserve
18398923de59SPiotr Kubaj  *
18408923de59SPiotr Kubaj  * Unreserves one or more section table entries in a package buffer, releasing
18418923de59SPiotr Kubaj  * space that can be used for section data. This routine can be called
18428923de59SPiotr Kubaj  * multiple times as long as they are made before calling
18438923de59SPiotr Kubaj  * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section()
18448923de59SPiotr Kubaj  * is called once, the number of sections that can be allocated will not be able
18458923de59SPiotr Kubaj  * to be increased; not using all reserved sections is fine, but this will
18468923de59SPiotr Kubaj  * result in some wasted space in the buffer.
18478923de59SPiotr Kubaj  * Note: all package contents must be in Little Endian form.
18488923de59SPiotr Kubaj  */
18498923de59SPiotr Kubaj enum ice_status
18508923de59SPiotr Kubaj ice_pkg_buf_unreserve_section(struct ice_buf_build *bld, u16 count)
18518923de59SPiotr Kubaj {
18528923de59SPiotr Kubaj 	struct ice_buf_hdr *buf;
18538923de59SPiotr Kubaj 	u16 section_count;
18548923de59SPiotr Kubaj 	u16 data_end;
18558923de59SPiotr Kubaj 
18568923de59SPiotr Kubaj 	if (!bld)
18578923de59SPiotr Kubaj 		return ICE_ERR_PARAM;
18588923de59SPiotr Kubaj 
18598923de59SPiotr Kubaj 	buf = (struct ice_buf_hdr *)&bld->buf;
18608923de59SPiotr Kubaj 
18618923de59SPiotr Kubaj 	/* already an active section, can't decrease table size */
18628923de59SPiotr Kubaj 	section_count = LE16_TO_CPU(buf->section_count);
18638923de59SPiotr Kubaj 	if (section_count > 0)
18648923de59SPiotr Kubaj 		return ICE_ERR_CFG;
18658923de59SPiotr Kubaj 
18668923de59SPiotr Kubaj 	if (count > bld->reserved_section_table_entries)
18678923de59SPiotr Kubaj 		return ICE_ERR_CFG;
18688923de59SPiotr Kubaj 	bld->reserved_section_table_entries -= count;
18698923de59SPiotr Kubaj 
18708923de59SPiotr Kubaj 	data_end = LE16_TO_CPU(buf->data_end) -
18718923de59SPiotr Kubaj 		FLEX_ARRAY_SIZE(buf, section_entry, count);
18728923de59SPiotr Kubaj 	buf->data_end = CPU_TO_LE16(data_end);
18738923de59SPiotr Kubaj 
18748923de59SPiotr Kubaj 	return ICE_SUCCESS;
18758923de59SPiotr Kubaj }
18768923de59SPiotr Kubaj 
18778923de59SPiotr Kubaj /**
18788923de59SPiotr Kubaj  * ice_pkg_buf_get_free_space
18798923de59SPiotr Kubaj  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
18808923de59SPiotr Kubaj  *
18818923de59SPiotr Kubaj  * Returns the number of free bytes remaining in the buffer.
18828923de59SPiotr Kubaj  * Note: all package contents must be in Little Endian form.
18838923de59SPiotr Kubaj  */
18848923de59SPiotr Kubaj u16 ice_pkg_buf_get_free_space(struct ice_buf_build *bld)
18858923de59SPiotr Kubaj {
18868923de59SPiotr Kubaj 	struct ice_buf_hdr *buf;
18878923de59SPiotr Kubaj 
18888923de59SPiotr Kubaj 	if (!bld)
18898923de59SPiotr Kubaj 		return 0;
18908923de59SPiotr Kubaj 
18918923de59SPiotr Kubaj 	buf = (struct ice_buf_hdr *)&bld->buf;
18928923de59SPiotr Kubaj 	return ICE_MAX_S_DATA_END - LE16_TO_CPU(buf->data_end);
18938923de59SPiotr Kubaj }
18948923de59SPiotr Kubaj 
18958923de59SPiotr Kubaj /**
18968923de59SPiotr Kubaj  * ice_pkg_buf_get_active_sections
18978923de59SPiotr Kubaj  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
18988923de59SPiotr Kubaj  *
18998923de59SPiotr Kubaj  * Returns the number of active sections. Before using the package buffer
19008923de59SPiotr Kubaj  * in an update package command, the caller should make sure that there is at
19018923de59SPiotr Kubaj  * least one active section - otherwise, the buffer is not legal and should
19028923de59SPiotr Kubaj  * not be used.
19038923de59SPiotr Kubaj  * Note: all package contents must be in Little Endian form.
19048923de59SPiotr Kubaj  */
19058923de59SPiotr Kubaj u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld)
19068923de59SPiotr Kubaj {
19078923de59SPiotr Kubaj 	struct ice_buf_hdr *buf;
19088923de59SPiotr Kubaj 
19098923de59SPiotr Kubaj 	if (!bld)
19108923de59SPiotr Kubaj 		return 0;
19118923de59SPiotr Kubaj 
19128923de59SPiotr Kubaj 	buf = (struct ice_buf_hdr *)&bld->buf;
19138923de59SPiotr Kubaj 	return LE16_TO_CPU(buf->section_count);
19148923de59SPiotr Kubaj }
19158923de59SPiotr Kubaj 
19168923de59SPiotr Kubaj /**
19178923de59SPiotr Kubaj  * ice_pkg_buf
19188923de59SPiotr Kubaj  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
19198923de59SPiotr Kubaj  *
19208923de59SPiotr Kubaj  * Return a pointer to the buffer's header
19218923de59SPiotr Kubaj  */
19228923de59SPiotr Kubaj struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
19238923de59SPiotr Kubaj {
19248923de59SPiotr Kubaj 	if (bld)
19258923de59SPiotr Kubaj 		return &bld->buf;
19268923de59SPiotr Kubaj 
19278923de59SPiotr Kubaj 	return NULL;
19288923de59SPiotr Kubaj }
19298923de59SPiotr Kubaj 
19308923de59SPiotr Kubaj /**
19318923de59SPiotr Kubaj  * ice_find_buf_table
19328923de59SPiotr Kubaj  * @ice_seg: pointer to the ice segment
19338923de59SPiotr Kubaj  *
19348923de59SPiotr Kubaj  * Returns the address of the buffer table within the ice segment.
19358923de59SPiotr Kubaj  */
19368923de59SPiotr Kubaj struct ice_buf_table *ice_find_buf_table(struct ice_seg *ice_seg)
19378923de59SPiotr Kubaj {
19388923de59SPiotr Kubaj 	struct ice_nvm_table *nvms;
19398923de59SPiotr Kubaj 
19408923de59SPiotr Kubaj 	nvms = (struct ice_nvm_table *)
19418923de59SPiotr Kubaj 		(ice_seg->device_table +
19428923de59SPiotr Kubaj 		 LE32_TO_CPU(ice_seg->device_table_count));
19438923de59SPiotr Kubaj 
19448923de59SPiotr Kubaj 	return (_FORCE_ struct ice_buf_table *)
19458923de59SPiotr Kubaj 		(nvms->vers + LE32_TO_CPU(nvms->table_count));
19468923de59SPiotr Kubaj }
19478923de59SPiotr Kubaj 
19488923de59SPiotr Kubaj /**
19498923de59SPiotr Kubaj  * ice_pkg_val_buf
19508923de59SPiotr Kubaj  * @buf: pointer to the ice buffer
19518923de59SPiotr Kubaj  *
19528923de59SPiotr Kubaj  * This helper function validates a buffer's header.
19538923de59SPiotr Kubaj  */
19548923de59SPiotr Kubaj static struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf)
19558923de59SPiotr Kubaj {
19568923de59SPiotr Kubaj 	struct ice_buf_hdr *hdr;
19578923de59SPiotr Kubaj 	u16 section_count;
19588923de59SPiotr Kubaj 	u16 data_end;
19598923de59SPiotr Kubaj 
19608923de59SPiotr Kubaj 	hdr = (struct ice_buf_hdr *)buf->buf;
19618923de59SPiotr Kubaj 	/* verify data */
19628923de59SPiotr Kubaj 	section_count = LE16_TO_CPU(hdr->section_count);
19638923de59SPiotr Kubaj 	if (section_count < ICE_MIN_S_COUNT || section_count > ICE_MAX_S_COUNT)
19648923de59SPiotr Kubaj 		return NULL;
19658923de59SPiotr Kubaj 
19668923de59SPiotr Kubaj 	data_end = LE16_TO_CPU(hdr->data_end);
19678923de59SPiotr Kubaj 	if (data_end < ICE_MIN_S_DATA_END || data_end > ICE_MAX_S_DATA_END)
19688923de59SPiotr Kubaj 		return NULL;
19698923de59SPiotr Kubaj 
19708923de59SPiotr Kubaj 	return hdr;
19718923de59SPiotr Kubaj }
19728923de59SPiotr Kubaj 
19738923de59SPiotr Kubaj /**
19748923de59SPiotr Kubaj  * ice_pkg_enum_buf
19758923de59SPiotr Kubaj  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
19768923de59SPiotr Kubaj  * @state: pointer to the enum state
19778923de59SPiotr Kubaj  *
19788923de59SPiotr Kubaj  * This function will enumerate all the buffers in the ice segment. The first
19798923de59SPiotr Kubaj  * call is made with the ice_seg parameter non-NULL; on subsequent calls,
19808923de59SPiotr Kubaj  * ice_seg is set to NULL which continues the enumeration. When the function
19818923de59SPiotr Kubaj  * returns a NULL pointer, then the end of the buffers has been reached, or an
19828923de59SPiotr Kubaj  * unexpected value has been detected (for example an invalid section count or
19838923de59SPiotr Kubaj  * an invalid buffer end value).
19848923de59SPiotr Kubaj  */
19858923de59SPiotr Kubaj struct ice_buf_hdr *
19868923de59SPiotr Kubaj ice_pkg_enum_buf(struct ice_seg *ice_seg, struct ice_pkg_enum *state)
19878923de59SPiotr Kubaj {
19888923de59SPiotr Kubaj 	if (ice_seg) {
19898923de59SPiotr Kubaj 		state->buf_table = ice_find_buf_table(ice_seg);
19908923de59SPiotr Kubaj 		if (!state->buf_table)
19918923de59SPiotr Kubaj 			return NULL;
19928923de59SPiotr Kubaj 
19938923de59SPiotr Kubaj 		state->buf_idx = 0;
19948923de59SPiotr Kubaj 		return ice_pkg_val_buf(state->buf_table->buf_array);
19958923de59SPiotr Kubaj 	}
19968923de59SPiotr Kubaj 
19978923de59SPiotr Kubaj 	if (++state->buf_idx < LE32_TO_CPU(state->buf_table->buf_count))
19988923de59SPiotr Kubaj 		return ice_pkg_val_buf(state->buf_table->buf_array +
19998923de59SPiotr Kubaj 				       state->buf_idx);
20008923de59SPiotr Kubaj 	else
20018923de59SPiotr Kubaj 		return NULL;
20028923de59SPiotr Kubaj }
20038923de59SPiotr Kubaj 
20048923de59SPiotr Kubaj /**
20058923de59SPiotr Kubaj  * ice_pkg_advance_sect
20068923de59SPiotr Kubaj  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
20078923de59SPiotr Kubaj  * @state: pointer to the enum state
20088923de59SPiotr Kubaj  *
20098923de59SPiotr Kubaj  * This helper function will advance the section within the ice segment,
20108923de59SPiotr Kubaj  * also advancing the buffer if needed.
20118923de59SPiotr Kubaj  */
20128923de59SPiotr Kubaj bool
20138923de59SPiotr Kubaj ice_pkg_advance_sect(struct ice_seg *ice_seg, struct ice_pkg_enum *state)
20148923de59SPiotr Kubaj {
20158923de59SPiotr Kubaj 	if (!ice_seg && !state->buf)
20168923de59SPiotr Kubaj 		return false;
20178923de59SPiotr Kubaj 
20188923de59SPiotr Kubaj 	if (!ice_seg && state->buf)
20198923de59SPiotr Kubaj 		if (++state->sect_idx < LE16_TO_CPU(state->buf->section_count))
20208923de59SPiotr Kubaj 			return true;
20218923de59SPiotr Kubaj 
20228923de59SPiotr Kubaj 	state->buf = ice_pkg_enum_buf(ice_seg, state);
20238923de59SPiotr Kubaj 	if (!state->buf)
20248923de59SPiotr Kubaj 		return false;
20258923de59SPiotr Kubaj 
20268923de59SPiotr Kubaj 	/* start of new buffer, reset section index */
20278923de59SPiotr Kubaj 	state->sect_idx = 0;
20288923de59SPiotr Kubaj 	return true;
20298923de59SPiotr Kubaj }
20308923de59SPiotr Kubaj 
20318923de59SPiotr Kubaj /**
20328923de59SPiotr Kubaj  * ice_pkg_enum_section
20338923de59SPiotr Kubaj  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
20348923de59SPiotr Kubaj  * @state: pointer to the enum state
20358923de59SPiotr Kubaj  * @sect_type: section type to enumerate
20368923de59SPiotr Kubaj  *
20378923de59SPiotr Kubaj  * This function will enumerate all the sections of a particular type in the
20388923de59SPiotr Kubaj  * ice segment. The first call is made with the ice_seg parameter non-NULL;
20398923de59SPiotr Kubaj  * on subsequent calls, ice_seg is set to NULL which continues the enumeration.
20408923de59SPiotr Kubaj  * When the function returns a NULL pointer, then the end of the matching
20418923de59SPiotr Kubaj  * sections has been reached.
20428923de59SPiotr Kubaj  */
20438923de59SPiotr Kubaj void *
20448923de59SPiotr Kubaj ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
20458923de59SPiotr Kubaj 		     u32 sect_type)
20468923de59SPiotr Kubaj {
20478923de59SPiotr Kubaj 	u16 offset, size;
20488923de59SPiotr Kubaj 
20498923de59SPiotr Kubaj 	if (ice_seg)
20508923de59SPiotr Kubaj 		state->type = sect_type;
20518923de59SPiotr Kubaj 
20528923de59SPiotr Kubaj 	if (!ice_pkg_advance_sect(ice_seg, state))
20538923de59SPiotr Kubaj 		return NULL;
20548923de59SPiotr Kubaj 
20558923de59SPiotr Kubaj 	/* scan for next matching section */
20568923de59SPiotr Kubaj 	while (state->buf->section_entry[state->sect_idx].type !=
20578923de59SPiotr Kubaj 	       CPU_TO_LE32(state->type))
20588923de59SPiotr Kubaj 		if (!ice_pkg_advance_sect(NULL, state))
20598923de59SPiotr Kubaj 			return NULL;
20608923de59SPiotr Kubaj 
20618923de59SPiotr Kubaj 	/* validate section */
20628923de59SPiotr Kubaj 	offset = LE16_TO_CPU(state->buf->section_entry[state->sect_idx].offset);
20638923de59SPiotr Kubaj 	if (offset < ICE_MIN_S_OFF || offset > ICE_MAX_S_OFF)
20648923de59SPiotr Kubaj 		return NULL;
20658923de59SPiotr Kubaj 
20668923de59SPiotr Kubaj 	size = LE16_TO_CPU(state->buf->section_entry[state->sect_idx].size);
20678923de59SPiotr Kubaj 	if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ)
20688923de59SPiotr Kubaj 		return NULL;
20698923de59SPiotr Kubaj 
20708923de59SPiotr Kubaj 	/* make sure the section fits in the buffer */
20718923de59SPiotr Kubaj 	if (offset + size > ICE_PKG_BUF_SIZE)
20728923de59SPiotr Kubaj 		return NULL;
20738923de59SPiotr Kubaj 
20748923de59SPiotr Kubaj 	state->sect_type =
20758923de59SPiotr Kubaj 		LE32_TO_CPU(state->buf->section_entry[state->sect_idx].type);
20768923de59SPiotr Kubaj 
20778923de59SPiotr Kubaj 	/* calc pointer to this section */
20788923de59SPiotr Kubaj 	state->sect = ((u8 *)state->buf) +
20798923de59SPiotr Kubaj 		LE16_TO_CPU(state->buf->section_entry[state->sect_idx].offset);
20808923de59SPiotr Kubaj 
20818923de59SPiotr Kubaj 	return state->sect;
20828923de59SPiotr Kubaj }
20838923de59SPiotr Kubaj 
20848923de59SPiotr Kubaj /**
20858923de59SPiotr Kubaj  * ice_pkg_enum_entry
20868923de59SPiotr Kubaj  * @ice_seg: pointer to the ice segment (or NULL on subsequent calls)
20878923de59SPiotr Kubaj  * @state: pointer to the enum state
20888923de59SPiotr Kubaj  * @sect_type: section type to enumerate
20898923de59SPiotr Kubaj  * @offset: pointer to variable that receives the offset in the table (optional)
20908923de59SPiotr Kubaj  * @handler: function that handles access to the entries into the section type
20918923de59SPiotr Kubaj  *
20928923de59SPiotr Kubaj  * This function will enumerate all the entries in particular section type in
20938923de59SPiotr Kubaj  * the ice segment. The first call is made with the ice_seg parameter non-NULL;
20948923de59SPiotr Kubaj  * on subsequent calls, ice_seg is set to NULL which continues the enumeration.
20958923de59SPiotr Kubaj  * When the function returns a NULL pointer, then the end of the entries has
20968923de59SPiotr Kubaj  * been reached.
20978923de59SPiotr Kubaj  *
20988923de59SPiotr Kubaj  * Since each section may have a different header and entry size, the handler
20998923de59SPiotr Kubaj  * function is needed to determine the number and location entries in each
21008923de59SPiotr Kubaj  * section.
21018923de59SPiotr Kubaj  *
21028923de59SPiotr Kubaj  * The offset parameter is optional, but should be used for sections that
21038923de59SPiotr Kubaj  * contain an offset for each section table. For such cases, the section handler
21048923de59SPiotr Kubaj  * function must return the appropriate offset + index to give the absolution
21058923de59SPiotr Kubaj  * offset for each entry. For example, if the base for a section's header
21068923de59SPiotr Kubaj  * indicates a base offset of 10, and the index for the entry is 2, then
21078923de59SPiotr Kubaj  * section handler function should set the offset to 10 + 2 = 12.
21088923de59SPiotr Kubaj  */
21098923de59SPiotr Kubaj void *
21108923de59SPiotr Kubaj ice_pkg_enum_entry(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
21118923de59SPiotr Kubaj 		   u32 sect_type, u32 *offset,
21128923de59SPiotr Kubaj 		   void *(*handler)(u32 sect_type, void *section,
21138923de59SPiotr Kubaj 				    u32 index, u32 *offset))
21148923de59SPiotr Kubaj {
21158923de59SPiotr Kubaj 	void *entry;
21168923de59SPiotr Kubaj 
21178923de59SPiotr Kubaj 	if (ice_seg) {
21188923de59SPiotr Kubaj 		if (!handler)
21198923de59SPiotr Kubaj 			return NULL;
21208923de59SPiotr Kubaj 
21218923de59SPiotr Kubaj 		if (!ice_pkg_enum_section(ice_seg, state, sect_type))
21228923de59SPiotr Kubaj 			return NULL;
21238923de59SPiotr Kubaj 
21248923de59SPiotr Kubaj 		state->entry_idx = 0;
21258923de59SPiotr Kubaj 		state->handler = handler;
21268923de59SPiotr Kubaj 	} else {
21278923de59SPiotr Kubaj 		state->entry_idx++;
21288923de59SPiotr Kubaj 	}
21298923de59SPiotr Kubaj 
21308923de59SPiotr Kubaj 	if (!state->handler)
21318923de59SPiotr Kubaj 		return NULL;
21328923de59SPiotr Kubaj 
21338923de59SPiotr Kubaj 	/* get entry */
21348923de59SPiotr Kubaj 	entry = state->handler(state->sect_type, state->sect, state->entry_idx,
21358923de59SPiotr Kubaj 			       offset);
21368923de59SPiotr Kubaj 	if (!entry) {
21378923de59SPiotr Kubaj 		/* end of a section, look for another section of this type */
21388923de59SPiotr Kubaj 		if (!ice_pkg_enum_section(NULL, state, 0))
21398923de59SPiotr Kubaj 			return NULL;
21408923de59SPiotr Kubaj 
21418923de59SPiotr Kubaj 		state->entry_idx = 0;
21428923de59SPiotr Kubaj 		entry = state->handler(state->sect_type, state->sect,
21438923de59SPiotr Kubaj 				       state->entry_idx, offset);
21448923de59SPiotr Kubaj 	}
21458923de59SPiotr Kubaj 
21468923de59SPiotr Kubaj 	return entry;
21478923de59SPiotr Kubaj }
21488923de59SPiotr Kubaj 
21498923de59SPiotr Kubaj /**
21508923de59SPiotr Kubaj  * ice_boost_tcam_handler
21518923de59SPiotr Kubaj  * @sect_type: section type
21528923de59SPiotr Kubaj  * @section: pointer to section
21538923de59SPiotr Kubaj  * @index: index of the boost TCAM entry to be returned
21548923de59SPiotr Kubaj  * @offset: pointer to receive absolute offset, always 0 for boost TCAM sections
21558923de59SPiotr Kubaj  *
21568923de59SPiotr Kubaj  * This is a callback function that can be passed to ice_pkg_enum_entry.
21578923de59SPiotr Kubaj  * Handles enumeration of individual boost TCAM entries.
21588923de59SPiotr Kubaj  */
21598923de59SPiotr Kubaj static void *
21608923de59SPiotr Kubaj ice_boost_tcam_handler(u32 sect_type, void *section, u32 index, u32 *offset)
21618923de59SPiotr Kubaj {
21628923de59SPiotr Kubaj 	struct ice_boost_tcam_section *boost;
21638923de59SPiotr Kubaj 
21648923de59SPiotr Kubaj 	if (!section)
21658923de59SPiotr Kubaj 		return NULL;
21668923de59SPiotr Kubaj 
21678923de59SPiotr Kubaj 	if (sect_type != ICE_SID_RXPARSER_BOOST_TCAM)
21688923de59SPiotr Kubaj 		return NULL;
21698923de59SPiotr Kubaj 
21708923de59SPiotr Kubaj 	if (index > ICE_MAX_BST_TCAMS_IN_BUF)
21718923de59SPiotr Kubaj 		return NULL;
21728923de59SPiotr Kubaj 
21738923de59SPiotr Kubaj 	if (offset)
21748923de59SPiotr Kubaj 		*offset = 0;
21758923de59SPiotr Kubaj 
21768923de59SPiotr Kubaj 	boost = (struct ice_boost_tcam_section *)section;
21778923de59SPiotr Kubaj 	if (index >= LE16_TO_CPU(boost->count))
21788923de59SPiotr Kubaj 		return NULL;
21798923de59SPiotr Kubaj 
21808923de59SPiotr Kubaj 	return boost->tcam + index;
21818923de59SPiotr Kubaj }
21828923de59SPiotr Kubaj 
21838923de59SPiotr Kubaj /**
21848923de59SPiotr Kubaj  * ice_find_boost_entry
21858923de59SPiotr Kubaj  * @ice_seg: pointer to the ice segment (non-NULL)
21868923de59SPiotr Kubaj  * @addr: Boost TCAM address of entry to search for
21878923de59SPiotr Kubaj  * @entry: returns pointer to the entry
21888923de59SPiotr Kubaj  *
21898923de59SPiotr Kubaj  * Finds a particular Boost TCAM entry and returns a pointer to that entry
21908923de59SPiotr Kubaj  * if it is found. The ice_seg parameter must not be NULL since the first call
21918923de59SPiotr Kubaj  * to ice_pkg_enum_entry requires a pointer to an actual ice_segment structure.
21928923de59SPiotr Kubaj  */
21938923de59SPiotr Kubaj static enum ice_status
21948923de59SPiotr Kubaj ice_find_boost_entry(struct ice_seg *ice_seg, u16 addr,
21958923de59SPiotr Kubaj 		     struct ice_boost_tcam_entry **entry)
21968923de59SPiotr Kubaj {
21978923de59SPiotr Kubaj 	struct ice_boost_tcam_entry *tcam;
21988923de59SPiotr Kubaj 	struct ice_pkg_enum state;
21998923de59SPiotr Kubaj 
22008923de59SPiotr Kubaj 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
22018923de59SPiotr Kubaj 
22028923de59SPiotr Kubaj 	if (!ice_seg)
22038923de59SPiotr Kubaj 		return ICE_ERR_PARAM;
22048923de59SPiotr Kubaj 
22058923de59SPiotr Kubaj 	do {
22068923de59SPiotr Kubaj 		tcam = (struct ice_boost_tcam_entry *)
22078923de59SPiotr Kubaj 		       ice_pkg_enum_entry(ice_seg, &state,
22088923de59SPiotr Kubaj 					  ICE_SID_RXPARSER_BOOST_TCAM, NULL,
22098923de59SPiotr Kubaj 					  ice_boost_tcam_handler);
22108923de59SPiotr Kubaj 		if (tcam && LE16_TO_CPU(tcam->addr) == addr) {
22118923de59SPiotr Kubaj 			*entry = tcam;
22128923de59SPiotr Kubaj 			return ICE_SUCCESS;
22138923de59SPiotr Kubaj 		}
22148923de59SPiotr Kubaj 
22158923de59SPiotr Kubaj 		ice_seg = NULL;
22168923de59SPiotr Kubaj 	} while (tcam);
22178923de59SPiotr Kubaj 
22188923de59SPiotr Kubaj 	*entry = NULL;
22198923de59SPiotr Kubaj 	return ICE_ERR_CFG;
22208923de59SPiotr Kubaj }
22218923de59SPiotr Kubaj 
22228923de59SPiotr Kubaj /**
22238923de59SPiotr Kubaj  * ice_init_pkg_hints
22248923de59SPiotr Kubaj  * @hw: pointer to the HW structure
22258923de59SPiotr Kubaj  * @ice_seg: pointer to the segment of the package scan (non-NULL)
22268923de59SPiotr Kubaj  *
22278923de59SPiotr Kubaj  * This function will scan the package and save off relevant information
22288923de59SPiotr Kubaj  * (hints or metadata) for driver use. The ice_seg parameter must not be NULL
22298923de59SPiotr Kubaj  * since the first call to ice_enum_labels requires a pointer to an actual
22308923de59SPiotr Kubaj  * ice_seg structure.
22318923de59SPiotr Kubaj  */
22328923de59SPiotr Kubaj void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg)
22338923de59SPiotr Kubaj {
22348923de59SPiotr Kubaj 	struct ice_pkg_enum state;
22358923de59SPiotr Kubaj 	char *label_name;
22368923de59SPiotr Kubaj 	u16 val;
22378923de59SPiotr Kubaj 	int i;
22388923de59SPiotr Kubaj 
22398923de59SPiotr Kubaj 	ice_memset(&hw->tnl, 0, sizeof(hw->tnl), ICE_NONDMA_MEM);
22408923de59SPiotr Kubaj 	ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
22418923de59SPiotr Kubaj 
22428923de59SPiotr Kubaj 	if (!ice_seg)
22438923de59SPiotr Kubaj 		return;
22448923de59SPiotr Kubaj 
22458923de59SPiotr Kubaj 	label_name = ice_enum_labels(ice_seg, ICE_SID_LBL_RXPARSER_TMEM, &state,
22468923de59SPiotr Kubaj 				     &val);
22478923de59SPiotr Kubaj 
22488923de59SPiotr Kubaj 	while (label_name) {
22498923de59SPiotr Kubaj /* TODO: Replace !strnsmp() with wrappers like match_some_pre() */
22508923de59SPiotr Kubaj 		if (!strncmp(label_name, ICE_TNL_PRE, strlen(ICE_TNL_PRE)))
22518923de59SPiotr Kubaj 			/* check for a tunnel entry */
22528923de59SPiotr Kubaj 			ice_add_tunnel_hint(hw, label_name, val);
22538923de59SPiotr Kubaj 
22548923de59SPiotr Kubaj 		label_name = ice_enum_labels(NULL, 0, &state, &val);
22558923de59SPiotr Kubaj 	}
22568923de59SPiotr Kubaj 
22578923de59SPiotr Kubaj 	/* Cache the appropriate boost TCAM entry pointers for tunnels */
22588923de59SPiotr Kubaj 	for (i = 0; i < hw->tnl.count; i++) {
22598923de59SPiotr Kubaj 		ice_find_boost_entry(ice_seg, hw->tnl.tbl[i].boost_addr,
22608923de59SPiotr Kubaj 				     &hw->tnl.tbl[i].boost_entry);
22618923de59SPiotr Kubaj 		if (hw->tnl.tbl[i].boost_entry)
22628923de59SPiotr Kubaj 			hw->tnl.tbl[i].valid = true;
22638923de59SPiotr Kubaj 	}
22648923de59SPiotr Kubaj }
22658923de59SPiotr Kubaj 
22668923de59SPiotr Kubaj /**
22678923de59SPiotr Kubaj  * ice_acquire_global_cfg_lock
22688923de59SPiotr Kubaj  * @hw: pointer to the HW structure
22698923de59SPiotr Kubaj  * @access: access type (read or write)
22708923de59SPiotr Kubaj  *
22718923de59SPiotr Kubaj  * This function will request ownership of the global config lock for reading
22728923de59SPiotr Kubaj  * or writing of the package. When attempting to obtain write access, the
22738923de59SPiotr Kubaj  * caller must check for the following two return values:
22748923de59SPiotr Kubaj  *
22758923de59SPiotr Kubaj  * ICE_SUCCESS        - Means the caller has acquired the global config lock
22768923de59SPiotr Kubaj  *                      and can perform writing of the package.
22778923de59SPiotr Kubaj  * ICE_ERR_AQ_NO_WORK - Indicates another driver has already written the
22788923de59SPiotr Kubaj  *                      package or has found that no update was necessary; in
22798923de59SPiotr Kubaj  *                      this case, the caller can just skip performing any
22808923de59SPiotr Kubaj  *                      update of the package.
22818923de59SPiotr Kubaj  */
22828923de59SPiotr Kubaj enum ice_status
22838923de59SPiotr Kubaj ice_acquire_global_cfg_lock(struct ice_hw *hw,
22848923de59SPiotr Kubaj 			    enum ice_aq_res_access_type access)
22858923de59SPiotr Kubaj {
22868923de59SPiotr Kubaj 	enum ice_status status;
22878923de59SPiotr Kubaj 
22888923de59SPiotr Kubaj 	status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, access,
22898923de59SPiotr Kubaj 				 ICE_GLOBAL_CFG_LOCK_TIMEOUT);
22908923de59SPiotr Kubaj 
22918923de59SPiotr Kubaj 	if (status == ICE_ERR_AQ_NO_WORK)
22928923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_PKG, "Global config lock: No work to do\n");
22938923de59SPiotr Kubaj 
22948923de59SPiotr Kubaj 	return status;
22958923de59SPiotr Kubaj }
22968923de59SPiotr Kubaj 
22978923de59SPiotr Kubaj /**
22988923de59SPiotr Kubaj  * ice_release_global_cfg_lock
22998923de59SPiotr Kubaj  * @hw: pointer to the HW structure
23008923de59SPiotr Kubaj  *
23018923de59SPiotr Kubaj  * This function will release the global config lock.
23028923de59SPiotr Kubaj  */
23038923de59SPiotr Kubaj void ice_release_global_cfg_lock(struct ice_hw *hw)
23048923de59SPiotr Kubaj {
23058923de59SPiotr Kubaj 	ice_release_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID);
23068923de59SPiotr Kubaj }
23078923de59SPiotr Kubaj 
23088923de59SPiotr Kubaj /**
23098923de59SPiotr Kubaj  * ice_acquire_change_lock
23108923de59SPiotr Kubaj  * @hw: pointer to the HW structure
23118923de59SPiotr Kubaj  * @access: access type (read or write)
23128923de59SPiotr Kubaj  *
23138923de59SPiotr Kubaj  * This function will request ownership of the change lock.
23148923de59SPiotr Kubaj  */
23158923de59SPiotr Kubaj enum ice_status
23168923de59SPiotr Kubaj ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access)
23178923de59SPiotr Kubaj {
23188923de59SPiotr Kubaj 	return ice_acquire_res(hw, ICE_CHANGE_LOCK_RES_ID, access,
23198923de59SPiotr Kubaj 			       ICE_CHANGE_LOCK_TIMEOUT);
23208923de59SPiotr Kubaj }
23218923de59SPiotr Kubaj 
23228923de59SPiotr Kubaj /**
23238923de59SPiotr Kubaj  * ice_release_change_lock
23248923de59SPiotr Kubaj  * @hw: pointer to the HW structure
23258923de59SPiotr Kubaj  *
23268923de59SPiotr Kubaj  * This function will release the change lock using the proper Admin Command.
23278923de59SPiotr Kubaj  */
23288923de59SPiotr Kubaj void ice_release_change_lock(struct ice_hw *hw)
23298923de59SPiotr Kubaj {
23308923de59SPiotr Kubaj 	ice_release_res(hw, ICE_CHANGE_LOCK_RES_ID);
23318923de59SPiotr Kubaj }
23328923de59SPiotr Kubaj 
23338923de59SPiotr Kubaj /**
23348923de59SPiotr Kubaj  * ice_get_set_tx_topo - get or set tx topology
23358923de59SPiotr Kubaj  * @hw: pointer to the HW struct
23368923de59SPiotr Kubaj  * @buf: pointer to tx topology buffer
23378923de59SPiotr Kubaj  * @buf_size: buffer size
23388923de59SPiotr Kubaj  * @cd: pointer to command details structure or NULL
23398923de59SPiotr Kubaj  * @flags: pointer to descriptor flags
23408923de59SPiotr Kubaj  * @set: 0-get, 1-set topology
23418923de59SPiotr Kubaj  *
23428923de59SPiotr Kubaj  * The function will get or set tx topology
23438923de59SPiotr Kubaj  */
23448923de59SPiotr Kubaj static enum ice_status
23458923de59SPiotr Kubaj ice_get_set_tx_topo(struct ice_hw *hw, u8 *buf, u16 buf_size,
23468923de59SPiotr Kubaj 		    struct ice_sq_cd *cd, u8 *flags, bool set)
23478923de59SPiotr Kubaj {
23488923de59SPiotr Kubaj 	struct ice_aqc_get_set_tx_topo *cmd;
23498923de59SPiotr Kubaj 	struct ice_aq_desc desc;
23508923de59SPiotr Kubaj 	enum ice_status status;
23518923de59SPiotr Kubaj 
23528923de59SPiotr Kubaj 	cmd = &desc.params.get_set_tx_topo;
23538923de59SPiotr Kubaj 	if (set) {
23548923de59SPiotr Kubaj 		ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_tx_topo);
23558923de59SPiotr Kubaj 		cmd->set_flags = ICE_AQC_TX_TOPO_FLAGS_ISSUED;
23568923de59SPiotr Kubaj 		/* requested to update a new topology, not a default topolgy */
23578923de59SPiotr Kubaj 		if (buf)
23588923de59SPiotr Kubaj 			cmd->set_flags |= ICE_AQC_TX_TOPO_FLAGS_SRC_RAM |
23598923de59SPiotr Kubaj 					  ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW;
23608923de59SPiotr Kubaj 	} else {
23618923de59SPiotr Kubaj 		ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_tx_topo);
23628923de59SPiotr Kubaj 		cmd->get_flags = ICE_AQC_TX_TOPO_GET_RAM;
23638923de59SPiotr Kubaj 	}
23648923de59SPiotr Kubaj 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
23658923de59SPiotr Kubaj 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
23668923de59SPiotr Kubaj 	if (status)
23678923de59SPiotr Kubaj 		return status;
23688923de59SPiotr Kubaj 	/* read the return flag values (first byte) for get operation */
23698923de59SPiotr Kubaj 	if (!set && flags)
23708923de59SPiotr Kubaj 		*flags = desc.params.get_set_tx_topo.set_flags;
23718923de59SPiotr Kubaj 
23728923de59SPiotr Kubaj 	return ICE_SUCCESS;
23738923de59SPiotr Kubaj }
23748923de59SPiotr Kubaj 
23758923de59SPiotr Kubaj /**
23768923de59SPiotr Kubaj  * ice_cfg_tx_topo - Initialize new tx topology if available
23778923de59SPiotr Kubaj  * @hw: pointer to the HW struct
23788923de59SPiotr Kubaj  * @buf: pointer to Tx topology buffer
23798923de59SPiotr Kubaj  * @len: buffer size
23808923de59SPiotr Kubaj  *
23818923de59SPiotr Kubaj  * The function will apply the new Tx topology from the package buffer
23828923de59SPiotr Kubaj  * if available.
23838923de59SPiotr Kubaj  */
23848923de59SPiotr Kubaj enum ice_status ice_cfg_tx_topo(struct ice_hw *hw, u8 *buf, u32 len)
23858923de59SPiotr Kubaj {
23868923de59SPiotr Kubaj 	u8 *current_topo, *new_topo = NULL;
23878923de59SPiotr Kubaj 	struct ice_run_time_cfg_seg *seg;
23888923de59SPiotr Kubaj 	struct ice_buf_hdr *section;
23898923de59SPiotr Kubaj 	struct ice_pkg_hdr *pkg_hdr;
23908923de59SPiotr Kubaj 	enum ice_ddp_state state;
23918923de59SPiotr Kubaj 	u16 i, size = 0, offset;
23928923de59SPiotr Kubaj 	enum ice_status status;
23938923de59SPiotr Kubaj 	u32 reg = 0;
23948923de59SPiotr Kubaj 	u8 flags;
23958923de59SPiotr Kubaj 
23968923de59SPiotr Kubaj 	if (!buf || !len)
23978923de59SPiotr Kubaj 		return ICE_ERR_PARAM;
23988923de59SPiotr Kubaj 
23998923de59SPiotr Kubaj 	/* Does FW support new Tx topology mode ? */
24008923de59SPiotr Kubaj 	if (!hw->func_caps.common_cap.tx_sched_topo_comp_mode_en) {
24018923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "FW doesn't support compatibility mode\n");
24028923de59SPiotr Kubaj 		return ICE_ERR_NOT_SUPPORTED;
24038923de59SPiotr Kubaj 	}
24048923de59SPiotr Kubaj 
24058923de59SPiotr Kubaj 	current_topo = (u8 *)ice_malloc(hw, ICE_AQ_MAX_BUF_LEN);
24068923de59SPiotr Kubaj 	if (!current_topo)
24078923de59SPiotr Kubaj 		return ICE_ERR_NO_MEMORY;
24088923de59SPiotr Kubaj 
24098923de59SPiotr Kubaj 	/* get the current Tx topology */
24108923de59SPiotr Kubaj 	status = ice_get_set_tx_topo(hw, current_topo, ICE_AQ_MAX_BUF_LEN, NULL,
24118923de59SPiotr Kubaj 				     &flags, false);
24128923de59SPiotr Kubaj 	ice_free(hw, current_topo);
24138923de59SPiotr Kubaj 
24148923de59SPiotr Kubaj 	if (status) {
24158923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "Get current topology is failed\n");
24168923de59SPiotr Kubaj 		return status;
24178923de59SPiotr Kubaj 	}
24188923de59SPiotr Kubaj 
24198923de59SPiotr Kubaj 	/* Is default topology already applied ? */
24208923de59SPiotr Kubaj 	if (!(flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) &&
24218923de59SPiotr Kubaj 	    hw->num_tx_sched_layers == 9) {
24228923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "Loaded default topology\n");
24238923de59SPiotr Kubaj 		/* Already default topology is loaded */
24248923de59SPiotr Kubaj 		return ICE_ERR_ALREADY_EXISTS;
24258923de59SPiotr Kubaj 	}
24268923de59SPiotr Kubaj 
24278923de59SPiotr Kubaj 	/* Is new topology already applied ? */
24288923de59SPiotr Kubaj 	if ((flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) &&
24298923de59SPiotr Kubaj 	    hw->num_tx_sched_layers == 5) {
24308923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "Loaded new topology\n");
24318923de59SPiotr Kubaj 		/* Already new topology is loaded */
24328923de59SPiotr Kubaj 		return ICE_ERR_ALREADY_EXISTS;
24338923de59SPiotr Kubaj 	}
24348923de59SPiotr Kubaj 
24358923de59SPiotr Kubaj 	/* Is set topology issued already ? */
24368923de59SPiotr Kubaj 	if (flags & ICE_AQC_TX_TOPO_FLAGS_ISSUED) {
24378923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "Update tx topology was done by another PF\n");
24388923de59SPiotr Kubaj 		/* add a small delay before exiting */
24398923de59SPiotr Kubaj 		for (i = 0; i < 20; i++)
24408923de59SPiotr Kubaj 			ice_msec_delay(100, true);
24418923de59SPiotr Kubaj 		return ICE_ERR_ALREADY_EXISTS;
24428923de59SPiotr Kubaj 	}
24438923de59SPiotr Kubaj 
24448923de59SPiotr Kubaj 	/* Change the topology from new to default (5 to 9) */
24458923de59SPiotr Kubaj 	if (!(flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) &&
24468923de59SPiotr Kubaj 	    hw->num_tx_sched_layers == 5) {
24478923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "Change topology from 5 to 9 layers\n");
24488923de59SPiotr Kubaj 		goto update_topo;
24498923de59SPiotr Kubaj 	}
24508923de59SPiotr Kubaj 
24518923de59SPiotr Kubaj 	pkg_hdr = (struct ice_pkg_hdr *)buf;
24528923de59SPiotr Kubaj 	state = ice_verify_pkg(pkg_hdr, len);
24538923de59SPiotr Kubaj 	if (state) {
24548923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n",
24558923de59SPiotr Kubaj 			  state);
24568923de59SPiotr Kubaj 		return ICE_ERR_CFG;
24578923de59SPiotr Kubaj 	}
24588923de59SPiotr Kubaj 
24598923de59SPiotr Kubaj 	/* find run time configuration segment */
24608923de59SPiotr Kubaj 	seg = (struct ice_run_time_cfg_seg *)
24618923de59SPiotr Kubaj 		ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE_RUN_TIME_CFG, pkg_hdr);
24628923de59SPiotr Kubaj 	if (!seg) {
24638923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "5 layer topology segment is missing\n");
24648923de59SPiotr Kubaj 		return ICE_ERR_CFG;
24658923de59SPiotr Kubaj 	}
24668923de59SPiotr Kubaj 
24678923de59SPiotr Kubaj 	if (LE32_TO_CPU(seg->buf_table.buf_count) < ICE_MIN_S_COUNT) {
24688923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "5 layer topology segment count(%d) is wrong\n",
24698923de59SPiotr Kubaj 			  seg->buf_table.buf_count);
24708923de59SPiotr Kubaj 		return ICE_ERR_CFG;
24718923de59SPiotr Kubaj 	}
24728923de59SPiotr Kubaj 
24738923de59SPiotr Kubaj 	section = ice_pkg_val_buf(seg->buf_table.buf_array);
24748923de59SPiotr Kubaj 
24758923de59SPiotr Kubaj 	if (!section || LE32_TO_CPU(section->section_entry[0].type) !=
24768923de59SPiotr Kubaj 		ICE_SID_TX_5_LAYER_TOPO) {
24778923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "5 layer topology section type is wrong\n");
24788923de59SPiotr Kubaj 		return ICE_ERR_CFG;
24798923de59SPiotr Kubaj 	}
24808923de59SPiotr Kubaj 
24818923de59SPiotr Kubaj 	size = LE16_TO_CPU(section->section_entry[0].size);
24828923de59SPiotr Kubaj 	offset = LE16_TO_CPU(section->section_entry[0].offset);
24838923de59SPiotr Kubaj 	if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ) {
24848923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "5 layer topology section size is wrong\n");
24858923de59SPiotr Kubaj 		return ICE_ERR_CFG;
24868923de59SPiotr Kubaj 	}
24878923de59SPiotr Kubaj 
24888923de59SPiotr Kubaj 	/* make sure the section fits in the buffer */
24898923de59SPiotr Kubaj 	if (offset + size > ICE_PKG_BUF_SIZE) {
24908923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "5 layer topology buffer > 4K\n");
24918923de59SPiotr Kubaj 		return ICE_ERR_CFG;
24928923de59SPiotr Kubaj 	}
24938923de59SPiotr Kubaj 
24948923de59SPiotr Kubaj 	/* Get the new topology buffer */
24958923de59SPiotr Kubaj 	new_topo = ((u8 *)section) + offset;
24968923de59SPiotr Kubaj 
24978923de59SPiotr Kubaj update_topo:
24988923de59SPiotr Kubaj 	/* acquire global lock to make sure that set topology issued
24998923de59SPiotr Kubaj 	 * by one PF
25008923de59SPiotr Kubaj 	 */
25018923de59SPiotr Kubaj 	status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, ICE_RES_WRITE,
25028923de59SPiotr Kubaj 				 ICE_GLOBAL_CFG_LOCK_TIMEOUT);
25038923de59SPiotr Kubaj 	if (status) {
25048923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "Failed to acquire global lock\n");
25058923de59SPiotr Kubaj 		return status;
25068923de59SPiotr Kubaj 	}
25078923de59SPiotr Kubaj 
25088923de59SPiotr Kubaj 	/* check reset was triggered already or not */
25098923de59SPiotr Kubaj 	reg = rd32(hw, GLGEN_RSTAT);
25108923de59SPiotr Kubaj 	if (reg & GLGEN_RSTAT_DEVSTATE_M) {
25118923de59SPiotr Kubaj 		/* Reset is in progress, re-init the hw again */
25128923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "Reset is in progress. layer topology might be applied already\n");
25138923de59SPiotr Kubaj 		ice_check_reset(hw);
25148923de59SPiotr Kubaj 		return ICE_SUCCESS;
25158923de59SPiotr Kubaj 	}
25168923de59SPiotr Kubaj 
25178923de59SPiotr Kubaj 	/* set new topology */
25188923de59SPiotr Kubaj 	status = ice_get_set_tx_topo(hw, new_topo, size, NULL, NULL, true);
25198923de59SPiotr Kubaj 	if (status) {
25208923de59SPiotr Kubaj 		ice_debug(hw, ICE_DBG_INIT, "Set tx topology is failed\n");
25218923de59SPiotr Kubaj 		return status;
25228923de59SPiotr Kubaj 	}
25238923de59SPiotr Kubaj 
25248923de59SPiotr Kubaj 	/* new topology is updated, delay 1 second before issuing the CORRER */
25258923de59SPiotr Kubaj 	for (i = 0; i < 10; i++)
25268923de59SPiotr Kubaj 		ice_msec_delay(100, true);
25278923de59SPiotr Kubaj 	ice_reset(hw, ICE_RESET_CORER);
25288923de59SPiotr Kubaj 	/* CORER will clear the global lock, so no explicit call
25298923de59SPiotr Kubaj 	 * required for release
25308923de59SPiotr Kubaj 	 */
25318923de59SPiotr Kubaj 	return ICE_SUCCESS;
25328923de59SPiotr Kubaj }
2533