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