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