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