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 7242ffd87d3SSergey Temerkhanov /** 7252ffd87d3SSergey Temerkhanov * ice_get_sw_prof_type - determine switch profile type 7262ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 7272ffd87d3SSergey Temerkhanov * @fv: pointer to the switch field vector 7282ffd87d3SSergey Temerkhanov * @prof_idx: profile index to check 7292ffd87d3SSergey Temerkhanov */ 7302ffd87d3SSergey Temerkhanov static enum ice_prof_type ice_get_sw_prof_type(struct ice_hw *hw, 7312ffd87d3SSergey Temerkhanov struct ice_fv *fv, u32 prof_idx) 7322ffd87d3SSergey Temerkhanov { 7332ffd87d3SSergey Temerkhanov u16 i; 7342ffd87d3SSergey Temerkhanov 7352ffd87d3SSergey Temerkhanov if (ice_is_gtp_c_profile(prof_idx)) 7362ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GTPC; 7372ffd87d3SSergey Temerkhanov 7382ffd87d3SSergey Temerkhanov if (ice_is_gtp_u_profile(prof_idx)) 7392ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GTPU; 7402ffd87d3SSergey Temerkhanov 7412ffd87d3SSergey Temerkhanov for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) { 7422ffd87d3SSergey Temerkhanov /* UDP tunnel will have UDP_OF protocol ID and VNI offset */ 7432ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF && 7442ffd87d3SSergey Temerkhanov fv->ew[i].off == ICE_VNI_OFFSET) 7452ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_UDP; 7462ffd87d3SSergey Temerkhanov 7472ffd87d3SSergey Temerkhanov /* GRE tunnel will have GRE protocol */ 7482ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == (u8)ICE_PROT_GRE_OF) 7492ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GRE; 7502ffd87d3SSergey Temerkhanov } 7512ffd87d3SSergey Temerkhanov 7522ffd87d3SSergey Temerkhanov return ICE_PROF_NON_TUN; 7532ffd87d3SSergey Temerkhanov } 7542ffd87d3SSergey Temerkhanov 7552ffd87d3SSergey Temerkhanov /** 7562ffd87d3SSergey Temerkhanov * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type 7572ffd87d3SSergey Temerkhanov * @hw: pointer to hardware structure 7582ffd87d3SSergey Temerkhanov * @req_profs: type of profiles requested 7592ffd87d3SSergey Temerkhanov * @bm: pointer to memory for returning the bitmap of field vectors 7602ffd87d3SSergey Temerkhanov */ 7612ffd87d3SSergey Temerkhanov void ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs, 7622ffd87d3SSergey Temerkhanov unsigned long *bm) 7632ffd87d3SSergey Temerkhanov { 7642ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 7652ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 7662ffd87d3SSergey Temerkhanov struct ice_fv *fv; 7672ffd87d3SSergey Temerkhanov 7682ffd87d3SSergey Temerkhanov if (req_profs == ICE_PROF_ALL) { 7692ffd87d3SSergey Temerkhanov bitmap_set(bm, 0, ICE_MAX_NUM_PROFILES); 7702ffd87d3SSergey Temerkhanov return; 7712ffd87d3SSergey Temerkhanov } 7722ffd87d3SSergey Temerkhanov 7732ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 7742ffd87d3SSergey Temerkhanov bitmap_zero(bm, ICE_MAX_NUM_PROFILES); 7752ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 7762ffd87d3SSergey Temerkhanov do { 7772ffd87d3SSergey Temerkhanov enum ice_prof_type prof_type; 7782ffd87d3SSergey Temerkhanov u32 offset; 7792ffd87d3SSergey Temerkhanov 7802ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 7812ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler); 7822ffd87d3SSergey Temerkhanov ice_seg = NULL; 7832ffd87d3SSergey Temerkhanov 7842ffd87d3SSergey Temerkhanov if (fv) { 7852ffd87d3SSergey Temerkhanov /* Determine field vector type */ 7862ffd87d3SSergey Temerkhanov prof_type = ice_get_sw_prof_type(hw, fv, offset); 7872ffd87d3SSergey Temerkhanov 7882ffd87d3SSergey Temerkhanov if (req_profs & prof_type) 7892ffd87d3SSergey Temerkhanov set_bit((u16)offset, bm); 7902ffd87d3SSergey Temerkhanov } 7912ffd87d3SSergey Temerkhanov } while (fv); 7922ffd87d3SSergey Temerkhanov } 7932ffd87d3SSergey Temerkhanov 7942ffd87d3SSergey Temerkhanov /** 7952ffd87d3SSergey Temerkhanov * ice_get_sw_fv_list 7962ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 7972ffd87d3SSergey Temerkhanov * @lkups: list of protocol types 7982ffd87d3SSergey Temerkhanov * @bm: bitmap of field vectors to consider 7992ffd87d3SSergey Temerkhanov * @fv_list: Head of a list 8002ffd87d3SSergey Temerkhanov * 8012ffd87d3SSergey Temerkhanov * Finds all the field vector entries from switch block that contain 8022ffd87d3SSergey Temerkhanov * a given protocol ID and offset and returns a list of structures of type 8032ffd87d3SSergey Temerkhanov * "ice_sw_fv_list_entry". Every structure in the list has a field vector 8042ffd87d3SSergey Temerkhanov * definition and profile ID information 8052ffd87d3SSergey Temerkhanov * NOTE: The caller of the function is responsible for freeing the memory 8062ffd87d3SSergey Temerkhanov * allocated for every list entry. 8072ffd87d3SSergey Temerkhanov */ 8082ffd87d3SSergey Temerkhanov int ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups, 8092ffd87d3SSergey Temerkhanov unsigned long *bm, struct list_head *fv_list) 8102ffd87d3SSergey Temerkhanov { 8112ffd87d3SSergey Temerkhanov struct ice_sw_fv_list_entry *fvl; 8122ffd87d3SSergey Temerkhanov struct ice_sw_fv_list_entry *tmp; 8132ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 8142ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 8152ffd87d3SSergey Temerkhanov struct ice_fv *fv; 8162ffd87d3SSergey Temerkhanov u32 offset; 8172ffd87d3SSergey Temerkhanov 8182ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 8192ffd87d3SSergey Temerkhanov 8202ffd87d3SSergey Temerkhanov if (!lkups->n_val_words || !hw->seg) 8212ffd87d3SSergey Temerkhanov return -EINVAL; 8222ffd87d3SSergey Temerkhanov 8232ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 8242ffd87d3SSergey Temerkhanov do { 8252ffd87d3SSergey Temerkhanov u16 i; 8262ffd87d3SSergey Temerkhanov 8272ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 8282ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler); 8292ffd87d3SSergey Temerkhanov if (!fv) 8302ffd87d3SSergey Temerkhanov break; 8312ffd87d3SSergey Temerkhanov ice_seg = NULL; 8322ffd87d3SSergey Temerkhanov 8332ffd87d3SSergey Temerkhanov /* If field vector is not in the bitmap list, then skip this 8342ffd87d3SSergey Temerkhanov * profile. 8352ffd87d3SSergey Temerkhanov */ 8362ffd87d3SSergey Temerkhanov if (!test_bit((u16)offset, bm)) 8372ffd87d3SSergey Temerkhanov continue; 8382ffd87d3SSergey Temerkhanov 8392ffd87d3SSergey Temerkhanov for (i = 0; i < lkups->n_val_words; i++) { 8402ffd87d3SSergey Temerkhanov int j; 8412ffd87d3SSergey Temerkhanov 8422ffd87d3SSergey Temerkhanov for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) 8432ffd87d3SSergey Temerkhanov if (fv->ew[j].prot_id == 8442ffd87d3SSergey Temerkhanov lkups->fv_words[i].prot_id && 8452ffd87d3SSergey Temerkhanov fv->ew[j].off == lkups->fv_words[i].off) 8462ffd87d3SSergey Temerkhanov break; 8472ffd87d3SSergey Temerkhanov if (j >= hw->blk[ICE_BLK_SW].es.fvw) 8482ffd87d3SSergey Temerkhanov break; 8492ffd87d3SSergey Temerkhanov if (i + 1 == lkups->n_val_words) { 8502ffd87d3SSergey Temerkhanov fvl = devm_kzalloc(ice_hw_to_dev(hw), 8512ffd87d3SSergey Temerkhanov sizeof(*fvl), GFP_KERNEL); 8522ffd87d3SSergey Temerkhanov if (!fvl) 8532ffd87d3SSergey Temerkhanov goto err; 8542ffd87d3SSergey Temerkhanov fvl->fv_ptr = fv; 8552ffd87d3SSergey Temerkhanov fvl->profile_id = offset; 8562ffd87d3SSergey Temerkhanov list_add(&fvl->list_entry, fv_list); 8572ffd87d3SSergey Temerkhanov break; 8582ffd87d3SSergey Temerkhanov } 8592ffd87d3SSergey Temerkhanov } 8602ffd87d3SSergey Temerkhanov } while (fv); 8612ffd87d3SSergey Temerkhanov if (list_empty(fv_list)) { 8622ffd87d3SSergey Temerkhanov dev_warn(ice_hw_to_dev(hw), 8632ffd87d3SSergey Temerkhanov "Required profiles not found in currently loaded DDP package"); 8642ffd87d3SSergey Temerkhanov return -EIO; 8652ffd87d3SSergey Temerkhanov } 8662ffd87d3SSergey Temerkhanov 8672ffd87d3SSergey Temerkhanov return 0; 8682ffd87d3SSergey Temerkhanov 8692ffd87d3SSergey Temerkhanov err: 8702ffd87d3SSergey Temerkhanov list_for_each_entry_safe(fvl, tmp, fv_list, list_entry) { 8712ffd87d3SSergey Temerkhanov list_del(&fvl->list_entry); 8722ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), fvl); 8732ffd87d3SSergey Temerkhanov } 8742ffd87d3SSergey Temerkhanov 8752ffd87d3SSergey Temerkhanov return -ENOMEM; 8762ffd87d3SSergey Temerkhanov } 8772ffd87d3SSergey Temerkhanov 8782ffd87d3SSergey Temerkhanov /** 8792ffd87d3SSergey Temerkhanov * ice_init_prof_result_bm - Initialize the profile result index bitmap 8802ffd87d3SSergey Temerkhanov * @hw: pointer to hardware structure 8812ffd87d3SSergey Temerkhanov */ 8822ffd87d3SSergey Temerkhanov void ice_init_prof_result_bm(struct ice_hw *hw) 8832ffd87d3SSergey Temerkhanov { 8842ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 8852ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 8862ffd87d3SSergey Temerkhanov struct ice_fv *fv; 8872ffd87d3SSergey Temerkhanov 8882ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 8892ffd87d3SSergey Temerkhanov 8902ffd87d3SSergey Temerkhanov if (!hw->seg) 8912ffd87d3SSergey Temerkhanov return; 8922ffd87d3SSergey Temerkhanov 8932ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 8942ffd87d3SSergey Temerkhanov do { 8952ffd87d3SSergey Temerkhanov u32 off; 8962ffd87d3SSergey Temerkhanov u16 i; 8972ffd87d3SSergey Temerkhanov 8982ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 8992ffd87d3SSergey Temerkhanov &off, ice_sw_fv_handler); 9002ffd87d3SSergey Temerkhanov ice_seg = NULL; 9012ffd87d3SSergey Temerkhanov if (!fv) 9022ffd87d3SSergey Temerkhanov break; 9032ffd87d3SSergey Temerkhanov 9042ffd87d3SSergey Temerkhanov bitmap_zero(hw->switch_info->prof_res_bm[off], 9052ffd87d3SSergey Temerkhanov ICE_MAX_FV_WORDS); 9062ffd87d3SSergey Temerkhanov 9072ffd87d3SSergey Temerkhanov /* Determine empty field vector indices, these can be 9082ffd87d3SSergey Temerkhanov * used for recipe results. Skip index 0, since it is 9092ffd87d3SSergey Temerkhanov * always used for Switch ID. 9102ffd87d3SSergey Temerkhanov */ 9112ffd87d3SSergey Temerkhanov for (i = 1; i < ICE_MAX_FV_WORDS; i++) 9122ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == ICE_PROT_INVALID && 9132ffd87d3SSergey Temerkhanov fv->ew[i].off == ICE_FV_OFFSET_INVAL) 9142ffd87d3SSergey Temerkhanov set_bit(i, hw->switch_info->prof_res_bm[off]); 9152ffd87d3SSergey Temerkhanov } while (fv); 9162ffd87d3SSergey Temerkhanov } 9172ffd87d3SSergey Temerkhanov 9182ffd87d3SSergey Temerkhanov /** 9192ffd87d3SSergey Temerkhanov * ice_pkg_buf_free 9202ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 9212ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 9222ffd87d3SSergey Temerkhanov * 9232ffd87d3SSergey Temerkhanov * Frees a package buffer 9242ffd87d3SSergey Temerkhanov */ 9252ffd87d3SSergey Temerkhanov void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld) 9262ffd87d3SSergey Temerkhanov { 9272ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), bld); 9282ffd87d3SSergey Temerkhanov } 9292ffd87d3SSergey Temerkhanov 9302ffd87d3SSergey Temerkhanov /** 9312ffd87d3SSergey Temerkhanov * ice_pkg_buf_reserve_section 9322ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 9332ffd87d3SSergey Temerkhanov * @count: the number of sections to reserve 9342ffd87d3SSergey Temerkhanov * 9352ffd87d3SSergey Temerkhanov * Reserves one or more section table entries in a package buffer. This routine 9362ffd87d3SSergey Temerkhanov * can be called multiple times as long as they are made before calling 9372ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section() 9382ffd87d3SSergey Temerkhanov * is called once, the number of sections that can be allocated will not be able 9392ffd87d3SSergey Temerkhanov * to be increased; not using all reserved sections is fine, but this will 9402ffd87d3SSergey Temerkhanov * result in some wasted space in the buffer. 9412ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 9422ffd87d3SSergey Temerkhanov */ 9432ffd87d3SSergey Temerkhanov int ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count) 9442ffd87d3SSergey Temerkhanov { 9452ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 9462ffd87d3SSergey Temerkhanov u16 section_count; 9472ffd87d3SSergey Temerkhanov u16 data_end; 9482ffd87d3SSergey Temerkhanov 9492ffd87d3SSergey Temerkhanov if (!bld) 9502ffd87d3SSergey Temerkhanov return -EINVAL; 9512ffd87d3SSergey Temerkhanov 9522ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf; 9532ffd87d3SSergey Temerkhanov 9542ffd87d3SSergey Temerkhanov /* already an active section, can't increase table size */ 9552ffd87d3SSergey Temerkhanov section_count = le16_to_cpu(buf->section_count); 9562ffd87d3SSergey Temerkhanov if (section_count > 0) 9572ffd87d3SSergey Temerkhanov return -EIO; 9582ffd87d3SSergey Temerkhanov 9592ffd87d3SSergey Temerkhanov if (bld->reserved_section_table_entries + count > ICE_MAX_S_COUNT) 9602ffd87d3SSergey Temerkhanov return -EIO; 9612ffd87d3SSergey Temerkhanov bld->reserved_section_table_entries += count; 9622ffd87d3SSergey Temerkhanov 9632ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(buf->data_end) + 9642ffd87d3SSergey Temerkhanov flex_array_size(buf, section_entry, count); 9652ffd87d3SSergey Temerkhanov buf->data_end = cpu_to_le16(data_end); 9662ffd87d3SSergey Temerkhanov 9672ffd87d3SSergey Temerkhanov return 0; 9682ffd87d3SSergey Temerkhanov } 9692ffd87d3SSergey Temerkhanov 9702ffd87d3SSergey Temerkhanov /** 9712ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_section 9722ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 9732ffd87d3SSergey Temerkhanov * @type: the section type value 9742ffd87d3SSergey Temerkhanov * @size: the size of the section to reserve (in bytes) 9752ffd87d3SSergey Temerkhanov * 9762ffd87d3SSergey Temerkhanov * Reserves memory in the buffer for a section's content and updates the 9772ffd87d3SSergey Temerkhanov * buffers' status accordingly. This routine returns a pointer to the first 9782ffd87d3SSergey Temerkhanov * byte of the section start within the buffer, which is used to fill in the 9792ffd87d3SSergey Temerkhanov * section contents. 9802ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 9812ffd87d3SSergey Temerkhanov */ 9822ffd87d3SSergey Temerkhanov void *ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size) 9832ffd87d3SSergey Temerkhanov { 9842ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 9852ffd87d3SSergey Temerkhanov u16 sect_count; 9862ffd87d3SSergey Temerkhanov u16 data_end; 9872ffd87d3SSergey Temerkhanov 9882ffd87d3SSergey Temerkhanov if (!bld || !type || !size) 9892ffd87d3SSergey Temerkhanov return NULL; 9902ffd87d3SSergey Temerkhanov 9912ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf; 9922ffd87d3SSergey Temerkhanov 9932ffd87d3SSergey Temerkhanov /* check for enough space left in buffer */ 9942ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(buf->data_end); 9952ffd87d3SSergey Temerkhanov 9962ffd87d3SSergey Temerkhanov /* section start must align on 4 byte boundary */ 9972ffd87d3SSergey Temerkhanov data_end = ALIGN(data_end, 4); 9982ffd87d3SSergey Temerkhanov 9992ffd87d3SSergey Temerkhanov if ((data_end + size) > ICE_MAX_S_DATA_END) 10002ffd87d3SSergey Temerkhanov return NULL; 10012ffd87d3SSergey Temerkhanov 10022ffd87d3SSergey Temerkhanov /* check for more available section table entries */ 10032ffd87d3SSergey Temerkhanov sect_count = le16_to_cpu(buf->section_count); 10042ffd87d3SSergey Temerkhanov if (sect_count < bld->reserved_section_table_entries) { 10052ffd87d3SSergey Temerkhanov void *section_ptr = ((u8 *)buf) + data_end; 10062ffd87d3SSergey Temerkhanov 10072ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].offset = cpu_to_le16(data_end); 10082ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].size = cpu_to_le16(size); 10092ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].type = cpu_to_le32(type); 10102ffd87d3SSergey Temerkhanov 10112ffd87d3SSergey Temerkhanov data_end += size; 10122ffd87d3SSergey Temerkhanov buf->data_end = cpu_to_le16(data_end); 10132ffd87d3SSergey Temerkhanov 10142ffd87d3SSergey Temerkhanov buf->section_count = cpu_to_le16(sect_count + 1); 10152ffd87d3SSergey Temerkhanov return section_ptr; 10162ffd87d3SSergey Temerkhanov } 10172ffd87d3SSergey Temerkhanov 10182ffd87d3SSergey Temerkhanov /* no free section table entries */ 10192ffd87d3SSergey Temerkhanov return NULL; 10202ffd87d3SSergey Temerkhanov } 10212ffd87d3SSergey Temerkhanov 10222ffd87d3SSergey Temerkhanov /** 10232ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_single_section 10242ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 10252ffd87d3SSergey Temerkhanov * @type: the section type value 10262ffd87d3SSergey Temerkhanov * @size: the size of the section to reserve (in bytes) 10272ffd87d3SSergey Temerkhanov * @section: returns pointer to the section 10282ffd87d3SSergey Temerkhanov * 10292ffd87d3SSergey Temerkhanov * Allocates a package buffer with a single section. 10302ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 10312ffd87d3SSergey Temerkhanov */ 10322ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc_single_section(struct ice_hw *hw, 10332ffd87d3SSergey Temerkhanov u32 type, u16 size, 10342ffd87d3SSergey Temerkhanov void **section) 10352ffd87d3SSergey Temerkhanov { 10362ffd87d3SSergey Temerkhanov struct ice_buf_build *buf; 10372ffd87d3SSergey Temerkhanov 10382ffd87d3SSergey Temerkhanov if (!section) 10392ffd87d3SSergey Temerkhanov return NULL; 10402ffd87d3SSergey Temerkhanov 10412ffd87d3SSergey Temerkhanov buf = ice_pkg_buf_alloc(hw); 10422ffd87d3SSergey Temerkhanov if (!buf) 10432ffd87d3SSergey Temerkhanov return NULL; 10442ffd87d3SSergey Temerkhanov 10452ffd87d3SSergey Temerkhanov if (ice_pkg_buf_reserve_section(buf, 1)) 10462ffd87d3SSergey Temerkhanov goto ice_pkg_buf_alloc_single_section_err; 10472ffd87d3SSergey Temerkhanov 10482ffd87d3SSergey Temerkhanov *section = ice_pkg_buf_alloc_section(buf, type, size); 10492ffd87d3SSergey Temerkhanov if (!*section) 10502ffd87d3SSergey Temerkhanov goto ice_pkg_buf_alloc_single_section_err; 10512ffd87d3SSergey Temerkhanov 10522ffd87d3SSergey Temerkhanov return buf; 10532ffd87d3SSergey Temerkhanov 10542ffd87d3SSergey Temerkhanov ice_pkg_buf_alloc_single_section_err: 10552ffd87d3SSergey Temerkhanov ice_pkg_buf_free(hw, buf); 10562ffd87d3SSergey Temerkhanov return NULL; 10572ffd87d3SSergey Temerkhanov } 10582ffd87d3SSergey Temerkhanov 10592ffd87d3SSergey Temerkhanov /** 10602ffd87d3SSergey Temerkhanov * ice_pkg_buf_get_active_sections 10612ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 10622ffd87d3SSergey Temerkhanov * 10632ffd87d3SSergey Temerkhanov * Returns the number of active sections. Before using the package buffer 10642ffd87d3SSergey Temerkhanov * in an update package command, the caller should make sure that there is at 10652ffd87d3SSergey Temerkhanov * least one active section - otherwise, the buffer is not legal and should 10662ffd87d3SSergey Temerkhanov * not be used. 10672ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 10682ffd87d3SSergey Temerkhanov */ 10692ffd87d3SSergey Temerkhanov u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld) 10702ffd87d3SSergey Temerkhanov { 10712ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 10722ffd87d3SSergey Temerkhanov 10732ffd87d3SSergey Temerkhanov if (!bld) 10742ffd87d3SSergey Temerkhanov return 0; 10752ffd87d3SSergey Temerkhanov 10762ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf; 10772ffd87d3SSergey Temerkhanov return le16_to_cpu(buf->section_count); 10782ffd87d3SSergey Temerkhanov } 10792ffd87d3SSergey Temerkhanov 10802ffd87d3SSergey Temerkhanov /** 10812ffd87d3SSergey Temerkhanov * ice_pkg_buf 10822ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 10832ffd87d3SSergey Temerkhanov * 10842ffd87d3SSergey Temerkhanov * Return a pointer to the buffer's header 10852ffd87d3SSergey Temerkhanov */ 10862ffd87d3SSergey Temerkhanov struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld) 10872ffd87d3SSergey Temerkhanov { 10882ffd87d3SSergey Temerkhanov if (!bld) 10892ffd87d3SSergey Temerkhanov return NULL; 10902ffd87d3SSergey Temerkhanov 10912ffd87d3SSergey Temerkhanov return &bld->buf; 10922ffd87d3SSergey Temerkhanov } 10932ffd87d3SSergey Temerkhanov 10942ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_map_aq_err_to_ddp_state(enum ice_aq_err aq_err) 10952ffd87d3SSergey Temerkhanov { 10962ffd87d3SSergey Temerkhanov switch (aq_err) { 10972ffd87d3SSergey Temerkhanov case ICE_AQ_RC_ENOSEC: 10982ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADSIG: 10992ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_SIGNATURE_INVALID; 11002ffd87d3SSergey Temerkhanov case ICE_AQ_RC_ESVN: 11012ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_REVISION_TOO_LOW; 11022ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADMAN: 11032ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADBUF: 11042ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_LOAD_ERROR; 11052ffd87d3SSergey Temerkhanov default: 11062ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 11072ffd87d3SSergey Temerkhanov } 11082ffd87d3SSergey Temerkhanov } 11092ffd87d3SSergey Temerkhanov 11102ffd87d3SSergey Temerkhanov /** 11112ffd87d3SSergey Temerkhanov * ice_acquire_global_cfg_lock 11122ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 11132ffd87d3SSergey Temerkhanov * @access: access type (read or write) 11142ffd87d3SSergey Temerkhanov * 11152ffd87d3SSergey Temerkhanov * This function will request ownership of the global config lock for reading 11162ffd87d3SSergey Temerkhanov * or writing of the package. When attempting to obtain write access, the 11172ffd87d3SSergey Temerkhanov * caller must check for the following two return values: 11182ffd87d3SSergey Temerkhanov * 11192ffd87d3SSergey Temerkhanov * 0 - Means the caller has acquired the global config lock 11202ffd87d3SSergey Temerkhanov * and can perform writing of the package. 11212ffd87d3SSergey Temerkhanov * -EALREADY - Indicates another driver has already written the 11222ffd87d3SSergey Temerkhanov * package or has found that no update was necessary; in 11232ffd87d3SSergey Temerkhanov * this case, the caller can just skip performing any 11242ffd87d3SSergey Temerkhanov * update of the package. 11252ffd87d3SSergey Temerkhanov */ 11262ffd87d3SSergey Temerkhanov static int ice_acquire_global_cfg_lock(struct ice_hw *hw, 11272ffd87d3SSergey Temerkhanov enum ice_aq_res_access_type access) 11282ffd87d3SSergey Temerkhanov { 11292ffd87d3SSergey Temerkhanov int status; 11302ffd87d3SSergey Temerkhanov 11312ffd87d3SSergey Temerkhanov status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, access, 11322ffd87d3SSergey Temerkhanov ICE_GLOBAL_CFG_LOCK_TIMEOUT); 11332ffd87d3SSergey Temerkhanov 11342ffd87d3SSergey Temerkhanov if (!status) 11352ffd87d3SSergey Temerkhanov mutex_lock(&ice_global_cfg_lock_sw); 11362ffd87d3SSergey Temerkhanov else if (status == -EALREADY) 11372ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, 11382ffd87d3SSergey Temerkhanov "Global config lock: No work to do\n"); 11392ffd87d3SSergey Temerkhanov 11402ffd87d3SSergey Temerkhanov return status; 11412ffd87d3SSergey Temerkhanov } 11422ffd87d3SSergey Temerkhanov 11432ffd87d3SSergey Temerkhanov /** 11442ffd87d3SSergey Temerkhanov * ice_release_global_cfg_lock 11452ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 11462ffd87d3SSergey Temerkhanov * 11472ffd87d3SSergey Temerkhanov * This function will release the global config lock. 11482ffd87d3SSergey Temerkhanov */ 11492ffd87d3SSergey Temerkhanov static void ice_release_global_cfg_lock(struct ice_hw *hw) 11502ffd87d3SSergey Temerkhanov { 11512ffd87d3SSergey Temerkhanov mutex_unlock(&ice_global_cfg_lock_sw); 11522ffd87d3SSergey Temerkhanov ice_release_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID); 11532ffd87d3SSergey Temerkhanov } 11542ffd87d3SSergey Temerkhanov 11552ffd87d3SSergey Temerkhanov /** 1156708b352fSJan Sokolowski * ice_aq_download_pkg 1157708b352fSJan Sokolowski * @hw: pointer to the hardware structure 1158708b352fSJan Sokolowski * @pkg_buf: the package buffer to transfer 1159708b352fSJan Sokolowski * @buf_size: the size of the package buffer 1160708b352fSJan Sokolowski * @last_buf: last buffer indicator 1161708b352fSJan Sokolowski * @error_offset: returns error offset 1162708b352fSJan Sokolowski * @error_info: returns error information 1163708b352fSJan Sokolowski * @cd: pointer to command details structure or NULL 1164708b352fSJan Sokolowski * 1165708b352fSJan Sokolowski * Download Package (0x0C40) 1166708b352fSJan Sokolowski */ 1167708b352fSJan Sokolowski static int 1168708b352fSJan Sokolowski ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 1169708b352fSJan Sokolowski u16 buf_size, bool last_buf, u32 *error_offset, 1170708b352fSJan Sokolowski u32 *error_info, struct ice_sq_cd *cd) 1171708b352fSJan Sokolowski { 1172708b352fSJan Sokolowski struct ice_aqc_download_pkg *cmd; 1173708b352fSJan Sokolowski struct ice_aq_desc desc; 1174708b352fSJan Sokolowski int status; 1175708b352fSJan Sokolowski 1176708b352fSJan Sokolowski if (error_offset) 1177708b352fSJan Sokolowski *error_offset = 0; 1178708b352fSJan Sokolowski if (error_info) 1179708b352fSJan Sokolowski *error_info = 0; 1180708b352fSJan Sokolowski 1181708b352fSJan Sokolowski cmd = &desc.params.download_pkg; 1182708b352fSJan Sokolowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg); 1183708b352fSJan Sokolowski desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 1184708b352fSJan Sokolowski 1185708b352fSJan Sokolowski if (last_buf) 1186708b352fSJan Sokolowski cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF; 1187708b352fSJan Sokolowski 1188708b352fSJan Sokolowski status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd); 1189708b352fSJan Sokolowski if (status == -EIO) { 1190708b352fSJan Sokolowski /* Read error from buffer only when the FW returned an error */ 1191708b352fSJan Sokolowski struct ice_aqc_download_pkg_resp *resp; 1192708b352fSJan Sokolowski 1193708b352fSJan Sokolowski resp = (struct ice_aqc_download_pkg_resp *)pkg_buf; 1194708b352fSJan Sokolowski if (error_offset) 1195708b352fSJan Sokolowski *error_offset = le32_to_cpu(resp->error_offset); 1196708b352fSJan Sokolowski if (error_info) 1197708b352fSJan Sokolowski *error_info = le32_to_cpu(resp->error_info); 1198708b352fSJan Sokolowski } 1199708b352fSJan Sokolowski 1200708b352fSJan Sokolowski return status; 1201708b352fSJan Sokolowski } 1202708b352fSJan Sokolowski 1203708b352fSJan Sokolowski /** 12043cbdb034SDan Nowlin * ice_get_pkg_seg_by_idx 12053cbdb034SDan Nowlin * @pkg_hdr: pointer to the package header to be searched 12063cbdb034SDan Nowlin * @idx: index of segment 12073cbdb034SDan Nowlin */ 12083cbdb034SDan Nowlin static struct ice_generic_seg_hdr * 12093cbdb034SDan Nowlin ice_get_pkg_seg_by_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx) 12103cbdb034SDan Nowlin { 12113cbdb034SDan Nowlin if (idx < le32_to_cpu(pkg_hdr->seg_count)) 12123cbdb034SDan Nowlin return (struct ice_generic_seg_hdr *) 12133cbdb034SDan Nowlin ((u8 *)pkg_hdr + 12143cbdb034SDan Nowlin le32_to_cpu(pkg_hdr->seg_offset[idx])); 12153cbdb034SDan Nowlin 12163cbdb034SDan Nowlin return NULL; 12173cbdb034SDan Nowlin } 12183cbdb034SDan Nowlin 12193cbdb034SDan Nowlin /** 12203cbdb034SDan Nowlin * ice_is_signing_seg_at_idx - determine if segment is a signing segment 12213cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 12223cbdb034SDan Nowlin * @idx: segment index 12233cbdb034SDan Nowlin */ 12243cbdb034SDan Nowlin static bool ice_is_signing_seg_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx) 12253cbdb034SDan Nowlin { 12263cbdb034SDan Nowlin struct ice_generic_seg_hdr *seg; 12273cbdb034SDan Nowlin 12283cbdb034SDan Nowlin seg = ice_get_pkg_seg_by_idx(pkg_hdr, idx); 12293cbdb034SDan Nowlin if (!seg) 12303cbdb034SDan Nowlin return false; 12313cbdb034SDan Nowlin 12323cbdb034SDan Nowlin return le32_to_cpu(seg->seg_type) == SEGMENT_TYPE_SIGNING; 12333cbdb034SDan Nowlin } 12343cbdb034SDan Nowlin 12353cbdb034SDan Nowlin /** 12363cbdb034SDan Nowlin * ice_is_signing_seg_type_at_idx 12373cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 12383cbdb034SDan Nowlin * @idx: segment index 12393cbdb034SDan Nowlin * @seg_id: segment id that is expected 12403cbdb034SDan Nowlin * @sign_type: signing type 12413cbdb034SDan Nowlin * 12423cbdb034SDan Nowlin * Determine if a segment is a signing segment of the correct type 12433cbdb034SDan Nowlin */ 12443cbdb034SDan Nowlin static bool 12453cbdb034SDan Nowlin ice_is_signing_seg_type_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx, 12463cbdb034SDan Nowlin u32 seg_id, u32 sign_type) 12473cbdb034SDan Nowlin { 12483cbdb034SDan Nowlin struct ice_sign_seg *seg; 12493cbdb034SDan Nowlin 12503cbdb034SDan Nowlin if (!ice_is_signing_seg_at_idx(pkg_hdr, idx)) 12513cbdb034SDan Nowlin return false; 12523cbdb034SDan Nowlin 12533cbdb034SDan Nowlin seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); 12543cbdb034SDan Nowlin 12553cbdb034SDan Nowlin if (seg && le32_to_cpu(seg->seg_id) == seg_id && 12563cbdb034SDan Nowlin le32_to_cpu(seg->sign_type) == sign_type) 12573cbdb034SDan Nowlin return true; 12583cbdb034SDan Nowlin 12593cbdb034SDan Nowlin return false; 12603cbdb034SDan Nowlin } 12613cbdb034SDan Nowlin 12623cbdb034SDan Nowlin /** 12633cbdb034SDan Nowlin * ice_is_buffer_metadata - determine if package buffer is a metadata buffer 12643cbdb034SDan Nowlin * @buf: pointer to buffer header 12653cbdb034SDan Nowlin */ 12663cbdb034SDan Nowlin static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf) 12673cbdb034SDan Nowlin { 12683cbdb034SDan Nowlin if (le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF) 12693cbdb034SDan Nowlin return true; 12703cbdb034SDan Nowlin 12713cbdb034SDan Nowlin return false; 12723cbdb034SDan Nowlin } 12733cbdb034SDan Nowlin 12743cbdb034SDan Nowlin /** 12753cbdb034SDan Nowlin * ice_is_last_download_buffer 12763cbdb034SDan Nowlin * @buf: pointer to current buffer header 12773cbdb034SDan Nowlin * @idx: index of the buffer in the current sequence 12783cbdb034SDan Nowlin * @count: the buffer count in the current sequence 12793cbdb034SDan Nowlin * 12803cbdb034SDan Nowlin * Note: this routine should only be called if the buffer is not the last buffer 12813cbdb034SDan Nowlin */ 12823cbdb034SDan Nowlin static bool 12833cbdb034SDan Nowlin ice_is_last_download_buffer(struct ice_buf_hdr *buf, u32 idx, u32 count) 12843cbdb034SDan Nowlin { 12853cbdb034SDan Nowlin struct ice_buf *next_buf; 12863cbdb034SDan Nowlin 12873cbdb034SDan Nowlin if ((idx + 1) == count) 12883cbdb034SDan Nowlin return true; 12893cbdb034SDan Nowlin 12903cbdb034SDan Nowlin /* A set metadata flag in the next buffer will signal that the current 12913cbdb034SDan Nowlin * buffer will be the last buffer downloaded 12923cbdb034SDan Nowlin */ 12933cbdb034SDan Nowlin next_buf = ((struct ice_buf *)buf) + 1; 12943cbdb034SDan Nowlin 12953cbdb034SDan Nowlin return ice_is_buffer_metadata((struct ice_buf_hdr *)next_buf); 12963cbdb034SDan Nowlin } 12973cbdb034SDan Nowlin 12983cbdb034SDan Nowlin /** 12993cbdb034SDan Nowlin * ice_dwnld_cfg_bufs_no_lock 13002ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 13012ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers 13023cbdb034SDan Nowlin * @start: buffer index of first buffer to download 13033cbdb034SDan Nowlin * @count: the number of buffers to download 13043cbdb034SDan Nowlin * @indicate_last: if true, then set last buffer flag on last buffer download 13052ffd87d3SSergey Temerkhanov * 13063cbdb034SDan Nowlin * Downloads package configuration buffers to the firmware. Metadata buffers 13073cbdb034SDan Nowlin * are skipped, and the first metadata buffer found indicates that the rest 13083cbdb034SDan Nowlin * of the buffers are all metadata buffers. 13092ffd87d3SSergey Temerkhanov */ 13103cbdb034SDan Nowlin static enum ice_ddp_state 13113cbdb034SDan Nowlin ice_dwnld_cfg_bufs_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 start, 13123cbdb034SDan Nowlin u32 count, bool indicate_last) 13132ffd87d3SSergey Temerkhanov { 13142ffd87d3SSergey Temerkhanov enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS; 13152ffd87d3SSergey Temerkhanov struct ice_buf_hdr *bh; 13162ffd87d3SSergey Temerkhanov enum ice_aq_err err; 13172ffd87d3SSergey Temerkhanov u32 offset, info, i; 13182ffd87d3SSergey Temerkhanov 13192ffd87d3SSergey Temerkhanov if (!bufs || !count) 13202ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 13212ffd87d3SSergey Temerkhanov 13222ffd87d3SSergey Temerkhanov /* If the first buffer's first section has its metadata bit set 13232ffd87d3SSergey Temerkhanov * then there are no buffers to be downloaded, and the operation is 13242ffd87d3SSergey Temerkhanov * considered a success. 13252ffd87d3SSergey Temerkhanov */ 13263cbdb034SDan Nowlin bh = (struct ice_buf_hdr *)(bufs + start); 13272ffd87d3SSergey Temerkhanov if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF) 13282ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 13292ffd87d3SSergey Temerkhanov 13302ffd87d3SSergey Temerkhanov for (i = 0; i < count; i++) { 13313cbdb034SDan Nowlin bool last = false; 13323cbdb034SDan Nowlin int status; 13332ffd87d3SSergey Temerkhanov 13343cbdb034SDan Nowlin bh = (struct ice_buf_hdr *)(bufs + start + i); 13352ffd87d3SSergey Temerkhanov 13363cbdb034SDan Nowlin if (indicate_last) 13373cbdb034SDan Nowlin last = ice_is_last_download_buffer(bh, i, count); 13382ffd87d3SSergey Temerkhanov 13392ffd87d3SSergey Temerkhanov status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE, last, 13402ffd87d3SSergey Temerkhanov &offset, &info, NULL); 13412ffd87d3SSergey Temerkhanov 13422ffd87d3SSergey Temerkhanov /* Save AQ status from download package */ 13432ffd87d3SSergey Temerkhanov if (status) { 13443cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n", 13452ffd87d3SSergey Temerkhanov status, offset, info); 13462ffd87d3SSergey Temerkhanov err = hw->adminq.sq_last_status; 13472ffd87d3SSergey Temerkhanov state = ice_map_aq_err_to_ddp_state(err); 13482ffd87d3SSergey Temerkhanov break; 13492ffd87d3SSergey Temerkhanov } 13502ffd87d3SSergey Temerkhanov 13512ffd87d3SSergey Temerkhanov if (last) 13522ffd87d3SSergey Temerkhanov break; 13532ffd87d3SSergey Temerkhanov } 13542ffd87d3SSergey Temerkhanov 13553cbdb034SDan Nowlin return state; 13562ffd87d3SSergey Temerkhanov } 13572ffd87d3SSergey Temerkhanov 13583cbdb034SDan Nowlin /** 13593cbdb034SDan Nowlin * ice_download_pkg_sig_seg - download a signature segment 13603cbdb034SDan Nowlin * @hw: pointer to the hardware structure 13613cbdb034SDan Nowlin * @seg: pointer to signature segment 13623cbdb034SDan Nowlin */ 13633cbdb034SDan Nowlin static enum ice_ddp_state 13643cbdb034SDan Nowlin ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg) 13653cbdb034SDan Nowlin { 13663cbdb034SDan Nowlin return ice_dwnld_cfg_bufs_no_lock(hw, seg->buf_tbl.buf_array, 0, 13673cbdb034SDan Nowlin le32_to_cpu(seg->buf_tbl.buf_count), 13683cbdb034SDan Nowlin false); 13693cbdb034SDan Nowlin } 13703cbdb034SDan Nowlin 13713cbdb034SDan Nowlin /** 13723cbdb034SDan Nowlin * ice_download_pkg_config_seg - download a config segment 13733cbdb034SDan Nowlin * @hw: pointer to the hardware structure 13743cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 13753cbdb034SDan Nowlin * @idx: segment index 13763cbdb034SDan Nowlin * @start: starting buffer 13773cbdb034SDan Nowlin * @count: buffer count 13783cbdb034SDan Nowlin * 13793cbdb034SDan Nowlin * Note: idx must reference a ICE segment 13803cbdb034SDan Nowlin */ 13813cbdb034SDan Nowlin static enum ice_ddp_state 13823cbdb034SDan Nowlin ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, 13833cbdb034SDan Nowlin u32 idx, u32 start, u32 count) 13843cbdb034SDan Nowlin { 13853cbdb034SDan Nowlin struct ice_buf_table *bufs; 13863cbdb034SDan Nowlin struct ice_seg *seg; 13873cbdb034SDan Nowlin u32 buf_count; 13883cbdb034SDan Nowlin 13893cbdb034SDan Nowlin seg = (struct ice_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); 13903cbdb034SDan Nowlin if (!seg) 13913cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 13923cbdb034SDan Nowlin 13933cbdb034SDan Nowlin bufs = ice_find_buf_table(seg); 13943cbdb034SDan Nowlin buf_count = le32_to_cpu(bufs->buf_count); 13953cbdb034SDan Nowlin 13963cbdb034SDan Nowlin if (start >= buf_count || start + count > buf_count) 13973cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 13983cbdb034SDan Nowlin 13993cbdb034SDan Nowlin return ice_dwnld_cfg_bufs_no_lock(hw, bufs->buf_array, start, count, 14003cbdb034SDan Nowlin true); 14013cbdb034SDan Nowlin } 14023cbdb034SDan Nowlin 14033cbdb034SDan Nowlin /** 14043cbdb034SDan Nowlin * ice_dwnld_sign_and_cfg_segs - download a signing segment and config segment 14053cbdb034SDan Nowlin * @hw: pointer to the hardware structure 14063cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 14073cbdb034SDan Nowlin * @idx: segment index (must be a signature segment) 14083cbdb034SDan Nowlin * 14093cbdb034SDan Nowlin * Note: idx must reference a signature segment 14103cbdb034SDan Nowlin */ 14113cbdb034SDan Nowlin static enum ice_ddp_state 14123cbdb034SDan Nowlin ice_dwnld_sign_and_cfg_segs(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, 14133cbdb034SDan Nowlin u32 idx) 14143cbdb034SDan Nowlin { 14153cbdb034SDan Nowlin enum ice_ddp_state state; 14163cbdb034SDan Nowlin struct ice_sign_seg *seg; 14173cbdb034SDan Nowlin u32 conf_idx; 14183cbdb034SDan Nowlin u32 start; 14193cbdb034SDan Nowlin u32 count; 14203cbdb034SDan Nowlin 14213cbdb034SDan Nowlin seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); 14223cbdb034SDan Nowlin if (!seg) { 14233cbdb034SDan Nowlin state = ICE_DDP_PKG_ERR; 14243cbdb034SDan Nowlin goto exit; 14253cbdb034SDan Nowlin } 14263cbdb034SDan Nowlin 1427*6d51d44eSDan Nowlin count = le32_to_cpu(seg->signed_buf_count); 1428*6d51d44eSDan Nowlin state = ice_download_pkg_sig_seg(hw, seg); 1429*6d51d44eSDan Nowlin if (state || !count) 1430*6d51d44eSDan Nowlin goto exit; 1431*6d51d44eSDan Nowlin 14323cbdb034SDan Nowlin conf_idx = le32_to_cpu(seg->signed_seg_idx); 14333cbdb034SDan Nowlin start = le32_to_cpu(seg->signed_buf_start); 14343cbdb034SDan Nowlin 14353cbdb034SDan Nowlin state = ice_download_pkg_config_seg(hw, pkg_hdr, conf_idx, start, 14363cbdb034SDan Nowlin count); 14373cbdb034SDan Nowlin 14383cbdb034SDan Nowlin exit: 14393cbdb034SDan Nowlin return state; 14403cbdb034SDan Nowlin } 14413cbdb034SDan Nowlin 14423cbdb034SDan Nowlin /** 14433cbdb034SDan Nowlin * ice_match_signing_seg - determine if a matching signing segment exists 14443cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 14453cbdb034SDan Nowlin * @seg_id: segment id that is expected 14463cbdb034SDan Nowlin * @sign_type: signing type 14473cbdb034SDan Nowlin */ 14483cbdb034SDan Nowlin static bool 14493cbdb034SDan Nowlin ice_match_signing_seg(struct ice_pkg_hdr *pkg_hdr, u32 seg_id, u32 sign_type) 14503cbdb034SDan Nowlin { 14513cbdb034SDan Nowlin u32 i; 14523cbdb034SDan Nowlin 14533cbdb034SDan Nowlin for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { 14543cbdb034SDan Nowlin if (ice_is_signing_seg_type_at_idx(pkg_hdr, i, seg_id, 14553cbdb034SDan Nowlin sign_type)) 14563cbdb034SDan Nowlin return true; 14573cbdb034SDan Nowlin } 14583cbdb034SDan Nowlin 14593cbdb034SDan Nowlin return false; 14603cbdb034SDan Nowlin } 14613cbdb034SDan Nowlin 14623cbdb034SDan Nowlin /** 14633cbdb034SDan Nowlin * ice_post_dwnld_pkg_actions - perform post download package actions 14643cbdb034SDan Nowlin * @hw: pointer to the hardware structure 14653cbdb034SDan Nowlin */ 14663cbdb034SDan Nowlin static enum ice_ddp_state 14673cbdb034SDan Nowlin ice_post_dwnld_pkg_actions(struct ice_hw *hw) 14683cbdb034SDan Nowlin { 14693cbdb034SDan Nowlin int status; 14703cbdb034SDan Nowlin 14713cbdb034SDan Nowlin status = ice_set_vlan_mode(hw); 14723cbdb034SDan Nowlin if (status) { 14733cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Failed to set VLAN mode: err %d\n", 14743cbdb034SDan Nowlin status); 14753cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 14763cbdb034SDan Nowlin } 14773cbdb034SDan Nowlin 14783cbdb034SDan Nowlin return ICE_DDP_PKG_SUCCESS; 14793cbdb034SDan Nowlin } 14803cbdb034SDan Nowlin 14813cbdb034SDan Nowlin /** 1482a778616eSDan Nowlin * ice_download_pkg_with_sig_seg 14833cbdb034SDan Nowlin * @hw: pointer to the hardware structure 14843cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 14853cbdb034SDan Nowlin * 14863cbdb034SDan Nowlin * Handles the download of a complete package. 14873cbdb034SDan Nowlin */ 14883cbdb034SDan Nowlin static enum ice_ddp_state 1489a778616eSDan Nowlin ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) 14903cbdb034SDan Nowlin { 14913cbdb034SDan Nowlin enum ice_aq_err aq_err = hw->adminq.sq_last_status; 14923cbdb034SDan Nowlin enum ice_ddp_state state = ICE_DDP_PKG_ERR; 14933cbdb034SDan Nowlin int status; 14943cbdb034SDan Nowlin u32 i; 14953cbdb034SDan Nowlin 14963cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_INIT, "Segment ID %d\n", hw->pkg_seg_id); 14973cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_INIT, "Signature type %d\n", hw->pkg_sign_type); 14983cbdb034SDan Nowlin 14993cbdb034SDan Nowlin status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE); 15003cbdb034SDan Nowlin if (status) { 15013cbdb034SDan Nowlin if (status == -EALREADY) 15023cbdb034SDan Nowlin state = ICE_DDP_PKG_ALREADY_LOADED; 15033cbdb034SDan Nowlin else 15043cbdb034SDan Nowlin state = ice_map_aq_err_to_ddp_state(aq_err); 15053cbdb034SDan Nowlin return state; 15063cbdb034SDan Nowlin } 15073cbdb034SDan Nowlin 15083cbdb034SDan Nowlin for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { 15093cbdb034SDan Nowlin if (!ice_is_signing_seg_type_at_idx(pkg_hdr, i, hw->pkg_seg_id, 15103cbdb034SDan Nowlin hw->pkg_sign_type)) 15113cbdb034SDan Nowlin continue; 15123cbdb034SDan Nowlin 15133cbdb034SDan Nowlin state = ice_dwnld_sign_and_cfg_segs(hw, pkg_hdr, i); 15143cbdb034SDan Nowlin if (state) 15153cbdb034SDan Nowlin break; 15163cbdb034SDan Nowlin } 15173cbdb034SDan Nowlin 15183cbdb034SDan Nowlin if (!state) 15193cbdb034SDan Nowlin state = ice_post_dwnld_pkg_actions(hw); 15203cbdb034SDan Nowlin 15212ffd87d3SSergey Temerkhanov ice_release_global_cfg_lock(hw); 1522a778616eSDan Nowlin 1523a778616eSDan Nowlin return state; 1524a778616eSDan Nowlin } 1525a778616eSDan Nowlin 1526a778616eSDan Nowlin /** 1527a778616eSDan Nowlin * ice_dwnld_cfg_bufs 1528a778616eSDan Nowlin * @hw: pointer to the hardware structure 1529a778616eSDan Nowlin * @bufs: pointer to an array of buffers 1530a778616eSDan Nowlin * @count: the number of buffers in the array 1531a778616eSDan Nowlin * 1532a778616eSDan Nowlin * Obtains global config lock and downloads the package configuration buffers 1533a778616eSDan Nowlin * to the firmware. 1534a778616eSDan Nowlin */ 1535a778616eSDan Nowlin static enum ice_ddp_state 1536a778616eSDan Nowlin ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count) 1537a778616eSDan Nowlin { 1538a778616eSDan Nowlin enum ice_ddp_state state; 1539a778616eSDan Nowlin struct ice_buf_hdr *bh; 1540a778616eSDan Nowlin int status; 1541a778616eSDan Nowlin 1542a778616eSDan Nowlin if (!bufs || !count) 1543a778616eSDan Nowlin return ICE_DDP_PKG_ERR; 1544a778616eSDan Nowlin 1545a778616eSDan Nowlin /* If the first buffer's first section has its metadata bit set 1546a778616eSDan Nowlin * then there are no buffers to be downloaded, and the operation is 1547a778616eSDan Nowlin * considered a success. 1548a778616eSDan Nowlin */ 1549a778616eSDan Nowlin bh = (struct ice_buf_hdr *)bufs; 1550a778616eSDan Nowlin if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF) 1551a778616eSDan Nowlin return ICE_DDP_PKG_SUCCESS; 1552a778616eSDan Nowlin 1553a778616eSDan Nowlin status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE); 1554a778616eSDan Nowlin if (status) { 1555a778616eSDan Nowlin if (status == -EALREADY) 1556a778616eSDan Nowlin return ICE_DDP_PKG_ALREADY_LOADED; 1557a778616eSDan Nowlin return ice_map_aq_err_to_ddp_state(hw->adminq.sq_last_status); 1558a778616eSDan Nowlin } 1559a778616eSDan Nowlin 1560a778616eSDan Nowlin state = ice_dwnld_cfg_bufs_no_lock(hw, bufs, 0, count, true); 1561a778616eSDan Nowlin if (!state) 1562a778616eSDan Nowlin state = ice_post_dwnld_pkg_actions(hw); 1563a778616eSDan Nowlin 1564a778616eSDan Nowlin ice_release_global_cfg_lock(hw); 1565a778616eSDan Nowlin 1566a778616eSDan Nowlin return state; 1567a778616eSDan Nowlin } 1568a778616eSDan Nowlin 1569a778616eSDan Nowlin /** 1570a778616eSDan Nowlin * ice_download_pkg_without_sig_seg 1571a778616eSDan Nowlin * @hw: pointer to the hardware structure 1572a778616eSDan Nowlin * @ice_seg: pointer to the segment of the package to be downloaded 1573a778616eSDan Nowlin * 1574a778616eSDan Nowlin * Handles the download of a complete package without signature segment. 1575a778616eSDan Nowlin */ 1576a778616eSDan Nowlin static enum ice_ddp_state 1577a778616eSDan Nowlin ice_download_pkg_without_sig_seg(struct ice_hw *hw, struct ice_seg *ice_seg) 1578a778616eSDan Nowlin { 1579a778616eSDan Nowlin struct ice_buf_table *ice_buf_tbl; 1580a778616eSDan Nowlin 1581a778616eSDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n", 1582a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.major, 1583a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.minor, 1584a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.update, 1585a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.draft); 1586a778616eSDan Nowlin 1587a778616eSDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n", 1588a778616eSDan Nowlin le32_to_cpu(ice_seg->hdr.seg_type), 1589a778616eSDan Nowlin le32_to_cpu(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id); 1590a778616eSDan Nowlin 1591a778616eSDan Nowlin ice_buf_tbl = ice_find_buf_table(ice_seg); 1592a778616eSDan Nowlin 1593a778616eSDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Seg buf count: %d\n", 1594a778616eSDan Nowlin le32_to_cpu(ice_buf_tbl->buf_count)); 1595a778616eSDan Nowlin 1596a778616eSDan Nowlin return ice_dwnld_cfg_bufs(hw, ice_buf_tbl->buf_array, 1597a778616eSDan Nowlin le32_to_cpu(ice_buf_tbl->buf_count)); 1598a778616eSDan Nowlin } 1599a778616eSDan Nowlin 1600a778616eSDan Nowlin /** 1601a778616eSDan Nowlin * ice_download_pkg 1602a778616eSDan Nowlin * @hw: pointer to the hardware structure 1603a778616eSDan Nowlin * @pkg_hdr: pointer to package header 1604a778616eSDan Nowlin * @ice_seg: pointer to the segment of the package to be downloaded 1605a778616eSDan Nowlin * 1606a778616eSDan Nowlin * Handles the download of a complete package. 1607a778616eSDan Nowlin */ 1608a778616eSDan Nowlin static enum ice_ddp_state 1609a778616eSDan Nowlin ice_download_pkg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, 1610a778616eSDan Nowlin struct ice_seg *ice_seg) 1611a778616eSDan Nowlin { 1612a778616eSDan Nowlin enum ice_ddp_state state; 1613a778616eSDan Nowlin 1614a778616eSDan Nowlin if (hw->pkg_has_signing_seg) 1615a778616eSDan Nowlin state = ice_download_pkg_with_sig_seg(hw, pkg_hdr); 1616a778616eSDan Nowlin else 1617a778616eSDan Nowlin state = ice_download_pkg_without_sig_seg(hw, ice_seg); 1618a778616eSDan Nowlin 16193cbdb034SDan Nowlin ice_post_pkg_dwnld_vlan_mode_cfg(hw); 16202ffd87d3SSergey Temerkhanov 16212ffd87d3SSergey Temerkhanov return state; 16222ffd87d3SSergey Temerkhanov } 16232ffd87d3SSergey Temerkhanov 16242ffd87d3SSergey Temerkhanov /** 16252ffd87d3SSergey Temerkhanov * ice_aq_get_pkg_info_list 16262ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 16272ffd87d3SSergey Temerkhanov * @pkg_info: the buffer which will receive the information list 16282ffd87d3SSergey Temerkhanov * @buf_size: the size of the pkg_info information buffer 16292ffd87d3SSergey Temerkhanov * @cd: pointer to command details structure or NULL 16302ffd87d3SSergey Temerkhanov * 16312ffd87d3SSergey Temerkhanov * Get Package Info List (0x0C43) 16322ffd87d3SSergey Temerkhanov */ 16332ffd87d3SSergey Temerkhanov static int ice_aq_get_pkg_info_list(struct ice_hw *hw, 16342ffd87d3SSergey Temerkhanov struct ice_aqc_get_pkg_info_resp *pkg_info, 16352ffd87d3SSergey Temerkhanov u16 buf_size, struct ice_sq_cd *cd) 16362ffd87d3SSergey Temerkhanov { 16372ffd87d3SSergey Temerkhanov struct ice_aq_desc desc; 16382ffd87d3SSergey Temerkhanov 16392ffd87d3SSergey Temerkhanov ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list); 16402ffd87d3SSergey Temerkhanov 16412ffd87d3SSergey Temerkhanov return ice_aq_send_cmd(hw, &desc, pkg_info, buf_size, cd); 16422ffd87d3SSergey Temerkhanov } 16432ffd87d3SSergey Temerkhanov 16442ffd87d3SSergey Temerkhanov /** 16452ffd87d3SSergey Temerkhanov * ice_aq_update_pkg 16462ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 16472ffd87d3SSergey Temerkhanov * @pkg_buf: the package cmd buffer 16482ffd87d3SSergey Temerkhanov * @buf_size: the size of the package cmd buffer 16492ffd87d3SSergey Temerkhanov * @last_buf: last buffer indicator 16502ffd87d3SSergey Temerkhanov * @error_offset: returns error offset 16512ffd87d3SSergey Temerkhanov * @error_info: returns error information 16522ffd87d3SSergey Temerkhanov * @cd: pointer to command details structure or NULL 16532ffd87d3SSergey Temerkhanov * 16542ffd87d3SSergey Temerkhanov * Update Package (0x0C42) 16552ffd87d3SSergey Temerkhanov */ 16562ffd87d3SSergey Temerkhanov static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 16572ffd87d3SSergey Temerkhanov u16 buf_size, bool last_buf, u32 *error_offset, 16582ffd87d3SSergey Temerkhanov u32 *error_info, struct ice_sq_cd *cd) 16592ffd87d3SSergey Temerkhanov { 16602ffd87d3SSergey Temerkhanov struct ice_aqc_download_pkg *cmd; 16612ffd87d3SSergey Temerkhanov struct ice_aq_desc desc; 16622ffd87d3SSergey Temerkhanov int status; 16632ffd87d3SSergey Temerkhanov 16642ffd87d3SSergey Temerkhanov if (error_offset) 16652ffd87d3SSergey Temerkhanov *error_offset = 0; 16662ffd87d3SSergey Temerkhanov if (error_info) 16672ffd87d3SSergey Temerkhanov *error_info = 0; 16682ffd87d3SSergey Temerkhanov 16692ffd87d3SSergey Temerkhanov cmd = &desc.params.download_pkg; 16702ffd87d3SSergey Temerkhanov ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg); 16712ffd87d3SSergey Temerkhanov desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 16722ffd87d3SSergey Temerkhanov 16732ffd87d3SSergey Temerkhanov if (last_buf) 16742ffd87d3SSergey Temerkhanov cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF; 16752ffd87d3SSergey Temerkhanov 16762ffd87d3SSergey Temerkhanov status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd); 16772ffd87d3SSergey Temerkhanov if (status == -EIO) { 16782ffd87d3SSergey Temerkhanov /* Read error from buffer only when the FW returned an error */ 16792ffd87d3SSergey Temerkhanov struct ice_aqc_download_pkg_resp *resp; 16802ffd87d3SSergey Temerkhanov 16812ffd87d3SSergey Temerkhanov resp = (struct ice_aqc_download_pkg_resp *)pkg_buf; 16822ffd87d3SSergey Temerkhanov if (error_offset) 16832ffd87d3SSergey Temerkhanov *error_offset = le32_to_cpu(resp->error_offset); 16842ffd87d3SSergey Temerkhanov if (error_info) 16852ffd87d3SSergey Temerkhanov *error_info = le32_to_cpu(resp->error_info); 16862ffd87d3SSergey Temerkhanov } 16872ffd87d3SSergey Temerkhanov 16882ffd87d3SSergey Temerkhanov return status; 16892ffd87d3SSergey Temerkhanov } 16902ffd87d3SSergey Temerkhanov 16912ffd87d3SSergey Temerkhanov /** 1692708b352fSJan Sokolowski * ice_aq_upload_section 1693708b352fSJan Sokolowski * @hw: pointer to the hardware structure 1694708b352fSJan Sokolowski * @pkg_buf: the package buffer which will receive the section 1695708b352fSJan Sokolowski * @buf_size: the size of the package buffer 1696708b352fSJan Sokolowski * @cd: pointer to command details structure or NULL 1697708b352fSJan Sokolowski * 1698708b352fSJan Sokolowski * Upload Section (0x0C41) 1699708b352fSJan Sokolowski */ 1700708b352fSJan Sokolowski int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 1701708b352fSJan Sokolowski u16 buf_size, struct ice_sq_cd *cd) 1702708b352fSJan Sokolowski { 1703708b352fSJan Sokolowski struct ice_aq_desc desc; 1704708b352fSJan Sokolowski 1705708b352fSJan Sokolowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section); 1706708b352fSJan Sokolowski desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 1707708b352fSJan Sokolowski 1708708b352fSJan Sokolowski return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd); 1709708b352fSJan Sokolowski } 1710708b352fSJan Sokolowski 1711708b352fSJan Sokolowski /** 17122ffd87d3SSergey Temerkhanov * ice_update_pkg_no_lock 17132ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 17142ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers 17152ffd87d3SSergey Temerkhanov * @count: the number of buffers in the array 17162ffd87d3SSergey Temerkhanov */ 17172ffd87d3SSergey Temerkhanov int ice_update_pkg_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 count) 17182ffd87d3SSergey Temerkhanov { 17192ffd87d3SSergey Temerkhanov int status = 0; 17202ffd87d3SSergey Temerkhanov u32 i; 17212ffd87d3SSergey Temerkhanov 17222ffd87d3SSergey Temerkhanov for (i = 0; i < count; i++) { 17232ffd87d3SSergey Temerkhanov struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i); 17242ffd87d3SSergey Temerkhanov bool last = ((i + 1) == count); 17252ffd87d3SSergey Temerkhanov u32 offset, info; 17262ffd87d3SSergey Temerkhanov 17272ffd87d3SSergey Temerkhanov status = ice_aq_update_pkg(hw, bh, le16_to_cpu(bh->data_end), 17282ffd87d3SSergey Temerkhanov last, &offset, &info, NULL); 17292ffd87d3SSergey Temerkhanov 17302ffd87d3SSergey Temerkhanov if (status) { 17312ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, 17322ffd87d3SSergey Temerkhanov "Update pkg failed: err %d off %d inf %d\n", 17332ffd87d3SSergey Temerkhanov status, offset, info); 17342ffd87d3SSergey Temerkhanov break; 17352ffd87d3SSergey Temerkhanov } 17362ffd87d3SSergey Temerkhanov } 17372ffd87d3SSergey Temerkhanov 17382ffd87d3SSergey Temerkhanov return status; 17392ffd87d3SSergey Temerkhanov } 17402ffd87d3SSergey Temerkhanov 17412ffd87d3SSergey Temerkhanov /** 17422ffd87d3SSergey Temerkhanov * ice_update_pkg 17432ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 17442ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers 17452ffd87d3SSergey Temerkhanov * @count: the number of buffers in the array 17462ffd87d3SSergey Temerkhanov * 17472ffd87d3SSergey Temerkhanov * Obtains change lock and updates package. 17482ffd87d3SSergey Temerkhanov */ 17492ffd87d3SSergey Temerkhanov int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count) 17502ffd87d3SSergey Temerkhanov { 17512ffd87d3SSergey Temerkhanov int status; 17522ffd87d3SSergey Temerkhanov 17532ffd87d3SSergey Temerkhanov status = ice_acquire_change_lock(hw, ICE_RES_WRITE); 17542ffd87d3SSergey Temerkhanov if (status) 17552ffd87d3SSergey Temerkhanov return status; 17562ffd87d3SSergey Temerkhanov 17572ffd87d3SSergey Temerkhanov status = ice_update_pkg_no_lock(hw, bufs, count); 17582ffd87d3SSergey Temerkhanov 17592ffd87d3SSergey Temerkhanov ice_release_change_lock(hw); 17602ffd87d3SSergey Temerkhanov 17612ffd87d3SSergey Temerkhanov return status; 17622ffd87d3SSergey Temerkhanov } 17632ffd87d3SSergey Temerkhanov 17642ffd87d3SSergey Temerkhanov /** 17652ffd87d3SSergey Temerkhanov * ice_find_seg_in_pkg 17662ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 17672ffd87d3SSergey Temerkhanov * @seg_type: the segment type to search for (i.e., SEGMENT_TYPE_CPK) 17682ffd87d3SSergey Temerkhanov * @pkg_hdr: pointer to the package header to be searched 17692ffd87d3SSergey Temerkhanov * 17702ffd87d3SSergey Temerkhanov * This function searches a package file for a particular segment type. On 17712ffd87d3SSergey Temerkhanov * success it returns a pointer to the segment header, otherwise it will 17722ffd87d3SSergey Temerkhanov * return NULL. 17732ffd87d3SSergey Temerkhanov */ 1774708b352fSJan Sokolowski static struct ice_generic_seg_hdr * 1775708b352fSJan Sokolowski ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type, 17762ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg_hdr) 17772ffd87d3SSergey Temerkhanov { 17782ffd87d3SSergey Temerkhanov u32 i; 17792ffd87d3SSergey Temerkhanov 17802ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n", 17812ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor, 17822ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.update, 17832ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.draft); 17842ffd87d3SSergey Temerkhanov 17852ffd87d3SSergey Temerkhanov /* Search all package segments for the requested segment type */ 17862ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { 17872ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg; 17882ffd87d3SSergey Temerkhanov 17892ffd87d3SSergey Temerkhanov seg = (struct ice_generic_seg_hdr 17902ffd87d3SSergey Temerkhanov *)((u8 *)pkg_hdr + 17912ffd87d3SSergey Temerkhanov le32_to_cpu(pkg_hdr->seg_offset[i])); 17922ffd87d3SSergey Temerkhanov 17932ffd87d3SSergey Temerkhanov if (le32_to_cpu(seg->seg_type) == seg_type) 17942ffd87d3SSergey Temerkhanov return seg; 17952ffd87d3SSergey Temerkhanov } 17962ffd87d3SSergey Temerkhanov 17972ffd87d3SSergey Temerkhanov return NULL; 17982ffd87d3SSergey Temerkhanov } 17992ffd87d3SSergey Temerkhanov 18002ffd87d3SSergey Temerkhanov /** 18013cbdb034SDan Nowlin * ice_has_signing_seg - determine if package has a signing segment 18023cbdb034SDan Nowlin * @hw: pointer to the hardware structure 18033cbdb034SDan Nowlin * @pkg_hdr: pointer to the driver's package hdr 18043cbdb034SDan Nowlin */ 18053cbdb034SDan Nowlin static bool ice_has_signing_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) 18063cbdb034SDan Nowlin { 18073cbdb034SDan Nowlin struct ice_generic_seg_hdr *seg_hdr; 18083cbdb034SDan Nowlin 18093cbdb034SDan Nowlin seg_hdr = (struct ice_generic_seg_hdr *) 18103cbdb034SDan Nowlin ice_find_seg_in_pkg(hw, SEGMENT_TYPE_SIGNING, pkg_hdr); 18113cbdb034SDan Nowlin 18123cbdb034SDan Nowlin return seg_hdr ? true : false; 18133cbdb034SDan Nowlin } 18143cbdb034SDan Nowlin 18153cbdb034SDan Nowlin /** 18163cbdb034SDan Nowlin * ice_get_pkg_segment_id - get correct package segment id, based on device 18173cbdb034SDan Nowlin * @mac_type: MAC type of the device 18183cbdb034SDan Nowlin */ 18193cbdb034SDan Nowlin static u32 ice_get_pkg_segment_id(enum ice_mac_type mac_type) 18203cbdb034SDan Nowlin { 18213cbdb034SDan Nowlin u32 seg_id; 18223cbdb034SDan Nowlin 18233cbdb034SDan Nowlin switch (mac_type) { 18243cbdb034SDan Nowlin case ICE_MAC_E830: 18253cbdb034SDan Nowlin seg_id = SEGMENT_TYPE_ICE_E830; 18263cbdb034SDan Nowlin break; 18273cbdb034SDan Nowlin case ICE_MAC_GENERIC: 1828372e27deSGrzegorz Nitka case ICE_MAC_GENERIC_3K_E825: 18293cbdb034SDan Nowlin default: 18303cbdb034SDan Nowlin seg_id = SEGMENT_TYPE_ICE_E810; 18313cbdb034SDan Nowlin break; 18323cbdb034SDan Nowlin } 18333cbdb034SDan Nowlin 18343cbdb034SDan Nowlin return seg_id; 18353cbdb034SDan Nowlin } 18363cbdb034SDan Nowlin 18373cbdb034SDan Nowlin /** 18383cbdb034SDan Nowlin * ice_get_pkg_sign_type - get package segment sign type, based on device 18393cbdb034SDan Nowlin * @mac_type: MAC type of the device 18403cbdb034SDan Nowlin */ 18413cbdb034SDan Nowlin static u32 ice_get_pkg_sign_type(enum ice_mac_type mac_type) 18423cbdb034SDan Nowlin { 18433cbdb034SDan Nowlin u32 sign_type; 18443cbdb034SDan Nowlin 18453cbdb034SDan Nowlin switch (mac_type) { 18463cbdb034SDan Nowlin case ICE_MAC_E830: 18473cbdb034SDan Nowlin sign_type = SEGMENT_SIGN_TYPE_RSA3K_SBB; 18483cbdb034SDan Nowlin break; 1849372e27deSGrzegorz Nitka case ICE_MAC_GENERIC_3K_E825: 1850372e27deSGrzegorz Nitka sign_type = SEGMENT_SIGN_TYPE_RSA3K_E825; 1851372e27deSGrzegorz Nitka break; 18523cbdb034SDan Nowlin case ICE_MAC_GENERIC: 18533cbdb034SDan Nowlin default: 18543cbdb034SDan Nowlin sign_type = SEGMENT_SIGN_TYPE_RSA2K; 18553cbdb034SDan Nowlin break; 18563cbdb034SDan Nowlin } 18573cbdb034SDan Nowlin 18583cbdb034SDan Nowlin return sign_type; 18593cbdb034SDan Nowlin } 18603cbdb034SDan Nowlin 18613cbdb034SDan Nowlin /** 18623cbdb034SDan Nowlin * ice_get_signing_req - get correct package requirements, based on device 18633cbdb034SDan Nowlin * @hw: pointer to the hardware structure 18643cbdb034SDan Nowlin */ 18653cbdb034SDan Nowlin static void ice_get_signing_req(struct ice_hw *hw) 18663cbdb034SDan Nowlin { 18673cbdb034SDan Nowlin hw->pkg_seg_id = ice_get_pkg_segment_id(hw->mac_type); 18683cbdb034SDan Nowlin hw->pkg_sign_type = ice_get_pkg_sign_type(hw->mac_type); 18693cbdb034SDan Nowlin } 18703cbdb034SDan Nowlin 18713cbdb034SDan Nowlin /** 18722ffd87d3SSergey Temerkhanov * ice_init_pkg_info 18732ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 18742ffd87d3SSergey Temerkhanov * @pkg_hdr: pointer to the driver's package hdr 18752ffd87d3SSergey Temerkhanov * 18762ffd87d3SSergey Temerkhanov * Saves off the package details into the HW structure. 18772ffd87d3SSergey Temerkhanov */ 18782ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_init_pkg_info(struct ice_hw *hw, 18792ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg_hdr) 18802ffd87d3SSergey Temerkhanov { 18812ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg_hdr; 18822ffd87d3SSergey Temerkhanov 18832ffd87d3SSergey Temerkhanov if (!pkg_hdr) 18842ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 18852ffd87d3SSergey Temerkhanov 18863cbdb034SDan Nowlin hw->pkg_has_signing_seg = ice_has_signing_seg(hw, pkg_hdr); 18873cbdb034SDan Nowlin ice_get_signing_req(hw); 18883cbdb034SDan Nowlin 18893cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_INIT, "Pkg using segment id: 0x%08X\n", 18903cbdb034SDan Nowlin hw->pkg_seg_id); 18913cbdb034SDan Nowlin 18923cbdb034SDan Nowlin seg_hdr = (struct ice_generic_seg_hdr *) 18933cbdb034SDan Nowlin ice_find_seg_in_pkg(hw, hw->pkg_seg_id, pkg_hdr); 18942ffd87d3SSergey Temerkhanov if (seg_hdr) { 18952ffd87d3SSergey Temerkhanov struct ice_meta_sect *meta; 18962ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 18972ffd87d3SSergey Temerkhanov 18982ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 18992ffd87d3SSergey Temerkhanov 19002ffd87d3SSergey Temerkhanov /* Get package information from the Metadata Section */ 19012ffd87d3SSergey Temerkhanov meta = ice_pkg_enum_section((struct ice_seg *)seg_hdr, &state, 19022ffd87d3SSergey Temerkhanov ICE_SID_METADATA); 19032ffd87d3SSergey Temerkhanov if (!meta) { 19042ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 19052ffd87d3SSergey Temerkhanov "Did not find ice metadata section in package\n"); 19062ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 19072ffd87d3SSergey Temerkhanov } 19082ffd87d3SSergey Temerkhanov 19092ffd87d3SSergey Temerkhanov hw->pkg_ver = meta->ver; 19102ffd87d3SSergey Temerkhanov memcpy(hw->pkg_name, meta->name, sizeof(meta->name)); 19112ffd87d3SSergey Temerkhanov 19122ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Pkg: %d.%d.%d.%d, %s\n", 19132ffd87d3SSergey Temerkhanov meta->ver.major, meta->ver.minor, meta->ver.update, 19142ffd87d3SSergey Temerkhanov meta->ver.draft, meta->name); 19152ffd87d3SSergey Temerkhanov 19162ffd87d3SSergey Temerkhanov hw->ice_seg_fmt_ver = seg_hdr->seg_format_ver; 19172ffd87d3SSergey Temerkhanov memcpy(hw->ice_seg_id, seg_hdr->seg_id, sizeof(hw->ice_seg_id)); 19182ffd87d3SSergey Temerkhanov 19192ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n", 19202ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.major, 19212ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.minor, 19222ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.update, 19232ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.draft, seg_hdr->seg_id); 19242ffd87d3SSergey Temerkhanov } else { 19252ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 19262ffd87d3SSergey Temerkhanov "Did not find ice segment in driver package\n"); 19272ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 19282ffd87d3SSergey Temerkhanov } 19292ffd87d3SSergey Temerkhanov 19302ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 19312ffd87d3SSergey Temerkhanov } 19322ffd87d3SSergey Temerkhanov 19332ffd87d3SSergey Temerkhanov /** 19342ffd87d3SSergey Temerkhanov * ice_get_pkg_info 19352ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 19362ffd87d3SSergey Temerkhanov * 19372ffd87d3SSergey Temerkhanov * Store details of the package currently loaded in HW into the HW structure. 19382ffd87d3SSergey Temerkhanov */ 19392ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw) 19402ffd87d3SSergey Temerkhanov { 1941d8e45f29SKees Cook DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg_info, pkg_info, 1942230064baSPrzemek Kitszel ICE_PKG_CNT); 1943230064baSPrzemek Kitszel u16 size = __struct_size(pkg_info); 19442ffd87d3SSergey Temerkhanov u32 i; 19452ffd87d3SSergey Temerkhanov 1946230064baSPrzemek Kitszel if (ice_aq_get_pkg_info_list(hw, pkg_info, size, NULL)) 19472ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 19482ffd87d3SSergey Temerkhanov 19492ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg_info->count); i++) { 19502ffd87d3SSergey Temerkhanov #define ICE_PKG_FLAG_COUNT 4 19512ffd87d3SSergey Temerkhanov char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 }; 19522ffd87d3SSergey Temerkhanov u8 place = 0; 19532ffd87d3SSergey Temerkhanov 19542ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_active) { 19552ffd87d3SSergey Temerkhanov flags[place++] = 'A'; 19562ffd87d3SSergey Temerkhanov hw->active_pkg_ver = pkg_info->pkg_info[i].ver; 19572ffd87d3SSergey Temerkhanov hw->active_track_id = 19582ffd87d3SSergey Temerkhanov le32_to_cpu(pkg_info->pkg_info[i].track_id); 19592ffd87d3SSergey Temerkhanov memcpy(hw->active_pkg_name, pkg_info->pkg_info[i].name, 19602ffd87d3SSergey Temerkhanov sizeof(pkg_info->pkg_info[i].name)); 19612ffd87d3SSergey Temerkhanov hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm; 19622ffd87d3SSergey Temerkhanov } 19632ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_active_at_boot) 19642ffd87d3SSergey Temerkhanov flags[place++] = 'B'; 19652ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_modified) 19662ffd87d3SSergey Temerkhanov flags[place++] = 'M'; 19672ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_in_nvm) 19682ffd87d3SSergey Temerkhanov flags[place++] = 'N'; 19692ffd87d3SSergey Temerkhanov 19702ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Pkg[%d]: %d.%d.%d.%d,%s,%s\n", i, 19712ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.major, 19722ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.minor, 19732ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.update, 19742ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.draft, 19752ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].name, flags); 19762ffd87d3SSergey Temerkhanov } 19772ffd87d3SSergey Temerkhanov 1978230064baSPrzemek Kitszel return ICE_DDP_PKG_SUCCESS; 19792ffd87d3SSergey Temerkhanov } 19802ffd87d3SSergey Temerkhanov 19812ffd87d3SSergey Temerkhanov /** 19822ffd87d3SSergey Temerkhanov * ice_chk_pkg_compat 19832ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 19842ffd87d3SSergey Temerkhanov * @ospkg: pointer to the package hdr 19852ffd87d3SSergey Temerkhanov * @seg: pointer to the package segment hdr 19862ffd87d3SSergey Temerkhanov * 19872ffd87d3SSergey Temerkhanov * This function checks the package version compatibility with driver and NVM 19882ffd87d3SSergey Temerkhanov */ 19892ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_compat(struct ice_hw *hw, 19902ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *ospkg, 19912ffd87d3SSergey Temerkhanov struct ice_seg **seg) 19922ffd87d3SSergey Temerkhanov { 1993d8e45f29SKees Cook DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg, pkg_info, 1994230064baSPrzemek Kitszel ICE_PKG_CNT); 1995230064baSPrzemek Kitszel u16 size = __struct_size(pkg); 19962ffd87d3SSergey Temerkhanov enum ice_ddp_state state; 19972ffd87d3SSergey Temerkhanov u32 i; 19982ffd87d3SSergey Temerkhanov 19992ffd87d3SSergey Temerkhanov /* Check package version compatibility */ 20002ffd87d3SSergey Temerkhanov state = ice_chk_pkg_version(&hw->pkg_ver); 20012ffd87d3SSergey Temerkhanov if (state) { 20022ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n"); 20032ffd87d3SSergey Temerkhanov return state; 20042ffd87d3SSergey Temerkhanov } 20052ffd87d3SSergey Temerkhanov 20062ffd87d3SSergey Temerkhanov /* find ICE segment in given package */ 20073cbdb034SDan Nowlin *seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, hw->pkg_seg_id, 20082ffd87d3SSergey Temerkhanov ospkg); 20092ffd87d3SSergey Temerkhanov if (!*seg) { 20102ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n"); 20112ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 20122ffd87d3SSergey Temerkhanov } 20132ffd87d3SSergey Temerkhanov 20142ffd87d3SSergey Temerkhanov /* Check if FW is compatible with the OS package */ 2015230064baSPrzemek Kitszel if (ice_aq_get_pkg_info_list(hw, pkg, size, NULL)) 2016230064baSPrzemek Kitszel return ICE_DDP_PKG_LOAD_ERROR; 20172ffd87d3SSergey Temerkhanov 20182ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg->count); i++) { 20192ffd87d3SSergey Temerkhanov /* loop till we find the NVM package */ 20202ffd87d3SSergey Temerkhanov if (!pkg->pkg_info[i].is_in_nvm) 20212ffd87d3SSergey Temerkhanov continue; 20222ffd87d3SSergey Temerkhanov if ((*seg)->hdr.seg_format_ver.major != 20232ffd87d3SSergey Temerkhanov pkg->pkg_info[i].ver.major || 20242ffd87d3SSergey Temerkhanov (*seg)->hdr.seg_format_ver.minor > 20252ffd87d3SSergey Temerkhanov pkg->pkg_info[i].ver.minor) { 20262ffd87d3SSergey Temerkhanov state = ICE_DDP_PKG_FW_MISMATCH; 20272ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 20282ffd87d3SSergey Temerkhanov "OS package is not compatible with NVM.\n"); 20292ffd87d3SSergey Temerkhanov } 20302ffd87d3SSergey Temerkhanov /* done processing NVM package so break */ 20312ffd87d3SSergey Temerkhanov break; 20322ffd87d3SSergey Temerkhanov } 2033230064baSPrzemek Kitszel 20342ffd87d3SSergey Temerkhanov return state; 20352ffd87d3SSergey Temerkhanov } 20362ffd87d3SSergey Temerkhanov 20372ffd87d3SSergey Temerkhanov /** 20382ffd87d3SSergey Temerkhanov * ice_init_pkg_hints 20392ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 20402ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the segment of the package scan (non-NULL) 20412ffd87d3SSergey Temerkhanov * 20422ffd87d3SSergey Temerkhanov * This function will scan the package and save off relevant information 20432ffd87d3SSergey Temerkhanov * (hints or metadata) for driver use. The ice_seg parameter must not be NULL 20442ffd87d3SSergey Temerkhanov * since the first call to ice_enum_labels requires a pointer to an actual 20452ffd87d3SSergey Temerkhanov * ice_seg structure. 20462ffd87d3SSergey Temerkhanov */ 20472ffd87d3SSergey Temerkhanov static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg) 20482ffd87d3SSergey Temerkhanov { 20492ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 20502ffd87d3SSergey Temerkhanov char *label_name; 20512ffd87d3SSergey Temerkhanov u16 val; 20522ffd87d3SSergey Temerkhanov int i; 20532ffd87d3SSergey Temerkhanov 20542ffd87d3SSergey Temerkhanov memset(&hw->tnl, 0, sizeof(hw->tnl)); 20552ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 20562ffd87d3SSergey Temerkhanov 20572ffd87d3SSergey Temerkhanov if (!ice_seg) 20582ffd87d3SSergey Temerkhanov return; 20592ffd87d3SSergey Temerkhanov 20602ffd87d3SSergey Temerkhanov label_name = ice_enum_labels(ice_seg, ICE_SID_LBL_RXPARSER_TMEM, &state, 20612ffd87d3SSergey Temerkhanov &val); 20622ffd87d3SSergey Temerkhanov 20632ffd87d3SSergey Temerkhanov while (label_name) { 20642ffd87d3SSergey Temerkhanov if (!strncmp(label_name, ICE_TNL_PRE, strlen(ICE_TNL_PRE))) 20652ffd87d3SSergey Temerkhanov /* check for a tunnel entry */ 20662ffd87d3SSergey Temerkhanov ice_add_tunnel_hint(hw, label_name, val); 20672ffd87d3SSergey Temerkhanov 20682ffd87d3SSergey Temerkhanov /* check for a dvm mode entry */ 20692ffd87d3SSergey Temerkhanov else if (!strncmp(label_name, ICE_DVM_PRE, strlen(ICE_DVM_PRE))) 20702ffd87d3SSergey Temerkhanov ice_add_dvm_hint(hw, val, true); 20712ffd87d3SSergey Temerkhanov 20722ffd87d3SSergey Temerkhanov /* check for a svm mode entry */ 20732ffd87d3SSergey Temerkhanov else if (!strncmp(label_name, ICE_SVM_PRE, strlen(ICE_SVM_PRE))) 20742ffd87d3SSergey Temerkhanov ice_add_dvm_hint(hw, val, false); 20752ffd87d3SSergey Temerkhanov 20762ffd87d3SSergey Temerkhanov label_name = ice_enum_labels(NULL, 0, &state, &val); 20772ffd87d3SSergey Temerkhanov } 20782ffd87d3SSergey Temerkhanov 20792ffd87d3SSergey Temerkhanov /* Cache the appropriate boost TCAM entry pointers for tunnels */ 20802ffd87d3SSergey Temerkhanov for (i = 0; i < hw->tnl.count; i++) { 20812ffd87d3SSergey Temerkhanov ice_find_boost_entry(ice_seg, hw->tnl.tbl[i].boost_addr, 20822ffd87d3SSergey Temerkhanov &hw->tnl.tbl[i].boost_entry); 20832ffd87d3SSergey Temerkhanov if (hw->tnl.tbl[i].boost_entry) { 20842ffd87d3SSergey Temerkhanov hw->tnl.tbl[i].valid = true; 20852ffd87d3SSergey Temerkhanov if (hw->tnl.tbl[i].type < __TNL_TYPE_CNT) 20862ffd87d3SSergey Temerkhanov hw->tnl.valid_count[hw->tnl.tbl[i].type]++; 20872ffd87d3SSergey Temerkhanov } 20882ffd87d3SSergey Temerkhanov } 20892ffd87d3SSergey Temerkhanov 20902ffd87d3SSergey Temerkhanov /* Cache the appropriate boost TCAM entry pointers for DVM and SVM */ 20912ffd87d3SSergey Temerkhanov for (i = 0; i < hw->dvm_upd.count; i++) 20922ffd87d3SSergey Temerkhanov ice_find_boost_entry(ice_seg, hw->dvm_upd.tbl[i].boost_addr, 20932ffd87d3SSergey Temerkhanov &hw->dvm_upd.tbl[i].boost_entry); 20942ffd87d3SSergey Temerkhanov } 20952ffd87d3SSergey Temerkhanov 20962ffd87d3SSergey Temerkhanov /** 20972ffd87d3SSergey Temerkhanov * ice_fill_hw_ptype - fill the enabled PTYPE bit information 20982ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 20992ffd87d3SSergey Temerkhanov */ 21002ffd87d3SSergey Temerkhanov static void ice_fill_hw_ptype(struct ice_hw *hw) 21012ffd87d3SSergey Temerkhanov { 21022ffd87d3SSergey Temerkhanov struct ice_marker_ptype_tcam_entry *tcam; 21032ffd87d3SSergey Temerkhanov struct ice_seg *seg = hw->seg; 21042ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 21052ffd87d3SSergey Temerkhanov 21062ffd87d3SSergey Temerkhanov bitmap_zero(hw->hw_ptype, ICE_FLOW_PTYPE_MAX); 21072ffd87d3SSergey Temerkhanov if (!seg) 21082ffd87d3SSergey Temerkhanov return; 21092ffd87d3SSergey Temerkhanov 21102ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 21112ffd87d3SSergey Temerkhanov 21122ffd87d3SSergey Temerkhanov do { 21132ffd87d3SSergey Temerkhanov tcam = ice_pkg_enum_entry(seg, &state, 21142ffd87d3SSergey Temerkhanov ICE_SID_RXPARSER_MARKER_PTYPE, NULL, 21152ffd87d3SSergey Temerkhanov ice_marker_ptype_tcam_handler); 21162ffd87d3SSergey Temerkhanov if (tcam && 21172ffd87d3SSergey Temerkhanov le16_to_cpu(tcam->addr) < ICE_MARKER_PTYPE_TCAM_ADDR_MAX && 21182ffd87d3SSergey Temerkhanov le16_to_cpu(tcam->ptype) < ICE_FLOW_PTYPE_MAX) 21192ffd87d3SSergey Temerkhanov set_bit(le16_to_cpu(tcam->ptype), hw->hw_ptype); 21202ffd87d3SSergey Temerkhanov 21212ffd87d3SSergey Temerkhanov seg = NULL; 21222ffd87d3SSergey Temerkhanov } while (tcam); 21232ffd87d3SSergey Temerkhanov } 21242ffd87d3SSergey Temerkhanov 21252ffd87d3SSergey Temerkhanov /** 21262ffd87d3SSergey Temerkhanov * ice_init_pkg - initialize/download package 21272ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 21282ffd87d3SSergey Temerkhanov * @buf: pointer to the package buffer 21292ffd87d3SSergey Temerkhanov * @len: size of the package buffer 21302ffd87d3SSergey Temerkhanov * 21312ffd87d3SSergey Temerkhanov * This function initializes a package. The package contains HW tables 21322ffd87d3SSergey Temerkhanov * required to do packet processing. First, the function extracts package 21332ffd87d3SSergey Temerkhanov * information such as version. Then it finds the ice configuration segment 21342ffd87d3SSergey Temerkhanov * within the package; this function then saves a copy of the segment pointer 21352ffd87d3SSergey Temerkhanov * within the supplied package buffer. Next, the function will cache any hints 21362ffd87d3SSergey Temerkhanov * from the package, followed by downloading the package itself. Note, that if 21372ffd87d3SSergey Temerkhanov * a previous PF driver has already downloaded the package successfully, then 21382ffd87d3SSergey Temerkhanov * the current driver will not have to download the package again. 21392ffd87d3SSergey Temerkhanov * 21402ffd87d3SSergey Temerkhanov * The local package contents will be used to query default behavior and to 21412ffd87d3SSergey Temerkhanov * update specific sections of the HW's version of the package (e.g. to update 21422ffd87d3SSergey Temerkhanov * the parse graph to understand new protocols). 21432ffd87d3SSergey Temerkhanov * 21442ffd87d3SSergey Temerkhanov * This function stores a pointer to the package buffer memory, and it is 21452ffd87d3SSergey Temerkhanov * expected that the supplied buffer will not be freed immediately. If the 21462ffd87d3SSergey Temerkhanov * package buffer needs to be freed, such as when read from a file, use 21472ffd87d3SSergey Temerkhanov * ice_copy_and_init_pkg() instead of directly calling ice_init_pkg() in this 21482ffd87d3SSergey Temerkhanov * case. 21492ffd87d3SSergey Temerkhanov */ 21502ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len) 21512ffd87d3SSergey Temerkhanov { 21522ffd87d3SSergey Temerkhanov bool already_loaded = false; 21532ffd87d3SSergey Temerkhanov enum ice_ddp_state state; 21542ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg; 21552ffd87d3SSergey Temerkhanov struct ice_seg *seg; 21562ffd87d3SSergey Temerkhanov 21572ffd87d3SSergey Temerkhanov if (!buf || !len) 21582ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 21592ffd87d3SSergey Temerkhanov 21602ffd87d3SSergey Temerkhanov pkg = (struct ice_pkg_hdr *)buf; 21612ffd87d3SSergey Temerkhanov state = ice_verify_pkg(pkg, len); 21622ffd87d3SSergey Temerkhanov if (state) { 21632ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n", 21642ffd87d3SSergey Temerkhanov state); 21652ffd87d3SSergey Temerkhanov return state; 21662ffd87d3SSergey Temerkhanov } 21672ffd87d3SSergey Temerkhanov 21682ffd87d3SSergey Temerkhanov /* initialize package info */ 21692ffd87d3SSergey Temerkhanov state = ice_init_pkg_info(hw, pkg); 21702ffd87d3SSergey Temerkhanov if (state) 21712ffd87d3SSergey Temerkhanov return state; 21722ffd87d3SSergey Temerkhanov 21733cbdb034SDan Nowlin /* must be a matching segment */ 21743cbdb034SDan Nowlin if (hw->pkg_has_signing_seg && 21753cbdb034SDan Nowlin !ice_match_signing_seg(pkg, hw->pkg_seg_id, hw->pkg_sign_type)) 21763cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 21773cbdb034SDan Nowlin 21782ffd87d3SSergey Temerkhanov /* before downloading the package, check package version for 21792ffd87d3SSergey Temerkhanov * compatibility with driver 21802ffd87d3SSergey Temerkhanov */ 21812ffd87d3SSergey Temerkhanov state = ice_chk_pkg_compat(hw, pkg, &seg); 21822ffd87d3SSergey Temerkhanov if (state) 21832ffd87d3SSergey Temerkhanov return state; 21842ffd87d3SSergey Temerkhanov 21852ffd87d3SSergey Temerkhanov /* initialize package hints and then download package */ 21862ffd87d3SSergey Temerkhanov ice_init_pkg_hints(hw, seg); 2187a778616eSDan Nowlin state = ice_download_pkg(hw, pkg, seg); 21882ffd87d3SSergey Temerkhanov if (state == ICE_DDP_PKG_ALREADY_LOADED) { 21892ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 21902ffd87d3SSergey Temerkhanov "package previously loaded - no work.\n"); 21912ffd87d3SSergey Temerkhanov already_loaded = true; 21922ffd87d3SSergey Temerkhanov } 21932ffd87d3SSergey Temerkhanov 21942ffd87d3SSergey Temerkhanov /* Get information on the package currently loaded in HW, then make sure 21952ffd87d3SSergey Temerkhanov * the driver is compatible with this version. 21962ffd87d3SSergey Temerkhanov */ 21972ffd87d3SSergey Temerkhanov if (!state || state == ICE_DDP_PKG_ALREADY_LOADED) { 21982ffd87d3SSergey Temerkhanov state = ice_get_pkg_info(hw); 21992ffd87d3SSergey Temerkhanov if (!state) 22002ffd87d3SSergey Temerkhanov state = ice_get_ddp_pkg_state(hw, already_loaded); 22012ffd87d3SSergey Temerkhanov } 22022ffd87d3SSergey Temerkhanov 22032ffd87d3SSergey Temerkhanov if (ice_is_init_pkg_successful(state)) { 22042ffd87d3SSergey Temerkhanov hw->seg = seg; 22052ffd87d3SSergey Temerkhanov /* on successful package download update other required 22062ffd87d3SSergey Temerkhanov * registers to support the package and fill HW tables 22072ffd87d3SSergey Temerkhanov * with package content. 22082ffd87d3SSergey Temerkhanov */ 22092ffd87d3SSergey Temerkhanov ice_init_pkg_regs(hw); 22102ffd87d3SSergey Temerkhanov ice_fill_blk_tbls(hw); 22112ffd87d3SSergey Temerkhanov ice_fill_hw_ptype(hw); 22122ffd87d3SSergey Temerkhanov ice_get_prof_index_max(hw); 22132ffd87d3SSergey Temerkhanov } else { 22142ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n", state); 22152ffd87d3SSergey Temerkhanov } 22162ffd87d3SSergey Temerkhanov 22172ffd87d3SSergey Temerkhanov return state; 22182ffd87d3SSergey Temerkhanov } 22192ffd87d3SSergey Temerkhanov 22202ffd87d3SSergey Temerkhanov /** 22212ffd87d3SSergey Temerkhanov * ice_copy_and_init_pkg - initialize/download a copy of the package 22222ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 22232ffd87d3SSergey Temerkhanov * @buf: pointer to the package buffer 22242ffd87d3SSergey Temerkhanov * @len: size of the package buffer 22252ffd87d3SSergey Temerkhanov * 22262ffd87d3SSergey Temerkhanov * This function copies the package buffer, and then calls ice_init_pkg() to 22272ffd87d3SSergey Temerkhanov * initialize the copied package contents. 22282ffd87d3SSergey Temerkhanov * 22292ffd87d3SSergey Temerkhanov * The copying is necessary if the package buffer supplied is constant, or if 22302ffd87d3SSergey Temerkhanov * the memory may disappear shortly after calling this function. 22312ffd87d3SSergey Temerkhanov * 22322ffd87d3SSergey Temerkhanov * If the package buffer resides in the data segment and can be modified, the 22332ffd87d3SSergey Temerkhanov * caller is free to use ice_init_pkg() instead of ice_copy_and_init_pkg(). 22342ffd87d3SSergey Temerkhanov * 22352ffd87d3SSergey Temerkhanov * However, if the package buffer needs to be copied first, such as when being 22362ffd87d3SSergey Temerkhanov * read from a file, the caller should use ice_copy_and_init_pkg(). 22372ffd87d3SSergey Temerkhanov * 22382ffd87d3SSergey Temerkhanov * This function will first copy the package buffer, before calling 22392ffd87d3SSergey Temerkhanov * ice_init_pkg(). The caller is free to immediately destroy the original 22402ffd87d3SSergey Temerkhanov * package buffer, as the new copy will be managed by this function and 22412ffd87d3SSergey Temerkhanov * related routines. 22422ffd87d3SSergey Temerkhanov */ 22432ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, 22442ffd87d3SSergey Temerkhanov u32 len) 22452ffd87d3SSergey Temerkhanov { 22462ffd87d3SSergey Temerkhanov enum ice_ddp_state state; 22472ffd87d3SSergey Temerkhanov u8 *buf_copy; 22482ffd87d3SSergey Temerkhanov 22492ffd87d3SSergey Temerkhanov if (!buf || !len) 22502ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 22512ffd87d3SSergey Temerkhanov 22522ffd87d3SSergey Temerkhanov buf_copy = devm_kmemdup(ice_hw_to_dev(hw), buf, len, GFP_KERNEL); 22532ffd87d3SSergey Temerkhanov 22542ffd87d3SSergey Temerkhanov state = ice_init_pkg(hw, buf_copy, len); 22552ffd87d3SSergey Temerkhanov if (!ice_is_init_pkg_successful(state)) { 22562ffd87d3SSergey Temerkhanov /* Free the copy, since we failed to initialize the package */ 22572ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), buf_copy); 22582ffd87d3SSergey Temerkhanov } else { 22592ffd87d3SSergey Temerkhanov /* Track the copied pkg so we can free it later */ 22602ffd87d3SSergey Temerkhanov hw->pkg_copy = buf_copy; 22612ffd87d3SSergey Temerkhanov hw->pkg_size = len; 22622ffd87d3SSergey Temerkhanov } 22632ffd87d3SSergey Temerkhanov 22642ffd87d3SSergey Temerkhanov return state; 22652ffd87d3SSergey Temerkhanov } 2266