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