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