12ffd87d3SSergey Temerkhanov // SPDX-License-Identifier: GPL-2.0 22ffd87d3SSergey Temerkhanov /* Copyright (c) 2022, Intel Corporation. */ 32ffd87d3SSergey Temerkhanov 42ffd87d3SSergey Temerkhanov #include "ice_common.h" 52ffd87d3SSergey Temerkhanov #include "ice.h" 62ffd87d3SSergey Temerkhanov #include "ice_ddp.h" 72ffd87d3SSergey Temerkhanov 82ffd87d3SSergey Temerkhanov /* For supporting double VLAN mode, it is necessary to enable or disable certain 92ffd87d3SSergey Temerkhanov * boost tcam entries. The metadata labels names that match the following 102ffd87d3SSergey Temerkhanov * prefixes will be saved to allow enabling double VLAN mode. 112ffd87d3SSergey Temerkhanov */ 122ffd87d3SSergey Temerkhanov #define ICE_DVM_PRE "BOOST_MAC_VLAN_DVM" /* enable these entries */ 132ffd87d3SSergey Temerkhanov #define ICE_SVM_PRE "BOOST_MAC_VLAN_SVM" /* disable these entries */ 142ffd87d3SSergey Temerkhanov 152ffd87d3SSergey Temerkhanov /* To support tunneling entries by PF, the package will append the PF number to 162ffd87d3SSergey Temerkhanov * the label; for example TNL_VXLAN_PF0, TNL_VXLAN_PF1, TNL_VXLAN_PF2, etc. 172ffd87d3SSergey Temerkhanov */ 182ffd87d3SSergey Temerkhanov #define ICE_TNL_PRE "TNL_" 192ffd87d3SSergey Temerkhanov static const struct ice_tunnel_type_scan tnls[] = { 202ffd87d3SSergey Temerkhanov { TNL_VXLAN, "TNL_VXLAN_PF" }, 212ffd87d3SSergey Temerkhanov { TNL_GENEVE, "TNL_GENEVE_PF" }, 222ffd87d3SSergey Temerkhanov { TNL_LAST, "" } 232ffd87d3SSergey Temerkhanov }; 242ffd87d3SSergey Temerkhanov 252ffd87d3SSergey Temerkhanov /** 262ffd87d3SSergey Temerkhanov * ice_verify_pkg - verify package 272ffd87d3SSergey Temerkhanov * @pkg: pointer to the package buffer 282ffd87d3SSergey Temerkhanov * @len: size of the package buffer 292ffd87d3SSergey Temerkhanov * 302ffd87d3SSergey Temerkhanov * Verifies various attributes of the package file, including length, format 312ffd87d3SSergey Temerkhanov * version, and the requirement of at least one segment. 322ffd87d3SSergey Temerkhanov */ 33708b352fSJan Sokolowski static enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len) 342ffd87d3SSergey Temerkhanov { 352ffd87d3SSergey Temerkhanov u32 seg_count; 362ffd87d3SSergey Temerkhanov u32 i; 372ffd87d3SSergey Temerkhanov 382ffd87d3SSergey Temerkhanov if (len < struct_size(pkg, seg_offset, 1)) 392ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 402ffd87d3SSergey Temerkhanov 412ffd87d3SSergey Temerkhanov if (pkg->pkg_format_ver.major != ICE_PKG_FMT_VER_MAJ || 422ffd87d3SSergey Temerkhanov pkg->pkg_format_ver.minor != ICE_PKG_FMT_VER_MNR || 432ffd87d3SSergey Temerkhanov pkg->pkg_format_ver.update != ICE_PKG_FMT_VER_UPD || 442ffd87d3SSergey Temerkhanov pkg->pkg_format_ver.draft != ICE_PKG_FMT_VER_DFT) 452ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 462ffd87d3SSergey Temerkhanov 472ffd87d3SSergey Temerkhanov /* pkg must have at least one segment */ 482ffd87d3SSergey Temerkhanov seg_count = le32_to_cpu(pkg->seg_count); 492ffd87d3SSergey Temerkhanov if (seg_count < 1) 502ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 512ffd87d3SSergey Temerkhanov 522ffd87d3SSergey Temerkhanov /* make sure segment array fits in package length */ 532ffd87d3SSergey Temerkhanov if (len < struct_size(pkg, seg_offset, seg_count)) 542ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 552ffd87d3SSergey Temerkhanov 562ffd87d3SSergey Temerkhanov /* all segments must fit within length */ 572ffd87d3SSergey Temerkhanov for (i = 0; i < seg_count; i++) { 582ffd87d3SSergey Temerkhanov u32 off = le32_to_cpu(pkg->seg_offset[i]); 592ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg; 602ffd87d3SSergey Temerkhanov 612ffd87d3SSergey Temerkhanov /* segment header must fit */ 622ffd87d3SSergey Temerkhanov if (len < off + sizeof(*seg)) 632ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 642ffd87d3SSergey Temerkhanov 652ffd87d3SSergey Temerkhanov seg = (struct ice_generic_seg_hdr *)((u8 *)pkg + off); 662ffd87d3SSergey Temerkhanov 672ffd87d3SSergey Temerkhanov /* segment body must fit */ 682ffd87d3SSergey Temerkhanov if (len < off + le32_to_cpu(seg->seg_size)) 692ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 702ffd87d3SSergey Temerkhanov } 712ffd87d3SSergey Temerkhanov 722ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 732ffd87d3SSergey Temerkhanov } 742ffd87d3SSergey Temerkhanov 752ffd87d3SSergey Temerkhanov /** 762ffd87d3SSergey Temerkhanov * ice_free_seg - free package segment pointer 772ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 782ffd87d3SSergey Temerkhanov * 792ffd87d3SSergey Temerkhanov * Frees the package segment pointer in the proper manner, depending on if the 802ffd87d3SSergey Temerkhanov * segment was allocated or just the passed in pointer was stored. 812ffd87d3SSergey Temerkhanov */ 822ffd87d3SSergey Temerkhanov void ice_free_seg(struct ice_hw *hw) 832ffd87d3SSergey Temerkhanov { 842ffd87d3SSergey Temerkhanov if (hw->pkg_copy) { 852ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), hw->pkg_copy); 862ffd87d3SSergey Temerkhanov hw->pkg_copy = NULL; 872ffd87d3SSergey Temerkhanov hw->pkg_size = 0; 882ffd87d3SSergey Temerkhanov } 892ffd87d3SSergey Temerkhanov hw->seg = NULL; 902ffd87d3SSergey Temerkhanov } 912ffd87d3SSergey Temerkhanov 922ffd87d3SSergey Temerkhanov /** 932ffd87d3SSergey Temerkhanov * ice_chk_pkg_version - check package version for compatibility with driver 942ffd87d3SSergey Temerkhanov * @pkg_ver: pointer to a version structure to check 952ffd87d3SSergey Temerkhanov * 962ffd87d3SSergey Temerkhanov * Check to make sure that the package about to be downloaded is compatible with 972ffd87d3SSergey Temerkhanov * the driver. To be compatible, the major and minor components of the package 982ffd87d3SSergey Temerkhanov * version must match our ICE_PKG_SUPP_VER_MAJ and ICE_PKG_SUPP_VER_MNR 992ffd87d3SSergey Temerkhanov * definitions. 1002ffd87d3SSergey Temerkhanov */ 1012ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver) 1022ffd87d3SSergey Temerkhanov { 1032ffd87d3SSergey Temerkhanov if (pkg_ver->major > ICE_PKG_SUPP_VER_MAJ || 1042ffd87d3SSergey Temerkhanov (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ && 1052ffd87d3SSergey Temerkhanov pkg_ver->minor > ICE_PKG_SUPP_VER_MNR)) 1062ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_VERSION_TOO_HIGH; 1072ffd87d3SSergey Temerkhanov else if (pkg_ver->major < ICE_PKG_SUPP_VER_MAJ || 1082ffd87d3SSergey Temerkhanov (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ && 1092ffd87d3SSergey Temerkhanov pkg_ver->minor < ICE_PKG_SUPP_VER_MNR)) 1102ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_VERSION_TOO_LOW; 1112ffd87d3SSergey Temerkhanov 1122ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 1132ffd87d3SSergey Temerkhanov } 1142ffd87d3SSergey Temerkhanov 1152ffd87d3SSergey Temerkhanov /** 1162ffd87d3SSergey Temerkhanov * ice_pkg_val_buf 1172ffd87d3SSergey Temerkhanov * @buf: pointer to the ice buffer 1182ffd87d3SSergey Temerkhanov * 1192ffd87d3SSergey Temerkhanov * This helper function validates a buffer's header. 1202ffd87d3SSergey Temerkhanov */ 121708b352fSJan Sokolowski static struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf) 1222ffd87d3SSergey Temerkhanov { 1232ffd87d3SSergey Temerkhanov struct ice_buf_hdr *hdr; 1242ffd87d3SSergey Temerkhanov u16 section_count; 1252ffd87d3SSergey Temerkhanov u16 data_end; 1262ffd87d3SSergey Temerkhanov 1272ffd87d3SSergey Temerkhanov hdr = (struct ice_buf_hdr *)buf->buf; 1282ffd87d3SSergey Temerkhanov /* verify data */ 1292ffd87d3SSergey Temerkhanov section_count = le16_to_cpu(hdr->section_count); 1302ffd87d3SSergey Temerkhanov if (section_count < ICE_MIN_S_COUNT || section_count > ICE_MAX_S_COUNT) 1312ffd87d3SSergey Temerkhanov return NULL; 1322ffd87d3SSergey Temerkhanov 1332ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(hdr->data_end); 1342ffd87d3SSergey Temerkhanov if (data_end < ICE_MIN_S_DATA_END || data_end > ICE_MAX_S_DATA_END) 1352ffd87d3SSergey Temerkhanov return NULL; 1362ffd87d3SSergey Temerkhanov 1372ffd87d3SSergey Temerkhanov return hdr; 1382ffd87d3SSergey Temerkhanov } 1392ffd87d3SSergey Temerkhanov 1402ffd87d3SSergey Temerkhanov /** 1412ffd87d3SSergey Temerkhanov * ice_find_buf_table 1422ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment 1432ffd87d3SSergey Temerkhanov * 1442ffd87d3SSergey Temerkhanov * Returns the address of the buffer table within the ice segment. 1452ffd87d3SSergey Temerkhanov */ 1462ffd87d3SSergey Temerkhanov static struct ice_buf_table *ice_find_buf_table(struct ice_seg *ice_seg) 1472ffd87d3SSergey Temerkhanov { 1482ffd87d3SSergey Temerkhanov struct ice_nvm_table *nvms = (struct ice_nvm_table *) 1492ffd87d3SSergey Temerkhanov (ice_seg->device_table + le32_to_cpu(ice_seg->device_table_count)); 1502ffd87d3SSergey Temerkhanov 1512ffd87d3SSergey Temerkhanov return (__force struct ice_buf_table *)(nvms->vers + 1522ffd87d3SSergey Temerkhanov le32_to_cpu(nvms->table_count)); 1532ffd87d3SSergey Temerkhanov } 1542ffd87d3SSergey Temerkhanov 1552ffd87d3SSergey Temerkhanov /** 1562ffd87d3SSergey Temerkhanov * ice_pkg_enum_buf 1572ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) 1582ffd87d3SSergey Temerkhanov * @state: pointer to the enum state 1592ffd87d3SSergey Temerkhanov * 1602ffd87d3SSergey Temerkhanov * This function will enumerate all the buffers in the ice segment. The first 1612ffd87d3SSergey Temerkhanov * call is made with the ice_seg parameter non-NULL; on subsequent calls, 1622ffd87d3SSergey Temerkhanov * ice_seg is set to NULL which continues the enumeration. When the function 1632ffd87d3SSergey Temerkhanov * returns a NULL pointer, then the end of the buffers has been reached, or an 1642ffd87d3SSergey Temerkhanov * unexpected value has been detected (for example an invalid section count or 1652ffd87d3SSergey Temerkhanov * an invalid buffer end value). 1662ffd87d3SSergey Temerkhanov */ 1672ffd87d3SSergey Temerkhanov static struct ice_buf_hdr *ice_pkg_enum_buf(struct ice_seg *ice_seg, 1682ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state) 1692ffd87d3SSergey Temerkhanov { 1702ffd87d3SSergey Temerkhanov if (ice_seg) { 1712ffd87d3SSergey Temerkhanov state->buf_table = ice_find_buf_table(ice_seg); 1722ffd87d3SSergey Temerkhanov if (!state->buf_table) 1732ffd87d3SSergey Temerkhanov return NULL; 1742ffd87d3SSergey Temerkhanov 1752ffd87d3SSergey Temerkhanov state->buf_idx = 0; 1762ffd87d3SSergey Temerkhanov return ice_pkg_val_buf(state->buf_table->buf_array); 1772ffd87d3SSergey Temerkhanov } 1782ffd87d3SSergey Temerkhanov 1792ffd87d3SSergey Temerkhanov if (++state->buf_idx < le32_to_cpu(state->buf_table->buf_count)) 1802ffd87d3SSergey Temerkhanov return ice_pkg_val_buf(state->buf_table->buf_array + 1812ffd87d3SSergey Temerkhanov state->buf_idx); 1822ffd87d3SSergey Temerkhanov else 1832ffd87d3SSergey Temerkhanov return NULL; 1842ffd87d3SSergey Temerkhanov } 1852ffd87d3SSergey Temerkhanov 1862ffd87d3SSergey Temerkhanov /** 1872ffd87d3SSergey Temerkhanov * ice_pkg_advance_sect 1882ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) 1892ffd87d3SSergey Temerkhanov * @state: pointer to the enum state 1902ffd87d3SSergey Temerkhanov * 1912ffd87d3SSergey Temerkhanov * This helper function will advance the section within the ice segment, 1922ffd87d3SSergey Temerkhanov * also advancing the buffer if needed. 1932ffd87d3SSergey Temerkhanov */ 1942ffd87d3SSergey Temerkhanov static bool ice_pkg_advance_sect(struct ice_seg *ice_seg, 1952ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state) 1962ffd87d3SSergey Temerkhanov { 1972ffd87d3SSergey Temerkhanov if (!ice_seg && !state->buf) 1982ffd87d3SSergey Temerkhanov return false; 1992ffd87d3SSergey Temerkhanov 2002ffd87d3SSergey Temerkhanov if (!ice_seg && state->buf) 2012ffd87d3SSergey Temerkhanov if (++state->sect_idx < le16_to_cpu(state->buf->section_count)) 2022ffd87d3SSergey Temerkhanov return true; 2032ffd87d3SSergey Temerkhanov 2042ffd87d3SSergey Temerkhanov state->buf = ice_pkg_enum_buf(ice_seg, state); 2052ffd87d3SSergey Temerkhanov if (!state->buf) 2062ffd87d3SSergey Temerkhanov return false; 2072ffd87d3SSergey Temerkhanov 2082ffd87d3SSergey Temerkhanov /* start of new buffer, reset section index */ 2092ffd87d3SSergey Temerkhanov state->sect_idx = 0; 2102ffd87d3SSergey Temerkhanov return true; 2112ffd87d3SSergey Temerkhanov } 2122ffd87d3SSergey Temerkhanov 2132ffd87d3SSergey Temerkhanov /** 2142ffd87d3SSergey Temerkhanov * ice_pkg_enum_section 2152ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) 2162ffd87d3SSergey Temerkhanov * @state: pointer to the enum state 2172ffd87d3SSergey Temerkhanov * @sect_type: section type to enumerate 2182ffd87d3SSergey Temerkhanov * 2192ffd87d3SSergey Temerkhanov * This function will enumerate all the sections of a particular type in the 2202ffd87d3SSergey Temerkhanov * ice segment. The first call is made with the ice_seg parameter non-NULL; 2212ffd87d3SSergey Temerkhanov * on subsequent calls, ice_seg is set to NULL which continues the enumeration. 2222ffd87d3SSergey Temerkhanov * When the function returns a NULL pointer, then the end of the matching 2232ffd87d3SSergey Temerkhanov * sections has been reached. 2242ffd87d3SSergey Temerkhanov */ 2252ffd87d3SSergey Temerkhanov void *ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state, 2262ffd87d3SSergey Temerkhanov u32 sect_type) 2272ffd87d3SSergey Temerkhanov { 2282ffd87d3SSergey Temerkhanov u16 offset, size; 2292ffd87d3SSergey Temerkhanov 2302ffd87d3SSergey Temerkhanov if (ice_seg) 2312ffd87d3SSergey Temerkhanov state->type = sect_type; 2322ffd87d3SSergey Temerkhanov 2332ffd87d3SSergey Temerkhanov if (!ice_pkg_advance_sect(ice_seg, state)) 2342ffd87d3SSergey Temerkhanov return NULL; 2352ffd87d3SSergey Temerkhanov 2362ffd87d3SSergey Temerkhanov /* scan for next matching section */ 2372ffd87d3SSergey Temerkhanov while (state->buf->section_entry[state->sect_idx].type != 2382ffd87d3SSergey Temerkhanov cpu_to_le32(state->type)) 2392ffd87d3SSergey Temerkhanov if (!ice_pkg_advance_sect(NULL, state)) 2402ffd87d3SSergey Temerkhanov return NULL; 2412ffd87d3SSergey Temerkhanov 2422ffd87d3SSergey Temerkhanov /* validate section */ 2432ffd87d3SSergey Temerkhanov offset = le16_to_cpu(state->buf->section_entry[state->sect_idx].offset); 2442ffd87d3SSergey Temerkhanov if (offset < ICE_MIN_S_OFF || offset > ICE_MAX_S_OFF) 2452ffd87d3SSergey Temerkhanov return NULL; 2462ffd87d3SSergey Temerkhanov 2472ffd87d3SSergey Temerkhanov size = le16_to_cpu(state->buf->section_entry[state->sect_idx].size); 2482ffd87d3SSergey Temerkhanov if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ) 2492ffd87d3SSergey Temerkhanov return NULL; 2502ffd87d3SSergey Temerkhanov 2512ffd87d3SSergey Temerkhanov /* make sure the section fits in the buffer */ 2522ffd87d3SSergey Temerkhanov if (offset + size > ICE_PKG_BUF_SIZE) 2532ffd87d3SSergey Temerkhanov return NULL; 2542ffd87d3SSergey Temerkhanov 2552ffd87d3SSergey Temerkhanov state->sect_type = 2562ffd87d3SSergey Temerkhanov le32_to_cpu(state->buf->section_entry[state->sect_idx].type); 2572ffd87d3SSergey Temerkhanov 2582ffd87d3SSergey Temerkhanov /* calc pointer to this section */ 2592ffd87d3SSergey Temerkhanov state->sect = 2602ffd87d3SSergey Temerkhanov ((u8 *)state->buf) + 2612ffd87d3SSergey Temerkhanov le16_to_cpu(state->buf->section_entry[state->sect_idx].offset); 2622ffd87d3SSergey Temerkhanov 2632ffd87d3SSergey Temerkhanov return state->sect; 2642ffd87d3SSergey Temerkhanov } 2652ffd87d3SSergey Temerkhanov 2662ffd87d3SSergey Temerkhanov /** 2672ffd87d3SSergey Temerkhanov * ice_pkg_enum_entry 2682ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) 2692ffd87d3SSergey Temerkhanov * @state: pointer to the enum state 2702ffd87d3SSergey Temerkhanov * @sect_type: section type to enumerate 2712ffd87d3SSergey Temerkhanov * @offset: pointer to variable that receives the offset in the table (optional) 2722ffd87d3SSergey Temerkhanov * @handler: function that handles access to the entries into the section type 2732ffd87d3SSergey Temerkhanov * 2742ffd87d3SSergey Temerkhanov * This function will enumerate all the entries in particular section type in 2752ffd87d3SSergey Temerkhanov * the ice segment. The first call is made with the ice_seg parameter non-NULL; 2762ffd87d3SSergey Temerkhanov * on subsequent calls, ice_seg is set to NULL which continues the enumeration. 2772ffd87d3SSergey Temerkhanov * When the function returns a NULL pointer, then the end of the entries has 2782ffd87d3SSergey Temerkhanov * been reached. 2792ffd87d3SSergey Temerkhanov * 2802ffd87d3SSergey Temerkhanov * Since each section may have a different header and entry size, the handler 2812ffd87d3SSergey Temerkhanov * function is needed to determine the number and location entries in each 2822ffd87d3SSergey Temerkhanov * section. 2832ffd87d3SSergey Temerkhanov * 2842ffd87d3SSergey Temerkhanov * The offset parameter is optional, but should be used for sections that 2852ffd87d3SSergey Temerkhanov * contain an offset for each section table. For such cases, the section handler 2862ffd87d3SSergey Temerkhanov * function must return the appropriate offset + index to give the absolution 2872ffd87d3SSergey Temerkhanov * offset for each entry. For example, if the base for a section's header 2882ffd87d3SSergey Temerkhanov * indicates a base offset of 10, and the index for the entry is 2, then 2892ffd87d3SSergey Temerkhanov * section handler function should set the offset to 10 + 2 = 12. 2902ffd87d3SSergey Temerkhanov */ 2912ffd87d3SSergey Temerkhanov static void *ice_pkg_enum_entry(struct ice_seg *ice_seg, 2922ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state, u32 sect_type, 2932ffd87d3SSergey Temerkhanov u32 *offset, 2942ffd87d3SSergey Temerkhanov void *(*handler)(u32 sect_type, void *section, 2952ffd87d3SSergey Temerkhanov u32 index, u32 *offset)) 2962ffd87d3SSergey Temerkhanov { 2972ffd87d3SSergey Temerkhanov void *entry; 2982ffd87d3SSergey Temerkhanov 2992ffd87d3SSergey Temerkhanov if (ice_seg) { 3002ffd87d3SSergey Temerkhanov if (!handler) 3012ffd87d3SSergey Temerkhanov return NULL; 3022ffd87d3SSergey Temerkhanov 3032ffd87d3SSergey Temerkhanov if (!ice_pkg_enum_section(ice_seg, state, sect_type)) 3042ffd87d3SSergey Temerkhanov return NULL; 3052ffd87d3SSergey Temerkhanov 3062ffd87d3SSergey Temerkhanov state->entry_idx = 0; 3072ffd87d3SSergey Temerkhanov state->handler = handler; 3082ffd87d3SSergey Temerkhanov } else { 3092ffd87d3SSergey Temerkhanov state->entry_idx++; 3102ffd87d3SSergey Temerkhanov } 3112ffd87d3SSergey Temerkhanov 3122ffd87d3SSergey Temerkhanov if (!state->handler) 3132ffd87d3SSergey Temerkhanov return NULL; 3142ffd87d3SSergey Temerkhanov 3152ffd87d3SSergey Temerkhanov /* get entry */ 3162ffd87d3SSergey Temerkhanov entry = state->handler(state->sect_type, state->sect, state->entry_idx, 3172ffd87d3SSergey Temerkhanov offset); 3182ffd87d3SSergey Temerkhanov if (!entry) { 3192ffd87d3SSergey Temerkhanov /* end of a section, look for another section of this type */ 3202ffd87d3SSergey Temerkhanov if (!ice_pkg_enum_section(NULL, state, 0)) 3212ffd87d3SSergey Temerkhanov return NULL; 3222ffd87d3SSergey Temerkhanov 3232ffd87d3SSergey Temerkhanov state->entry_idx = 0; 3242ffd87d3SSergey Temerkhanov entry = state->handler(state->sect_type, state->sect, 3252ffd87d3SSergey Temerkhanov state->entry_idx, offset); 3262ffd87d3SSergey Temerkhanov } 3272ffd87d3SSergey Temerkhanov 3282ffd87d3SSergey Temerkhanov return entry; 3292ffd87d3SSergey Temerkhanov } 3302ffd87d3SSergey Temerkhanov 3312ffd87d3SSergey Temerkhanov /** 3322ffd87d3SSergey Temerkhanov * ice_sw_fv_handler 3332ffd87d3SSergey Temerkhanov * @sect_type: section type 3342ffd87d3SSergey Temerkhanov * @section: pointer to section 3352ffd87d3SSergey Temerkhanov * @index: index of the field vector entry to be returned 3362ffd87d3SSergey Temerkhanov * @offset: ptr to variable that receives the offset in the field vector table 3372ffd87d3SSergey Temerkhanov * 3382ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry. 3392ffd87d3SSergey Temerkhanov * This function treats the given section as of type ice_sw_fv_section and 3402ffd87d3SSergey Temerkhanov * enumerates offset field. "offset" is an index into the field vector table. 3412ffd87d3SSergey Temerkhanov */ 3422ffd87d3SSergey Temerkhanov static void *ice_sw_fv_handler(u32 sect_type, void *section, u32 index, 3432ffd87d3SSergey Temerkhanov u32 *offset) 3442ffd87d3SSergey Temerkhanov { 3452ffd87d3SSergey Temerkhanov struct ice_sw_fv_section *fv_section = section; 3462ffd87d3SSergey Temerkhanov 3472ffd87d3SSergey Temerkhanov if (!section || sect_type != ICE_SID_FLD_VEC_SW) 3482ffd87d3SSergey Temerkhanov return NULL; 3492ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(fv_section->count)) 3502ffd87d3SSergey Temerkhanov return NULL; 3512ffd87d3SSergey Temerkhanov if (offset) 3522ffd87d3SSergey Temerkhanov /* "index" passed in to this function is relative to a given 3532ffd87d3SSergey Temerkhanov * 4k block. To get to the true index into the field vector 3542ffd87d3SSergey Temerkhanov * table need to add the relative index to the base_offset 3552ffd87d3SSergey Temerkhanov * field of this section 3562ffd87d3SSergey Temerkhanov */ 3572ffd87d3SSergey Temerkhanov *offset = le16_to_cpu(fv_section->base_offset) + index; 3582ffd87d3SSergey Temerkhanov return fv_section->fv + index; 3592ffd87d3SSergey Temerkhanov } 3602ffd87d3SSergey Temerkhanov 3612ffd87d3SSergey Temerkhanov /** 3622ffd87d3SSergey Temerkhanov * ice_get_prof_index_max - get the max profile index for used profile 3632ffd87d3SSergey Temerkhanov * @hw: pointer to the HW struct 3642ffd87d3SSergey Temerkhanov * 3652ffd87d3SSergey Temerkhanov * Calling this function will get the max profile index for used profile 3662ffd87d3SSergey Temerkhanov * and store the index number in struct ice_switch_info *switch_info 3672ffd87d3SSergey Temerkhanov * in HW for following use. 3682ffd87d3SSergey Temerkhanov */ 3692ffd87d3SSergey Temerkhanov static int ice_get_prof_index_max(struct ice_hw *hw) 3702ffd87d3SSergey Temerkhanov { 3712ffd87d3SSergey Temerkhanov u16 prof_index = 0, j, max_prof_index = 0; 3722ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 3732ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 3742ffd87d3SSergey Temerkhanov bool flag = false; 3752ffd87d3SSergey Temerkhanov struct ice_fv *fv; 3762ffd87d3SSergey Temerkhanov u32 offset; 3772ffd87d3SSergey Temerkhanov 3782ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 3792ffd87d3SSergey Temerkhanov 3802ffd87d3SSergey Temerkhanov if (!hw->seg) 3812ffd87d3SSergey Temerkhanov return -EINVAL; 3822ffd87d3SSergey Temerkhanov 3832ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 3842ffd87d3SSergey Temerkhanov 3852ffd87d3SSergey Temerkhanov do { 3862ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 3872ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler); 3882ffd87d3SSergey Temerkhanov if (!fv) 3892ffd87d3SSergey Temerkhanov break; 3902ffd87d3SSergey Temerkhanov ice_seg = NULL; 3912ffd87d3SSergey Temerkhanov 3922ffd87d3SSergey Temerkhanov /* in the profile that not be used, the prot_id is set to 0xff 3932ffd87d3SSergey Temerkhanov * and the off is set to 0x1ff for all the field vectors. 3942ffd87d3SSergey Temerkhanov */ 3952ffd87d3SSergey Temerkhanov for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) 3962ffd87d3SSergey Temerkhanov if (fv->ew[j].prot_id != ICE_PROT_INVALID || 3972ffd87d3SSergey Temerkhanov fv->ew[j].off != ICE_FV_OFFSET_INVAL) 3982ffd87d3SSergey Temerkhanov flag = true; 3992ffd87d3SSergey Temerkhanov if (flag && prof_index > max_prof_index) 4002ffd87d3SSergey Temerkhanov max_prof_index = prof_index; 4012ffd87d3SSergey Temerkhanov 4022ffd87d3SSergey Temerkhanov prof_index++; 4032ffd87d3SSergey Temerkhanov flag = false; 4042ffd87d3SSergey Temerkhanov } while (fv); 4052ffd87d3SSergey Temerkhanov 4062ffd87d3SSergey Temerkhanov hw->switch_info->max_used_prof_index = max_prof_index; 4072ffd87d3SSergey Temerkhanov 4082ffd87d3SSergey Temerkhanov return 0; 4092ffd87d3SSergey Temerkhanov } 4102ffd87d3SSergey Temerkhanov 4112ffd87d3SSergey Temerkhanov /** 4122ffd87d3SSergey Temerkhanov * ice_get_ddp_pkg_state - get DDP pkg state after download 4132ffd87d3SSergey Temerkhanov * @hw: pointer to the HW struct 4142ffd87d3SSergey Temerkhanov * @already_loaded: indicates if pkg was already loaded onto the device 4152ffd87d3SSergey Temerkhanov */ 4162ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_ddp_pkg_state(struct ice_hw *hw, 4172ffd87d3SSergey Temerkhanov bool already_loaded) 4182ffd87d3SSergey Temerkhanov { 4192ffd87d3SSergey Temerkhanov if (hw->pkg_ver.major == hw->active_pkg_ver.major && 4202ffd87d3SSergey Temerkhanov hw->pkg_ver.minor == hw->active_pkg_ver.minor && 4212ffd87d3SSergey Temerkhanov hw->pkg_ver.update == hw->active_pkg_ver.update && 4222ffd87d3SSergey Temerkhanov hw->pkg_ver.draft == hw->active_pkg_ver.draft && 4232ffd87d3SSergey Temerkhanov !memcmp(hw->pkg_name, hw->active_pkg_name, sizeof(hw->pkg_name))) { 4242ffd87d3SSergey Temerkhanov if (already_loaded) 4252ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED; 4262ffd87d3SSergey Temerkhanov else 4272ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 4282ffd87d3SSergey Temerkhanov } else if (hw->active_pkg_ver.major != ICE_PKG_SUPP_VER_MAJ || 4292ffd87d3SSergey Temerkhanov hw->active_pkg_ver.minor != ICE_PKG_SUPP_VER_MNR) { 4302ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ALREADY_LOADED_NOT_SUPPORTED; 4312ffd87d3SSergey Temerkhanov } else if (hw->active_pkg_ver.major == ICE_PKG_SUPP_VER_MAJ && 4322ffd87d3SSergey Temerkhanov hw->active_pkg_ver.minor == ICE_PKG_SUPP_VER_MNR) { 4332ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED; 4342ffd87d3SSergey Temerkhanov } else { 4352ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 4362ffd87d3SSergey Temerkhanov } 4372ffd87d3SSergey Temerkhanov } 4382ffd87d3SSergey Temerkhanov 4392ffd87d3SSergey Temerkhanov /** 4402ffd87d3SSergey Temerkhanov * ice_init_pkg_regs - initialize additional package registers 4412ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 4422ffd87d3SSergey Temerkhanov */ 4432ffd87d3SSergey Temerkhanov static void ice_init_pkg_regs(struct ice_hw *hw) 4442ffd87d3SSergey Temerkhanov { 4452ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_INP_MASK_L 0xFFFFFFFF 4462ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_INP_MASK_H 0x0000FFFF 4472ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_IDX 0 4482ffd87d3SSergey Temerkhanov 4492ffd87d3SSergey Temerkhanov /* setup Switch block input mask, which is 48-bits in two parts */ 4502ffd87d3SSergey Temerkhanov wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L); 4512ffd87d3SSergey Temerkhanov wr32(hw, GL_PREEXT_L2_PMASK1(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_H); 4522ffd87d3SSergey Temerkhanov } 4532ffd87d3SSergey Temerkhanov 4542ffd87d3SSergey Temerkhanov /** 4552ffd87d3SSergey Temerkhanov * ice_marker_ptype_tcam_handler 4562ffd87d3SSergey Temerkhanov * @sect_type: section type 4572ffd87d3SSergey Temerkhanov * @section: pointer to section 4582ffd87d3SSergey Temerkhanov * @index: index of the Marker PType TCAM entry to be returned 4592ffd87d3SSergey Temerkhanov * @offset: pointer to receive absolute offset, always 0 for ptype TCAM sections 4602ffd87d3SSergey Temerkhanov * 4612ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry. 4622ffd87d3SSergey Temerkhanov * Handles enumeration of individual Marker PType TCAM entries. 4632ffd87d3SSergey Temerkhanov */ 4642ffd87d3SSergey Temerkhanov static void *ice_marker_ptype_tcam_handler(u32 sect_type, void *section, 4652ffd87d3SSergey Temerkhanov u32 index, u32 *offset) 4662ffd87d3SSergey Temerkhanov { 4672ffd87d3SSergey Temerkhanov struct ice_marker_ptype_tcam_section *marker_ptype; 4682ffd87d3SSergey Temerkhanov 4692ffd87d3SSergey Temerkhanov if (sect_type != ICE_SID_RXPARSER_MARKER_PTYPE) 4702ffd87d3SSergey Temerkhanov return NULL; 4712ffd87d3SSergey Temerkhanov 4722ffd87d3SSergey Temerkhanov if (index > ICE_MAX_MARKER_PTYPE_TCAMS_IN_BUF) 4732ffd87d3SSergey Temerkhanov return NULL; 4742ffd87d3SSergey Temerkhanov 4752ffd87d3SSergey Temerkhanov if (offset) 4762ffd87d3SSergey Temerkhanov *offset = 0; 4772ffd87d3SSergey Temerkhanov 4782ffd87d3SSergey Temerkhanov marker_ptype = section; 4792ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(marker_ptype->count)) 4802ffd87d3SSergey Temerkhanov return NULL; 4812ffd87d3SSergey Temerkhanov 4822ffd87d3SSergey Temerkhanov return marker_ptype->tcam + index; 4832ffd87d3SSergey Temerkhanov } 4842ffd87d3SSergey Temerkhanov 4852ffd87d3SSergey Temerkhanov /** 4862ffd87d3SSergey Temerkhanov * ice_add_dvm_hint 4872ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 4882ffd87d3SSergey Temerkhanov * @val: value of the boost entry 4892ffd87d3SSergey Temerkhanov * @enable: true if entry needs to be enabled, or false if needs to be disabled 4902ffd87d3SSergey Temerkhanov */ 4912ffd87d3SSergey Temerkhanov static void ice_add_dvm_hint(struct ice_hw *hw, u16 val, bool enable) 4922ffd87d3SSergey Temerkhanov { 4932ffd87d3SSergey Temerkhanov if (hw->dvm_upd.count < ICE_DVM_MAX_ENTRIES) { 4942ffd87d3SSergey Temerkhanov hw->dvm_upd.tbl[hw->dvm_upd.count].boost_addr = val; 4952ffd87d3SSergey Temerkhanov hw->dvm_upd.tbl[hw->dvm_upd.count].enable = enable; 4962ffd87d3SSergey Temerkhanov hw->dvm_upd.count++; 4972ffd87d3SSergey Temerkhanov } 4982ffd87d3SSergey Temerkhanov } 4992ffd87d3SSergey Temerkhanov 5002ffd87d3SSergey Temerkhanov /** 5012ffd87d3SSergey Temerkhanov * ice_add_tunnel_hint 5022ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 5032ffd87d3SSergey Temerkhanov * @label_name: label text 5042ffd87d3SSergey Temerkhanov * @val: value of the tunnel port boost entry 5052ffd87d3SSergey Temerkhanov */ 5062ffd87d3SSergey Temerkhanov static void ice_add_tunnel_hint(struct ice_hw *hw, char *label_name, u16 val) 5072ffd87d3SSergey Temerkhanov { 5082ffd87d3SSergey Temerkhanov if (hw->tnl.count < ICE_TUNNEL_MAX_ENTRIES) { 5092ffd87d3SSergey Temerkhanov u16 i; 5102ffd87d3SSergey Temerkhanov 5112ffd87d3SSergey Temerkhanov for (i = 0; tnls[i].type != TNL_LAST; i++) { 5122ffd87d3SSergey Temerkhanov size_t len = strlen(tnls[i].label_prefix); 5132ffd87d3SSergey Temerkhanov 5142ffd87d3SSergey Temerkhanov /* Look for matching label start, before continuing */ 5152ffd87d3SSergey Temerkhanov if (strncmp(label_name, tnls[i].label_prefix, len)) 5162ffd87d3SSergey Temerkhanov continue; 5172ffd87d3SSergey Temerkhanov 5182ffd87d3SSergey Temerkhanov /* Make sure this label matches our PF. Note that the PF 5192ffd87d3SSergey Temerkhanov * character ('0' - '7') will be located where our 5202ffd87d3SSergey Temerkhanov * prefix string's null terminator is located. 5212ffd87d3SSergey Temerkhanov */ 5222ffd87d3SSergey Temerkhanov if ((label_name[len] - '0') == hw->pf_id) { 5232ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].type = tnls[i].type; 5242ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].valid = false; 5252ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].boost_addr = val; 5262ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].port = 0; 5272ffd87d3SSergey Temerkhanov hw->tnl.count++; 5282ffd87d3SSergey Temerkhanov break; 5292ffd87d3SSergey Temerkhanov } 5302ffd87d3SSergey Temerkhanov } 5312ffd87d3SSergey Temerkhanov } 5322ffd87d3SSergey Temerkhanov } 5332ffd87d3SSergey Temerkhanov 5342ffd87d3SSergey Temerkhanov /** 5352ffd87d3SSergey Temerkhanov * ice_label_enum_handler 5362ffd87d3SSergey Temerkhanov * @sect_type: section type 5372ffd87d3SSergey Temerkhanov * @section: pointer to section 5382ffd87d3SSergey Temerkhanov * @index: index of the label entry to be returned 5392ffd87d3SSergey Temerkhanov * @offset: pointer to receive absolute offset, always zero for label sections 5402ffd87d3SSergey Temerkhanov * 5412ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry. 5422ffd87d3SSergey Temerkhanov * Handles enumeration of individual label entries. 5432ffd87d3SSergey Temerkhanov */ 5442ffd87d3SSergey Temerkhanov static void *ice_label_enum_handler(u32 __always_unused sect_type, 5452ffd87d3SSergey Temerkhanov void *section, u32 index, u32 *offset) 5462ffd87d3SSergey Temerkhanov { 5472ffd87d3SSergey Temerkhanov struct ice_label_section *labels; 5482ffd87d3SSergey Temerkhanov 5492ffd87d3SSergey Temerkhanov if (!section) 5502ffd87d3SSergey Temerkhanov return NULL; 5512ffd87d3SSergey Temerkhanov 5522ffd87d3SSergey Temerkhanov if (index > ICE_MAX_LABELS_IN_BUF) 5532ffd87d3SSergey Temerkhanov return NULL; 5542ffd87d3SSergey Temerkhanov 5552ffd87d3SSergey Temerkhanov if (offset) 5562ffd87d3SSergey Temerkhanov *offset = 0; 5572ffd87d3SSergey Temerkhanov 5582ffd87d3SSergey Temerkhanov labels = section; 5592ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(labels->count)) 5602ffd87d3SSergey Temerkhanov return NULL; 5612ffd87d3SSergey Temerkhanov 5622ffd87d3SSergey Temerkhanov return labels->label + index; 5632ffd87d3SSergey Temerkhanov } 5642ffd87d3SSergey Temerkhanov 5652ffd87d3SSergey Temerkhanov /** 5662ffd87d3SSergey Temerkhanov * ice_enum_labels 5672ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (NULL on subsequent calls) 5682ffd87d3SSergey Temerkhanov * @type: the section type that will contain the label (0 on subsequent calls) 5692ffd87d3SSergey Temerkhanov * @state: ice_pkg_enum structure that will hold the state of the enumeration 5702ffd87d3SSergey Temerkhanov * @value: pointer to a value that will return the label's value if found 5712ffd87d3SSergey Temerkhanov * 5722ffd87d3SSergey Temerkhanov * Enumerates a list of labels in the package. The caller will call 5732ffd87d3SSergey Temerkhanov * ice_enum_labels(ice_seg, type, ...) to start the enumeration, then call 5742ffd87d3SSergey Temerkhanov * ice_enum_labels(NULL, 0, ...) to continue. When the function returns a NULL 5752ffd87d3SSergey Temerkhanov * the end of the list has been reached. 5762ffd87d3SSergey Temerkhanov */ 5772ffd87d3SSergey Temerkhanov static char *ice_enum_labels(struct ice_seg *ice_seg, u32 type, 5782ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state, u16 *value) 5792ffd87d3SSergey Temerkhanov { 5802ffd87d3SSergey Temerkhanov struct ice_label *label; 5812ffd87d3SSergey Temerkhanov 5822ffd87d3SSergey Temerkhanov /* Check for valid label section on first call */ 5832ffd87d3SSergey Temerkhanov if (type && !(type >= ICE_SID_LBL_FIRST && type <= ICE_SID_LBL_LAST)) 5842ffd87d3SSergey Temerkhanov return NULL; 5852ffd87d3SSergey Temerkhanov 5862ffd87d3SSergey Temerkhanov label = ice_pkg_enum_entry(ice_seg, state, type, NULL, 5872ffd87d3SSergey Temerkhanov ice_label_enum_handler); 5882ffd87d3SSergey Temerkhanov if (!label) 5892ffd87d3SSergey Temerkhanov return NULL; 5902ffd87d3SSergey Temerkhanov 5912ffd87d3SSergey Temerkhanov *value = le16_to_cpu(label->value); 5922ffd87d3SSergey Temerkhanov return label->name; 5932ffd87d3SSergey Temerkhanov } 5942ffd87d3SSergey Temerkhanov 5952ffd87d3SSergey Temerkhanov /** 5962ffd87d3SSergey Temerkhanov * ice_boost_tcam_handler 5972ffd87d3SSergey Temerkhanov * @sect_type: section type 5982ffd87d3SSergey Temerkhanov * @section: pointer to section 5992ffd87d3SSergey Temerkhanov * @index: index of the boost TCAM entry to be returned 6002ffd87d3SSergey Temerkhanov * @offset: pointer to receive absolute offset, always 0 for boost TCAM sections 6012ffd87d3SSergey Temerkhanov * 6022ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry. 6032ffd87d3SSergey Temerkhanov * Handles enumeration of individual boost TCAM entries. 6042ffd87d3SSergey Temerkhanov */ 6052ffd87d3SSergey Temerkhanov static void *ice_boost_tcam_handler(u32 sect_type, void *section, u32 index, 6062ffd87d3SSergey Temerkhanov u32 *offset) 6072ffd87d3SSergey Temerkhanov { 6082ffd87d3SSergey Temerkhanov struct ice_boost_tcam_section *boost; 6092ffd87d3SSergey Temerkhanov 6102ffd87d3SSergey Temerkhanov if (!section) 6112ffd87d3SSergey Temerkhanov return NULL; 6122ffd87d3SSergey Temerkhanov 6132ffd87d3SSergey Temerkhanov if (sect_type != ICE_SID_RXPARSER_BOOST_TCAM) 6142ffd87d3SSergey Temerkhanov return NULL; 6152ffd87d3SSergey Temerkhanov 6162ffd87d3SSergey Temerkhanov if (index > ICE_MAX_BST_TCAMS_IN_BUF) 6172ffd87d3SSergey Temerkhanov return NULL; 6182ffd87d3SSergey Temerkhanov 6192ffd87d3SSergey Temerkhanov if (offset) 6202ffd87d3SSergey Temerkhanov *offset = 0; 6212ffd87d3SSergey Temerkhanov 6222ffd87d3SSergey Temerkhanov boost = section; 6232ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(boost->count)) 6242ffd87d3SSergey Temerkhanov return NULL; 6252ffd87d3SSergey Temerkhanov 6262ffd87d3SSergey Temerkhanov return boost->tcam + index; 6272ffd87d3SSergey Temerkhanov } 6282ffd87d3SSergey Temerkhanov 6292ffd87d3SSergey Temerkhanov /** 6302ffd87d3SSergey Temerkhanov * ice_find_boost_entry 6312ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (non-NULL) 6322ffd87d3SSergey Temerkhanov * @addr: Boost TCAM address of entry to search for 6332ffd87d3SSergey Temerkhanov * @entry: returns pointer to the entry 6342ffd87d3SSergey Temerkhanov * 6352ffd87d3SSergey Temerkhanov * Finds a particular Boost TCAM entry and returns a pointer to that entry 6362ffd87d3SSergey Temerkhanov * if it is found. The ice_seg parameter must not be NULL since the first call 6372ffd87d3SSergey Temerkhanov * to ice_pkg_enum_entry requires a pointer to an actual ice_segment structure. 6382ffd87d3SSergey Temerkhanov */ 6392ffd87d3SSergey Temerkhanov static int ice_find_boost_entry(struct ice_seg *ice_seg, u16 addr, 6402ffd87d3SSergey Temerkhanov struct ice_boost_tcam_entry **entry) 6412ffd87d3SSergey Temerkhanov { 6422ffd87d3SSergey Temerkhanov struct ice_boost_tcam_entry *tcam; 6432ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 6442ffd87d3SSergey Temerkhanov 6452ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 6462ffd87d3SSergey Temerkhanov 6472ffd87d3SSergey Temerkhanov if (!ice_seg) 6482ffd87d3SSergey Temerkhanov return -EINVAL; 6492ffd87d3SSergey Temerkhanov 6502ffd87d3SSergey Temerkhanov do { 6512ffd87d3SSergey Temerkhanov tcam = ice_pkg_enum_entry(ice_seg, &state, 6522ffd87d3SSergey Temerkhanov ICE_SID_RXPARSER_BOOST_TCAM, NULL, 6532ffd87d3SSergey Temerkhanov ice_boost_tcam_handler); 6542ffd87d3SSergey Temerkhanov if (tcam && le16_to_cpu(tcam->addr) == addr) { 6552ffd87d3SSergey Temerkhanov *entry = tcam; 6562ffd87d3SSergey Temerkhanov return 0; 6572ffd87d3SSergey Temerkhanov } 6582ffd87d3SSergey Temerkhanov 6592ffd87d3SSergey Temerkhanov ice_seg = NULL; 6602ffd87d3SSergey Temerkhanov } while (tcam); 6612ffd87d3SSergey Temerkhanov 6622ffd87d3SSergey Temerkhanov *entry = NULL; 6632ffd87d3SSergey Temerkhanov return -EIO; 6642ffd87d3SSergey Temerkhanov } 6652ffd87d3SSergey Temerkhanov 6662ffd87d3SSergey Temerkhanov /** 6672ffd87d3SSergey Temerkhanov * ice_is_init_pkg_successful - check if DDP init was successful 6682ffd87d3SSergey Temerkhanov * @state: state of the DDP pkg after download 6692ffd87d3SSergey Temerkhanov */ 6702ffd87d3SSergey Temerkhanov bool ice_is_init_pkg_successful(enum ice_ddp_state state) 6712ffd87d3SSergey Temerkhanov { 6722ffd87d3SSergey Temerkhanov switch (state) { 6732ffd87d3SSergey Temerkhanov case ICE_DDP_PKG_SUCCESS: 6742ffd87d3SSergey Temerkhanov case ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED: 6752ffd87d3SSergey Temerkhanov case ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED: 6762ffd87d3SSergey Temerkhanov return true; 6772ffd87d3SSergey Temerkhanov default: 6782ffd87d3SSergey Temerkhanov return false; 6792ffd87d3SSergey Temerkhanov } 6802ffd87d3SSergey Temerkhanov } 6812ffd87d3SSergey Temerkhanov 6822ffd87d3SSergey Temerkhanov /** 6832ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc 6842ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 6852ffd87d3SSergey Temerkhanov * 6862ffd87d3SSergey Temerkhanov * Allocates a package buffer and returns a pointer to the buffer header. 6872ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 6882ffd87d3SSergey Temerkhanov */ 6892ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw) 6902ffd87d3SSergey Temerkhanov { 6912ffd87d3SSergey Temerkhanov struct ice_buf_build *bld; 6922ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 6932ffd87d3SSergey Temerkhanov 6942ffd87d3SSergey Temerkhanov bld = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*bld), GFP_KERNEL); 6952ffd87d3SSergey Temerkhanov if (!bld) 6962ffd87d3SSergey Temerkhanov return NULL; 6972ffd87d3SSergey Temerkhanov 6982ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)bld; 6992ffd87d3SSergey Temerkhanov buf->data_end = 7002ffd87d3SSergey Temerkhanov cpu_to_le16(offsetof(struct ice_buf_hdr, section_entry)); 7012ffd87d3SSergey Temerkhanov return bld; 7022ffd87d3SSergey Temerkhanov } 7032ffd87d3SSergey Temerkhanov 7042ffd87d3SSergey Temerkhanov static bool ice_is_gtp_u_profile(u16 prof_idx) 7052ffd87d3SSergey Temerkhanov { 7062ffd87d3SSergey Temerkhanov return (prof_idx >= ICE_PROFID_IPV6_GTPU_TEID && 7072ffd87d3SSergey Temerkhanov prof_idx <= ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER) || 7082ffd87d3SSergey Temerkhanov prof_idx == ICE_PROFID_IPV4_GTPU_TEID; 7092ffd87d3SSergey Temerkhanov } 7102ffd87d3SSergey Temerkhanov 7112ffd87d3SSergey Temerkhanov static bool ice_is_gtp_c_profile(u16 prof_idx) 7122ffd87d3SSergey Temerkhanov { 7132ffd87d3SSergey Temerkhanov switch (prof_idx) { 7142ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV4_GTPC_TEID: 7152ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV4_GTPC_NO_TEID: 7162ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV6_GTPC_TEID: 7172ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV6_GTPC_NO_TEID: 7182ffd87d3SSergey Temerkhanov return true; 7192ffd87d3SSergey Temerkhanov default: 7202ffd87d3SSergey Temerkhanov return false; 7212ffd87d3SSergey Temerkhanov } 7222ffd87d3SSergey Temerkhanov } 7232ffd87d3SSergey Temerkhanov 724*784feaa6SMarcin Szycik static bool ice_is_pfcp_profile(u16 prof_idx) 725*784feaa6SMarcin Szycik { 726*784feaa6SMarcin Szycik return prof_idx >= ICE_PROFID_IPV4_PFCP_NODE && 727*784feaa6SMarcin Szycik prof_idx <= ICE_PROFID_IPV6_PFCP_SESSION; 728*784feaa6SMarcin Szycik } 729*784feaa6SMarcin Szycik 7302ffd87d3SSergey Temerkhanov /** 7312ffd87d3SSergey Temerkhanov * ice_get_sw_prof_type - determine switch profile type 7322ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 7332ffd87d3SSergey Temerkhanov * @fv: pointer to the switch field vector 7342ffd87d3SSergey Temerkhanov * @prof_idx: profile index to check 7352ffd87d3SSergey Temerkhanov */ 7362ffd87d3SSergey Temerkhanov static enum ice_prof_type ice_get_sw_prof_type(struct ice_hw *hw, 7372ffd87d3SSergey Temerkhanov struct ice_fv *fv, u32 prof_idx) 7382ffd87d3SSergey Temerkhanov { 7392ffd87d3SSergey Temerkhanov u16 i; 7402ffd87d3SSergey Temerkhanov 7412ffd87d3SSergey Temerkhanov if (ice_is_gtp_c_profile(prof_idx)) 7422ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GTPC; 7432ffd87d3SSergey Temerkhanov 7442ffd87d3SSergey Temerkhanov if (ice_is_gtp_u_profile(prof_idx)) 7452ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GTPU; 7462ffd87d3SSergey Temerkhanov 747*784feaa6SMarcin Szycik if (ice_is_pfcp_profile(prof_idx)) 748*784feaa6SMarcin Szycik return ICE_PROF_TUN_PFCP; 749*784feaa6SMarcin Szycik 7502ffd87d3SSergey Temerkhanov for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) { 7512ffd87d3SSergey Temerkhanov /* UDP tunnel will have UDP_OF protocol ID and VNI offset */ 7522ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF && 7532ffd87d3SSergey Temerkhanov fv->ew[i].off == ICE_VNI_OFFSET) 7542ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_UDP; 7552ffd87d3SSergey Temerkhanov 7562ffd87d3SSergey Temerkhanov /* GRE tunnel will have GRE protocol */ 7572ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == (u8)ICE_PROT_GRE_OF) 7582ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GRE; 7592ffd87d3SSergey Temerkhanov } 7602ffd87d3SSergey Temerkhanov 7612ffd87d3SSergey Temerkhanov return ICE_PROF_NON_TUN; 7622ffd87d3SSergey Temerkhanov } 7632ffd87d3SSergey Temerkhanov 7642ffd87d3SSergey Temerkhanov /** 7652ffd87d3SSergey Temerkhanov * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type 7662ffd87d3SSergey Temerkhanov * @hw: pointer to hardware structure 7672ffd87d3SSergey Temerkhanov * @req_profs: type of profiles requested 7682ffd87d3SSergey Temerkhanov * @bm: pointer to memory for returning the bitmap of field vectors 7692ffd87d3SSergey Temerkhanov */ 7702ffd87d3SSergey Temerkhanov void ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs, 7712ffd87d3SSergey Temerkhanov unsigned long *bm) 7722ffd87d3SSergey Temerkhanov { 7732ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 7742ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 7752ffd87d3SSergey Temerkhanov struct ice_fv *fv; 7762ffd87d3SSergey Temerkhanov 7772ffd87d3SSergey Temerkhanov if (req_profs == ICE_PROF_ALL) { 7782ffd87d3SSergey Temerkhanov bitmap_set(bm, 0, ICE_MAX_NUM_PROFILES); 7792ffd87d3SSergey Temerkhanov return; 7802ffd87d3SSergey Temerkhanov } 7812ffd87d3SSergey Temerkhanov 7822ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 7832ffd87d3SSergey Temerkhanov bitmap_zero(bm, ICE_MAX_NUM_PROFILES); 7842ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 7852ffd87d3SSergey Temerkhanov do { 7862ffd87d3SSergey Temerkhanov enum ice_prof_type prof_type; 7872ffd87d3SSergey Temerkhanov u32 offset; 7882ffd87d3SSergey Temerkhanov 7892ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 7902ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler); 7912ffd87d3SSergey Temerkhanov ice_seg = NULL; 7922ffd87d3SSergey Temerkhanov 7932ffd87d3SSergey Temerkhanov if (fv) { 7942ffd87d3SSergey Temerkhanov /* Determine field vector type */ 7952ffd87d3SSergey Temerkhanov prof_type = ice_get_sw_prof_type(hw, fv, offset); 7962ffd87d3SSergey Temerkhanov 7972ffd87d3SSergey Temerkhanov if (req_profs & prof_type) 7982ffd87d3SSergey Temerkhanov set_bit((u16)offset, bm); 7992ffd87d3SSergey Temerkhanov } 8002ffd87d3SSergey Temerkhanov } while (fv); 8012ffd87d3SSergey Temerkhanov } 8022ffd87d3SSergey Temerkhanov 8032ffd87d3SSergey Temerkhanov /** 8042ffd87d3SSergey Temerkhanov * ice_get_sw_fv_list 8052ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 8062ffd87d3SSergey Temerkhanov * @lkups: list of protocol types 8072ffd87d3SSergey Temerkhanov * @bm: bitmap of field vectors to consider 8082ffd87d3SSergey Temerkhanov * @fv_list: Head of a list 8092ffd87d3SSergey Temerkhanov * 8102ffd87d3SSergey Temerkhanov * Finds all the field vector entries from switch block that contain 8112ffd87d3SSergey Temerkhanov * a given protocol ID and offset and returns a list of structures of type 8122ffd87d3SSergey Temerkhanov * "ice_sw_fv_list_entry". Every structure in the list has a field vector 8132ffd87d3SSergey Temerkhanov * definition and profile ID information 8142ffd87d3SSergey Temerkhanov * NOTE: The caller of the function is responsible for freeing the memory 8152ffd87d3SSergey Temerkhanov * allocated for every list entry. 8162ffd87d3SSergey Temerkhanov */ 8172ffd87d3SSergey Temerkhanov int ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups, 8182ffd87d3SSergey Temerkhanov unsigned long *bm, struct list_head *fv_list) 8192ffd87d3SSergey Temerkhanov { 8202ffd87d3SSergey Temerkhanov struct ice_sw_fv_list_entry *fvl; 8212ffd87d3SSergey Temerkhanov struct ice_sw_fv_list_entry *tmp; 8222ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 8232ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 8242ffd87d3SSergey Temerkhanov struct ice_fv *fv; 8252ffd87d3SSergey Temerkhanov u32 offset; 8262ffd87d3SSergey Temerkhanov 8272ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 8282ffd87d3SSergey Temerkhanov 8292ffd87d3SSergey Temerkhanov if (!lkups->n_val_words || !hw->seg) 8302ffd87d3SSergey Temerkhanov return -EINVAL; 8312ffd87d3SSergey Temerkhanov 8322ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 8332ffd87d3SSergey Temerkhanov do { 8342ffd87d3SSergey Temerkhanov u16 i; 8352ffd87d3SSergey Temerkhanov 8362ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 8372ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler); 8382ffd87d3SSergey Temerkhanov if (!fv) 8392ffd87d3SSergey Temerkhanov break; 8402ffd87d3SSergey Temerkhanov ice_seg = NULL; 8412ffd87d3SSergey Temerkhanov 8422ffd87d3SSergey Temerkhanov /* If field vector is not in the bitmap list, then skip this 8432ffd87d3SSergey Temerkhanov * profile. 8442ffd87d3SSergey Temerkhanov */ 8452ffd87d3SSergey Temerkhanov if (!test_bit((u16)offset, bm)) 8462ffd87d3SSergey Temerkhanov continue; 8472ffd87d3SSergey Temerkhanov 8482ffd87d3SSergey Temerkhanov for (i = 0; i < lkups->n_val_words; i++) { 8492ffd87d3SSergey Temerkhanov int j; 8502ffd87d3SSergey Temerkhanov 8512ffd87d3SSergey Temerkhanov for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) 8522ffd87d3SSergey Temerkhanov if (fv->ew[j].prot_id == 8532ffd87d3SSergey Temerkhanov lkups->fv_words[i].prot_id && 8542ffd87d3SSergey Temerkhanov fv->ew[j].off == lkups->fv_words[i].off) 8552ffd87d3SSergey Temerkhanov break; 8562ffd87d3SSergey Temerkhanov if (j >= hw->blk[ICE_BLK_SW].es.fvw) 8572ffd87d3SSergey Temerkhanov break; 8582ffd87d3SSergey Temerkhanov if (i + 1 == lkups->n_val_words) { 8592ffd87d3SSergey Temerkhanov fvl = devm_kzalloc(ice_hw_to_dev(hw), 8602ffd87d3SSergey Temerkhanov sizeof(*fvl), GFP_KERNEL); 8612ffd87d3SSergey Temerkhanov if (!fvl) 8622ffd87d3SSergey Temerkhanov goto err; 8632ffd87d3SSergey Temerkhanov fvl->fv_ptr = fv; 8642ffd87d3SSergey Temerkhanov fvl->profile_id = offset; 8652ffd87d3SSergey Temerkhanov list_add(&fvl->list_entry, fv_list); 8662ffd87d3SSergey Temerkhanov break; 8672ffd87d3SSergey Temerkhanov } 8682ffd87d3SSergey Temerkhanov } 8692ffd87d3SSergey Temerkhanov } while (fv); 8702ffd87d3SSergey Temerkhanov if (list_empty(fv_list)) { 8712ffd87d3SSergey Temerkhanov dev_warn(ice_hw_to_dev(hw), 8722ffd87d3SSergey Temerkhanov "Required profiles not found in currently loaded DDP package"); 8732ffd87d3SSergey Temerkhanov return -EIO; 8742ffd87d3SSergey Temerkhanov } 8752ffd87d3SSergey Temerkhanov 8762ffd87d3SSergey Temerkhanov return 0; 8772ffd87d3SSergey Temerkhanov 8782ffd87d3SSergey Temerkhanov err: 8792ffd87d3SSergey Temerkhanov list_for_each_entry_safe(fvl, tmp, fv_list, list_entry) { 8802ffd87d3SSergey Temerkhanov list_del(&fvl->list_entry); 8812ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), fvl); 8822ffd87d3SSergey Temerkhanov } 8832ffd87d3SSergey Temerkhanov 8842ffd87d3SSergey Temerkhanov return -ENOMEM; 8852ffd87d3SSergey Temerkhanov } 8862ffd87d3SSergey Temerkhanov 8872ffd87d3SSergey Temerkhanov /** 8882ffd87d3SSergey Temerkhanov * ice_init_prof_result_bm - Initialize the profile result index bitmap 8892ffd87d3SSergey Temerkhanov * @hw: pointer to hardware structure 8902ffd87d3SSergey Temerkhanov */ 8912ffd87d3SSergey Temerkhanov void ice_init_prof_result_bm(struct ice_hw *hw) 8922ffd87d3SSergey Temerkhanov { 8932ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 8942ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 8952ffd87d3SSergey Temerkhanov struct ice_fv *fv; 8962ffd87d3SSergey Temerkhanov 8972ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 8982ffd87d3SSergey Temerkhanov 8992ffd87d3SSergey Temerkhanov if (!hw->seg) 9002ffd87d3SSergey Temerkhanov return; 9012ffd87d3SSergey Temerkhanov 9022ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 9032ffd87d3SSergey Temerkhanov do { 9042ffd87d3SSergey Temerkhanov u32 off; 9052ffd87d3SSergey Temerkhanov u16 i; 9062ffd87d3SSergey Temerkhanov 9072ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 9082ffd87d3SSergey Temerkhanov &off, ice_sw_fv_handler); 9092ffd87d3SSergey Temerkhanov ice_seg = NULL; 9102ffd87d3SSergey Temerkhanov if (!fv) 9112ffd87d3SSergey Temerkhanov break; 9122ffd87d3SSergey Temerkhanov 9132ffd87d3SSergey Temerkhanov bitmap_zero(hw->switch_info->prof_res_bm[off], 9142ffd87d3SSergey Temerkhanov ICE_MAX_FV_WORDS); 9152ffd87d3SSergey Temerkhanov 9162ffd87d3SSergey Temerkhanov /* Determine empty field vector indices, these can be 9172ffd87d3SSergey Temerkhanov * used for recipe results. Skip index 0, since it is 9182ffd87d3SSergey Temerkhanov * always used for Switch ID. 9192ffd87d3SSergey Temerkhanov */ 9202ffd87d3SSergey Temerkhanov for (i = 1; i < ICE_MAX_FV_WORDS; i++) 9212ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == ICE_PROT_INVALID && 9222ffd87d3SSergey Temerkhanov fv->ew[i].off == ICE_FV_OFFSET_INVAL) 9232ffd87d3SSergey Temerkhanov set_bit(i, hw->switch_info->prof_res_bm[off]); 9242ffd87d3SSergey Temerkhanov } while (fv); 9252ffd87d3SSergey Temerkhanov } 9262ffd87d3SSergey Temerkhanov 9272ffd87d3SSergey Temerkhanov /** 9282ffd87d3SSergey Temerkhanov * ice_pkg_buf_free 9292ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 9302ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 9312ffd87d3SSergey Temerkhanov * 9322ffd87d3SSergey Temerkhanov * Frees a package buffer 9332ffd87d3SSergey Temerkhanov */ 9342ffd87d3SSergey Temerkhanov void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld) 9352ffd87d3SSergey Temerkhanov { 9362ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), bld); 9372ffd87d3SSergey Temerkhanov } 9382ffd87d3SSergey Temerkhanov 9392ffd87d3SSergey Temerkhanov /** 9402ffd87d3SSergey Temerkhanov * ice_pkg_buf_reserve_section 9412ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 9422ffd87d3SSergey Temerkhanov * @count: the number of sections to reserve 9432ffd87d3SSergey Temerkhanov * 9442ffd87d3SSergey Temerkhanov * Reserves one or more section table entries in a package buffer. This routine 9452ffd87d3SSergey Temerkhanov * can be called multiple times as long as they are made before calling 9462ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section() 9472ffd87d3SSergey Temerkhanov * is called once, the number of sections that can be allocated will not be able 9482ffd87d3SSergey Temerkhanov * to be increased; not using all reserved sections is fine, but this will 9492ffd87d3SSergey Temerkhanov * result in some wasted space in the buffer. 9502ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 9512ffd87d3SSergey Temerkhanov */ 9522ffd87d3SSergey Temerkhanov int ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count) 9532ffd87d3SSergey Temerkhanov { 9542ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 9552ffd87d3SSergey Temerkhanov u16 section_count; 9562ffd87d3SSergey Temerkhanov u16 data_end; 9572ffd87d3SSergey Temerkhanov 9582ffd87d3SSergey Temerkhanov if (!bld) 9592ffd87d3SSergey Temerkhanov return -EINVAL; 9602ffd87d3SSergey Temerkhanov 9612ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf; 9622ffd87d3SSergey Temerkhanov 9632ffd87d3SSergey Temerkhanov /* already an active section, can't increase table size */ 9642ffd87d3SSergey Temerkhanov section_count = le16_to_cpu(buf->section_count); 9652ffd87d3SSergey Temerkhanov if (section_count > 0) 9662ffd87d3SSergey Temerkhanov return -EIO; 9672ffd87d3SSergey Temerkhanov 9682ffd87d3SSergey Temerkhanov if (bld->reserved_section_table_entries + count > ICE_MAX_S_COUNT) 9692ffd87d3SSergey Temerkhanov return -EIO; 9702ffd87d3SSergey Temerkhanov bld->reserved_section_table_entries += count; 9712ffd87d3SSergey Temerkhanov 9722ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(buf->data_end) + 9732ffd87d3SSergey Temerkhanov flex_array_size(buf, section_entry, count); 9742ffd87d3SSergey Temerkhanov buf->data_end = cpu_to_le16(data_end); 9752ffd87d3SSergey Temerkhanov 9762ffd87d3SSergey Temerkhanov return 0; 9772ffd87d3SSergey Temerkhanov } 9782ffd87d3SSergey Temerkhanov 9792ffd87d3SSergey Temerkhanov /** 9802ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_section 9812ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 9822ffd87d3SSergey Temerkhanov * @type: the section type value 9832ffd87d3SSergey Temerkhanov * @size: the size of the section to reserve (in bytes) 9842ffd87d3SSergey Temerkhanov * 9852ffd87d3SSergey Temerkhanov * Reserves memory in the buffer for a section's content and updates the 9862ffd87d3SSergey Temerkhanov * buffers' status accordingly. This routine returns a pointer to the first 9872ffd87d3SSergey Temerkhanov * byte of the section start within the buffer, which is used to fill in the 9882ffd87d3SSergey Temerkhanov * section contents. 9892ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 9902ffd87d3SSergey Temerkhanov */ 9912ffd87d3SSergey Temerkhanov void *ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size) 9922ffd87d3SSergey Temerkhanov { 9932ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 9942ffd87d3SSergey Temerkhanov u16 sect_count; 9952ffd87d3SSergey Temerkhanov u16 data_end; 9962ffd87d3SSergey Temerkhanov 9972ffd87d3SSergey Temerkhanov if (!bld || !type || !size) 9982ffd87d3SSergey Temerkhanov return NULL; 9992ffd87d3SSergey Temerkhanov 10002ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf; 10012ffd87d3SSergey Temerkhanov 10022ffd87d3SSergey Temerkhanov /* check for enough space left in buffer */ 10032ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(buf->data_end); 10042ffd87d3SSergey Temerkhanov 10052ffd87d3SSergey Temerkhanov /* section start must align on 4 byte boundary */ 10062ffd87d3SSergey Temerkhanov data_end = ALIGN(data_end, 4); 10072ffd87d3SSergey Temerkhanov 10082ffd87d3SSergey Temerkhanov if ((data_end + size) > ICE_MAX_S_DATA_END) 10092ffd87d3SSergey Temerkhanov return NULL; 10102ffd87d3SSergey Temerkhanov 10112ffd87d3SSergey Temerkhanov /* check for more available section table entries */ 10122ffd87d3SSergey Temerkhanov sect_count = le16_to_cpu(buf->section_count); 10132ffd87d3SSergey Temerkhanov if (sect_count < bld->reserved_section_table_entries) { 10142ffd87d3SSergey Temerkhanov void *section_ptr = ((u8 *)buf) + data_end; 10152ffd87d3SSergey Temerkhanov 10162ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].offset = cpu_to_le16(data_end); 10172ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].size = cpu_to_le16(size); 10182ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].type = cpu_to_le32(type); 10192ffd87d3SSergey Temerkhanov 10202ffd87d3SSergey Temerkhanov data_end += size; 10212ffd87d3SSergey Temerkhanov buf->data_end = cpu_to_le16(data_end); 10222ffd87d3SSergey Temerkhanov 10232ffd87d3SSergey Temerkhanov buf->section_count = cpu_to_le16(sect_count + 1); 10242ffd87d3SSergey Temerkhanov return section_ptr; 10252ffd87d3SSergey Temerkhanov } 10262ffd87d3SSergey Temerkhanov 10272ffd87d3SSergey Temerkhanov /* no free section table entries */ 10282ffd87d3SSergey Temerkhanov return NULL; 10292ffd87d3SSergey Temerkhanov } 10302ffd87d3SSergey Temerkhanov 10312ffd87d3SSergey Temerkhanov /** 10322ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_single_section 10332ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 10342ffd87d3SSergey Temerkhanov * @type: the section type value 10352ffd87d3SSergey Temerkhanov * @size: the size of the section to reserve (in bytes) 10362ffd87d3SSergey Temerkhanov * @section: returns pointer to the section 10372ffd87d3SSergey Temerkhanov * 10382ffd87d3SSergey Temerkhanov * Allocates a package buffer with a single section. 10392ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 10402ffd87d3SSergey Temerkhanov */ 10412ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc_single_section(struct ice_hw *hw, 10422ffd87d3SSergey Temerkhanov u32 type, u16 size, 10432ffd87d3SSergey Temerkhanov void **section) 10442ffd87d3SSergey Temerkhanov { 10452ffd87d3SSergey Temerkhanov struct ice_buf_build *buf; 10462ffd87d3SSergey Temerkhanov 10472ffd87d3SSergey Temerkhanov if (!section) 10482ffd87d3SSergey Temerkhanov return NULL; 10492ffd87d3SSergey Temerkhanov 10502ffd87d3SSergey Temerkhanov buf = ice_pkg_buf_alloc(hw); 10512ffd87d3SSergey Temerkhanov if (!buf) 10522ffd87d3SSergey Temerkhanov return NULL; 10532ffd87d3SSergey Temerkhanov 10542ffd87d3SSergey Temerkhanov if (ice_pkg_buf_reserve_section(buf, 1)) 10552ffd87d3SSergey Temerkhanov goto ice_pkg_buf_alloc_single_section_err; 10562ffd87d3SSergey Temerkhanov 10572ffd87d3SSergey Temerkhanov *section = ice_pkg_buf_alloc_section(buf, type, size); 10582ffd87d3SSergey Temerkhanov if (!*section) 10592ffd87d3SSergey Temerkhanov goto ice_pkg_buf_alloc_single_section_err; 10602ffd87d3SSergey Temerkhanov 10612ffd87d3SSergey Temerkhanov return buf; 10622ffd87d3SSergey Temerkhanov 10632ffd87d3SSergey Temerkhanov ice_pkg_buf_alloc_single_section_err: 10642ffd87d3SSergey Temerkhanov ice_pkg_buf_free(hw, buf); 10652ffd87d3SSergey Temerkhanov return NULL; 10662ffd87d3SSergey Temerkhanov } 10672ffd87d3SSergey Temerkhanov 10682ffd87d3SSergey Temerkhanov /** 10692ffd87d3SSergey Temerkhanov * ice_pkg_buf_get_active_sections 10702ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 10712ffd87d3SSergey Temerkhanov * 10722ffd87d3SSergey Temerkhanov * Returns the number of active sections. Before using the package buffer 10732ffd87d3SSergey Temerkhanov * in an update package command, the caller should make sure that there is at 10742ffd87d3SSergey Temerkhanov * least one active section - otherwise, the buffer is not legal and should 10752ffd87d3SSergey Temerkhanov * not be used. 10762ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 10772ffd87d3SSergey Temerkhanov */ 10782ffd87d3SSergey Temerkhanov u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld) 10792ffd87d3SSergey Temerkhanov { 10802ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 10812ffd87d3SSergey Temerkhanov 10822ffd87d3SSergey Temerkhanov if (!bld) 10832ffd87d3SSergey Temerkhanov return 0; 10842ffd87d3SSergey Temerkhanov 10852ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf; 10862ffd87d3SSergey Temerkhanov return le16_to_cpu(buf->section_count); 10872ffd87d3SSergey Temerkhanov } 10882ffd87d3SSergey Temerkhanov 10892ffd87d3SSergey Temerkhanov /** 10902ffd87d3SSergey Temerkhanov * ice_pkg_buf 10912ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 10922ffd87d3SSergey Temerkhanov * 10932ffd87d3SSergey Temerkhanov * Return a pointer to the buffer's header 10942ffd87d3SSergey Temerkhanov */ 10952ffd87d3SSergey Temerkhanov struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld) 10962ffd87d3SSergey Temerkhanov { 10972ffd87d3SSergey Temerkhanov if (!bld) 10982ffd87d3SSergey Temerkhanov return NULL; 10992ffd87d3SSergey Temerkhanov 11002ffd87d3SSergey Temerkhanov return &bld->buf; 11012ffd87d3SSergey Temerkhanov } 11022ffd87d3SSergey Temerkhanov 11032ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_map_aq_err_to_ddp_state(enum ice_aq_err aq_err) 11042ffd87d3SSergey Temerkhanov { 11052ffd87d3SSergey Temerkhanov switch (aq_err) { 11062ffd87d3SSergey Temerkhanov case ICE_AQ_RC_ENOSEC: 11072ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADSIG: 11082ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_SIGNATURE_INVALID; 11092ffd87d3SSergey Temerkhanov case ICE_AQ_RC_ESVN: 11102ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_REVISION_TOO_LOW; 11112ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADMAN: 11122ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADBUF: 11132ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_LOAD_ERROR; 11142ffd87d3SSergey Temerkhanov default: 11152ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 11162ffd87d3SSergey Temerkhanov } 11172ffd87d3SSergey Temerkhanov } 11182ffd87d3SSergey Temerkhanov 11192ffd87d3SSergey Temerkhanov /** 11202ffd87d3SSergey Temerkhanov * ice_acquire_global_cfg_lock 11212ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 11222ffd87d3SSergey Temerkhanov * @access: access type (read or write) 11232ffd87d3SSergey Temerkhanov * 11242ffd87d3SSergey Temerkhanov * This function will request ownership of the global config lock for reading 11252ffd87d3SSergey Temerkhanov * or writing of the package. When attempting to obtain write access, the 11262ffd87d3SSergey Temerkhanov * caller must check for the following two return values: 11272ffd87d3SSergey Temerkhanov * 11282ffd87d3SSergey Temerkhanov * 0 - Means the caller has acquired the global config lock 11292ffd87d3SSergey Temerkhanov * and can perform writing of the package. 11302ffd87d3SSergey Temerkhanov * -EALREADY - Indicates another driver has already written the 11312ffd87d3SSergey Temerkhanov * package or has found that no update was necessary; in 11322ffd87d3SSergey Temerkhanov * this case, the caller can just skip performing any 11332ffd87d3SSergey Temerkhanov * update of the package. 11342ffd87d3SSergey Temerkhanov */ 11352ffd87d3SSergey Temerkhanov static int ice_acquire_global_cfg_lock(struct ice_hw *hw, 11362ffd87d3SSergey Temerkhanov enum ice_aq_res_access_type access) 11372ffd87d3SSergey Temerkhanov { 11382ffd87d3SSergey Temerkhanov int status; 11392ffd87d3SSergey Temerkhanov 11402ffd87d3SSergey Temerkhanov status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, access, 11412ffd87d3SSergey Temerkhanov ICE_GLOBAL_CFG_LOCK_TIMEOUT); 11422ffd87d3SSergey Temerkhanov 11432ffd87d3SSergey Temerkhanov if (!status) 11442ffd87d3SSergey Temerkhanov mutex_lock(&ice_global_cfg_lock_sw); 11452ffd87d3SSergey Temerkhanov else if (status == -EALREADY) 11462ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, 11472ffd87d3SSergey Temerkhanov "Global config lock: No work to do\n"); 11482ffd87d3SSergey Temerkhanov 11492ffd87d3SSergey Temerkhanov return status; 11502ffd87d3SSergey Temerkhanov } 11512ffd87d3SSergey Temerkhanov 11522ffd87d3SSergey Temerkhanov /** 11532ffd87d3SSergey Temerkhanov * ice_release_global_cfg_lock 11542ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 11552ffd87d3SSergey Temerkhanov * 11562ffd87d3SSergey Temerkhanov * This function will release the global config lock. 11572ffd87d3SSergey Temerkhanov */ 11582ffd87d3SSergey Temerkhanov static void ice_release_global_cfg_lock(struct ice_hw *hw) 11592ffd87d3SSergey Temerkhanov { 11602ffd87d3SSergey Temerkhanov mutex_unlock(&ice_global_cfg_lock_sw); 11612ffd87d3SSergey Temerkhanov ice_release_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID); 11622ffd87d3SSergey Temerkhanov } 11632ffd87d3SSergey Temerkhanov 11642ffd87d3SSergey Temerkhanov /** 1165708b352fSJan Sokolowski * ice_aq_download_pkg 1166708b352fSJan Sokolowski * @hw: pointer to the hardware structure 1167708b352fSJan Sokolowski * @pkg_buf: the package buffer to transfer 1168708b352fSJan Sokolowski * @buf_size: the size of the package buffer 1169708b352fSJan Sokolowski * @last_buf: last buffer indicator 1170708b352fSJan Sokolowski * @error_offset: returns error offset 1171708b352fSJan Sokolowski * @error_info: returns error information 1172708b352fSJan Sokolowski * @cd: pointer to command details structure or NULL 1173708b352fSJan Sokolowski * 1174708b352fSJan Sokolowski * Download Package (0x0C40) 1175708b352fSJan Sokolowski */ 1176708b352fSJan Sokolowski static int 1177708b352fSJan Sokolowski ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 1178708b352fSJan Sokolowski u16 buf_size, bool last_buf, u32 *error_offset, 1179708b352fSJan Sokolowski u32 *error_info, struct ice_sq_cd *cd) 1180708b352fSJan Sokolowski { 1181708b352fSJan Sokolowski struct ice_aqc_download_pkg *cmd; 1182708b352fSJan Sokolowski struct ice_aq_desc desc; 1183708b352fSJan Sokolowski int status; 1184708b352fSJan Sokolowski 1185708b352fSJan Sokolowski if (error_offset) 1186708b352fSJan Sokolowski *error_offset = 0; 1187708b352fSJan Sokolowski if (error_info) 1188708b352fSJan Sokolowski *error_info = 0; 1189708b352fSJan Sokolowski 1190708b352fSJan Sokolowski cmd = &desc.params.download_pkg; 1191708b352fSJan Sokolowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg); 1192708b352fSJan Sokolowski desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 1193708b352fSJan Sokolowski 1194708b352fSJan Sokolowski if (last_buf) 1195708b352fSJan Sokolowski cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF; 1196708b352fSJan Sokolowski 1197708b352fSJan Sokolowski status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd); 1198708b352fSJan Sokolowski if (status == -EIO) { 1199708b352fSJan Sokolowski /* Read error from buffer only when the FW returned an error */ 1200708b352fSJan Sokolowski struct ice_aqc_download_pkg_resp *resp; 1201708b352fSJan Sokolowski 1202708b352fSJan Sokolowski resp = (struct ice_aqc_download_pkg_resp *)pkg_buf; 1203708b352fSJan Sokolowski if (error_offset) 1204708b352fSJan Sokolowski *error_offset = le32_to_cpu(resp->error_offset); 1205708b352fSJan Sokolowski if (error_info) 1206708b352fSJan Sokolowski *error_info = le32_to_cpu(resp->error_info); 1207708b352fSJan Sokolowski } 1208708b352fSJan Sokolowski 1209708b352fSJan Sokolowski return status; 1210708b352fSJan Sokolowski } 1211708b352fSJan Sokolowski 1212708b352fSJan Sokolowski /** 12133cbdb034SDan Nowlin * ice_get_pkg_seg_by_idx 12143cbdb034SDan Nowlin * @pkg_hdr: pointer to the package header to be searched 12153cbdb034SDan Nowlin * @idx: index of segment 12163cbdb034SDan Nowlin */ 12173cbdb034SDan Nowlin static struct ice_generic_seg_hdr * 12183cbdb034SDan Nowlin ice_get_pkg_seg_by_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx) 12193cbdb034SDan Nowlin { 12203cbdb034SDan Nowlin if (idx < le32_to_cpu(pkg_hdr->seg_count)) 12213cbdb034SDan Nowlin return (struct ice_generic_seg_hdr *) 12223cbdb034SDan Nowlin ((u8 *)pkg_hdr + 12233cbdb034SDan Nowlin le32_to_cpu(pkg_hdr->seg_offset[idx])); 12243cbdb034SDan Nowlin 12253cbdb034SDan Nowlin return NULL; 12263cbdb034SDan Nowlin } 12273cbdb034SDan Nowlin 12283cbdb034SDan Nowlin /** 12293cbdb034SDan Nowlin * ice_is_signing_seg_at_idx - determine if segment is a signing segment 12303cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 12313cbdb034SDan Nowlin * @idx: segment index 12323cbdb034SDan Nowlin */ 12333cbdb034SDan Nowlin static bool ice_is_signing_seg_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx) 12343cbdb034SDan Nowlin { 12353cbdb034SDan Nowlin struct ice_generic_seg_hdr *seg; 12363cbdb034SDan Nowlin 12373cbdb034SDan Nowlin seg = ice_get_pkg_seg_by_idx(pkg_hdr, idx); 12383cbdb034SDan Nowlin if (!seg) 12393cbdb034SDan Nowlin return false; 12403cbdb034SDan Nowlin 12413cbdb034SDan Nowlin return le32_to_cpu(seg->seg_type) == SEGMENT_TYPE_SIGNING; 12423cbdb034SDan Nowlin } 12433cbdb034SDan Nowlin 12443cbdb034SDan Nowlin /** 12453cbdb034SDan Nowlin * ice_is_signing_seg_type_at_idx 12463cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 12473cbdb034SDan Nowlin * @idx: segment index 12483cbdb034SDan Nowlin * @seg_id: segment id that is expected 12493cbdb034SDan Nowlin * @sign_type: signing type 12503cbdb034SDan Nowlin * 12513cbdb034SDan Nowlin * Determine if a segment is a signing segment of the correct type 12523cbdb034SDan Nowlin */ 12533cbdb034SDan Nowlin static bool 12543cbdb034SDan Nowlin ice_is_signing_seg_type_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx, 12553cbdb034SDan Nowlin u32 seg_id, u32 sign_type) 12563cbdb034SDan Nowlin { 12573cbdb034SDan Nowlin struct ice_sign_seg *seg; 12583cbdb034SDan Nowlin 12593cbdb034SDan Nowlin if (!ice_is_signing_seg_at_idx(pkg_hdr, idx)) 12603cbdb034SDan Nowlin return false; 12613cbdb034SDan Nowlin 12623cbdb034SDan Nowlin seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); 12633cbdb034SDan Nowlin 12643cbdb034SDan Nowlin if (seg && le32_to_cpu(seg->seg_id) == seg_id && 12653cbdb034SDan Nowlin le32_to_cpu(seg->sign_type) == sign_type) 12663cbdb034SDan Nowlin return true; 12673cbdb034SDan Nowlin 12683cbdb034SDan Nowlin return false; 12693cbdb034SDan Nowlin } 12703cbdb034SDan Nowlin 12713cbdb034SDan Nowlin /** 12723cbdb034SDan Nowlin * ice_is_buffer_metadata - determine if package buffer is a metadata buffer 12733cbdb034SDan Nowlin * @buf: pointer to buffer header 12743cbdb034SDan Nowlin */ 12753cbdb034SDan Nowlin static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf) 12763cbdb034SDan Nowlin { 12773cbdb034SDan Nowlin if (le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF) 12783cbdb034SDan Nowlin return true; 12793cbdb034SDan Nowlin 12803cbdb034SDan Nowlin return false; 12813cbdb034SDan Nowlin } 12823cbdb034SDan Nowlin 12833cbdb034SDan Nowlin /** 12843cbdb034SDan Nowlin * ice_is_last_download_buffer 12853cbdb034SDan Nowlin * @buf: pointer to current buffer header 12863cbdb034SDan Nowlin * @idx: index of the buffer in the current sequence 12873cbdb034SDan Nowlin * @count: the buffer count in the current sequence 12883cbdb034SDan Nowlin * 12893cbdb034SDan Nowlin * Note: this routine should only be called if the buffer is not the last buffer 12903cbdb034SDan Nowlin */ 12913cbdb034SDan Nowlin static bool 12923cbdb034SDan Nowlin ice_is_last_download_buffer(struct ice_buf_hdr *buf, u32 idx, u32 count) 12933cbdb034SDan Nowlin { 12943cbdb034SDan Nowlin struct ice_buf *next_buf; 12953cbdb034SDan Nowlin 12963cbdb034SDan Nowlin if ((idx + 1) == count) 12973cbdb034SDan Nowlin return true; 12983cbdb034SDan Nowlin 12993cbdb034SDan Nowlin /* A set metadata flag in the next buffer will signal that the current 13003cbdb034SDan Nowlin * buffer will be the last buffer downloaded 13013cbdb034SDan Nowlin */ 13023cbdb034SDan Nowlin next_buf = ((struct ice_buf *)buf) + 1; 13033cbdb034SDan Nowlin 13043cbdb034SDan Nowlin return ice_is_buffer_metadata((struct ice_buf_hdr *)next_buf); 13053cbdb034SDan Nowlin } 13063cbdb034SDan Nowlin 13073cbdb034SDan Nowlin /** 13083cbdb034SDan Nowlin * ice_dwnld_cfg_bufs_no_lock 13092ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 13102ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers 13113cbdb034SDan Nowlin * @start: buffer index of first buffer to download 13123cbdb034SDan Nowlin * @count: the number of buffers to download 13133cbdb034SDan Nowlin * @indicate_last: if true, then set last buffer flag on last buffer download 13142ffd87d3SSergey Temerkhanov * 13153cbdb034SDan Nowlin * Downloads package configuration buffers to the firmware. Metadata buffers 13163cbdb034SDan Nowlin * are skipped, and the first metadata buffer found indicates that the rest 13173cbdb034SDan Nowlin * of the buffers are all metadata buffers. 13182ffd87d3SSergey Temerkhanov */ 13193cbdb034SDan Nowlin static enum ice_ddp_state 13203cbdb034SDan Nowlin ice_dwnld_cfg_bufs_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 start, 13213cbdb034SDan Nowlin u32 count, bool indicate_last) 13222ffd87d3SSergey Temerkhanov { 13232ffd87d3SSergey Temerkhanov enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS; 13242ffd87d3SSergey Temerkhanov struct ice_buf_hdr *bh; 13252ffd87d3SSergey Temerkhanov enum ice_aq_err err; 13262ffd87d3SSergey Temerkhanov u32 offset, info, i; 13272ffd87d3SSergey Temerkhanov 13282ffd87d3SSergey Temerkhanov if (!bufs || !count) 13292ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 13302ffd87d3SSergey Temerkhanov 13312ffd87d3SSergey Temerkhanov /* If the first buffer's first section has its metadata bit set 13322ffd87d3SSergey Temerkhanov * then there are no buffers to be downloaded, and the operation is 13332ffd87d3SSergey Temerkhanov * considered a success. 13342ffd87d3SSergey Temerkhanov */ 13353cbdb034SDan Nowlin bh = (struct ice_buf_hdr *)(bufs + start); 13362ffd87d3SSergey Temerkhanov if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF) 13372ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 13382ffd87d3SSergey Temerkhanov 13392ffd87d3SSergey Temerkhanov for (i = 0; i < count; i++) { 13403cbdb034SDan Nowlin bool last = false; 13413cbdb034SDan Nowlin int status; 13422ffd87d3SSergey Temerkhanov 13433cbdb034SDan Nowlin bh = (struct ice_buf_hdr *)(bufs + start + i); 13442ffd87d3SSergey Temerkhanov 13453cbdb034SDan Nowlin if (indicate_last) 13463cbdb034SDan Nowlin last = ice_is_last_download_buffer(bh, i, count); 13472ffd87d3SSergey Temerkhanov 13482ffd87d3SSergey Temerkhanov status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE, last, 13492ffd87d3SSergey Temerkhanov &offset, &info, NULL); 13502ffd87d3SSergey Temerkhanov 13512ffd87d3SSergey Temerkhanov /* Save AQ status from download package */ 13522ffd87d3SSergey Temerkhanov if (status) { 13533cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n", 13542ffd87d3SSergey Temerkhanov status, offset, info); 13552ffd87d3SSergey Temerkhanov err = hw->adminq.sq_last_status; 13562ffd87d3SSergey Temerkhanov state = ice_map_aq_err_to_ddp_state(err); 13572ffd87d3SSergey Temerkhanov break; 13582ffd87d3SSergey Temerkhanov } 13592ffd87d3SSergey Temerkhanov 13602ffd87d3SSergey Temerkhanov if (last) 13612ffd87d3SSergey Temerkhanov break; 13622ffd87d3SSergey Temerkhanov } 13632ffd87d3SSergey Temerkhanov 13643cbdb034SDan Nowlin return state; 13652ffd87d3SSergey Temerkhanov } 13662ffd87d3SSergey Temerkhanov 13673cbdb034SDan Nowlin /** 13683cbdb034SDan Nowlin * ice_download_pkg_sig_seg - download a signature segment 13693cbdb034SDan Nowlin * @hw: pointer to the hardware structure 13703cbdb034SDan Nowlin * @seg: pointer to signature segment 13713cbdb034SDan Nowlin */ 13723cbdb034SDan Nowlin static enum ice_ddp_state 13733cbdb034SDan Nowlin ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg) 13743cbdb034SDan Nowlin { 13753cbdb034SDan Nowlin return ice_dwnld_cfg_bufs_no_lock(hw, seg->buf_tbl.buf_array, 0, 13763cbdb034SDan Nowlin le32_to_cpu(seg->buf_tbl.buf_count), 13773cbdb034SDan Nowlin false); 13783cbdb034SDan Nowlin } 13793cbdb034SDan Nowlin 13803cbdb034SDan Nowlin /** 13813cbdb034SDan Nowlin * ice_download_pkg_config_seg - download a config segment 13823cbdb034SDan Nowlin * @hw: pointer to the hardware structure 13833cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 13843cbdb034SDan Nowlin * @idx: segment index 13853cbdb034SDan Nowlin * @start: starting buffer 13863cbdb034SDan Nowlin * @count: buffer count 13873cbdb034SDan Nowlin * 13883cbdb034SDan Nowlin * Note: idx must reference a ICE segment 13893cbdb034SDan Nowlin */ 13903cbdb034SDan Nowlin static enum ice_ddp_state 13913cbdb034SDan Nowlin ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, 13923cbdb034SDan Nowlin u32 idx, u32 start, u32 count) 13933cbdb034SDan Nowlin { 13943cbdb034SDan Nowlin struct ice_buf_table *bufs; 13953cbdb034SDan Nowlin struct ice_seg *seg; 13963cbdb034SDan Nowlin u32 buf_count; 13973cbdb034SDan Nowlin 13983cbdb034SDan Nowlin seg = (struct ice_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); 13993cbdb034SDan Nowlin if (!seg) 14003cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 14013cbdb034SDan Nowlin 14023cbdb034SDan Nowlin bufs = ice_find_buf_table(seg); 14033cbdb034SDan Nowlin buf_count = le32_to_cpu(bufs->buf_count); 14043cbdb034SDan Nowlin 14053cbdb034SDan Nowlin if (start >= buf_count || start + count > buf_count) 14063cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 14073cbdb034SDan Nowlin 14083cbdb034SDan Nowlin return ice_dwnld_cfg_bufs_no_lock(hw, bufs->buf_array, start, count, 14093cbdb034SDan Nowlin true); 14103cbdb034SDan Nowlin } 14113cbdb034SDan Nowlin 14123cbdb034SDan Nowlin /** 14133cbdb034SDan Nowlin * ice_dwnld_sign_and_cfg_segs - download a signing segment and config segment 14143cbdb034SDan Nowlin * @hw: pointer to the hardware structure 14153cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 14163cbdb034SDan Nowlin * @idx: segment index (must be a signature segment) 14173cbdb034SDan Nowlin * 14183cbdb034SDan Nowlin * Note: idx must reference a signature segment 14193cbdb034SDan Nowlin */ 14203cbdb034SDan Nowlin static enum ice_ddp_state 14213cbdb034SDan Nowlin ice_dwnld_sign_and_cfg_segs(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, 14223cbdb034SDan Nowlin u32 idx) 14233cbdb034SDan Nowlin { 14243cbdb034SDan Nowlin enum ice_ddp_state state; 14253cbdb034SDan Nowlin struct ice_sign_seg *seg; 14263cbdb034SDan Nowlin u32 conf_idx; 14273cbdb034SDan Nowlin u32 start; 14283cbdb034SDan Nowlin u32 count; 14293cbdb034SDan Nowlin 14303cbdb034SDan Nowlin seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); 14313cbdb034SDan Nowlin if (!seg) { 14323cbdb034SDan Nowlin state = ICE_DDP_PKG_ERR; 14333cbdb034SDan Nowlin goto exit; 14343cbdb034SDan Nowlin } 14353cbdb034SDan Nowlin 14363cbdb034SDan Nowlin conf_idx = le32_to_cpu(seg->signed_seg_idx); 14373cbdb034SDan Nowlin start = le32_to_cpu(seg->signed_buf_start); 14383cbdb034SDan Nowlin count = le32_to_cpu(seg->signed_buf_count); 14393cbdb034SDan Nowlin 14403cbdb034SDan Nowlin state = ice_download_pkg_sig_seg(hw, seg); 14413cbdb034SDan Nowlin if (state) 14423cbdb034SDan Nowlin goto exit; 14433cbdb034SDan Nowlin 14443cbdb034SDan Nowlin state = ice_download_pkg_config_seg(hw, pkg_hdr, conf_idx, start, 14453cbdb034SDan Nowlin count); 14463cbdb034SDan Nowlin 14473cbdb034SDan Nowlin exit: 14483cbdb034SDan Nowlin return state; 14493cbdb034SDan Nowlin } 14503cbdb034SDan Nowlin 14513cbdb034SDan Nowlin /** 14523cbdb034SDan Nowlin * ice_match_signing_seg - determine if a matching signing segment exists 14533cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 14543cbdb034SDan Nowlin * @seg_id: segment id that is expected 14553cbdb034SDan Nowlin * @sign_type: signing type 14563cbdb034SDan Nowlin */ 14573cbdb034SDan Nowlin static bool 14583cbdb034SDan Nowlin ice_match_signing_seg(struct ice_pkg_hdr *pkg_hdr, u32 seg_id, u32 sign_type) 14593cbdb034SDan Nowlin { 14603cbdb034SDan Nowlin u32 i; 14613cbdb034SDan Nowlin 14623cbdb034SDan Nowlin for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { 14633cbdb034SDan Nowlin if (ice_is_signing_seg_type_at_idx(pkg_hdr, i, seg_id, 14643cbdb034SDan Nowlin sign_type)) 14653cbdb034SDan Nowlin return true; 14663cbdb034SDan Nowlin } 14673cbdb034SDan Nowlin 14683cbdb034SDan Nowlin return false; 14693cbdb034SDan Nowlin } 14703cbdb034SDan Nowlin 14713cbdb034SDan Nowlin /** 14723cbdb034SDan Nowlin * ice_post_dwnld_pkg_actions - perform post download package actions 14733cbdb034SDan Nowlin * @hw: pointer to the hardware structure 14743cbdb034SDan Nowlin */ 14753cbdb034SDan Nowlin static enum ice_ddp_state 14763cbdb034SDan Nowlin ice_post_dwnld_pkg_actions(struct ice_hw *hw) 14773cbdb034SDan Nowlin { 14783cbdb034SDan Nowlin int status; 14793cbdb034SDan Nowlin 14803cbdb034SDan Nowlin status = ice_set_vlan_mode(hw); 14813cbdb034SDan Nowlin if (status) { 14823cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Failed to set VLAN mode: err %d\n", 14833cbdb034SDan Nowlin status); 14843cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 14853cbdb034SDan Nowlin } 14863cbdb034SDan Nowlin 14873cbdb034SDan Nowlin return ICE_DDP_PKG_SUCCESS; 14883cbdb034SDan Nowlin } 14893cbdb034SDan Nowlin 14903cbdb034SDan Nowlin /** 1491a778616eSDan Nowlin * ice_download_pkg_with_sig_seg 14923cbdb034SDan Nowlin * @hw: pointer to the hardware structure 14933cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 14943cbdb034SDan Nowlin * 14953cbdb034SDan Nowlin * Handles the download of a complete package. 14963cbdb034SDan Nowlin */ 14973cbdb034SDan Nowlin static enum ice_ddp_state 1498a778616eSDan Nowlin ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) 14993cbdb034SDan Nowlin { 15003cbdb034SDan Nowlin enum ice_aq_err aq_err = hw->adminq.sq_last_status; 15013cbdb034SDan Nowlin enum ice_ddp_state state = ICE_DDP_PKG_ERR; 15023cbdb034SDan Nowlin int status; 15033cbdb034SDan Nowlin u32 i; 15043cbdb034SDan Nowlin 15053cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_INIT, "Segment ID %d\n", hw->pkg_seg_id); 15063cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_INIT, "Signature type %d\n", hw->pkg_sign_type); 15073cbdb034SDan Nowlin 15083cbdb034SDan Nowlin status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE); 15093cbdb034SDan Nowlin if (status) { 15103cbdb034SDan Nowlin if (status == -EALREADY) 15113cbdb034SDan Nowlin state = ICE_DDP_PKG_ALREADY_LOADED; 15123cbdb034SDan Nowlin else 15133cbdb034SDan Nowlin state = ice_map_aq_err_to_ddp_state(aq_err); 15143cbdb034SDan Nowlin return state; 15153cbdb034SDan Nowlin } 15163cbdb034SDan Nowlin 15173cbdb034SDan Nowlin for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { 15183cbdb034SDan Nowlin if (!ice_is_signing_seg_type_at_idx(pkg_hdr, i, hw->pkg_seg_id, 15193cbdb034SDan Nowlin hw->pkg_sign_type)) 15203cbdb034SDan Nowlin continue; 15213cbdb034SDan Nowlin 15223cbdb034SDan Nowlin state = ice_dwnld_sign_and_cfg_segs(hw, pkg_hdr, i); 15233cbdb034SDan Nowlin if (state) 15243cbdb034SDan Nowlin break; 15253cbdb034SDan Nowlin } 15263cbdb034SDan Nowlin 15273cbdb034SDan Nowlin if (!state) 15283cbdb034SDan Nowlin state = ice_post_dwnld_pkg_actions(hw); 15293cbdb034SDan Nowlin 15302ffd87d3SSergey Temerkhanov ice_release_global_cfg_lock(hw); 1531a778616eSDan Nowlin 1532a778616eSDan Nowlin return state; 1533a778616eSDan Nowlin } 1534a778616eSDan Nowlin 1535a778616eSDan Nowlin /** 1536a778616eSDan Nowlin * ice_dwnld_cfg_bufs 1537a778616eSDan Nowlin * @hw: pointer to the hardware structure 1538a778616eSDan Nowlin * @bufs: pointer to an array of buffers 1539a778616eSDan Nowlin * @count: the number of buffers in the array 1540a778616eSDan Nowlin * 1541a778616eSDan Nowlin * Obtains global config lock and downloads the package configuration buffers 1542a778616eSDan Nowlin * to the firmware. 1543a778616eSDan Nowlin */ 1544a778616eSDan Nowlin static enum ice_ddp_state 1545a778616eSDan Nowlin ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count) 1546a778616eSDan Nowlin { 1547a778616eSDan Nowlin enum ice_ddp_state state; 1548a778616eSDan Nowlin struct ice_buf_hdr *bh; 1549a778616eSDan Nowlin int status; 1550a778616eSDan Nowlin 1551a778616eSDan Nowlin if (!bufs || !count) 1552a778616eSDan Nowlin return ICE_DDP_PKG_ERR; 1553a778616eSDan Nowlin 1554a778616eSDan Nowlin /* If the first buffer's first section has its metadata bit set 1555a778616eSDan Nowlin * then there are no buffers to be downloaded, and the operation is 1556a778616eSDan Nowlin * considered a success. 1557a778616eSDan Nowlin */ 1558a778616eSDan Nowlin bh = (struct ice_buf_hdr *)bufs; 1559a778616eSDan Nowlin if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF) 1560a778616eSDan Nowlin return ICE_DDP_PKG_SUCCESS; 1561a778616eSDan Nowlin 1562a778616eSDan Nowlin status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE); 1563a778616eSDan Nowlin if (status) { 1564a778616eSDan Nowlin if (status == -EALREADY) 1565a778616eSDan Nowlin return ICE_DDP_PKG_ALREADY_LOADED; 1566a778616eSDan Nowlin return ice_map_aq_err_to_ddp_state(hw->adminq.sq_last_status); 1567a778616eSDan Nowlin } 1568a778616eSDan Nowlin 1569a778616eSDan Nowlin state = ice_dwnld_cfg_bufs_no_lock(hw, bufs, 0, count, true); 1570a778616eSDan Nowlin if (!state) 1571a778616eSDan Nowlin state = ice_post_dwnld_pkg_actions(hw); 1572a778616eSDan Nowlin 1573a778616eSDan Nowlin ice_release_global_cfg_lock(hw); 1574a778616eSDan Nowlin 1575a778616eSDan Nowlin return state; 1576a778616eSDan Nowlin } 1577a778616eSDan Nowlin 1578a778616eSDan Nowlin /** 1579a778616eSDan Nowlin * ice_download_pkg_without_sig_seg 1580a778616eSDan Nowlin * @hw: pointer to the hardware structure 1581a778616eSDan Nowlin * @ice_seg: pointer to the segment of the package to be downloaded 1582a778616eSDan Nowlin * 1583a778616eSDan Nowlin * Handles the download of a complete package without signature segment. 1584a778616eSDan Nowlin */ 1585a778616eSDan Nowlin static enum ice_ddp_state 1586a778616eSDan Nowlin ice_download_pkg_without_sig_seg(struct ice_hw *hw, struct ice_seg *ice_seg) 1587a778616eSDan Nowlin { 1588a778616eSDan Nowlin struct ice_buf_table *ice_buf_tbl; 1589a778616eSDan Nowlin 1590a778616eSDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n", 1591a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.major, 1592a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.minor, 1593a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.update, 1594a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.draft); 1595a778616eSDan Nowlin 1596a778616eSDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n", 1597a778616eSDan Nowlin le32_to_cpu(ice_seg->hdr.seg_type), 1598a778616eSDan Nowlin le32_to_cpu(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id); 1599a778616eSDan Nowlin 1600a778616eSDan Nowlin ice_buf_tbl = ice_find_buf_table(ice_seg); 1601a778616eSDan Nowlin 1602a778616eSDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Seg buf count: %d\n", 1603a778616eSDan Nowlin le32_to_cpu(ice_buf_tbl->buf_count)); 1604a778616eSDan Nowlin 1605a778616eSDan Nowlin return ice_dwnld_cfg_bufs(hw, ice_buf_tbl->buf_array, 1606a778616eSDan Nowlin le32_to_cpu(ice_buf_tbl->buf_count)); 1607a778616eSDan Nowlin } 1608a778616eSDan Nowlin 1609a778616eSDan Nowlin /** 1610a778616eSDan Nowlin * ice_download_pkg 1611a778616eSDan Nowlin * @hw: pointer to the hardware structure 1612a778616eSDan Nowlin * @pkg_hdr: pointer to package header 1613a778616eSDan Nowlin * @ice_seg: pointer to the segment of the package to be downloaded 1614a778616eSDan Nowlin * 1615a778616eSDan Nowlin * Handles the download of a complete package. 1616a778616eSDan Nowlin */ 1617a778616eSDan Nowlin static enum ice_ddp_state 1618a778616eSDan Nowlin ice_download_pkg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, 1619a778616eSDan Nowlin struct ice_seg *ice_seg) 1620a778616eSDan Nowlin { 1621a778616eSDan Nowlin enum ice_ddp_state state; 1622a778616eSDan Nowlin 1623a778616eSDan Nowlin if (hw->pkg_has_signing_seg) 1624a778616eSDan Nowlin state = ice_download_pkg_with_sig_seg(hw, pkg_hdr); 1625a778616eSDan Nowlin else 1626a778616eSDan Nowlin state = ice_download_pkg_without_sig_seg(hw, ice_seg); 1627a778616eSDan Nowlin 16283cbdb034SDan Nowlin ice_post_pkg_dwnld_vlan_mode_cfg(hw); 16292ffd87d3SSergey Temerkhanov 16302ffd87d3SSergey Temerkhanov return state; 16312ffd87d3SSergey Temerkhanov } 16322ffd87d3SSergey Temerkhanov 16332ffd87d3SSergey Temerkhanov /** 16342ffd87d3SSergey Temerkhanov * ice_aq_get_pkg_info_list 16352ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 16362ffd87d3SSergey Temerkhanov * @pkg_info: the buffer which will receive the information list 16372ffd87d3SSergey Temerkhanov * @buf_size: the size of the pkg_info information buffer 16382ffd87d3SSergey Temerkhanov * @cd: pointer to command details structure or NULL 16392ffd87d3SSergey Temerkhanov * 16402ffd87d3SSergey Temerkhanov * Get Package Info List (0x0C43) 16412ffd87d3SSergey Temerkhanov */ 16422ffd87d3SSergey Temerkhanov static int ice_aq_get_pkg_info_list(struct ice_hw *hw, 16432ffd87d3SSergey Temerkhanov struct ice_aqc_get_pkg_info_resp *pkg_info, 16442ffd87d3SSergey Temerkhanov u16 buf_size, struct ice_sq_cd *cd) 16452ffd87d3SSergey Temerkhanov { 16462ffd87d3SSergey Temerkhanov struct ice_aq_desc desc; 16472ffd87d3SSergey Temerkhanov 16482ffd87d3SSergey Temerkhanov ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list); 16492ffd87d3SSergey Temerkhanov 16502ffd87d3SSergey Temerkhanov return ice_aq_send_cmd(hw, &desc, pkg_info, buf_size, cd); 16512ffd87d3SSergey Temerkhanov } 16522ffd87d3SSergey Temerkhanov 16532ffd87d3SSergey Temerkhanov /** 16542ffd87d3SSergey Temerkhanov * ice_aq_update_pkg 16552ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 16562ffd87d3SSergey Temerkhanov * @pkg_buf: the package cmd buffer 16572ffd87d3SSergey Temerkhanov * @buf_size: the size of the package cmd buffer 16582ffd87d3SSergey Temerkhanov * @last_buf: last buffer indicator 16592ffd87d3SSergey Temerkhanov * @error_offset: returns error offset 16602ffd87d3SSergey Temerkhanov * @error_info: returns error information 16612ffd87d3SSergey Temerkhanov * @cd: pointer to command details structure or NULL 16622ffd87d3SSergey Temerkhanov * 16632ffd87d3SSergey Temerkhanov * Update Package (0x0C42) 16642ffd87d3SSergey Temerkhanov */ 16652ffd87d3SSergey Temerkhanov static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 16662ffd87d3SSergey Temerkhanov u16 buf_size, bool last_buf, u32 *error_offset, 16672ffd87d3SSergey Temerkhanov u32 *error_info, struct ice_sq_cd *cd) 16682ffd87d3SSergey Temerkhanov { 16692ffd87d3SSergey Temerkhanov struct ice_aqc_download_pkg *cmd; 16702ffd87d3SSergey Temerkhanov struct ice_aq_desc desc; 16712ffd87d3SSergey Temerkhanov int status; 16722ffd87d3SSergey Temerkhanov 16732ffd87d3SSergey Temerkhanov if (error_offset) 16742ffd87d3SSergey Temerkhanov *error_offset = 0; 16752ffd87d3SSergey Temerkhanov if (error_info) 16762ffd87d3SSergey Temerkhanov *error_info = 0; 16772ffd87d3SSergey Temerkhanov 16782ffd87d3SSergey Temerkhanov cmd = &desc.params.download_pkg; 16792ffd87d3SSergey Temerkhanov ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg); 16802ffd87d3SSergey Temerkhanov desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 16812ffd87d3SSergey Temerkhanov 16822ffd87d3SSergey Temerkhanov if (last_buf) 16832ffd87d3SSergey Temerkhanov cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF; 16842ffd87d3SSergey Temerkhanov 16852ffd87d3SSergey Temerkhanov status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd); 16862ffd87d3SSergey Temerkhanov if (status == -EIO) { 16872ffd87d3SSergey Temerkhanov /* Read error from buffer only when the FW returned an error */ 16882ffd87d3SSergey Temerkhanov struct ice_aqc_download_pkg_resp *resp; 16892ffd87d3SSergey Temerkhanov 16902ffd87d3SSergey Temerkhanov resp = (struct ice_aqc_download_pkg_resp *)pkg_buf; 16912ffd87d3SSergey Temerkhanov if (error_offset) 16922ffd87d3SSergey Temerkhanov *error_offset = le32_to_cpu(resp->error_offset); 16932ffd87d3SSergey Temerkhanov if (error_info) 16942ffd87d3SSergey Temerkhanov *error_info = le32_to_cpu(resp->error_info); 16952ffd87d3SSergey Temerkhanov } 16962ffd87d3SSergey Temerkhanov 16972ffd87d3SSergey Temerkhanov return status; 16982ffd87d3SSergey Temerkhanov } 16992ffd87d3SSergey Temerkhanov 17002ffd87d3SSergey Temerkhanov /** 1701708b352fSJan Sokolowski * ice_aq_upload_section 1702708b352fSJan Sokolowski * @hw: pointer to the hardware structure 1703708b352fSJan Sokolowski * @pkg_buf: the package buffer which will receive the section 1704708b352fSJan Sokolowski * @buf_size: the size of the package buffer 1705708b352fSJan Sokolowski * @cd: pointer to command details structure or NULL 1706708b352fSJan Sokolowski * 1707708b352fSJan Sokolowski * Upload Section (0x0C41) 1708708b352fSJan Sokolowski */ 1709708b352fSJan Sokolowski int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 1710708b352fSJan Sokolowski u16 buf_size, struct ice_sq_cd *cd) 1711708b352fSJan Sokolowski { 1712708b352fSJan Sokolowski struct ice_aq_desc desc; 1713708b352fSJan Sokolowski 1714708b352fSJan Sokolowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section); 1715708b352fSJan Sokolowski desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 1716708b352fSJan Sokolowski 1717708b352fSJan Sokolowski return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd); 1718708b352fSJan Sokolowski } 1719708b352fSJan Sokolowski 1720708b352fSJan Sokolowski /** 17212ffd87d3SSergey Temerkhanov * ice_update_pkg_no_lock 17222ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 17232ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers 17242ffd87d3SSergey Temerkhanov * @count: the number of buffers in the array 17252ffd87d3SSergey Temerkhanov */ 17262ffd87d3SSergey Temerkhanov int ice_update_pkg_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 count) 17272ffd87d3SSergey Temerkhanov { 17282ffd87d3SSergey Temerkhanov int status = 0; 17292ffd87d3SSergey Temerkhanov u32 i; 17302ffd87d3SSergey Temerkhanov 17312ffd87d3SSergey Temerkhanov for (i = 0; i < count; i++) { 17322ffd87d3SSergey Temerkhanov struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i); 17332ffd87d3SSergey Temerkhanov bool last = ((i + 1) == count); 17342ffd87d3SSergey Temerkhanov u32 offset, info; 17352ffd87d3SSergey Temerkhanov 17362ffd87d3SSergey Temerkhanov status = ice_aq_update_pkg(hw, bh, le16_to_cpu(bh->data_end), 17372ffd87d3SSergey Temerkhanov last, &offset, &info, NULL); 17382ffd87d3SSergey Temerkhanov 17392ffd87d3SSergey Temerkhanov if (status) { 17402ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, 17412ffd87d3SSergey Temerkhanov "Update pkg failed: err %d off %d inf %d\n", 17422ffd87d3SSergey Temerkhanov status, offset, info); 17432ffd87d3SSergey Temerkhanov break; 17442ffd87d3SSergey Temerkhanov } 17452ffd87d3SSergey Temerkhanov } 17462ffd87d3SSergey Temerkhanov 17472ffd87d3SSergey Temerkhanov return status; 17482ffd87d3SSergey Temerkhanov } 17492ffd87d3SSergey Temerkhanov 17502ffd87d3SSergey Temerkhanov /** 17512ffd87d3SSergey Temerkhanov * ice_update_pkg 17522ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 17532ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers 17542ffd87d3SSergey Temerkhanov * @count: the number of buffers in the array 17552ffd87d3SSergey Temerkhanov * 17562ffd87d3SSergey Temerkhanov * Obtains change lock and updates package. 17572ffd87d3SSergey Temerkhanov */ 17582ffd87d3SSergey Temerkhanov int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count) 17592ffd87d3SSergey Temerkhanov { 17602ffd87d3SSergey Temerkhanov int status; 17612ffd87d3SSergey Temerkhanov 17622ffd87d3SSergey Temerkhanov status = ice_acquire_change_lock(hw, ICE_RES_WRITE); 17632ffd87d3SSergey Temerkhanov if (status) 17642ffd87d3SSergey Temerkhanov return status; 17652ffd87d3SSergey Temerkhanov 17662ffd87d3SSergey Temerkhanov status = ice_update_pkg_no_lock(hw, bufs, count); 17672ffd87d3SSergey Temerkhanov 17682ffd87d3SSergey Temerkhanov ice_release_change_lock(hw); 17692ffd87d3SSergey Temerkhanov 17702ffd87d3SSergey Temerkhanov return status; 17712ffd87d3SSergey Temerkhanov } 17722ffd87d3SSergey Temerkhanov 17732ffd87d3SSergey Temerkhanov /** 17742ffd87d3SSergey Temerkhanov * ice_find_seg_in_pkg 17752ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 17762ffd87d3SSergey Temerkhanov * @seg_type: the segment type to search for (i.e., SEGMENT_TYPE_CPK) 17772ffd87d3SSergey Temerkhanov * @pkg_hdr: pointer to the package header to be searched 17782ffd87d3SSergey Temerkhanov * 17792ffd87d3SSergey Temerkhanov * This function searches a package file for a particular segment type. On 17802ffd87d3SSergey Temerkhanov * success it returns a pointer to the segment header, otherwise it will 17812ffd87d3SSergey Temerkhanov * return NULL. 17822ffd87d3SSergey Temerkhanov */ 1783708b352fSJan Sokolowski static struct ice_generic_seg_hdr * 1784708b352fSJan Sokolowski ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type, 17852ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg_hdr) 17862ffd87d3SSergey Temerkhanov { 17872ffd87d3SSergey Temerkhanov u32 i; 17882ffd87d3SSergey Temerkhanov 17892ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n", 17902ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor, 17912ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.update, 17922ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.draft); 17932ffd87d3SSergey Temerkhanov 17942ffd87d3SSergey Temerkhanov /* Search all package segments for the requested segment type */ 17952ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { 17962ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg; 17972ffd87d3SSergey Temerkhanov 17982ffd87d3SSergey Temerkhanov seg = (struct ice_generic_seg_hdr 17992ffd87d3SSergey Temerkhanov *)((u8 *)pkg_hdr + 18002ffd87d3SSergey Temerkhanov le32_to_cpu(pkg_hdr->seg_offset[i])); 18012ffd87d3SSergey Temerkhanov 18022ffd87d3SSergey Temerkhanov if (le32_to_cpu(seg->seg_type) == seg_type) 18032ffd87d3SSergey Temerkhanov return seg; 18042ffd87d3SSergey Temerkhanov } 18052ffd87d3SSergey Temerkhanov 18062ffd87d3SSergey Temerkhanov return NULL; 18072ffd87d3SSergey Temerkhanov } 18082ffd87d3SSergey Temerkhanov 18092ffd87d3SSergey Temerkhanov /** 18103cbdb034SDan Nowlin * ice_has_signing_seg - determine if package has a signing segment 18113cbdb034SDan Nowlin * @hw: pointer to the hardware structure 18123cbdb034SDan Nowlin * @pkg_hdr: pointer to the driver's package hdr 18133cbdb034SDan Nowlin */ 18143cbdb034SDan Nowlin static bool ice_has_signing_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) 18153cbdb034SDan Nowlin { 18163cbdb034SDan Nowlin struct ice_generic_seg_hdr *seg_hdr; 18173cbdb034SDan Nowlin 18183cbdb034SDan Nowlin seg_hdr = (struct ice_generic_seg_hdr *) 18193cbdb034SDan Nowlin ice_find_seg_in_pkg(hw, SEGMENT_TYPE_SIGNING, pkg_hdr); 18203cbdb034SDan Nowlin 18213cbdb034SDan Nowlin return seg_hdr ? true : false; 18223cbdb034SDan Nowlin } 18233cbdb034SDan Nowlin 18243cbdb034SDan Nowlin /** 18253cbdb034SDan Nowlin * ice_get_pkg_segment_id - get correct package segment id, based on device 18263cbdb034SDan Nowlin * @mac_type: MAC type of the device 18273cbdb034SDan Nowlin */ 18283cbdb034SDan Nowlin static u32 ice_get_pkg_segment_id(enum ice_mac_type mac_type) 18293cbdb034SDan Nowlin { 18303cbdb034SDan Nowlin u32 seg_id; 18313cbdb034SDan Nowlin 18323cbdb034SDan Nowlin switch (mac_type) { 18333cbdb034SDan Nowlin case ICE_MAC_E830: 18343cbdb034SDan Nowlin seg_id = SEGMENT_TYPE_ICE_E830; 18353cbdb034SDan Nowlin break; 18363cbdb034SDan Nowlin case ICE_MAC_GENERIC: 1837372e27deSGrzegorz Nitka case ICE_MAC_GENERIC_3K_E825: 18383cbdb034SDan Nowlin default: 18393cbdb034SDan Nowlin seg_id = SEGMENT_TYPE_ICE_E810; 18403cbdb034SDan Nowlin break; 18413cbdb034SDan Nowlin } 18423cbdb034SDan Nowlin 18433cbdb034SDan Nowlin return seg_id; 18443cbdb034SDan Nowlin } 18453cbdb034SDan Nowlin 18463cbdb034SDan Nowlin /** 18473cbdb034SDan Nowlin * ice_get_pkg_sign_type - get package segment sign type, based on device 18483cbdb034SDan Nowlin * @mac_type: MAC type of the device 18493cbdb034SDan Nowlin */ 18503cbdb034SDan Nowlin static u32 ice_get_pkg_sign_type(enum ice_mac_type mac_type) 18513cbdb034SDan Nowlin { 18523cbdb034SDan Nowlin u32 sign_type; 18533cbdb034SDan Nowlin 18543cbdb034SDan Nowlin switch (mac_type) { 18553cbdb034SDan Nowlin case ICE_MAC_E830: 18563cbdb034SDan Nowlin sign_type = SEGMENT_SIGN_TYPE_RSA3K_SBB; 18573cbdb034SDan Nowlin break; 1858372e27deSGrzegorz Nitka case ICE_MAC_GENERIC_3K_E825: 1859372e27deSGrzegorz Nitka sign_type = SEGMENT_SIGN_TYPE_RSA3K_E825; 1860372e27deSGrzegorz Nitka break; 18613cbdb034SDan Nowlin case ICE_MAC_GENERIC: 18623cbdb034SDan Nowlin default: 18633cbdb034SDan Nowlin sign_type = SEGMENT_SIGN_TYPE_RSA2K; 18643cbdb034SDan Nowlin break; 18653cbdb034SDan Nowlin } 18663cbdb034SDan Nowlin 18673cbdb034SDan Nowlin return sign_type; 18683cbdb034SDan Nowlin } 18693cbdb034SDan Nowlin 18703cbdb034SDan Nowlin /** 18713cbdb034SDan Nowlin * ice_get_signing_req - get correct package requirements, based on device 18723cbdb034SDan Nowlin * @hw: pointer to the hardware structure 18733cbdb034SDan Nowlin */ 18743cbdb034SDan Nowlin static void ice_get_signing_req(struct ice_hw *hw) 18753cbdb034SDan Nowlin { 18763cbdb034SDan Nowlin hw->pkg_seg_id = ice_get_pkg_segment_id(hw->mac_type); 18773cbdb034SDan Nowlin hw->pkg_sign_type = ice_get_pkg_sign_type(hw->mac_type); 18783cbdb034SDan Nowlin } 18793cbdb034SDan Nowlin 18803cbdb034SDan Nowlin /** 18812ffd87d3SSergey Temerkhanov * ice_init_pkg_info 18822ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 18832ffd87d3SSergey Temerkhanov * @pkg_hdr: pointer to the driver's package hdr 18842ffd87d3SSergey Temerkhanov * 18852ffd87d3SSergey Temerkhanov * Saves off the package details into the HW structure. 18862ffd87d3SSergey Temerkhanov */ 18872ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_init_pkg_info(struct ice_hw *hw, 18882ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg_hdr) 18892ffd87d3SSergey Temerkhanov { 18902ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg_hdr; 18912ffd87d3SSergey Temerkhanov 18922ffd87d3SSergey Temerkhanov if (!pkg_hdr) 18932ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 18942ffd87d3SSergey Temerkhanov 18953cbdb034SDan Nowlin hw->pkg_has_signing_seg = ice_has_signing_seg(hw, pkg_hdr); 18963cbdb034SDan Nowlin ice_get_signing_req(hw); 18973cbdb034SDan Nowlin 18983cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_INIT, "Pkg using segment id: 0x%08X\n", 18993cbdb034SDan Nowlin hw->pkg_seg_id); 19003cbdb034SDan Nowlin 19013cbdb034SDan Nowlin seg_hdr = (struct ice_generic_seg_hdr *) 19023cbdb034SDan Nowlin ice_find_seg_in_pkg(hw, hw->pkg_seg_id, pkg_hdr); 19032ffd87d3SSergey Temerkhanov if (seg_hdr) { 19042ffd87d3SSergey Temerkhanov struct ice_meta_sect *meta; 19052ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 19062ffd87d3SSergey Temerkhanov 19072ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 19082ffd87d3SSergey Temerkhanov 19092ffd87d3SSergey Temerkhanov /* Get package information from the Metadata Section */ 19102ffd87d3SSergey Temerkhanov meta = ice_pkg_enum_section((struct ice_seg *)seg_hdr, &state, 19112ffd87d3SSergey Temerkhanov ICE_SID_METADATA); 19122ffd87d3SSergey Temerkhanov if (!meta) { 19132ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 19142ffd87d3SSergey Temerkhanov "Did not find ice metadata section in package\n"); 19152ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 19162ffd87d3SSergey Temerkhanov } 19172ffd87d3SSergey Temerkhanov 19182ffd87d3SSergey Temerkhanov hw->pkg_ver = meta->ver; 19192ffd87d3SSergey Temerkhanov memcpy(hw->pkg_name, meta->name, sizeof(meta->name)); 19202ffd87d3SSergey Temerkhanov 19212ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Pkg: %d.%d.%d.%d, %s\n", 19222ffd87d3SSergey Temerkhanov meta->ver.major, meta->ver.minor, meta->ver.update, 19232ffd87d3SSergey Temerkhanov meta->ver.draft, meta->name); 19242ffd87d3SSergey Temerkhanov 19252ffd87d3SSergey Temerkhanov hw->ice_seg_fmt_ver = seg_hdr->seg_format_ver; 19262ffd87d3SSergey Temerkhanov memcpy(hw->ice_seg_id, seg_hdr->seg_id, sizeof(hw->ice_seg_id)); 19272ffd87d3SSergey Temerkhanov 19282ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n", 19292ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.major, 19302ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.minor, 19312ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.update, 19322ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.draft, seg_hdr->seg_id); 19332ffd87d3SSergey Temerkhanov } else { 19342ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 19352ffd87d3SSergey Temerkhanov "Did not find ice segment in driver package\n"); 19362ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 19372ffd87d3SSergey Temerkhanov } 19382ffd87d3SSergey Temerkhanov 19392ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 19402ffd87d3SSergey Temerkhanov } 19412ffd87d3SSergey Temerkhanov 19422ffd87d3SSergey Temerkhanov /** 19432ffd87d3SSergey Temerkhanov * ice_get_pkg_info 19442ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 19452ffd87d3SSergey Temerkhanov * 19462ffd87d3SSergey Temerkhanov * Store details of the package currently loaded in HW into the HW structure. 19472ffd87d3SSergey Temerkhanov */ 19482ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw) 19492ffd87d3SSergey Temerkhanov { 1950d8e45f29SKees Cook DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg_info, pkg_info, 1951230064baSPrzemek Kitszel ICE_PKG_CNT); 1952230064baSPrzemek Kitszel u16 size = __struct_size(pkg_info); 19532ffd87d3SSergey Temerkhanov u32 i; 19542ffd87d3SSergey Temerkhanov 1955230064baSPrzemek Kitszel if (ice_aq_get_pkg_info_list(hw, pkg_info, size, NULL)) 19562ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 19572ffd87d3SSergey Temerkhanov 19582ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg_info->count); i++) { 19592ffd87d3SSergey Temerkhanov #define ICE_PKG_FLAG_COUNT 4 19602ffd87d3SSergey Temerkhanov char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 }; 19612ffd87d3SSergey Temerkhanov u8 place = 0; 19622ffd87d3SSergey Temerkhanov 19632ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_active) { 19642ffd87d3SSergey Temerkhanov flags[place++] = 'A'; 19652ffd87d3SSergey Temerkhanov hw->active_pkg_ver = pkg_info->pkg_info[i].ver; 19662ffd87d3SSergey Temerkhanov hw->active_track_id = 19672ffd87d3SSergey Temerkhanov le32_to_cpu(pkg_info->pkg_info[i].track_id); 19682ffd87d3SSergey Temerkhanov memcpy(hw->active_pkg_name, pkg_info->pkg_info[i].name, 19692ffd87d3SSergey Temerkhanov sizeof(pkg_info->pkg_info[i].name)); 19702ffd87d3SSergey Temerkhanov hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm; 19712ffd87d3SSergey Temerkhanov } 19722ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_active_at_boot) 19732ffd87d3SSergey Temerkhanov flags[place++] = 'B'; 19742ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_modified) 19752ffd87d3SSergey Temerkhanov flags[place++] = 'M'; 19762ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_in_nvm) 19772ffd87d3SSergey Temerkhanov flags[place++] = 'N'; 19782ffd87d3SSergey Temerkhanov 19792ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Pkg[%d]: %d.%d.%d.%d,%s,%s\n", i, 19802ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.major, 19812ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.minor, 19822ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.update, 19832ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.draft, 19842ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].name, flags); 19852ffd87d3SSergey Temerkhanov } 19862ffd87d3SSergey Temerkhanov 1987230064baSPrzemek Kitszel return ICE_DDP_PKG_SUCCESS; 19882ffd87d3SSergey Temerkhanov } 19892ffd87d3SSergey Temerkhanov 19902ffd87d3SSergey Temerkhanov /** 19912ffd87d3SSergey Temerkhanov * ice_chk_pkg_compat 19922ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 19932ffd87d3SSergey Temerkhanov * @ospkg: pointer to the package hdr 19942ffd87d3SSergey Temerkhanov * @seg: pointer to the package segment hdr 19952ffd87d3SSergey Temerkhanov * 19962ffd87d3SSergey Temerkhanov * This function checks the package version compatibility with driver and NVM 19972ffd87d3SSergey Temerkhanov */ 19982ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_compat(struct ice_hw *hw, 19992ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *ospkg, 20002ffd87d3SSergey Temerkhanov struct ice_seg **seg) 20012ffd87d3SSergey Temerkhanov { 2002d8e45f29SKees Cook DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg, pkg_info, 2003230064baSPrzemek Kitszel ICE_PKG_CNT); 2004230064baSPrzemek Kitszel u16 size = __struct_size(pkg); 20052ffd87d3SSergey Temerkhanov enum ice_ddp_state state; 20062ffd87d3SSergey Temerkhanov u32 i; 20072ffd87d3SSergey Temerkhanov 20082ffd87d3SSergey Temerkhanov /* Check package version compatibility */ 20092ffd87d3SSergey Temerkhanov state = ice_chk_pkg_version(&hw->pkg_ver); 20102ffd87d3SSergey Temerkhanov if (state) { 20112ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n"); 20122ffd87d3SSergey Temerkhanov return state; 20132ffd87d3SSergey Temerkhanov } 20142ffd87d3SSergey Temerkhanov 20152ffd87d3SSergey Temerkhanov /* find ICE segment in given package */ 20163cbdb034SDan Nowlin *seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, hw->pkg_seg_id, 20172ffd87d3SSergey Temerkhanov ospkg); 20182ffd87d3SSergey Temerkhanov if (!*seg) { 20192ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n"); 20202ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 20212ffd87d3SSergey Temerkhanov } 20222ffd87d3SSergey Temerkhanov 20232ffd87d3SSergey Temerkhanov /* Check if FW is compatible with the OS package */ 2024230064baSPrzemek Kitszel if (ice_aq_get_pkg_info_list(hw, pkg, size, NULL)) 2025230064baSPrzemek Kitszel return ICE_DDP_PKG_LOAD_ERROR; 20262ffd87d3SSergey Temerkhanov 20272ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg->count); i++) { 20282ffd87d3SSergey Temerkhanov /* loop till we find the NVM package */ 20292ffd87d3SSergey Temerkhanov if (!pkg->pkg_info[i].is_in_nvm) 20302ffd87d3SSergey Temerkhanov continue; 20312ffd87d3SSergey Temerkhanov if ((*seg)->hdr.seg_format_ver.major != 20322ffd87d3SSergey Temerkhanov pkg->pkg_info[i].ver.major || 20332ffd87d3SSergey Temerkhanov (*seg)->hdr.seg_format_ver.minor > 20342ffd87d3SSergey Temerkhanov pkg->pkg_info[i].ver.minor) { 20352ffd87d3SSergey Temerkhanov state = ICE_DDP_PKG_FW_MISMATCH; 20362ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 20372ffd87d3SSergey Temerkhanov "OS package is not compatible with NVM.\n"); 20382ffd87d3SSergey Temerkhanov } 20392ffd87d3SSergey Temerkhanov /* done processing NVM package so break */ 20402ffd87d3SSergey Temerkhanov break; 20412ffd87d3SSergey Temerkhanov } 2042230064baSPrzemek Kitszel 20432ffd87d3SSergey Temerkhanov return state; 20442ffd87d3SSergey Temerkhanov } 20452ffd87d3SSergey Temerkhanov 20462ffd87d3SSergey Temerkhanov /** 20472ffd87d3SSergey Temerkhanov * ice_init_pkg_hints 20482ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 20492ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the segment of the package scan (non-NULL) 20502ffd87d3SSergey Temerkhanov * 20512ffd87d3SSergey Temerkhanov * This function will scan the package and save off relevant information 20522ffd87d3SSergey Temerkhanov * (hints or metadata) for driver use. The ice_seg parameter must not be NULL 20532ffd87d3SSergey Temerkhanov * since the first call to ice_enum_labels requires a pointer to an actual 20542ffd87d3SSergey Temerkhanov * ice_seg structure. 20552ffd87d3SSergey Temerkhanov */ 20562ffd87d3SSergey Temerkhanov static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg) 20572ffd87d3SSergey Temerkhanov { 20582ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 20592ffd87d3SSergey Temerkhanov char *label_name; 20602ffd87d3SSergey Temerkhanov u16 val; 20612ffd87d3SSergey Temerkhanov int i; 20622ffd87d3SSergey Temerkhanov 20632ffd87d3SSergey Temerkhanov memset(&hw->tnl, 0, sizeof(hw->tnl)); 20642ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 20652ffd87d3SSergey Temerkhanov 20662ffd87d3SSergey Temerkhanov if (!ice_seg) 20672ffd87d3SSergey Temerkhanov return; 20682ffd87d3SSergey Temerkhanov 20692ffd87d3SSergey Temerkhanov label_name = ice_enum_labels(ice_seg, ICE_SID_LBL_RXPARSER_TMEM, &state, 20702ffd87d3SSergey Temerkhanov &val); 20712ffd87d3SSergey Temerkhanov 20722ffd87d3SSergey Temerkhanov while (label_name) { 20732ffd87d3SSergey Temerkhanov if (!strncmp(label_name, ICE_TNL_PRE, strlen(ICE_TNL_PRE))) 20742ffd87d3SSergey Temerkhanov /* check for a tunnel entry */ 20752ffd87d3SSergey Temerkhanov ice_add_tunnel_hint(hw, label_name, val); 20762ffd87d3SSergey Temerkhanov 20772ffd87d3SSergey Temerkhanov /* check for a dvm mode entry */ 20782ffd87d3SSergey Temerkhanov else if (!strncmp(label_name, ICE_DVM_PRE, strlen(ICE_DVM_PRE))) 20792ffd87d3SSergey Temerkhanov ice_add_dvm_hint(hw, val, true); 20802ffd87d3SSergey Temerkhanov 20812ffd87d3SSergey Temerkhanov /* check for a svm mode entry */ 20822ffd87d3SSergey Temerkhanov else if (!strncmp(label_name, ICE_SVM_PRE, strlen(ICE_SVM_PRE))) 20832ffd87d3SSergey Temerkhanov ice_add_dvm_hint(hw, val, false); 20842ffd87d3SSergey Temerkhanov 20852ffd87d3SSergey Temerkhanov label_name = ice_enum_labels(NULL, 0, &state, &val); 20862ffd87d3SSergey Temerkhanov } 20872ffd87d3SSergey Temerkhanov 20882ffd87d3SSergey Temerkhanov /* Cache the appropriate boost TCAM entry pointers for tunnels */ 20892ffd87d3SSergey Temerkhanov for (i = 0; i < hw->tnl.count; i++) { 20902ffd87d3SSergey Temerkhanov ice_find_boost_entry(ice_seg, hw->tnl.tbl[i].boost_addr, 20912ffd87d3SSergey Temerkhanov &hw->tnl.tbl[i].boost_entry); 20922ffd87d3SSergey Temerkhanov if (hw->tnl.tbl[i].boost_entry) { 20932ffd87d3SSergey Temerkhanov hw->tnl.tbl[i].valid = true; 20942ffd87d3SSergey Temerkhanov if (hw->tnl.tbl[i].type < __TNL_TYPE_CNT) 20952ffd87d3SSergey Temerkhanov hw->tnl.valid_count[hw->tnl.tbl[i].type]++; 20962ffd87d3SSergey Temerkhanov } 20972ffd87d3SSergey Temerkhanov } 20982ffd87d3SSergey Temerkhanov 20992ffd87d3SSergey Temerkhanov /* Cache the appropriate boost TCAM entry pointers for DVM and SVM */ 21002ffd87d3SSergey Temerkhanov for (i = 0; i < hw->dvm_upd.count; i++) 21012ffd87d3SSergey Temerkhanov ice_find_boost_entry(ice_seg, hw->dvm_upd.tbl[i].boost_addr, 21022ffd87d3SSergey Temerkhanov &hw->dvm_upd.tbl[i].boost_entry); 21032ffd87d3SSergey Temerkhanov } 21042ffd87d3SSergey Temerkhanov 21052ffd87d3SSergey Temerkhanov /** 21062ffd87d3SSergey Temerkhanov * ice_fill_hw_ptype - fill the enabled PTYPE bit information 21072ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 21082ffd87d3SSergey Temerkhanov */ 21092ffd87d3SSergey Temerkhanov static void ice_fill_hw_ptype(struct ice_hw *hw) 21102ffd87d3SSergey Temerkhanov { 21112ffd87d3SSergey Temerkhanov struct ice_marker_ptype_tcam_entry *tcam; 21122ffd87d3SSergey Temerkhanov struct ice_seg *seg = hw->seg; 21132ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 21142ffd87d3SSergey Temerkhanov 21152ffd87d3SSergey Temerkhanov bitmap_zero(hw->hw_ptype, ICE_FLOW_PTYPE_MAX); 21162ffd87d3SSergey Temerkhanov if (!seg) 21172ffd87d3SSergey Temerkhanov return; 21182ffd87d3SSergey Temerkhanov 21192ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 21202ffd87d3SSergey Temerkhanov 21212ffd87d3SSergey Temerkhanov do { 21222ffd87d3SSergey Temerkhanov tcam = ice_pkg_enum_entry(seg, &state, 21232ffd87d3SSergey Temerkhanov ICE_SID_RXPARSER_MARKER_PTYPE, NULL, 21242ffd87d3SSergey Temerkhanov ice_marker_ptype_tcam_handler); 21252ffd87d3SSergey Temerkhanov if (tcam && 21262ffd87d3SSergey Temerkhanov le16_to_cpu(tcam->addr) < ICE_MARKER_PTYPE_TCAM_ADDR_MAX && 21272ffd87d3SSergey Temerkhanov le16_to_cpu(tcam->ptype) < ICE_FLOW_PTYPE_MAX) 21282ffd87d3SSergey Temerkhanov set_bit(le16_to_cpu(tcam->ptype), hw->hw_ptype); 21292ffd87d3SSergey Temerkhanov 21302ffd87d3SSergey Temerkhanov seg = NULL; 21312ffd87d3SSergey Temerkhanov } while (tcam); 21322ffd87d3SSergey Temerkhanov } 21332ffd87d3SSergey Temerkhanov 21342ffd87d3SSergey Temerkhanov /** 21352ffd87d3SSergey Temerkhanov * ice_init_pkg - initialize/download package 21362ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 21372ffd87d3SSergey Temerkhanov * @buf: pointer to the package buffer 21382ffd87d3SSergey Temerkhanov * @len: size of the package buffer 21392ffd87d3SSergey Temerkhanov * 21402ffd87d3SSergey Temerkhanov * This function initializes a package. The package contains HW tables 21412ffd87d3SSergey Temerkhanov * required to do packet processing. First, the function extracts package 21422ffd87d3SSergey Temerkhanov * information such as version. Then it finds the ice configuration segment 21432ffd87d3SSergey Temerkhanov * within the package; this function then saves a copy of the segment pointer 21442ffd87d3SSergey Temerkhanov * within the supplied package buffer. Next, the function will cache any hints 21452ffd87d3SSergey Temerkhanov * from the package, followed by downloading the package itself. Note, that if 21462ffd87d3SSergey Temerkhanov * a previous PF driver has already downloaded the package successfully, then 21472ffd87d3SSergey Temerkhanov * the current driver will not have to download the package again. 21482ffd87d3SSergey Temerkhanov * 21492ffd87d3SSergey Temerkhanov * The local package contents will be used to query default behavior and to 21502ffd87d3SSergey Temerkhanov * update specific sections of the HW's version of the package (e.g. to update 21512ffd87d3SSergey Temerkhanov * the parse graph to understand new protocols). 21522ffd87d3SSergey Temerkhanov * 21532ffd87d3SSergey Temerkhanov * This function stores a pointer to the package buffer memory, and it is 21542ffd87d3SSergey Temerkhanov * expected that the supplied buffer will not be freed immediately. If the 21552ffd87d3SSergey Temerkhanov * package buffer needs to be freed, such as when read from a file, use 21562ffd87d3SSergey Temerkhanov * ice_copy_and_init_pkg() instead of directly calling ice_init_pkg() in this 21572ffd87d3SSergey Temerkhanov * case. 21582ffd87d3SSergey Temerkhanov */ 21592ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len) 21602ffd87d3SSergey Temerkhanov { 21612ffd87d3SSergey Temerkhanov bool already_loaded = false; 21622ffd87d3SSergey Temerkhanov enum ice_ddp_state state; 21632ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg; 21642ffd87d3SSergey Temerkhanov struct ice_seg *seg; 21652ffd87d3SSergey Temerkhanov 21662ffd87d3SSergey Temerkhanov if (!buf || !len) 21672ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 21682ffd87d3SSergey Temerkhanov 21692ffd87d3SSergey Temerkhanov pkg = (struct ice_pkg_hdr *)buf; 21702ffd87d3SSergey Temerkhanov state = ice_verify_pkg(pkg, len); 21712ffd87d3SSergey Temerkhanov if (state) { 21722ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n", 21732ffd87d3SSergey Temerkhanov state); 21742ffd87d3SSergey Temerkhanov return state; 21752ffd87d3SSergey Temerkhanov } 21762ffd87d3SSergey Temerkhanov 21772ffd87d3SSergey Temerkhanov /* initialize package info */ 21782ffd87d3SSergey Temerkhanov state = ice_init_pkg_info(hw, pkg); 21792ffd87d3SSergey Temerkhanov if (state) 21802ffd87d3SSergey Temerkhanov return state; 21812ffd87d3SSergey Temerkhanov 21823cbdb034SDan Nowlin /* must be a matching segment */ 21833cbdb034SDan Nowlin if (hw->pkg_has_signing_seg && 21843cbdb034SDan Nowlin !ice_match_signing_seg(pkg, hw->pkg_seg_id, hw->pkg_sign_type)) 21853cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 21863cbdb034SDan Nowlin 21872ffd87d3SSergey Temerkhanov /* before downloading the package, check package version for 21882ffd87d3SSergey Temerkhanov * compatibility with driver 21892ffd87d3SSergey Temerkhanov */ 21902ffd87d3SSergey Temerkhanov state = ice_chk_pkg_compat(hw, pkg, &seg); 21912ffd87d3SSergey Temerkhanov if (state) 21922ffd87d3SSergey Temerkhanov return state; 21932ffd87d3SSergey Temerkhanov 21942ffd87d3SSergey Temerkhanov /* initialize package hints and then download package */ 21952ffd87d3SSergey Temerkhanov ice_init_pkg_hints(hw, seg); 2196a778616eSDan Nowlin state = ice_download_pkg(hw, pkg, seg); 21972ffd87d3SSergey Temerkhanov if (state == ICE_DDP_PKG_ALREADY_LOADED) { 21982ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 21992ffd87d3SSergey Temerkhanov "package previously loaded - no work.\n"); 22002ffd87d3SSergey Temerkhanov already_loaded = true; 22012ffd87d3SSergey Temerkhanov } 22022ffd87d3SSergey Temerkhanov 22032ffd87d3SSergey Temerkhanov /* Get information on the package currently loaded in HW, then make sure 22042ffd87d3SSergey Temerkhanov * the driver is compatible with this version. 22052ffd87d3SSergey Temerkhanov */ 22062ffd87d3SSergey Temerkhanov if (!state || state == ICE_DDP_PKG_ALREADY_LOADED) { 22072ffd87d3SSergey Temerkhanov state = ice_get_pkg_info(hw); 22082ffd87d3SSergey Temerkhanov if (!state) 22092ffd87d3SSergey Temerkhanov state = ice_get_ddp_pkg_state(hw, already_loaded); 22102ffd87d3SSergey Temerkhanov } 22112ffd87d3SSergey Temerkhanov 22122ffd87d3SSergey Temerkhanov if (ice_is_init_pkg_successful(state)) { 22132ffd87d3SSergey Temerkhanov hw->seg = seg; 22142ffd87d3SSergey Temerkhanov /* on successful package download update other required 22152ffd87d3SSergey Temerkhanov * registers to support the package and fill HW tables 22162ffd87d3SSergey Temerkhanov * with package content. 22172ffd87d3SSergey Temerkhanov */ 22182ffd87d3SSergey Temerkhanov ice_init_pkg_regs(hw); 22192ffd87d3SSergey Temerkhanov ice_fill_blk_tbls(hw); 22202ffd87d3SSergey Temerkhanov ice_fill_hw_ptype(hw); 22212ffd87d3SSergey Temerkhanov ice_get_prof_index_max(hw); 22222ffd87d3SSergey Temerkhanov } else { 22232ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n", state); 22242ffd87d3SSergey Temerkhanov } 22252ffd87d3SSergey Temerkhanov 22262ffd87d3SSergey Temerkhanov return state; 22272ffd87d3SSergey Temerkhanov } 22282ffd87d3SSergey Temerkhanov 22292ffd87d3SSergey Temerkhanov /** 22302ffd87d3SSergey Temerkhanov * ice_copy_and_init_pkg - initialize/download a copy of the package 22312ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 22322ffd87d3SSergey Temerkhanov * @buf: pointer to the package buffer 22332ffd87d3SSergey Temerkhanov * @len: size of the package buffer 22342ffd87d3SSergey Temerkhanov * 22352ffd87d3SSergey Temerkhanov * This function copies the package buffer, and then calls ice_init_pkg() to 22362ffd87d3SSergey Temerkhanov * initialize the copied package contents. 22372ffd87d3SSergey Temerkhanov * 22382ffd87d3SSergey Temerkhanov * The copying is necessary if the package buffer supplied is constant, or if 22392ffd87d3SSergey Temerkhanov * the memory may disappear shortly after calling this function. 22402ffd87d3SSergey Temerkhanov * 22412ffd87d3SSergey Temerkhanov * If the package buffer resides in the data segment and can be modified, the 22422ffd87d3SSergey Temerkhanov * caller is free to use ice_init_pkg() instead of ice_copy_and_init_pkg(). 22432ffd87d3SSergey Temerkhanov * 22442ffd87d3SSergey Temerkhanov * However, if the package buffer needs to be copied first, such as when being 22452ffd87d3SSergey Temerkhanov * read from a file, the caller should use ice_copy_and_init_pkg(). 22462ffd87d3SSergey Temerkhanov * 22472ffd87d3SSergey Temerkhanov * This function will first copy the package buffer, before calling 22482ffd87d3SSergey Temerkhanov * ice_init_pkg(). The caller is free to immediately destroy the original 22492ffd87d3SSergey Temerkhanov * package buffer, as the new copy will be managed by this function and 22502ffd87d3SSergey Temerkhanov * related routines. 22512ffd87d3SSergey Temerkhanov */ 22522ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, 22532ffd87d3SSergey Temerkhanov u32 len) 22542ffd87d3SSergey Temerkhanov { 22552ffd87d3SSergey Temerkhanov enum ice_ddp_state state; 22562ffd87d3SSergey Temerkhanov u8 *buf_copy; 22572ffd87d3SSergey Temerkhanov 22582ffd87d3SSergey Temerkhanov if (!buf || !len) 22592ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 22602ffd87d3SSergey Temerkhanov 22612ffd87d3SSergey Temerkhanov buf_copy = devm_kmemdup(ice_hw_to_dev(hw), buf, len, GFP_KERNEL); 22622ffd87d3SSergey Temerkhanov 22632ffd87d3SSergey Temerkhanov state = ice_init_pkg(hw, buf_copy, len); 22642ffd87d3SSergey Temerkhanov if (!ice_is_init_pkg_successful(state)) { 22652ffd87d3SSergey Temerkhanov /* Free the copy, since we failed to initialize the package */ 22662ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), buf_copy); 22672ffd87d3SSergey Temerkhanov } else { 22682ffd87d3SSergey Temerkhanov /* Track the copied pkg so we can free it later */ 22692ffd87d3SSergey Temerkhanov hw->pkg_copy = buf_copy; 22702ffd87d3SSergey Temerkhanov hw->pkg_size = len; 22712ffd87d3SSergey Temerkhanov } 22722ffd87d3SSergey Temerkhanov 22732ffd87d3SSergey Temerkhanov return state; 22742ffd87d3SSergey Temerkhanov } 2275