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" 791427e6dSRaj Victor #include "ice_sched.h" 82ffd87d3SSergey Temerkhanov 92ffd87d3SSergey Temerkhanov /* For supporting double VLAN mode, it is necessary to enable or disable certain 102ffd87d3SSergey Temerkhanov * boost tcam entries. The metadata labels names that match the following 112ffd87d3SSergey Temerkhanov * prefixes will be saved to allow enabling double VLAN mode. 122ffd87d3SSergey Temerkhanov */ 132ffd87d3SSergey Temerkhanov #define ICE_DVM_PRE "BOOST_MAC_VLAN_DVM" /* enable these entries */ 142ffd87d3SSergey Temerkhanov #define ICE_SVM_PRE "BOOST_MAC_VLAN_SVM" /* disable these entries */ 152ffd87d3SSergey Temerkhanov 162ffd87d3SSergey Temerkhanov /* To support tunneling entries by PF, the package will append the PF number to 172ffd87d3SSergey Temerkhanov * the label; for example TNL_VXLAN_PF0, TNL_VXLAN_PF1, TNL_VXLAN_PF2, etc. 182ffd87d3SSergey Temerkhanov */ 192ffd87d3SSergey Temerkhanov #define ICE_TNL_PRE "TNL_" 202ffd87d3SSergey Temerkhanov static const struct ice_tunnel_type_scan tnls[] = { 212ffd87d3SSergey Temerkhanov { TNL_VXLAN, "TNL_VXLAN_PF" }, 222ffd87d3SSergey Temerkhanov { TNL_GENEVE, "TNL_GENEVE_PF" }, 232ffd87d3SSergey Temerkhanov { TNL_LAST, "" } 242ffd87d3SSergey Temerkhanov }; 252ffd87d3SSergey Temerkhanov 262ffd87d3SSergey Temerkhanov /** 272ffd87d3SSergey Temerkhanov * ice_verify_pkg - verify package 282ffd87d3SSergey Temerkhanov * @pkg: pointer to the package buffer 292ffd87d3SSergey Temerkhanov * @len: size of the package buffer 302ffd87d3SSergey Temerkhanov * 312ffd87d3SSergey Temerkhanov * Verifies various attributes of the package file, including length, format 322ffd87d3SSergey Temerkhanov * version, and the requirement of at least one segment. 332ffd87d3SSergey Temerkhanov */ 34708b352fSJan Sokolowski static enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len) 352ffd87d3SSergey Temerkhanov { 362ffd87d3SSergey Temerkhanov u32 seg_count; 372ffd87d3SSergey Temerkhanov u32 i; 382ffd87d3SSergey Temerkhanov 392ffd87d3SSergey Temerkhanov if (len < struct_size(pkg, seg_offset, 1)) 402ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 412ffd87d3SSergey Temerkhanov 422ffd87d3SSergey Temerkhanov if (pkg->pkg_format_ver.major != ICE_PKG_FMT_VER_MAJ || 432ffd87d3SSergey Temerkhanov pkg->pkg_format_ver.minor != ICE_PKG_FMT_VER_MNR || 442ffd87d3SSergey Temerkhanov pkg->pkg_format_ver.update != ICE_PKG_FMT_VER_UPD || 452ffd87d3SSergey Temerkhanov pkg->pkg_format_ver.draft != ICE_PKG_FMT_VER_DFT) 462ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 472ffd87d3SSergey Temerkhanov 482ffd87d3SSergey Temerkhanov /* pkg must have at least one segment */ 492ffd87d3SSergey Temerkhanov seg_count = le32_to_cpu(pkg->seg_count); 502ffd87d3SSergey Temerkhanov if (seg_count < 1) 512ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 522ffd87d3SSergey Temerkhanov 532ffd87d3SSergey Temerkhanov /* make sure segment array fits in package length */ 542ffd87d3SSergey Temerkhanov if (len < struct_size(pkg, seg_offset, seg_count)) 552ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 562ffd87d3SSergey Temerkhanov 572ffd87d3SSergey Temerkhanov /* all segments must fit within length */ 582ffd87d3SSergey Temerkhanov for (i = 0; i < seg_count; i++) { 592ffd87d3SSergey Temerkhanov u32 off = le32_to_cpu(pkg->seg_offset[i]); 602ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg; 612ffd87d3SSergey Temerkhanov 622ffd87d3SSergey Temerkhanov /* segment header must fit */ 632ffd87d3SSergey Temerkhanov if (len < off + sizeof(*seg)) 642ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 652ffd87d3SSergey Temerkhanov 662ffd87d3SSergey Temerkhanov seg = (struct ice_generic_seg_hdr *)((u8 *)pkg + off); 672ffd87d3SSergey Temerkhanov 682ffd87d3SSergey Temerkhanov /* segment body must fit */ 692ffd87d3SSergey Temerkhanov if (len < off + le32_to_cpu(seg->seg_size)) 702ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 712ffd87d3SSergey Temerkhanov } 722ffd87d3SSergey Temerkhanov 732ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 742ffd87d3SSergey Temerkhanov } 752ffd87d3SSergey Temerkhanov 762ffd87d3SSergey Temerkhanov /** 772ffd87d3SSergey Temerkhanov * ice_free_seg - free package segment pointer 782ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 792ffd87d3SSergey Temerkhanov * 802ffd87d3SSergey Temerkhanov * Frees the package segment pointer in the proper manner, depending on if the 812ffd87d3SSergey Temerkhanov * segment was allocated or just the passed in pointer was stored. 822ffd87d3SSergey Temerkhanov */ 832ffd87d3SSergey Temerkhanov void ice_free_seg(struct ice_hw *hw) 842ffd87d3SSergey Temerkhanov { 852ffd87d3SSergey Temerkhanov if (hw->pkg_copy) { 862ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), hw->pkg_copy); 872ffd87d3SSergey Temerkhanov hw->pkg_copy = NULL; 882ffd87d3SSergey Temerkhanov hw->pkg_size = 0; 892ffd87d3SSergey Temerkhanov } 902ffd87d3SSergey Temerkhanov hw->seg = NULL; 912ffd87d3SSergey Temerkhanov } 922ffd87d3SSergey Temerkhanov 932ffd87d3SSergey Temerkhanov /** 942ffd87d3SSergey Temerkhanov * ice_chk_pkg_version - check package version for compatibility with driver 952ffd87d3SSergey Temerkhanov * @pkg_ver: pointer to a version structure to check 962ffd87d3SSergey Temerkhanov * 972ffd87d3SSergey Temerkhanov * Check to make sure that the package about to be downloaded is compatible with 982ffd87d3SSergey Temerkhanov * the driver. To be compatible, the major and minor components of the package 992ffd87d3SSergey Temerkhanov * version must match our ICE_PKG_SUPP_VER_MAJ and ICE_PKG_SUPP_VER_MNR 1002ffd87d3SSergey Temerkhanov * definitions. 1012ffd87d3SSergey Temerkhanov */ 1022ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver) 1032ffd87d3SSergey Temerkhanov { 1042ffd87d3SSergey Temerkhanov if (pkg_ver->major > ICE_PKG_SUPP_VER_MAJ || 1052ffd87d3SSergey Temerkhanov (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ && 1062ffd87d3SSergey Temerkhanov pkg_ver->minor > ICE_PKG_SUPP_VER_MNR)) 1072ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_VERSION_TOO_HIGH; 1082ffd87d3SSergey Temerkhanov else if (pkg_ver->major < ICE_PKG_SUPP_VER_MAJ || 1092ffd87d3SSergey Temerkhanov (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ && 1102ffd87d3SSergey Temerkhanov pkg_ver->minor < ICE_PKG_SUPP_VER_MNR)) 1112ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_VERSION_TOO_LOW; 1122ffd87d3SSergey Temerkhanov 1132ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 1142ffd87d3SSergey Temerkhanov } 1152ffd87d3SSergey Temerkhanov 1162ffd87d3SSergey Temerkhanov /** 1172ffd87d3SSergey Temerkhanov * ice_pkg_val_buf 1182ffd87d3SSergey Temerkhanov * @buf: pointer to the ice buffer 1192ffd87d3SSergey Temerkhanov * 1202ffd87d3SSergey Temerkhanov * This helper function validates a buffer's header. 1212ffd87d3SSergey Temerkhanov */ 122708b352fSJan Sokolowski static struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf) 1232ffd87d3SSergey Temerkhanov { 1242ffd87d3SSergey Temerkhanov struct ice_buf_hdr *hdr; 1252ffd87d3SSergey Temerkhanov u16 section_count; 1262ffd87d3SSergey Temerkhanov u16 data_end; 1272ffd87d3SSergey Temerkhanov 1282ffd87d3SSergey Temerkhanov hdr = (struct ice_buf_hdr *)buf->buf; 1292ffd87d3SSergey Temerkhanov /* verify data */ 1302ffd87d3SSergey Temerkhanov section_count = le16_to_cpu(hdr->section_count); 1312ffd87d3SSergey Temerkhanov if (section_count < ICE_MIN_S_COUNT || section_count > ICE_MAX_S_COUNT) 1322ffd87d3SSergey Temerkhanov return NULL; 1332ffd87d3SSergey Temerkhanov 1342ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(hdr->data_end); 1352ffd87d3SSergey Temerkhanov if (data_end < ICE_MIN_S_DATA_END || data_end > ICE_MAX_S_DATA_END) 1362ffd87d3SSergey Temerkhanov return NULL; 1372ffd87d3SSergey Temerkhanov 1382ffd87d3SSergey Temerkhanov return hdr; 1392ffd87d3SSergey Temerkhanov } 1402ffd87d3SSergey Temerkhanov 1412ffd87d3SSergey Temerkhanov /** 1422ffd87d3SSergey Temerkhanov * ice_find_buf_table 1432ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment 1442ffd87d3SSergey Temerkhanov * 1452ffd87d3SSergey Temerkhanov * Returns the address of the buffer table within the ice segment. 1462ffd87d3SSergey Temerkhanov */ 1472ffd87d3SSergey Temerkhanov static struct ice_buf_table *ice_find_buf_table(struct ice_seg *ice_seg) 1482ffd87d3SSergey Temerkhanov { 1492ffd87d3SSergey Temerkhanov struct ice_nvm_table *nvms = (struct ice_nvm_table *) 1502ffd87d3SSergey Temerkhanov (ice_seg->device_table + le32_to_cpu(ice_seg->device_table_count)); 1512ffd87d3SSergey Temerkhanov 1522ffd87d3SSergey Temerkhanov return (__force struct ice_buf_table *)(nvms->vers + 1532ffd87d3SSergey Temerkhanov le32_to_cpu(nvms->table_count)); 1542ffd87d3SSergey Temerkhanov } 1552ffd87d3SSergey Temerkhanov 1562ffd87d3SSergey Temerkhanov /** 1572ffd87d3SSergey Temerkhanov * ice_pkg_enum_buf 1582ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) 1592ffd87d3SSergey Temerkhanov * @state: pointer to the enum state 1602ffd87d3SSergey Temerkhanov * 1612ffd87d3SSergey Temerkhanov * This function will enumerate all the buffers in the ice segment. The first 1622ffd87d3SSergey Temerkhanov * call is made with the ice_seg parameter non-NULL; on subsequent calls, 1632ffd87d3SSergey Temerkhanov * ice_seg is set to NULL which continues the enumeration. When the function 1642ffd87d3SSergey Temerkhanov * returns a NULL pointer, then the end of the buffers has been reached, or an 1652ffd87d3SSergey Temerkhanov * unexpected value has been detected (for example an invalid section count or 1662ffd87d3SSergey Temerkhanov * an invalid buffer end value). 1672ffd87d3SSergey Temerkhanov */ 1682ffd87d3SSergey Temerkhanov static struct ice_buf_hdr *ice_pkg_enum_buf(struct ice_seg *ice_seg, 1692ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state) 1702ffd87d3SSergey Temerkhanov { 1712ffd87d3SSergey Temerkhanov if (ice_seg) { 1722ffd87d3SSergey Temerkhanov state->buf_table = ice_find_buf_table(ice_seg); 1732ffd87d3SSergey Temerkhanov if (!state->buf_table) 1742ffd87d3SSergey Temerkhanov return NULL; 1752ffd87d3SSergey Temerkhanov 1762ffd87d3SSergey Temerkhanov state->buf_idx = 0; 1772ffd87d3SSergey Temerkhanov return ice_pkg_val_buf(state->buf_table->buf_array); 1782ffd87d3SSergey Temerkhanov } 1792ffd87d3SSergey Temerkhanov 1802ffd87d3SSergey Temerkhanov if (++state->buf_idx < le32_to_cpu(state->buf_table->buf_count)) 1812ffd87d3SSergey Temerkhanov return ice_pkg_val_buf(state->buf_table->buf_array + 1822ffd87d3SSergey Temerkhanov state->buf_idx); 1832ffd87d3SSergey Temerkhanov else 1842ffd87d3SSergey Temerkhanov return NULL; 1852ffd87d3SSergey Temerkhanov } 1862ffd87d3SSergey Temerkhanov 1872ffd87d3SSergey Temerkhanov /** 1882ffd87d3SSergey Temerkhanov * ice_pkg_advance_sect 1892ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) 1902ffd87d3SSergey Temerkhanov * @state: pointer to the enum state 1912ffd87d3SSergey Temerkhanov * 1922ffd87d3SSergey Temerkhanov * This helper function will advance the section within the ice segment, 1932ffd87d3SSergey Temerkhanov * also advancing the buffer if needed. 1942ffd87d3SSergey Temerkhanov */ 1952ffd87d3SSergey Temerkhanov static bool ice_pkg_advance_sect(struct ice_seg *ice_seg, 1962ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state) 1972ffd87d3SSergey Temerkhanov { 1982ffd87d3SSergey Temerkhanov if (!ice_seg && !state->buf) 1992ffd87d3SSergey Temerkhanov return false; 2002ffd87d3SSergey Temerkhanov 2012ffd87d3SSergey Temerkhanov if (!ice_seg && state->buf) 2022ffd87d3SSergey Temerkhanov if (++state->sect_idx < le16_to_cpu(state->buf->section_count)) 2032ffd87d3SSergey Temerkhanov return true; 2042ffd87d3SSergey Temerkhanov 2052ffd87d3SSergey Temerkhanov state->buf = ice_pkg_enum_buf(ice_seg, state); 2062ffd87d3SSergey Temerkhanov if (!state->buf) 2072ffd87d3SSergey Temerkhanov return false; 2082ffd87d3SSergey Temerkhanov 2092ffd87d3SSergey Temerkhanov /* start of new buffer, reset section index */ 2102ffd87d3SSergey Temerkhanov state->sect_idx = 0; 2112ffd87d3SSergey Temerkhanov return true; 2122ffd87d3SSergey Temerkhanov } 2132ffd87d3SSergey Temerkhanov 2142ffd87d3SSergey Temerkhanov /** 2152ffd87d3SSergey Temerkhanov * ice_pkg_enum_section 2162ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) 2172ffd87d3SSergey Temerkhanov * @state: pointer to the enum state 2182ffd87d3SSergey Temerkhanov * @sect_type: section type to enumerate 2192ffd87d3SSergey Temerkhanov * 2202ffd87d3SSergey Temerkhanov * This function will enumerate all the sections of a particular type in the 2212ffd87d3SSergey Temerkhanov * ice segment. The first call is made with the ice_seg parameter non-NULL; 2222ffd87d3SSergey Temerkhanov * on subsequent calls, ice_seg is set to NULL which continues the enumeration. 2232ffd87d3SSergey Temerkhanov * When the function returns a NULL pointer, then the end of the matching 2242ffd87d3SSergey Temerkhanov * sections has been reached. 2252ffd87d3SSergey Temerkhanov */ 2262ffd87d3SSergey Temerkhanov void *ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state, 2272ffd87d3SSergey Temerkhanov u32 sect_type) 2282ffd87d3SSergey Temerkhanov { 2292ffd87d3SSergey Temerkhanov u16 offset, size; 2302ffd87d3SSergey Temerkhanov 2312ffd87d3SSergey Temerkhanov if (ice_seg) 2322ffd87d3SSergey Temerkhanov state->type = sect_type; 2332ffd87d3SSergey Temerkhanov 2342ffd87d3SSergey Temerkhanov if (!ice_pkg_advance_sect(ice_seg, state)) 2352ffd87d3SSergey Temerkhanov return NULL; 2362ffd87d3SSergey Temerkhanov 2372ffd87d3SSergey Temerkhanov /* scan for next matching section */ 2382ffd87d3SSergey Temerkhanov while (state->buf->section_entry[state->sect_idx].type != 2392ffd87d3SSergey Temerkhanov cpu_to_le32(state->type)) 2402ffd87d3SSergey Temerkhanov if (!ice_pkg_advance_sect(NULL, state)) 2412ffd87d3SSergey Temerkhanov return NULL; 2422ffd87d3SSergey Temerkhanov 2432ffd87d3SSergey Temerkhanov /* validate section */ 2442ffd87d3SSergey Temerkhanov offset = le16_to_cpu(state->buf->section_entry[state->sect_idx].offset); 2452ffd87d3SSergey Temerkhanov if (offset < ICE_MIN_S_OFF || offset > ICE_MAX_S_OFF) 2462ffd87d3SSergey Temerkhanov return NULL; 2472ffd87d3SSergey Temerkhanov 2482ffd87d3SSergey Temerkhanov size = le16_to_cpu(state->buf->section_entry[state->sect_idx].size); 2492ffd87d3SSergey Temerkhanov if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ) 2502ffd87d3SSergey Temerkhanov return NULL; 2512ffd87d3SSergey Temerkhanov 2522ffd87d3SSergey Temerkhanov /* make sure the section fits in the buffer */ 2532ffd87d3SSergey Temerkhanov if (offset + size > ICE_PKG_BUF_SIZE) 2542ffd87d3SSergey Temerkhanov return NULL; 2552ffd87d3SSergey Temerkhanov 2562ffd87d3SSergey Temerkhanov state->sect_type = 2572ffd87d3SSergey Temerkhanov le32_to_cpu(state->buf->section_entry[state->sect_idx].type); 2582ffd87d3SSergey Temerkhanov 2592ffd87d3SSergey Temerkhanov /* calc pointer to this section */ 2602ffd87d3SSergey Temerkhanov state->sect = 2612ffd87d3SSergey Temerkhanov ((u8 *)state->buf) + 2622ffd87d3SSergey Temerkhanov le16_to_cpu(state->buf->section_entry[state->sect_idx].offset); 2632ffd87d3SSergey Temerkhanov 2642ffd87d3SSergey Temerkhanov return state->sect; 2652ffd87d3SSergey Temerkhanov } 2662ffd87d3SSergey Temerkhanov 2672ffd87d3SSergey Temerkhanov /** 2682ffd87d3SSergey Temerkhanov * ice_pkg_enum_entry 2692ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) 2702ffd87d3SSergey Temerkhanov * @state: pointer to the enum state 2712ffd87d3SSergey Temerkhanov * @sect_type: section type to enumerate 2722ffd87d3SSergey Temerkhanov * @offset: pointer to variable that receives the offset in the table (optional) 2732ffd87d3SSergey Temerkhanov * @handler: function that handles access to the entries into the section type 2742ffd87d3SSergey Temerkhanov * 2752ffd87d3SSergey Temerkhanov * This function will enumerate all the entries in particular section type in 2762ffd87d3SSergey Temerkhanov * the ice segment. The first call is made with the ice_seg parameter non-NULL; 2772ffd87d3SSergey Temerkhanov * on subsequent calls, ice_seg is set to NULL which continues the enumeration. 2782ffd87d3SSergey Temerkhanov * When the function returns a NULL pointer, then the end of the entries has 2792ffd87d3SSergey Temerkhanov * been reached. 2802ffd87d3SSergey Temerkhanov * 2812ffd87d3SSergey Temerkhanov * Since each section may have a different header and entry size, the handler 2822ffd87d3SSergey Temerkhanov * function is needed to determine the number and location entries in each 2832ffd87d3SSergey Temerkhanov * section. 2842ffd87d3SSergey Temerkhanov * 2852ffd87d3SSergey Temerkhanov * The offset parameter is optional, but should be used for sections that 2862ffd87d3SSergey Temerkhanov * contain an offset for each section table. For such cases, the section handler 2872ffd87d3SSergey Temerkhanov * function must return the appropriate offset + index to give the absolution 2882ffd87d3SSergey Temerkhanov * offset for each entry. For example, if the base for a section's header 2892ffd87d3SSergey Temerkhanov * indicates a base offset of 10, and the index for the entry is 2, then 2902ffd87d3SSergey Temerkhanov * section handler function should set the offset to 10 + 2 = 12. 2912ffd87d3SSergey Temerkhanov */ 292*75b4a938SJunfeng Guo void *ice_pkg_enum_entry(struct ice_seg *ice_seg, 2932ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state, u32 sect_type, 2942ffd87d3SSergey Temerkhanov u32 *offset, 2952ffd87d3SSergey Temerkhanov void *(*handler)(u32 sect_type, void *section, 2962ffd87d3SSergey Temerkhanov u32 index, u32 *offset)) 2972ffd87d3SSergey Temerkhanov { 2982ffd87d3SSergey Temerkhanov void *entry; 2992ffd87d3SSergey Temerkhanov 3002ffd87d3SSergey Temerkhanov if (ice_seg) { 3012ffd87d3SSergey Temerkhanov if (!handler) 3022ffd87d3SSergey Temerkhanov return NULL; 3032ffd87d3SSergey Temerkhanov 3042ffd87d3SSergey Temerkhanov if (!ice_pkg_enum_section(ice_seg, state, sect_type)) 3052ffd87d3SSergey Temerkhanov return NULL; 3062ffd87d3SSergey Temerkhanov 3072ffd87d3SSergey Temerkhanov state->entry_idx = 0; 3082ffd87d3SSergey Temerkhanov state->handler = handler; 3092ffd87d3SSergey Temerkhanov } else { 3102ffd87d3SSergey Temerkhanov state->entry_idx++; 3112ffd87d3SSergey Temerkhanov } 3122ffd87d3SSergey Temerkhanov 3132ffd87d3SSergey Temerkhanov if (!state->handler) 3142ffd87d3SSergey Temerkhanov return NULL; 3152ffd87d3SSergey Temerkhanov 3162ffd87d3SSergey Temerkhanov /* get entry */ 3172ffd87d3SSergey Temerkhanov entry = state->handler(state->sect_type, state->sect, state->entry_idx, 3182ffd87d3SSergey Temerkhanov offset); 3192ffd87d3SSergey Temerkhanov if (!entry) { 3202ffd87d3SSergey Temerkhanov /* end of a section, look for another section of this type */ 3212ffd87d3SSergey Temerkhanov if (!ice_pkg_enum_section(NULL, state, 0)) 3222ffd87d3SSergey Temerkhanov return NULL; 3232ffd87d3SSergey Temerkhanov 3242ffd87d3SSergey Temerkhanov state->entry_idx = 0; 3252ffd87d3SSergey Temerkhanov entry = state->handler(state->sect_type, state->sect, 3262ffd87d3SSergey Temerkhanov state->entry_idx, offset); 3272ffd87d3SSergey Temerkhanov } 3282ffd87d3SSergey Temerkhanov 3292ffd87d3SSergey Temerkhanov return entry; 3302ffd87d3SSergey Temerkhanov } 3312ffd87d3SSergey Temerkhanov 3322ffd87d3SSergey Temerkhanov /** 3332ffd87d3SSergey Temerkhanov * ice_sw_fv_handler 3342ffd87d3SSergey Temerkhanov * @sect_type: section type 3352ffd87d3SSergey Temerkhanov * @section: pointer to section 3362ffd87d3SSergey Temerkhanov * @index: index of the field vector entry to be returned 3372ffd87d3SSergey Temerkhanov * @offset: ptr to variable that receives the offset in the field vector table 3382ffd87d3SSergey Temerkhanov * 3392ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry. 3402ffd87d3SSergey Temerkhanov * This function treats the given section as of type ice_sw_fv_section and 3412ffd87d3SSergey Temerkhanov * enumerates offset field. "offset" is an index into the field vector table. 3422ffd87d3SSergey Temerkhanov */ 3432ffd87d3SSergey Temerkhanov static void *ice_sw_fv_handler(u32 sect_type, void *section, u32 index, 3442ffd87d3SSergey Temerkhanov u32 *offset) 3452ffd87d3SSergey Temerkhanov { 3462ffd87d3SSergey Temerkhanov struct ice_sw_fv_section *fv_section = section; 3472ffd87d3SSergey Temerkhanov 3482ffd87d3SSergey Temerkhanov if (!section || sect_type != ICE_SID_FLD_VEC_SW) 3492ffd87d3SSergey Temerkhanov return NULL; 3502ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(fv_section->count)) 3512ffd87d3SSergey Temerkhanov return NULL; 3522ffd87d3SSergey Temerkhanov if (offset) 3532ffd87d3SSergey Temerkhanov /* "index" passed in to this function is relative to a given 3542ffd87d3SSergey Temerkhanov * 4k block. To get to the true index into the field vector 3552ffd87d3SSergey Temerkhanov * table need to add the relative index to the base_offset 3562ffd87d3SSergey Temerkhanov * field of this section 3572ffd87d3SSergey Temerkhanov */ 3582ffd87d3SSergey Temerkhanov *offset = le16_to_cpu(fv_section->base_offset) + index; 3592ffd87d3SSergey Temerkhanov return fv_section->fv + index; 3602ffd87d3SSergey Temerkhanov } 3612ffd87d3SSergey Temerkhanov 3622ffd87d3SSergey Temerkhanov /** 3632ffd87d3SSergey Temerkhanov * ice_get_prof_index_max - get the max profile index for used profile 3642ffd87d3SSergey Temerkhanov * @hw: pointer to the HW struct 3652ffd87d3SSergey Temerkhanov * 3662ffd87d3SSergey Temerkhanov * Calling this function will get the max profile index for used profile 3672ffd87d3SSergey Temerkhanov * and store the index number in struct ice_switch_info *switch_info 3682ffd87d3SSergey Temerkhanov * in HW for following use. 3692ffd87d3SSergey Temerkhanov */ 3702ffd87d3SSergey Temerkhanov static int ice_get_prof_index_max(struct ice_hw *hw) 3712ffd87d3SSergey Temerkhanov { 3722ffd87d3SSergey Temerkhanov u16 prof_index = 0, j, max_prof_index = 0; 3732ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 3742ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 3752ffd87d3SSergey Temerkhanov bool flag = false; 3762ffd87d3SSergey Temerkhanov struct ice_fv *fv; 3772ffd87d3SSergey Temerkhanov u32 offset; 3782ffd87d3SSergey Temerkhanov 3792ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 3802ffd87d3SSergey Temerkhanov 3812ffd87d3SSergey Temerkhanov if (!hw->seg) 3822ffd87d3SSergey Temerkhanov return -EINVAL; 3832ffd87d3SSergey Temerkhanov 3842ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 3852ffd87d3SSergey Temerkhanov 3862ffd87d3SSergey Temerkhanov do { 3872ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 3882ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler); 3892ffd87d3SSergey Temerkhanov if (!fv) 3902ffd87d3SSergey Temerkhanov break; 3912ffd87d3SSergey Temerkhanov ice_seg = NULL; 3922ffd87d3SSergey Temerkhanov 3932ffd87d3SSergey Temerkhanov /* in the profile that not be used, the prot_id is set to 0xff 3942ffd87d3SSergey Temerkhanov * and the off is set to 0x1ff for all the field vectors. 3952ffd87d3SSergey Temerkhanov */ 3962ffd87d3SSergey Temerkhanov for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) 3972ffd87d3SSergey Temerkhanov if (fv->ew[j].prot_id != ICE_PROT_INVALID || 3982ffd87d3SSergey Temerkhanov fv->ew[j].off != ICE_FV_OFFSET_INVAL) 3992ffd87d3SSergey Temerkhanov flag = true; 4002ffd87d3SSergey Temerkhanov if (flag && prof_index > max_prof_index) 4012ffd87d3SSergey Temerkhanov max_prof_index = prof_index; 4022ffd87d3SSergey Temerkhanov 4032ffd87d3SSergey Temerkhanov prof_index++; 4042ffd87d3SSergey Temerkhanov flag = false; 4052ffd87d3SSergey Temerkhanov } while (fv); 4062ffd87d3SSergey Temerkhanov 4072ffd87d3SSergey Temerkhanov hw->switch_info->max_used_prof_index = max_prof_index; 4082ffd87d3SSergey Temerkhanov 4092ffd87d3SSergey Temerkhanov return 0; 4102ffd87d3SSergey Temerkhanov } 4112ffd87d3SSergey Temerkhanov 4122ffd87d3SSergey Temerkhanov /** 4132ffd87d3SSergey Temerkhanov * ice_get_ddp_pkg_state - get DDP pkg state after download 4142ffd87d3SSergey Temerkhanov * @hw: pointer to the HW struct 4152ffd87d3SSergey Temerkhanov * @already_loaded: indicates if pkg was already loaded onto the device 4162ffd87d3SSergey Temerkhanov */ 4172ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_ddp_pkg_state(struct ice_hw *hw, 4182ffd87d3SSergey Temerkhanov bool already_loaded) 4192ffd87d3SSergey Temerkhanov { 4202ffd87d3SSergey Temerkhanov if (hw->pkg_ver.major == hw->active_pkg_ver.major && 4212ffd87d3SSergey Temerkhanov hw->pkg_ver.minor == hw->active_pkg_ver.minor && 4222ffd87d3SSergey Temerkhanov hw->pkg_ver.update == hw->active_pkg_ver.update && 4232ffd87d3SSergey Temerkhanov hw->pkg_ver.draft == hw->active_pkg_ver.draft && 4242ffd87d3SSergey Temerkhanov !memcmp(hw->pkg_name, hw->active_pkg_name, sizeof(hw->pkg_name))) { 4252ffd87d3SSergey Temerkhanov if (already_loaded) 4262ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED; 4272ffd87d3SSergey Temerkhanov else 4282ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 4292ffd87d3SSergey Temerkhanov } else if (hw->active_pkg_ver.major != ICE_PKG_SUPP_VER_MAJ || 4302ffd87d3SSergey Temerkhanov hw->active_pkg_ver.minor != ICE_PKG_SUPP_VER_MNR) { 4312ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ALREADY_LOADED_NOT_SUPPORTED; 4322ffd87d3SSergey Temerkhanov } else if (hw->active_pkg_ver.major == ICE_PKG_SUPP_VER_MAJ && 4332ffd87d3SSergey Temerkhanov hw->active_pkg_ver.minor == ICE_PKG_SUPP_VER_MNR) { 4342ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED; 4352ffd87d3SSergey Temerkhanov } else { 4362ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 4372ffd87d3SSergey Temerkhanov } 4382ffd87d3SSergey Temerkhanov } 4392ffd87d3SSergey Temerkhanov 4402ffd87d3SSergey Temerkhanov /** 4412ffd87d3SSergey Temerkhanov * ice_init_pkg_regs - initialize additional package registers 4422ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 4432ffd87d3SSergey Temerkhanov */ 4442ffd87d3SSergey Temerkhanov static void ice_init_pkg_regs(struct ice_hw *hw) 4452ffd87d3SSergey Temerkhanov { 4462ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_INP_MASK_L 0xFFFFFFFF 4472ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_INP_MASK_H 0x0000FFFF 4482ffd87d3SSergey Temerkhanov #define ICE_SW_BLK_IDX 0 4492ffd87d3SSergey Temerkhanov 4502ffd87d3SSergey Temerkhanov /* setup Switch block input mask, which is 48-bits in two parts */ 4512ffd87d3SSergey Temerkhanov wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L); 4522ffd87d3SSergey Temerkhanov wr32(hw, GL_PREEXT_L2_PMASK1(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_H); 4532ffd87d3SSergey Temerkhanov } 4542ffd87d3SSergey Temerkhanov 4552ffd87d3SSergey Temerkhanov /** 4562ffd87d3SSergey Temerkhanov * ice_marker_ptype_tcam_handler 4572ffd87d3SSergey Temerkhanov * @sect_type: section type 4582ffd87d3SSergey Temerkhanov * @section: pointer to section 4592ffd87d3SSergey Temerkhanov * @index: index of the Marker PType TCAM entry to be returned 4602ffd87d3SSergey Temerkhanov * @offset: pointer to receive absolute offset, always 0 for ptype TCAM sections 4612ffd87d3SSergey Temerkhanov * 4622ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry. 4632ffd87d3SSergey Temerkhanov * Handles enumeration of individual Marker PType TCAM entries. 4642ffd87d3SSergey Temerkhanov */ 4652ffd87d3SSergey Temerkhanov static void *ice_marker_ptype_tcam_handler(u32 sect_type, void *section, 4662ffd87d3SSergey Temerkhanov u32 index, u32 *offset) 4672ffd87d3SSergey Temerkhanov { 4682ffd87d3SSergey Temerkhanov struct ice_marker_ptype_tcam_section *marker_ptype; 4692ffd87d3SSergey Temerkhanov 4702ffd87d3SSergey Temerkhanov if (sect_type != ICE_SID_RXPARSER_MARKER_PTYPE) 4712ffd87d3SSergey Temerkhanov return NULL; 4722ffd87d3SSergey Temerkhanov 4732ffd87d3SSergey Temerkhanov if (index > ICE_MAX_MARKER_PTYPE_TCAMS_IN_BUF) 4742ffd87d3SSergey Temerkhanov return NULL; 4752ffd87d3SSergey Temerkhanov 4762ffd87d3SSergey Temerkhanov if (offset) 4772ffd87d3SSergey Temerkhanov *offset = 0; 4782ffd87d3SSergey Temerkhanov 4792ffd87d3SSergey Temerkhanov marker_ptype = section; 4802ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(marker_ptype->count)) 4812ffd87d3SSergey Temerkhanov return NULL; 4822ffd87d3SSergey Temerkhanov 4832ffd87d3SSergey Temerkhanov return marker_ptype->tcam + index; 4842ffd87d3SSergey Temerkhanov } 4852ffd87d3SSergey Temerkhanov 4862ffd87d3SSergey Temerkhanov /** 4872ffd87d3SSergey Temerkhanov * ice_add_dvm_hint 4882ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 4892ffd87d3SSergey Temerkhanov * @val: value of the boost entry 4902ffd87d3SSergey Temerkhanov * @enable: true if entry needs to be enabled, or false if needs to be disabled 4912ffd87d3SSergey Temerkhanov */ 4922ffd87d3SSergey Temerkhanov static void ice_add_dvm_hint(struct ice_hw *hw, u16 val, bool enable) 4932ffd87d3SSergey Temerkhanov { 4942ffd87d3SSergey Temerkhanov if (hw->dvm_upd.count < ICE_DVM_MAX_ENTRIES) { 4952ffd87d3SSergey Temerkhanov hw->dvm_upd.tbl[hw->dvm_upd.count].boost_addr = val; 4962ffd87d3SSergey Temerkhanov hw->dvm_upd.tbl[hw->dvm_upd.count].enable = enable; 4972ffd87d3SSergey Temerkhanov hw->dvm_upd.count++; 4982ffd87d3SSergey Temerkhanov } 4992ffd87d3SSergey Temerkhanov } 5002ffd87d3SSergey Temerkhanov 5012ffd87d3SSergey Temerkhanov /** 5022ffd87d3SSergey Temerkhanov * ice_add_tunnel_hint 5032ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 5042ffd87d3SSergey Temerkhanov * @label_name: label text 5052ffd87d3SSergey Temerkhanov * @val: value of the tunnel port boost entry 5062ffd87d3SSergey Temerkhanov */ 5072ffd87d3SSergey Temerkhanov static void ice_add_tunnel_hint(struct ice_hw *hw, char *label_name, u16 val) 5082ffd87d3SSergey Temerkhanov { 5092ffd87d3SSergey Temerkhanov if (hw->tnl.count < ICE_TUNNEL_MAX_ENTRIES) { 5102ffd87d3SSergey Temerkhanov u16 i; 5112ffd87d3SSergey Temerkhanov 5122ffd87d3SSergey Temerkhanov for (i = 0; tnls[i].type != TNL_LAST; i++) { 5132ffd87d3SSergey Temerkhanov size_t len = strlen(tnls[i].label_prefix); 5142ffd87d3SSergey Temerkhanov 5152ffd87d3SSergey Temerkhanov /* Look for matching label start, before continuing */ 5162ffd87d3SSergey Temerkhanov if (strncmp(label_name, tnls[i].label_prefix, len)) 5172ffd87d3SSergey Temerkhanov continue; 5182ffd87d3SSergey Temerkhanov 5192ffd87d3SSergey Temerkhanov /* Make sure this label matches our PF. Note that the PF 5202ffd87d3SSergey Temerkhanov * character ('0' - '7') will be located where our 5212ffd87d3SSergey Temerkhanov * prefix string's null terminator is located. 5222ffd87d3SSergey Temerkhanov */ 5232ffd87d3SSergey Temerkhanov if ((label_name[len] - '0') == hw->pf_id) { 5242ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].type = tnls[i].type; 5252ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].valid = false; 5262ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].boost_addr = val; 5272ffd87d3SSergey Temerkhanov hw->tnl.tbl[hw->tnl.count].port = 0; 5282ffd87d3SSergey Temerkhanov hw->tnl.count++; 5292ffd87d3SSergey Temerkhanov break; 5302ffd87d3SSergey Temerkhanov } 5312ffd87d3SSergey Temerkhanov } 5322ffd87d3SSergey Temerkhanov } 5332ffd87d3SSergey Temerkhanov } 5342ffd87d3SSergey Temerkhanov 5352ffd87d3SSergey Temerkhanov /** 5362ffd87d3SSergey Temerkhanov * ice_label_enum_handler 5372ffd87d3SSergey Temerkhanov * @sect_type: section type 5382ffd87d3SSergey Temerkhanov * @section: pointer to section 5392ffd87d3SSergey Temerkhanov * @index: index of the label entry to be returned 5402ffd87d3SSergey Temerkhanov * @offset: pointer to receive absolute offset, always zero for label sections 5412ffd87d3SSergey Temerkhanov * 5422ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry. 5432ffd87d3SSergey Temerkhanov * Handles enumeration of individual label entries. 5442ffd87d3SSergey Temerkhanov */ 5452ffd87d3SSergey Temerkhanov static void *ice_label_enum_handler(u32 __always_unused sect_type, 5462ffd87d3SSergey Temerkhanov void *section, u32 index, u32 *offset) 5472ffd87d3SSergey Temerkhanov { 5482ffd87d3SSergey Temerkhanov struct ice_label_section *labels; 5492ffd87d3SSergey Temerkhanov 5502ffd87d3SSergey Temerkhanov if (!section) 5512ffd87d3SSergey Temerkhanov return NULL; 5522ffd87d3SSergey Temerkhanov 5532ffd87d3SSergey Temerkhanov if (index > ICE_MAX_LABELS_IN_BUF) 5542ffd87d3SSergey Temerkhanov return NULL; 5552ffd87d3SSergey Temerkhanov 5562ffd87d3SSergey Temerkhanov if (offset) 5572ffd87d3SSergey Temerkhanov *offset = 0; 5582ffd87d3SSergey Temerkhanov 5592ffd87d3SSergey Temerkhanov labels = section; 5602ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(labels->count)) 5612ffd87d3SSergey Temerkhanov return NULL; 5622ffd87d3SSergey Temerkhanov 5632ffd87d3SSergey Temerkhanov return labels->label + index; 5642ffd87d3SSergey Temerkhanov } 5652ffd87d3SSergey Temerkhanov 5662ffd87d3SSergey Temerkhanov /** 5672ffd87d3SSergey Temerkhanov * ice_enum_labels 5682ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (NULL on subsequent calls) 5692ffd87d3SSergey Temerkhanov * @type: the section type that will contain the label (0 on subsequent calls) 5702ffd87d3SSergey Temerkhanov * @state: ice_pkg_enum structure that will hold the state of the enumeration 5712ffd87d3SSergey Temerkhanov * @value: pointer to a value that will return the label's value if found 5722ffd87d3SSergey Temerkhanov * 5732ffd87d3SSergey Temerkhanov * Enumerates a list of labels in the package. The caller will call 5742ffd87d3SSergey Temerkhanov * ice_enum_labels(ice_seg, type, ...) to start the enumeration, then call 5752ffd87d3SSergey Temerkhanov * ice_enum_labels(NULL, 0, ...) to continue. When the function returns a NULL 5762ffd87d3SSergey Temerkhanov * the end of the list has been reached. 5772ffd87d3SSergey Temerkhanov */ 5782ffd87d3SSergey Temerkhanov static char *ice_enum_labels(struct ice_seg *ice_seg, u32 type, 5792ffd87d3SSergey Temerkhanov struct ice_pkg_enum *state, u16 *value) 5802ffd87d3SSergey Temerkhanov { 5812ffd87d3SSergey Temerkhanov struct ice_label *label; 5822ffd87d3SSergey Temerkhanov 5832ffd87d3SSergey Temerkhanov /* Check for valid label section on first call */ 5842ffd87d3SSergey Temerkhanov if (type && !(type >= ICE_SID_LBL_FIRST && type <= ICE_SID_LBL_LAST)) 5852ffd87d3SSergey Temerkhanov return NULL; 5862ffd87d3SSergey Temerkhanov 5872ffd87d3SSergey Temerkhanov label = ice_pkg_enum_entry(ice_seg, state, type, NULL, 5882ffd87d3SSergey Temerkhanov ice_label_enum_handler); 5892ffd87d3SSergey Temerkhanov if (!label) 5902ffd87d3SSergey Temerkhanov return NULL; 5912ffd87d3SSergey Temerkhanov 5922ffd87d3SSergey Temerkhanov *value = le16_to_cpu(label->value); 5932ffd87d3SSergey Temerkhanov return label->name; 5942ffd87d3SSergey Temerkhanov } 5952ffd87d3SSergey Temerkhanov 5962ffd87d3SSergey Temerkhanov /** 5972ffd87d3SSergey Temerkhanov * ice_boost_tcam_handler 5982ffd87d3SSergey Temerkhanov * @sect_type: section type 5992ffd87d3SSergey Temerkhanov * @section: pointer to section 6002ffd87d3SSergey Temerkhanov * @index: index of the boost TCAM entry to be returned 6012ffd87d3SSergey Temerkhanov * @offset: pointer to receive absolute offset, always 0 for boost TCAM sections 6022ffd87d3SSergey Temerkhanov * 6032ffd87d3SSergey Temerkhanov * This is a callback function that can be passed to ice_pkg_enum_entry. 6042ffd87d3SSergey Temerkhanov * Handles enumeration of individual boost TCAM entries. 6052ffd87d3SSergey Temerkhanov */ 6062ffd87d3SSergey Temerkhanov static void *ice_boost_tcam_handler(u32 sect_type, void *section, u32 index, 6072ffd87d3SSergey Temerkhanov u32 *offset) 6082ffd87d3SSergey Temerkhanov { 6092ffd87d3SSergey Temerkhanov struct ice_boost_tcam_section *boost; 6102ffd87d3SSergey Temerkhanov 6112ffd87d3SSergey Temerkhanov if (!section) 6122ffd87d3SSergey Temerkhanov return NULL; 6132ffd87d3SSergey Temerkhanov 6142ffd87d3SSergey Temerkhanov if (sect_type != ICE_SID_RXPARSER_BOOST_TCAM) 6152ffd87d3SSergey Temerkhanov return NULL; 6162ffd87d3SSergey Temerkhanov 6172ffd87d3SSergey Temerkhanov if (index > ICE_MAX_BST_TCAMS_IN_BUF) 6182ffd87d3SSergey Temerkhanov return NULL; 6192ffd87d3SSergey Temerkhanov 6202ffd87d3SSergey Temerkhanov if (offset) 6212ffd87d3SSergey Temerkhanov *offset = 0; 6222ffd87d3SSergey Temerkhanov 6232ffd87d3SSergey Temerkhanov boost = section; 6242ffd87d3SSergey Temerkhanov if (index >= le16_to_cpu(boost->count)) 6252ffd87d3SSergey Temerkhanov return NULL; 6262ffd87d3SSergey Temerkhanov 6272ffd87d3SSergey Temerkhanov return boost->tcam + index; 6282ffd87d3SSergey Temerkhanov } 6292ffd87d3SSergey Temerkhanov 6302ffd87d3SSergey Temerkhanov /** 6312ffd87d3SSergey Temerkhanov * ice_find_boost_entry 6322ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the ice segment (non-NULL) 6332ffd87d3SSergey Temerkhanov * @addr: Boost TCAM address of entry to search for 6342ffd87d3SSergey Temerkhanov * @entry: returns pointer to the entry 6352ffd87d3SSergey Temerkhanov * 6362ffd87d3SSergey Temerkhanov * Finds a particular Boost TCAM entry and returns a pointer to that entry 6372ffd87d3SSergey Temerkhanov * if it is found. The ice_seg parameter must not be NULL since the first call 6382ffd87d3SSergey Temerkhanov * to ice_pkg_enum_entry requires a pointer to an actual ice_segment structure. 6392ffd87d3SSergey Temerkhanov */ 6402ffd87d3SSergey Temerkhanov static int ice_find_boost_entry(struct ice_seg *ice_seg, u16 addr, 6412ffd87d3SSergey Temerkhanov struct ice_boost_tcam_entry **entry) 6422ffd87d3SSergey Temerkhanov { 6432ffd87d3SSergey Temerkhanov struct ice_boost_tcam_entry *tcam; 6442ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 6452ffd87d3SSergey Temerkhanov 6462ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 6472ffd87d3SSergey Temerkhanov 6482ffd87d3SSergey Temerkhanov if (!ice_seg) 6492ffd87d3SSergey Temerkhanov return -EINVAL; 6502ffd87d3SSergey Temerkhanov 6512ffd87d3SSergey Temerkhanov do { 6522ffd87d3SSergey Temerkhanov tcam = ice_pkg_enum_entry(ice_seg, &state, 6532ffd87d3SSergey Temerkhanov ICE_SID_RXPARSER_BOOST_TCAM, NULL, 6542ffd87d3SSergey Temerkhanov ice_boost_tcam_handler); 6552ffd87d3SSergey Temerkhanov if (tcam && le16_to_cpu(tcam->addr) == addr) { 6562ffd87d3SSergey Temerkhanov *entry = tcam; 6572ffd87d3SSergey Temerkhanov return 0; 6582ffd87d3SSergey Temerkhanov } 6592ffd87d3SSergey Temerkhanov 6602ffd87d3SSergey Temerkhanov ice_seg = NULL; 6612ffd87d3SSergey Temerkhanov } while (tcam); 6622ffd87d3SSergey Temerkhanov 6632ffd87d3SSergey Temerkhanov *entry = NULL; 6642ffd87d3SSergey Temerkhanov return -EIO; 6652ffd87d3SSergey Temerkhanov } 6662ffd87d3SSergey Temerkhanov 6672ffd87d3SSergey Temerkhanov /** 6682ffd87d3SSergey Temerkhanov * ice_is_init_pkg_successful - check if DDP init was successful 6692ffd87d3SSergey Temerkhanov * @state: state of the DDP pkg after download 6702ffd87d3SSergey Temerkhanov */ 6712ffd87d3SSergey Temerkhanov bool ice_is_init_pkg_successful(enum ice_ddp_state state) 6722ffd87d3SSergey Temerkhanov { 6732ffd87d3SSergey Temerkhanov switch (state) { 6742ffd87d3SSergey Temerkhanov case ICE_DDP_PKG_SUCCESS: 6752ffd87d3SSergey Temerkhanov case ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED: 6762ffd87d3SSergey Temerkhanov case ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED: 6772ffd87d3SSergey Temerkhanov return true; 6782ffd87d3SSergey Temerkhanov default: 6792ffd87d3SSergey Temerkhanov return false; 6802ffd87d3SSergey Temerkhanov } 6812ffd87d3SSergey Temerkhanov } 6822ffd87d3SSergey Temerkhanov 6832ffd87d3SSergey Temerkhanov /** 6842ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc 6852ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 6862ffd87d3SSergey Temerkhanov * 6872ffd87d3SSergey Temerkhanov * Allocates a package buffer and returns a pointer to the buffer header. 6882ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 6892ffd87d3SSergey Temerkhanov */ 6902ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw) 6912ffd87d3SSergey Temerkhanov { 6922ffd87d3SSergey Temerkhanov struct ice_buf_build *bld; 6932ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 6942ffd87d3SSergey Temerkhanov 6952ffd87d3SSergey Temerkhanov bld = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*bld), GFP_KERNEL); 6962ffd87d3SSergey Temerkhanov if (!bld) 6972ffd87d3SSergey Temerkhanov return NULL; 6982ffd87d3SSergey Temerkhanov 6992ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)bld; 7002ffd87d3SSergey Temerkhanov buf->data_end = 7012ffd87d3SSergey Temerkhanov cpu_to_le16(offsetof(struct ice_buf_hdr, section_entry)); 7022ffd87d3SSergey Temerkhanov return bld; 7032ffd87d3SSergey Temerkhanov } 7042ffd87d3SSergey Temerkhanov 7052ffd87d3SSergey Temerkhanov static bool ice_is_gtp_u_profile(u16 prof_idx) 7062ffd87d3SSergey Temerkhanov { 7072ffd87d3SSergey Temerkhanov return (prof_idx >= ICE_PROFID_IPV6_GTPU_TEID && 7082ffd87d3SSergey Temerkhanov prof_idx <= ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER) || 7092ffd87d3SSergey Temerkhanov prof_idx == ICE_PROFID_IPV4_GTPU_TEID; 7102ffd87d3SSergey Temerkhanov } 7112ffd87d3SSergey Temerkhanov 7122ffd87d3SSergey Temerkhanov static bool ice_is_gtp_c_profile(u16 prof_idx) 7132ffd87d3SSergey Temerkhanov { 7142ffd87d3SSergey Temerkhanov switch (prof_idx) { 7152ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV4_GTPC_TEID: 7162ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV4_GTPC_NO_TEID: 7172ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV6_GTPC_TEID: 7182ffd87d3SSergey Temerkhanov case ICE_PROFID_IPV6_GTPC_NO_TEID: 7192ffd87d3SSergey Temerkhanov return true; 7202ffd87d3SSergey Temerkhanov default: 7212ffd87d3SSergey Temerkhanov return false; 7222ffd87d3SSergey Temerkhanov } 7232ffd87d3SSergey Temerkhanov } 7242ffd87d3SSergey Temerkhanov 725784feaa6SMarcin Szycik static bool ice_is_pfcp_profile(u16 prof_idx) 726784feaa6SMarcin Szycik { 727784feaa6SMarcin Szycik return prof_idx >= ICE_PROFID_IPV4_PFCP_NODE && 728784feaa6SMarcin Szycik prof_idx <= ICE_PROFID_IPV6_PFCP_SESSION; 729784feaa6SMarcin Szycik } 730784feaa6SMarcin Szycik 7312ffd87d3SSergey Temerkhanov /** 7322ffd87d3SSergey Temerkhanov * ice_get_sw_prof_type - determine switch profile type 7332ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 7342ffd87d3SSergey Temerkhanov * @fv: pointer to the switch field vector 7352ffd87d3SSergey Temerkhanov * @prof_idx: profile index to check 7362ffd87d3SSergey Temerkhanov */ 7372ffd87d3SSergey Temerkhanov static enum ice_prof_type ice_get_sw_prof_type(struct ice_hw *hw, 7382ffd87d3SSergey Temerkhanov struct ice_fv *fv, u32 prof_idx) 7392ffd87d3SSergey Temerkhanov { 7402ffd87d3SSergey Temerkhanov u16 i; 7412ffd87d3SSergey Temerkhanov 7422ffd87d3SSergey Temerkhanov if (ice_is_gtp_c_profile(prof_idx)) 7432ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GTPC; 7442ffd87d3SSergey Temerkhanov 7452ffd87d3SSergey Temerkhanov if (ice_is_gtp_u_profile(prof_idx)) 7462ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GTPU; 7472ffd87d3SSergey Temerkhanov 748784feaa6SMarcin Szycik if (ice_is_pfcp_profile(prof_idx)) 749784feaa6SMarcin Szycik return ICE_PROF_TUN_PFCP; 750784feaa6SMarcin Szycik 7512ffd87d3SSergey Temerkhanov for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) { 7522ffd87d3SSergey Temerkhanov /* UDP tunnel will have UDP_OF protocol ID and VNI offset */ 7532ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF && 7542ffd87d3SSergey Temerkhanov fv->ew[i].off == ICE_VNI_OFFSET) 7552ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_UDP; 7562ffd87d3SSergey Temerkhanov 7572ffd87d3SSergey Temerkhanov /* GRE tunnel will have GRE protocol */ 7582ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == (u8)ICE_PROT_GRE_OF) 7592ffd87d3SSergey Temerkhanov return ICE_PROF_TUN_GRE; 7602ffd87d3SSergey Temerkhanov } 7612ffd87d3SSergey Temerkhanov 7622ffd87d3SSergey Temerkhanov return ICE_PROF_NON_TUN; 7632ffd87d3SSergey Temerkhanov } 7642ffd87d3SSergey Temerkhanov 7652ffd87d3SSergey Temerkhanov /** 7662ffd87d3SSergey Temerkhanov * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type 7672ffd87d3SSergey Temerkhanov * @hw: pointer to hardware structure 7682ffd87d3SSergey Temerkhanov * @req_profs: type of profiles requested 7692ffd87d3SSergey Temerkhanov * @bm: pointer to memory for returning the bitmap of field vectors 7702ffd87d3SSergey Temerkhanov */ 7712ffd87d3SSergey Temerkhanov void ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs, 7722ffd87d3SSergey Temerkhanov unsigned long *bm) 7732ffd87d3SSergey Temerkhanov { 7742ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 7752ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 7762ffd87d3SSergey Temerkhanov struct ice_fv *fv; 7772ffd87d3SSergey Temerkhanov 7782ffd87d3SSergey Temerkhanov if (req_profs == ICE_PROF_ALL) { 7792ffd87d3SSergey Temerkhanov bitmap_set(bm, 0, ICE_MAX_NUM_PROFILES); 7802ffd87d3SSergey Temerkhanov return; 7812ffd87d3SSergey Temerkhanov } 7822ffd87d3SSergey Temerkhanov 7832ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 7842ffd87d3SSergey Temerkhanov bitmap_zero(bm, ICE_MAX_NUM_PROFILES); 7852ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 7862ffd87d3SSergey Temerkhanov do { 7872ffd87d3SSergey Temerkhanov enum ice_prof_type prof_type; 7882ffd87d3SSergey Temerkhanov u32 offset; 7892ffd87d3SSergey Temerkhanov 7902ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 7912ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler); 7922ffd87d3SSergey Temerkhanov ice_seg = NULL; 7932ffd87d3SSergey Temerkhanov 7942ffd87d3SSergey Temerkhanov if (fv) { 7952ffd87d3SSergey Temerkhanov /* Determine field vector type */ 7962ffd87d3SSergey Temerkhanov prof_type = ice_get_sw_prof_type(hw, fv, offset); 7972ffd87d3SSergey Temerkhanov 7982ffd87d3SSergey Temerkhanov if (req_profs & prof_type) 7992ffd87d3SSergey Temerkhanov set_bit((u16)offset, bm); 8002ffd87d3SSergey Temerkhanov } 8012ffd87d3SSergey Temerkhanov } while (fv); 8022ffd87d3SSergey Temerkhanov } 8032ffd87d3SSergey Temerkhanov 8042ffd87d3SSergey Temerkhanov /** 8052ffd87d3SSergey Temerkhanov * ice_get_sw_fv_list 8062ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 8072ffd87d3SSergey Temerkhanov * @lkups: list of protocol types 8082ffd87d3SSergey Temerkhanov * @bm: bitmap of field vectors to consider 8092ffd87d3SSergey Temerkhanov * @fv_list: Head of a list 8102ffd87d3SSergey Temerkhanov * 8112ffd87d3SSergey Temerkhanov * Finds all the field vector entries from switch block that contain 8122ffd87d3SSergey Temerkhanov * a given protocol ID and offset and returns a list of structures of type 8132ffd87d3SSergey Temerkhanov * "ice_sw_fv_list_entry". Every structure in the list has a field vector 8142ffd87d3SSergey Temerkhanov * definition and profile ID information 8152ffd87d3SSergey Temerkhanov * NOTE: The caller of the function is responsible for freeing the memory 8162ffd87d3SSergey Temerkhanov * allocated for every list entry. 8172ffd87d3SSergey Temerkhanov */ 8182ffd87d3SSergey Temerkhanov int ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups, 8192ffd87d3SSergey Temerkhanov unsigned long *bm, struct list_head *fv_list) 8202ffd87d3SSergey Temerkhanov { 8212ffd87d3SSergey Temerkhanov struct ice_sw_fv_list_entry *fvl; 8222ffd87d3SSergey Temerkhanov struct ice_sw_fv_list_entry *tmp; 8232ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 8242ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 8252ffd87d3SSergey Temerkhanov struct ice_fv *fv; 8262ffd87d3SSergey Temerkhanov u32 offset; 8272ffd87d3SSergey Temerkhanov 8282ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 8292ffd87d3SSergey Temerkhanov 8302ffd87d3SSergey Temerkhanov if (!lkups->n_val_words || !hw->seg) 8312ffd87d3SSergey Temerkhanov return -EINVAL; 8322ffd87d3SSergey Temerkhanov 8332ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 8342ffd87d3SSergey Temerkhanov do { 8352ffd87d3SSergey Temerkhanov u16 i; 8362ffd87d3SSergey Temerkhanov 8372ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 8382ffd87d3SSergey Temerkhanov &offset, ice_sw_fv_handler); 8392ffd87d3SSergey Temerkhanov if (!fv) 8402ffd87d3SSergey Temerkhanov break; 8412ffd87d3SSergey Temerkhanov ice_seg = NULL; 8422ffd87d3SSergey Temerkhanov 8432ffd87d3SSergey Temerkhanov /* If field vector is not in the bitmap list, then skip this 8442ffd87d3SSergey Temerkhanov * profile. 8452ffd87d3SSergey Temerkhanov */ 8462ffd87d3SSergey Temerkhanov if (!test_bit((u16)offset, bm)) 8472ffd87d3SSergey Temerkhanov continue; 8482ffd87d3SSergey Temerkhanov 8492ffd87d3SSergey Temerkhanov for (i = 0; i < lkups->n_val_words; i++) { 8502ffd87d3SSergey Temerkhanov int j; 8512ffd87d3SSergey Temerkhanov 8522ffd87d3SSergey Temerkhanov for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) 8532ffd87d3SSergey Temerkhanov if (fv->ew[j].prot_id == 8542ffd87d3SSergey Temerkhanov lkups->fv_words[i].prot_id && 8552ffd87d3SSergey Temerkhanov fv->ew[j].off == lkups->fv_words[i].off) 8562ffd87d3SSergey Temerkhanov break; 8572ffd87d3SSergey Temerkhanov if (j >= hw->blk[ICE_BLK_SW].es.fvw) 8582ffd87d3SSergey Temerkhanov break; 8592ffd87d3SSergey Temerkhanov if (i + 1 == lkups->n_val_words) { 8602ffd87d3SSergey Temerkhanov fvl = devm_kzalloc(ice_hw_to_dev(hw), 8612ffd87d3SSergey Temerkhanov sizeof(*fvl), GFP_KERNEL); 8622ffd87d3SSergey Temerkhanov if (!fvl) 8632ffd87d3SSergey Temerkhanov goto err; 8642ffd87d3SSergey Temerkhanov fvl->fv_ptr = fv; 8652ffd87d3SSergey Temerkhanov fvl->profile_id = offset; 8662ffd87d3SSergey Temerkhanov list_add(&fvl->list_entry, fv_list); 8672ffd87d3SSergey Temerkhanov break; 8682ffd87d3SSergey Temerkhanov } 8692ffd87d3SSergey Temerkhanov } 8702ffd87d3SSergey Temerkhanov } while (fv); 8712ffd87d3SSergey Temerkhanov if (list_empty(fv_list)) { 8722ffd87d3SSergey Temerkhanov dev_warn(ice_hw_to_dev(hw), 8732ffd87d3SSergey Temerkhanov "Required profiles not found in currently loaded DDP package"); 8742ffd87d3SSergey Temerkhanov return -EIO; 8752ffd87d3SSergey Temerkhanov } 8762ffd87d3SSergey Temerkhanov 8772ffd87d3SSergey Temerkhanov return 0; 8782ffd87d3SSergey Temerkhanov 8792ffd87d3SSergey Temerkhanov err: 8802ffd87d3SSergey Temerkhanov list_for_each_entry_safe(fvl, tmp, fv_list, list_entry) { 8812ffd87d3SSergey Temerkhanov list_del(&fvl->list_entry); 8822ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), fvl); 8832ffd87d3SSergey Temerkhanov } 8842ffd87d3SSergey Temerkhanov 8852ffd87d3SSergey Temerkhanov return -ENOMEM; 8862ffd87d3SSergey Temerkhanov } 8872ffd87d3SSergey Temerkhanov 8882ffd87d3SSergey Temerkhanov /** 8892ffd87d3SSergey Temerkhanov * ice_init_prof_result_bm - Initialize the profile result index bitmap 8902ffd87d3SSergey Temerkhanov * @hw: pointer to hardware structure 8912ffd87d3SSergey Temerkhanov */ 8922ffd87d3SSergey Temerkhanov void ice_init_prof_result_bm(struct ice_hw *hw) 8932ffd87d3SSergey Temerkhanov { 8942ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 8952ffd87d3SSergey Temerkhanov struct ice_seg *ice_seg; 8962ffd87d3SSergey Temerkhanov struct ice_fv *fv; 8972ffd87d3SSergey Temerkhanov 8982ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 8992ffd87d3SSergey Temerkhanov 9002ffd87d3SSergey Temerkhanov if (!hw->seg) 9012ffd87d3SSergey Temerkhanov return; 9022ffd87d3SSergey Temerkhanov 9032ffd87d3SSergey Temerkhanov ice_seg = hw->seg; 9042ffd87d3SSergey Temerkhanov do { 9052ffd87d3SSergey Temerkhanov u32 off; 9062ffd87d3SSergey Temerkhanov u16 i; 9072ffd87d3SSergey Temerkhanov 9082ffd87d3SSergey Temerkhanov fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, 9092ffd87d3SSergey Temerkhanov &off, ice_sw_fv_handler); 9102ffd87d3SSergey Temerkhanov ice_seg = NULL; 9112ffd87d3SSergey Temerkhanov if (!fv) 9122ffd87d3SSergey Temerkhanov break; 9132ffd87d3SSergey Temerkhanov 9142ffd87d3SSergey Temerkhanov bitmap_zero(hw->switch_info->prof_res_bm[off], 9152ffd87d3SSergey Temerkhanov ICE_MAX_FV_WORDS); 9162ffd87d3SSergey Temerkhanov 9172ffd87d3SSergey Temerkhanov /* Determine empty field vector indices, these can be 9182ffd87d3SSergey Temerkhanov * used for recipe results. Skip index 0, since it is 9192ffd87d3SSergey Temerkhanov * always used for Switch ID. 9202ffd87d3SSergey Temerkhanov */ 9212ffd87d3SSergey Temerkhanov for (i = 1; i < ICE_MAX_FV_WORDS; i++) 9222ffd87d3SSergey Temerkhanov if (fv->ew[i].prot_id == ICE_PROT_INVALID && 9232ffd87d3SSergey Temerkhanov fv->ew[i].off == ICE_FV_OFFSET_INVAL) 9242ffd87d3SSergey Temerkhanov set_bit(i, hw->switch_info->prof_res_bm[off]); 9252ffd87d3SSergey Temerkhanov } while (fv); 9262ffd87d3SSergey Temerkhanov } 9272ffd87d3SSergey Temerkhanov 9282ffd87d3SSergey Temerkhanov /** 9292ffd87d3SSergey Temerkhanov * ice_pkg_buf_free 9302ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 9312ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 9322ffd87d3SSergey Temerkhanov * 9332ffd87d3SSergey Temerkhanov * Frees a package buffer 9342ffd87d3SSergey Temerkhanov */ 9352ffd87d3SSergey Temerkhanov void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld) 9362ffd87d3SSergey Temerkhanov { 9372ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), bld); 9382ffd87d3SSergey Temerkhanov } 9392ffd87d3SSergey Temerkhanov 9402ffd87d3SSergey Temerkhanov /** 9412ffd87d3SSergey Temerkhanov * ice_pkg_buf_reserve_section 9422ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 9432ffd87d3SSergey Temerkhanov * @count: the number of sections to reserve 9442ffd87d3SSergey Temerkhanov * 9452ffd87d3SSergey Temerkhanov * Reserves one or more section table entries in a package buffer. This routine 9462ffd87d3SSergey Temerkhanov * can be called multiple times as long as they are made before calling 9472ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section() 9482ffd87d3SSergey Temerkhanov * is called once, the number of sections that can be allocated will not be able 9492ffd87d3SSergey Temerkhanov * to be increased; not using all reserved sections is fine, but this will 9502ffd87d3SSergey Temerkhanov * result in some wasted space in the buffer. 9512ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 9522ffd87d3SSergey Temerkhanov */ 9532ffd87d3SSergey Temerkhanov int ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count) 9542ffd87d3SSergey Temerkhanov { 9552ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 9562ffd87d3SSergey Temerkhanov u16 section_count; 9572ffd87d3SSergey Temerkhanov u16 data_end; 9582ffd87d3SSergey Temerkhanov 9592ffd87d3SSergey Temerkhanov if (!bld) 9602ffd87d3SSergey Temerkhanov return -EINVAL; 9612ffd87d3SSergey Temerkhanov 9622ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf; 9632ffd87d3SSergey Temerkhanov 9642ffd87d3SSergey Temerkhanov /* already an active section, can't increase table size */ 9652ffd87d3SSergey Temerkhanov section_count = le16_to_cpu(buf->section_count); 9662ffd87d3SSergey Temerkhanov if (section_count > 0) 9672ffd87d3SSergey Temerkhanov return -EIO; 9682ffd87d3SSergey Temerkhanov 9692ffd87d3SSergey Temerkhanov if (bld->reserved_section_table_entries + count > ICE_MAX_S_COUNT) 9702ffd87d3SSergey Temerkhanov return -EIO; 9712ffd87d3SSergey Temerkhanov bld->reserved_section_table_entries += count; 9722ffd87d3SSergey Temerkhanov 9732ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(buf->data_end) + 9742ffd87d3SSergey Temerkhanov flex_array_size(buf, section_entry, count); 9752ffd87d3SSergey Temerkhanov buf->data_end = cpu_to_le16(data_end); 9762ffd87d3SSergey Temerkhanov 9772ffd87d3SSergey Temerkhanov return 0; 9782ffd87d3SSergey Temerkhanov } 9792ffd87d3SSergey Temerkhanov 9802ffd87d3SSergey Temerkhanov /** 9812ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_section 9822ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 9832ffd87d3SSergey Temerkhanov * @type: the section type value 9842ffd87d3SSergey Temerkhanov * @size: the size of the section to reserve (in bytes) 9852ffd87d3SSergey Temerkhanov * 9862ffd87d3SSergey Temerkhanov * Reserves memory in the buffer for a section's content and updates the 9872ffd87d3SSergey Temerkhanov * buffers' status accordingly. This routine returns a pointer to the first 9882ffd87d3SSergey Temerkhanov * byte of the section start within the buffer, which is used to fill in the 9892ffd87d3SSergey Temerkhanov * section contents. 9902ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 9912ffd87d3SSergey Temerkhanov */ 9922ffd87d3SSergey Temerkhanov void *ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size) 9932ffd87d3SSergey Temerkhanov { 9942ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 9952ffd87d3SSergey Temerkhanov u16 sect_count; 9962ffd87d3SSergey Temerkhanov u16 data_end; 9972ffd87d3SSergey Temerkhanov 9982ffd87d3SSergey Temerkhanov if (!bld || !type || !size) 9992ffd87d3SSergey Temerkhanov return NULL; 10002ffd87d3SSergey Temerkhanov 10012ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf; 10022ffd87d3SSergey Temerkhanov 10032ffd87d3SSergey Temerkhanov /* check for enough space left in buffer */ 10042ffd87d3SSergey Temerkhanov data_end = le16_to_cpu(buf->data_end); 10052ffd87d3SSergey Temerkhanov 10062ffd87d3SSergey Temerkhanov /* section start must align on 4 byte boundary */ 10072ffd87d3SSergey Temerkhanov data_end = ALIGN(data_end, 4); 10082ffd87d3SSergey Temerkhanov 10092ffd87d3SSergey Temerkhanov if ((data_end + size) > ICE_MAX_S_DATA_END) 10102ffd87d3SSergey Temerkhanov return NULL; 10112ffd87d3SSergey Temerkhanov 10122ffd87d3SSergey Temerkhanov /* check for more available section table entries */ 10132ffd87d3SSergey Temerkhanov sect_count = le16_to_cpu(buf->section_count); 10142ffd87d3SSergey Temerkhanov if (sect_count < bld->reserved_section_table_entries) { 10152ffd87d3SSergey Temerkhanov void *section_ptr = ((u8 *)buf) + data_end; 10162ffd87d3SSergey Temerkhanov 10172ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].offset = cpu_to_le16(data_end); 10182ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].size = cpu_to_le16(size); 10192ffd87d3SSergey Temerkhanov buf->section_entry[sect_count].type = cpu_to_le32(type); 10202ffd87d3SSergey Temerkhanov 10212ffd87d3SSergey Temerkhanov data_end += size; 10222ffd87d3SSergey Temerkhanov buf->data_end = cpu_to_le16(data_end); 10232ffd87d3SSergey Temerkhanov 10242ffd87d3SSergey Temerkhanov buf->section_count = cpu_to_le16(sect_count + 1); 10252ffd87d3SSergey Temerkhanov return section_ptr; 10262ffd87d3SSergey Temerkhanov } 10272ffd87d3SSergey Temerkhanov 10282ffd87d3SSergey Temerkhanov /* no free section table entries */ 10292ffd87d3SSergey Temerkhanov return NULL; 10302ffd87d3SSergey Temerkhanov } 10312ffd87d3SSergey Temerkhanov 10322ffd87d3SSergey Temerkhanov /** 10332ffd87d3SSergey Temerkhanov * ice_pkg_buf_alloc_single_section 10342ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 10352ffd87d3SSergey Temerkhanov * @type: the section type value 10362ffd87d3SSergey Temerkhanov * @size: the size of the section to reserve (in bytes) 10372ffd87d3SSergey Temerkhanov * @section: returns pointer to the section 10382ffd87d3SSergey Temerkhanov * 10392ffd87d3SSergey Temerkhanov * Allocates a package buffer with a single section. 10402ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 10412ffd87d3SSergey Temerkhanov */ 10422ffd87d3SSergey Temerkhanov struct ice_buf_build *ice_pkg_buf_alloc_single_section(struct ice_hw *hw, 10432ffd87d3SSergey Temerkhanov u32 type, u16 size, 10442ffd87d3SSergey Temerkhanov void **section) 10452ffd87d3SSergey Temerkhanov { 10462ffd87d3SSergey Temerkhanov struct ice_buf_build *buf; 10472ffd87d3SSergey Temerkhanov 10482ffd87d3SSergey Temerkhanov if (!section) 10492ffd87d3SSergey Temerkhanov return NULL; 10502ffd87d3SSergey Temerkhanov 10512ffd87d3SSergey Temerkhanov buf = ice_pkg_buf_alloc(hw); 10522ffd87d3SSergey Temerkhanov if (!buf) 10532ffd87d3SSergey Temerkhanov return NULL; 10542ffd87d3SSergey Temerkhanov 10552ffd87d3SSergey Temerkhanov if (ice_pkg_buf_reserve_section(buf, 1)) 10562ffd87d3SSergey Temerkhanov goto ice_pkg_buf_alloc_single_section_err; 10572ffd87d3SSergey Temerkhanov 10582ffd87d3SSergey Temerkhanov *section = ice_pkg_buf_alloc_section(buf, type, size); 10592ffd87d3SSergey Temerkhanov if (!*section) 10602ffd87d3SSergey Temerkhanov goto ice_pkg_buf_alloc_single_section_err; 10612ffd87d3SSergey Temerkhanov 10622ffd87d3SSergey Temerkhanov return buf; 10632ffd87d3SSergey Temerkhanov 10642ffd87d3SSergey Temerkhanov ice_pkg_buf_alloc_single_section_err: 10652ffd87d3SSergey Temerkhanov ice_pkg_buf_free(hw, buf); 10662ffd87d3SSergey Temerkhanov return NULL; 10672ffd87d3SSergey Temerkhanov } 10682ffd87d3SSergey Temerkhanov 10692ffd87d3SSergey Temerkhanov /** 10702ffd87d3SSergey Temerkhanov * ice_pkg_buf_get_active_sections 10712ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 10722ffd87d3SSergey Temerkhanov * 10732ffd87d3SSergey Temerkhanov * Returns the number of active sections. Before using the package buffer 10742ffd87d3SSergey Temerkhanov * in an update package command, the caller should make sure that there is at 10752ffd87d3SSergey Temerkhanov * least one active section - otherwise, the buffer is not legal and should 10762ffd87d3SSergey Temerkhanov * not be used. 10772ffd87d3SSergey Temerkhanov * Note: all package contents must be in Little Endian form. 10782ffd87d3SSergey Temerkhanov */ 10792ffd87d3SSergey Temerkhanov u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld) 10802ffd87d3SSergey Temerkhanov { 10812ffd87d3SSergey Temerkhanov struct ice_buf_hdr *buf; 10822ffd87d3SSergey Temerkhanov 10832ffd87d3SSergey Temerkhanov if (!bld) 10842ffd87d3SSergey Temerkhanov return 0; 10852ffd87d3SSergey Temerkhanov 10862ffd87d3SSergey Temerkhanov buf = (struct ice_buf_hdr *)&bld->buf; 10872ffd87d3SSergey Temerkhanov return le16_to_cpu(buf->section_count); 10882ffd87d3SSergey Temerkhanov } 10892ffd87d3SSergey Temerkhanov 10902ffd87d3SSergey Temerkhanov /** 10912ffd87d3SSergey Temerkhanov * ice_pkg_buf 10922ffd87d3SSergey Temerkhanov * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) 10932ffd87d3SSergey Temerkhanov * 10942ffd87d3SSergey Temerkhanov * Return a pointer to the buffer's header 10952ffd87d3SSergey Temerkhanov */ 10962ffd87d3SSergey Temerkhanov struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld) 10972ffd87d3SSergey Temerkhanov { 10982ffd87d3SSergey Temerkhanov if (!bld) 10992ffd87d3SSergey Temerkhanov return NULL; 11002ffd87d3SSergey Temerkhanov 11012ffd87d3SSergey Temerkhanov return &bld->buf; 11022ffd87d3SSergey Temerkhanov } 11032ffd87d3SSergey Temerkhanov 11042ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_map_aq_err_to_ddp_state(enum ice_aq_err aq_err) 11052ffd87d3SSergey Temerkhanov { 11062ffd87d3SSergey Temerkhanov switch (aq_err) { 11072ffd87d3SSergey Temerkhanov case ICE_AQ_RC_ENOSEC: 11082ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADSIG: 11092ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_SIGNATURE_INVALID; 11102ffd87d3SSergey Temerkhanov case ICE_AQ_RC_ESVN: 11112ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_FILE_REVISION_TOO_LOW; 11122ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADMAN: 11132ffd87d3SSergey Temerkhanov case ICE_AQ_RC_EBADBUF: 11142ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_LOAD_ERROR; 11152ffd87d3SSergey Temerkhanov default: 11162ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 11172ffd87d3SSergey Temerkhanov } 11182ffd87d3SSergey Temerkhanov } 11192ffd87d3SSergey Temerkhanov 11202ffd87d3SSergey Temerkhanov /** 11212ffd87d3SSergey Temerkhanov * ice_acquire_global_cfg_lock 11222ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 11232ffd87d3SSergey Temerkhanov * @access: access type (read or write) 11242ffd87d3SSergey Temerkhanov * 11252ffd87d3SSergey Temerkhanov * This function will request ownership of the global config lock for reading 11262ffd87d3SSergey Temerkhanov * or writing of the package. When attempting to obtain write access, the 11272ffd87d3SSergey Temerkhanov * caller must check for the following two return values: 11282ffd87d3SSergey Temerkhanov * 11292ffd87d3SSergey Temerkhanov * 0 - Means the caller has acquired the global config lock 11302ffd87d3SSergey Temerkhanov * and can perform writing of the package. 11312ffd87d3SSergey Temerkhanov * -EALREADY - Indicates another driver has already written the 11322ffd87d3SSergey Temerkhanov * package or has found that no update was necessary; in 11332ffd87d3SSergey Temerkhanov * this case, the caller can just skip performing any 11342ffd87d3SSergey Temerkhanov * update of the package. 11352ffd87d3SSergey Temerkhanov */ 11362ffd87d3SSergey Temerkhanov static int ice_acquire_global_cfg_lock(struct ice_hw *hw, 11372ffd87d3SSergey Temerkhanov enum ice_aq_res_access_type access) 11382ffd87d3SSergey Temerkhanov { 11392ffd87d3SSergey Temerkhanov int status; 11402ffd87d3SSergey Temerkhanov 11412ffd87d3SSergey Temerkhanov status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, access, 11422ffd87d3SSergey Temerkhanov ICE_GLOBAL_CFG_LOCK_TIMEOUT); 11432ffd87d3SSergey Temerkhanov 11442ffd87d3SSergey Temerkhanov if (!status) 11452ffd87d3SSergey Temerkhanov mutex_lock(&ice_global_cfg_lock_sw); 11462ffd87d3SSergey Temerkhanov else if (status == -EALREADY) 11472ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, 11482ffd87d3SSergey Temerkhanov "Global config lock: No work to do\n"); 11492ffd87d3SSergey Temerkhanov 11502ffd87d3SSergey Temerkhanov return status; 11512ffd87d3SSergey Temerkhanov } 11522ffd87d3SSergey Temerkhanov 11532ffd87d3SSergey Temerkhanov /** 11542ffd87d3SSergey Temerkhanov * ice_release_global_cfg_lock 11552ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 11562ffd87d3SSergey Temerkhanov * 11572ffd87d3SSergey Temerkhanov * This function will release the global config lock. 11582ffd87d3SSergey Temerkhanov */ 11592ffd87d3SSergey Temerkhanov static void ice_release_global_cfg_lock(struct ice_hw *hw) 11602ffd87d3SSergey Temerkhanov { 11612ffd87d3SSergey Temerkhanov mutex_unlock(&ice_global_cfg_lock_sw); 11622ffd87d3SSergey Temerkhanov ice_release_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID); 11632ffd87d3SSergey Temerkhanov } 11642ffd87d3SSergey Temerkhanov 11652ffd87d3SSergey Temerkhanov /** 1166708b352fSJan Sokolowski * ice_aq_download_pkg 1167708b352fSJan Sokolowski * @hw: pointer to the hardware structure 1168708b352fSJan Sokolowski * @pkg_buf: the package buffer to transfer 1169708b352fSJan Sokolowski * @buf_size: the size of the package buffer 1170708b352fSJan Sokolowski * @last_buf: last buffer indicator 1171708b352fSJan Sokolowski * @error_offset: returns error offset 1172708b352fSJan Sokolowski * @error_info: returns error information 1173708b352fSJan Sokolowski * @cd: pointer to command details structure or NULL 1174708b352fSJan Sokolowski * 1175708b352fSJan Sokolowski * Download Package (0x0C40) 1176708b352fSJan Sokolowski */ 1177708b352fSJan Sokolowski static int 1178708b352fSJan Sokolowski ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 1179708b352fSJan Sokolowski u16 buf_size, bool last_buf, u32 *error_offset, 1180708b352fSJan Sokolowski u32 *error_info, struct ice_sq_cd *cd) 1181708b352fSJan Sokolowski { 1182708b352fSJan Sokolowski struct ice_aqc_download_pkg *cmd; 1183708b352fSJan Sokolowski struct ice_aq_desc desc; 1184708b352fSJan Sokolowski int status; 1185708b352fSJan Sokolowski 1186708b352fSJan Sokolowski if (error_offset) 1187708b352fSJan Sokolowski *error_offset = 0; 1188708b352fSJan Sokolowski if (error_info) 1189708b352fSJan Sokolowski *error_info = 0; 1190708b352fSJan Sokolowski 1191708b352fSJan Sokolowski cmd = &desc.params.download_pkg; 1192708b352fSJan Sokolowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg); 1193708b352fSJan Sokolowski desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 1194708b352fSJan Sokolowski 1195708b352fSJan Sokolowski if (last_buf) 1196708b352fSJan Sokolowski cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF; 1197708b352fSJan Sokolowski 1198708b352fSJan Sokolowski status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd); 1199708b352fSJan Sokolowski if (status == -EIO) { 1200708b352fSJan Sokolowski /* Read error from buffer only when the FW returned an error */ 1201708b352fSJan Sokolowski struct ice_aqc_download_pkg_resp *resp; 1202708b352fSJan Sokolowski 1203708b352fSJan Sokolowski resp = (struct ice_aqc_download_pkg_resp *)pkg_buf; 1204708b352fSJan Sokolowski if (error_offset) 1205708b352fSJan Sokolowski *error_offset = le32_to_cpu(resp->error_offset); 1206708b352fSJan Sokolowski if (error_info) 1207708b352fSJan Sokolowski *error_info = le32_to_cpu(resp->error_info); 1208708b352fSJan Sokolowski } 1209708b352fSJan Sokolowski 1210708b352fSJan Sokolowski return status; 1211708b352fSJan Sokolowski } 1212708b352fSJan Sokolowski 1213708b352fSJan Sokolowski /** 12143cbdb034SDan Nowlin * ice_get_pkg_seg_by_idx 12153cbdb034SDan Nowlin * @pkg_hdr: pointer to the package header to be searched 12163cbdb034SDan Nowlin * @idx: index of segment 12173cbdb034SDan Nowlin */ 12183cbdb034SDan Nowlin static struct ice_generic_seg_hdr * 12193cbdb034SDan Nowlin ice_get_pkg_seg_by_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx) 12203cbdb034SDan Nowlin { 12213cbdb034SDan Nowlin if (idx < le32_to_cpu(pkg_hdr->seg_count)) 12223cbdb034SDan Nowlin return (struct ice_generic_seg_hdr *) 12233cbdb034SDan Nowlin ((u8 *)pkg_hdr + 12243cbdb034SDan Nowlin le32_to_cpu(pkg_hdr->seg_offset[idx])); 12253cbdb034SDan Nowlin 12263cbdb034SDan Nowlin return NULL; 12273cbdb034SDan Nowlin } 12283cbdb034SDan Nowlin 12293cbdb034SDan Nowlin /** 12303cbdb034SDan Nowlin * ice_is_signing_seg_at_idx - determine if segment is a signing segment 12313cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 12323cbdb034SDan Nowlin * @idx: segment index 12333cbdb034SDan Nowlin */ 12343cbdb034SDan Nowlin static bool ice_is_signing_seg_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx) 12353cbdb034SDan Nowlin { 12363cbdb034SDan Nowlin struct ice_generic_seg_hdr *seg; 12373cbdb034SDan Nowlin 12383cbdb034SDan Nowlin seg = ice_get_pkg_seg_by_idx(pkg_hdr, idx); 12393cbdb034SDan Nowlin if (!seg) 12403cbdb034SDan Nowlin return false; 12413cbdb034SDan Nowlin 12423cbdb034SDan Nowlin return le32_to_cpu(seg->seg_type) == SEGMENT_TYPE_SIGNING; 12433cbdb034SDan Nowlin } 12443cbdb034SDan Nowlin 12453cbdb034SDan Nowlin /** 12463cbdb034SDan Nowlin * ice_is_signing_seg_type_at_idx 12473cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 12483cbdb034SDan Nowlin * @idx: segment index 12493cbdb034SDan Nowlin * @seg_id: segment id that is expected 12503cbdb034SDan Nowlin * @sign_type: signing type 12513cbdb034SDan Nowlin * 12523cbdb034SDan Nowlin * Determine if a segment is a signing segment of the correct type 12533cbdb034SDan Nowlin */ 12543cbdb034SDan Nowlin static bool 12553cbdb034SDan Nowlin ice_is_signing_seg_type_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx, 12563cbdb034SDan Nowlin u32 seg_id, u32 sign_type) 12573cbdb034SDan Nowlin { 12583cbdb034SDan Nowlin struct ice_sign_seg *seg; 12593cbdb034SDan Nowlin 12603cbdb034SDan Nowlin if (!ice_is_signing_seg_at_idx(pkg_hdr, idx)) 12613cbdb034SDan Nowlin return false; 12623cbdb034SDan Nowlin 12633cbdb034SDan Nowlin seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); 12643cbdb034SDan Nowlin 12653cbdb034SDan Nowlin if (seg && le32_to_cpu(seg->seg_id) == seg_id && 12663cbdb034SDan Nowlin le32_to_cpu(seg->sign_type) == sign_type) 12673cbdb034SDan Nowlin return true; 12683cbdb034SDan Nowlin 12693cbdb034SDan Nowlin return false; 12703cbdb034SDan Nowlin } 12713cbdb034SDan Nowlin 12723cbdb034SDan Nowlin /** 12733cbdb034SDan Nowlin * ice_is_buffer_metadata - determine if package buffer is a metadata buffer 12743cbdb034SDan Nowlin * @buf: pointer to buffer header 12753cbdb034SDan Nowlin */ 12763cbdb034SDan Nowlin static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf) 12773cbdb034SDan Nowlin { 12783cbdb034SDan Nowlin if (le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF) 12793cbdb034SDan Nowlin return true; 12803cbdb034SDan Nowlin 12813cbdb034SDan Nowlin return false; 12823cbdb034SDan Nowlin } 12833cbdb034SDan Nowlin 12843cbdb034SDan Nowlin /** 12853cbdb034SDan Nowlin * ice_is_last_download_buffer 12863cbdb034SDan Nowlin * @buf: pointer to current buffer header 12873cbdb034SDan Nowlin * @idx: index of the buffer in the current sequence 12883cbdb034SDan Nowlin * @count: the buffer count in the current sequence 12893cbdb034SDan Nowlin * 12903cbdb034SDan Nowlin * Note: this routine should only be called if the buffer is not the last buffer 12913cbdb034SDan Nowlin */ 12923cbdb034SDan Nowlin static bool 12933cbdb034SDan Nowlin ice_is_last_download_buffer(struct ice_buf_hdr *buf, u32 idx, u32 count) 12943cbdb034SDan Nowlin { 12953cbdb034SDan Nowlin struct ice_buf *next_buf; 12963cbdb034SDan Nowlin 12973cbdb034SDan Nowlin if ((idx + 1) == count) 12983cbdb034SDan Nowlin return true; 12993cbdb034SDan Nowlin 13003cbdb034SDan Nowlin /* A set metadata flag in the next buffer will signal that the current 13013cbdb034SDan Nowlin * buffer will be the last buffer downloaded 13023cbdb034SDan Nowlin */ 13033cbdb034SDan Nowlin next_buf = ((struct ice_buf *)buf) + 1; 13043cbdb034SDan Nowlin 13053cbdb034SDan Nowlin return ice_is_buffer_metadata((struct ice_buf_hdr *)next_buf); 13063cbdb034SDan Nowlin } 13073cbdb034SDan Nowlin 13083cbdb034SDan Nowlin /** 13093cbdb034SDan Nowlin * ice_dwnld_cfg_bufs_no_lock 13102ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 13112ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers 13123cbdb034SDan Nowlin * @start: buffer index of first buffer to download 13133cbdb034SDan Nowlin * @count: the number of buffers to download 13143cbdb034SDan Nowlin * @indicate_last: if true, then set last buffer flag on last buffer download 13152ffd87d3SSergey Temerkhanov * 13163cbdb034SDan Nowlin * Downloads package configuration buffers to the firmware. Metadata buffers 13173cbdb034SDan Nowlin * are skipped, and the first metadata buffer found indicates that the rest 13183cbdb034SDan Nowlin * of the buffers are all metadata buffers. 13192ffd87d3SSergey Temerkhanov */ 13203cbdb034SDan Nowlin static enum ice_ddp_state 13213cbdb034SDan Nowlin ice_dwnld_cfg_bufs_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 start, 13223cbdb034SDan Nowlin u32 count, bool indicate_last) 13232ffd87d3SSergey Temerkhanov { 13242ffd87d3SSergey Temerkhanov enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS; 13252ffd87d3SSergey Temerkhanov struct ice_buf_hdr *bh; 13262ffd87d3SSergey Temerkhanov enum ice_aq_err err; 13272ffd87d3SSergey Temerkhanov u32 offset, info, i; 13282ffd87d3SSergey Temerkhanov 13292ffd87d3SSergey Temerkhanov if (!bufs || !count) 13302ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 13312ffd87d3SSergey Temerkhanov 13322ffd87d3SSergey Temerkhanov /* If the first buffer's first section has its metadata bit set 13332ffd87d3SSergey Temerkhanov * then there are no buffers to be downloaded, and the operation is 13342ffd87d3SSergey Temerkhanov * considered a success. 13352ffd87d3SSergey Temerkhanov */ 13363cbdb034SDan Nowlin bh = (struct ice_buf_hdr *)(bufs + start); 13372ffd87d3SSergey Temerkhanov if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF) 13382ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 13392ffd87d3SSergey Temerkhanov 13402ffd87d3SSergey Temerkhanov for (i = 0; i < count; i++) { 13413cbdb034SDan Nowlin bool last = false; 1342a27f6ac9SWojciech Drewek int try_cnt = 0; 13433cbdb034SDan Nowlin int status; 13442ffd87d3SSergey Temerkhanov 13453cbdb034SDan Nowlin bh = (struct ice_buf_hdr *)(bufs + start + i); 13462ffd87d3SSergey Temerkhanov 13473cbdb034SDan Nowlin if (indicate_last) 13483cbdb034SDan Nowlin last = ice_is_last_download_buffer(bh, i, count); 13492ffd87d3SSergey Temerkhanov 1350a27f6ac9SWojciech Drewek while (1) { 1351a27f6ac9SWojciech Drewek status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE, 1352a27f6ac9SWojciech Drewek last, &offset, &info, 1353a27f6ac9SWojciech Drewek NULL); 1354a27f6ac9SWojciech Drewek if (hw->adminq.sq_last_status != ICE_AQ_RC_ENOSEC && 1355a27f6ac9SWojciech Drewek hw->adminq.sq_last_status != ICE_AQ_RC_EBADSIG) 1356a27f6ac9SWojciech Drewek break; 1357a27f6ac9SWojciech Drewek 1358a27f6ac9SWojciech Drewek try_cnt++; 1359a27f6ac9SWojciech Drewek 1360a27f6ac9SWojciech Drewek if (try_cnt == 5) 1361a27f6ac9SWojciech Drewek break; 1362a27f6ac9SWojciech Drewek 1363a27f6ac9SWojciech Drewek msleep(20); 1364a27f6ac9SWojciech Drewek } 1365a27f6ac9SWojciech Drewek 1366a27f6ac9SWojciech Drewek if (try_cnt) 1367a27f6ac9SWojciech Drewek dev_dbg(ice_hw_to_dev(hw), 1368a27f6ac9SWojciech Drewek "ice_aq_download_pkg number of retries: %d\n", 1369a27f6ac9SWojciech Drewek try_cnt); 13702ffd87d3SSergey Temerkhanov 13712ffd87d3SSergey Temerkhanov /* Save AQ status from download package */ 13722ffd87d3SSergey Temerkhanov if (status) { 13733cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n", 13742ffd87d3SSergey Temerkhanov status, offset, info); 13752ffd87d3SSergey Temerkhanov err = hw->adminq.sq_last_status; 13762ffd87d3SSergey Temerkhanov state = ice_map_aq_err_to_ddp_state(err); 13772ffd87d3SSergey Temerkhanov break; 13782ffd87d3SSergey Temerkhanov } 13792ffd87d3SSergey Temerkhanov 13802ffd87d3SSergey Temerkhanov if (last) 13812ffd87d3SSergey Temerkhanov break; 13822ffd87d3SSergey Temerkhanov } 13832ffd87d3SSergey Temerkhanov 13843cbdb034SDan Nowlin return state; 13852ffd87d3SSergey Temerkhanov } 13862ffd87d3SSergey Temerkhanov 13873cbdb034SDan Nowlin /** 13883cbdb034SDan Nowlin * ice_download_pkg_sig_seg - download a signature segment 13893cbdb034SDan Nowlin * @hw: pointer to the hardware structure 13903cbdb034SDan Nowlin * @seg: pointer to signature segment 13913cbdb034SDan Nowlin */ 13923cbdb034SDan Nowlin static enum ice_ddp_state 13933cbdb034SDan Nowlin ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg) 13943cbdb034SDan Nowlin { 13953cbdb034SDan Nowlin return ice_dwnld_cfg_bufs_no_lock(hw, seg->buf_tbl.buf_array, 0, 13963cbdb034SDan Nowlin le32_to_cpu(seg->buf_tbl.buf_count), 13973cbdb034SDan Nowlin false); 13983cbdb034SDan Nowlin } 13993cbdb034SDan Nowlin 14003cbdb034SDan Nowlin /** 14013cbdb034SDan Nowlin * ice_download_pkg_config_seg - download a config segment 14023cbdb034SDan Nowlin * @hw: pointer to the hardware structure 14033cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 14043cbdb034SDan Nowlin * @idx: segment index 14053cbdb034SDan Nowlin * @start: starting buffer 14063cbdb034SDan Nowlin * @count: buffer count 14073cbdb034SDan Nowlin * 14083cbdb034SDan Nowlin * Note: idx must reference a ICE segment 14093cbdb034SDan Nowlin */ 14103cbdb034SDan Nowlin static enum ice_ddp_state 14113cbdb034SDan Nowlin ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, 14123cbdb034SDan Nowlin u32 idx, u32 start, u32 count) 14133cbdb034SDan Nowlin { 14143cbdb034SDan Nowlin struct ice_buf_table *bufs; 14153cbdb034SDan Nowlin struct ice_seg *seg; 14163cbdb034SDan Nowlin u32 buf_count; 14173cbdb034SDan Nowlin 14183cbdb034SDan Nowlin seg = (struct ice_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); 14193cbdb034SDan Nowlin if (!seg) 14203cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 14213cbdb034SDan Nowlin 14223cbdb034SDan Nowlin bufs = ice_find_buf_table(seg); 14233cbdb034SDan Nowlin buf_count = le32_to_cpu(bufs->buf_count); 14243cbdb034SDan Nowlin 14253cbdb034SDan Nowlin if (start >= buf_count || start + count > buf_count) 14263cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 14273cbdb034SDan Nowlin 14283cbdb034SDan Nowlin return ice_dwnld_cfg_bufs_no_lock(hw, bufs->buf_array, start, count, 14293cbdb034SDan Nowlin true); 14303cbdb034SDan Nowlin } 14313cbdb034SDan Nowlin 14323cbdb034SDan Nowlin /** 14333cbdb034SDan Nowlin * ice_dwnld_sign_and_cfg_segs - download a signing segment and config segment 14343cbdb034SDan Nowlin * @hw: pointer to the hardware structure 14353cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 14363cbdb034SDan Nowlin * @idx: segment index (must be a signature segment) 14373cbdb034SDan Nowlin * 14383cbdb034SDan Nowlin * Note: idx must reference a signature segment 14393cbdb034SDan Nowlin */ 14403cbdb034SDan Nowlin static enum ice_ddp_state 14413cbdb034SDan Nowlin ice_dwnld_sign_and_cfg_segs(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, 14423cbdb034SDan Nowlin u32 idx) 14433cbdb034SDan Nowlin { 14443cbdb034SDan Nowlin enum ice_ddp_state state; 14453cbdb034SDan Nowlin struct ice_sign_seg *seg; 14463cbdb034SDan Nowlin u32 conf_idx; 14473cbdb034SDan Nowlin u32 start; 14483cbdb034SDan Nowlin u32 count; 14493cbdb034SDan Nowlin 14503cbdb034SDan Nowlin seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); 14513cbdb034SDan Nowlin if (!seg) { 14523cbdb034SDan Nowlin state = ICE_DDP_PKG_ERR; 14533cbdb034SDan Nowlin goto exit; 14543cbdb034SDan Nowlin } 14553cbdb034SDan Nowlin 14566d51d44eSDan Nowlin count = le32_to_cpu(seg->signed_buf_count); 14576d51d44eSDan Nowlin state = ice_download_pkg_sig_seg(hw, seg); 14586d51d44eSDan Nowlin if (state || !count) 14596d51d44eSDan Nowlin goto exit; 14606d51d44eSDan Nowlin 14613cbdb034SDan Nowlin conf_idx = le32_to_cpu(seg->signed_seg_idx); 14623cbdb034SDan Nowlin start = le32_to_cpu(seg->signed_buf_start); 14633cbdb034SDan Nowlin 14643cbdb034SDan Nowlin state = ice_download_pkg_config_seg(hw, pkg_hdr, conf_idx, start, 14653cbdb034SDan Nowlin count); 14663cbdb034SDan Nowlin 14673cbdb034SDan Nowlin exit: 14683cbdb034SDan Nowlin return state; 14693cbdb034SDan Nowlin } 14703cbdb034SDan Nowlin 14713cbdb034SDan Nowlin /** 14723cbdb034SDan Nowlin * ice_match_signing_seg - determine if a matching signing segment exists 14733cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 14743cbdb034SDan Nowlin * @seg_id: segment id that is expected 14753cbdb034SDan Nowlin * @sign_type: signing type 14763cbdb034SDan Nowlin */ 14773cbdb034SDan Nowlin static bool 14783cbdb034SDan Nowlin ice_match_signing_seg(struct ice_pkg_hdr *pkg_hdr, u32 seg_id, u32 sign_type) 14793cbdb034SDan Nowlin { 14803cbdb034SDan Nowlin u32 i; 14813cbdb034SDan Nowlin 14823cbdb034SDan Nowlin for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { 14833cbdb034SDan Nowlin if (ice_is_signing_seg_type_at_idx(pkg_hdr, i, seg_id, 14843cbdb034SDan Nowlin sign_type)) 14853cbdb034SDan Nowlin return true; 14863cbdb034SDan Nowlin } 14873cbdb034SDan Nowlin 14883cbdb034SDan Nowlin return false; 14893cbdb034SDan Nowlin } 14903cbdb034SDan Nowlin 14913cbdb034SDan Nowlin /** 14923cbdb034SDan Nowlin * ice_post_dwnld_pkg_actions - perform post download package actions 14933cbdb034SDan Nowlin * @hw: pointer to the hardware structure 14943cbdb034SDan Nowlin */ 14953cbdb034SDan Nowlin static enum ice_ddp_state 14963cbdb034SDan Nowlin ice_post_dwnld_pkg_actions(struct ice_hw *hw) 14973cbdb034SDan Nowlin { 14983cbdb034SDan Nowlin int status; 14993cbdb034SDan Nowlin 15003cbdb034SDan Nowlin status = ice_set_vlan_mode(hw); 15013cbdb034SDan Nowlin if (status) { 15023cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Failed to set VLAN mode: err %d\n", 15033cbdb034SDan Nowlin status); 15043cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 15053cbdb034SDan Nowlin } 15063cbdb034SDan Nowlin 15073cbdb034SDan Nowlin return ICE_DDP_PKG_SUCCESS; 15083cbdb034SDan Nowlin } 15093cbdb034SDan Nowlin 15103cbdb034SDan Nowlin /** 1511a778616eSDan Nowlin * ice_download_pkg_with_sig_seg 15123cbdb034SDan Nowlin * @hw: pointer to the hardware structure 15133cbdb034SDan Nowlin * @pkg_hdr: pointer to package header 15143cbdb034SDan Nowlin * 15153cbdb034SDan Nowlin * Handles the download of a complete package. 15163cbdb034SDan Nowlin */ 15173cbdb034SDan Nowlin static enum ice_ddp_state 1518a778616eSDan Nowlin ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) 15193cbdb034SDan Nowlin { 15203cbdb034SDan Nowlin enum ice_aq_err aq_err = hw->adminq.sq_last_status; 15213cbdb034SDan Nowlin enum ice_ddp_state state = ICE_DDP_PKG_ERR; 15223cbdb034SDan Nowlin int status; 15233cbdb034SDan Nowlin u32 i; 15243cbdb034SDan Nowlin 15253cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_INIT, "Segment ID %d\n", hw->pkg_seg_id); 15263cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_INIT, "Signature type %d\n", hw->pkg_sign_type); 15273cbdb034SDan Nowlin 15283cbdb034SDan Nowlin status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE); 15293cbdb034SDan Nowlin if (status) { 15303cbdb034SDan Nowlin if (status == -EALREADY) 15313cbdb034SDan Nowlin state = ICE_DDP_PKG_ALREADY_LOADED; 15323cbdb034SDan Nowlin else 15333cbdb034SDan Nowlin state = ice_map_aq_err_to_ddp_state(aq_err); 15343cbdb034SDan Nowlin return state; 15353cbdb034SDan Nowlin } 15363cbdb034SDan Nowlin 15373cbdb034SDan Nowlin for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { 15383cbdb034SDan Nowlin if (!ice_is_signing_seg_type_at_idx(pkg_hdr, i, hw->pkg_seg_id, 15393cbdb034SDan Nowlin hw->pkg_sign_type)) 15403cbdb034SDan Nowlin continue; 15413cbdb034SDan Nowlin 15423cbdb034SDan Nowlin state = ice_dwnld_sign_and_cfg_segs(hw, pkg_hdr, i); 15433cbdb034SDan Nowlin if (state) 15443cbdb034SDan Nowlin break; 15453cbdb034SDan Nowlin } 15463cbdb034SDan Nowlin 15473cbdb034SDan Nowlin if (!state) 15483cbdb034SDan Nowlin state = ice_post_dwnld_pkg_actions(hw); 15493cbdb034SDan Nowlin 15502ffd87d3SSergey Temerkhanov ice_release_global_cfg_lock(hw); 1551a778616eSDan Nowlin 1552a778616eSDan Nowlin return state; 1553a778616eSDan Nowlin } 1554a778616eSDan Nowlin 1555a778616eSDan Nowlin /** 1556a778616eSDan Nowlin * ice_dwnld_cfg_bufs 1557a778616eSDan Nowlin * @hw: pointer to the hardware structure 1558a778616eSDan Nowlin * @bufs: pointer to an array of buffers 1559a778616eSDan Nowlin * @count: the number of buffers in the array 1560a778616eSDan Nowlin * 1561a778616eSDan Nowlin * Obtains global config lock and downloads the package configuration buffers 1562a778616eSDan Nowlin * to the firmware. 1563a778616eSDan Nowlin */ 1564a778616eSDan Nowlin static enum ice_ddp_state 1565a778616eSDan Nowlin ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count) 1566a778616eSDan Nowlin { 1567a778616eSDan Nowlin enum ice_ddp_state state; 1568a778616eSDan Nowlin struct ice_buf_hdr *bh; 1569a778616eSDan Nowlin int status; 1570a778616eSDan Nowlin 1571a778616eSDan Nowlin if (!bufs || !count) 1572a778616eSDan Nowlin return ICE_DDP_PKG_ERR; 1573a778616eSDan Nowlin 1574a778616eSDan Nowlin /* If the first buffer's first section has its metadata bit set 1575a778616eSDan Nowlin * then there are no buffers to be downloaded, and the operation is 1576a778616eSDan Nowlin * considered a success. 1577a778616eSDan Nowlin */ 1578a778616eSDan Nowlin bh = (struct ice_buf_hdr *)bufs; 1579a778616eSDan Nowlin if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF) 1580a778616eSDan Nowlin return ICE_DDP_PKG_SUCCESS; 1581a778616eSDan Nowlin 1582a778616eSDan Nowlin status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE); 1583a778616eSDan Nowlin if (status) { 1584a778616eSDan Nowlin if (status == -EALREADY) 1585a778616eSDan Nowlin return ICE_DDP_PKG_ALREADY_LOADED; 1586a778616eSDan Nowlin return ice_map_aq_err_to_ddp_state(hw->adminq.sq_last_status); 1587a778616eSDan Nowlin } 1588a778616eSDan Nowlin 1589a778616eSDan Nowlin state = ice_dwnld_cfg_bufs_no_lock(hw, bufs, 0, count, true); 1590a778616eSDan Nowlin if (!state) 1591a778616eSDan Nowlin state = ice_post_dwnld_pkg_actions(hw); 1592a778616eSDan Nowlin 1593a778616eSDan Nowlin ice_release_global_cfg_lock(hw); 1594a778616eSDan Nowlin 1595a778616eSDan Nowlin return state; 1596a778616eSDan Nowlin } 1597a778616eSDan Nowlin 1598a778616eSDan Nowlin /** 1599a778616eSDan Nowlin * ice_download_pkg_without_sig_seg 1600a778616eSDan Nowlin * @hw: pointer to the hardware structure 1601a778616eSDan Nowlin * @ice_seg: pointer to the segment of the package to be downloaded 1602a778616eSDan Nowlin * 1603a778616eSDan Nowlin * Handles the download of a complete package without signature segment. 1604a778616eSDan Nowlin */ 1605a778616eSDan Nowlin static enum ice_ddp_state 1606a778616eSDan Nowlin ice_download_pkg_without_sig_seg(struct ice_hw *hw, struct ice_seg *ice_seg) 1607a778616eSDan Nowlin { 1608a778616eSDan Nowlin struct ice_buf_table *ice_buf_tbl; 1609a778616eSDan Nowlin 1610a778616eSDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n", 1611a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.major, 1612a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.minor, 1613a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.update, 1614a778616eSDan Nowlin ice_seg->hdr.seg_format_ver.draft); 1615a778616eSDan Nowlin 1616a778616eSDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n", 1617a778616eSDan Nowlin le32_to_cpu(ice_seg->hdr.seg_type), 1618a778616eSDan Nowlin le32_to_cpu(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id); 1619a778616eSDan Nowlin 1620a778616eSDan Nowlin ice_buf_tbl = ice_find_buf_table(ice_seg); 1621a778616eSDan Nowlin 1622a778616eSDan Nowlin ice_debug(hw, ICE_DBG_PKG, "Seg buf count: %d\n", 1623a778616eSDan Nowlin le32_to_cpu(ice_buf_tbl->buf_count)); 1624a778616eSDan Nowlin 1625a778616eSDan Nowlin return ice_dwnld_cfg_bufs(hw, ice_buf_tbl->buf_array, 1626a778616eSDan Nowlin le32_to_cpu(ice_buf_tbl->buf_count)); 1627a778616eSDan Nowlin } 1628a778616eSDan Nowlin 1629a778616eSDan Nowlin /** 1630a778616eSDan Nowlin * ice_download_pkg 1631a778616eSDan Nowlin * @hw: pointer to the hardware structure 1632a778616eSDan Nowlin * @pkg_hdr: pointer to package header 1633a778616eSDan Nowlin * @ice_seg: pointer to the segment of the package to be downloaded 1634a778616eSDan Nowlin * 1635a778616eSDan Nowlin * Handles the download of a complete package. 1636a778616eSDan Nowlin */ 1637a778616eSDan Nowlin static enum ice_ddp_state 1638a778616eSDan Nowlin ice_download_pkg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, 1639a778616eSDan Nowlin struct ice_seg *ice_seg) 1640a778616eSDan Nowlin { 1641a778616eSDan Nowlin enum ice_ddp_state state; 1642a778616eSDan Nowlin 1643a778616eSDan Nowlin if (hw->pkg_has_signing_seg) 1644a778616eSDan Nowlin state = ice_download_pkg_with_sig_seg(hw, pkg_hdr); 1645a778616eSDan Nowlin else 1646a778616eSDan Nowlin state = ice_download_pkg_without_sig_seg(hw, ice_seg); 1647a778616eSDan Nowlin 16483cbdb034SDan Nowlin ice_post_pkg_dwnld_vlan_mode_cfg(hw); 16492ffd87d3SSergey Temerkhanov 16502ffd87d3SSergey Temerkhanov return state; 16512ffd87d3SSergey Temerkhanov } 16522ffd87d3SSergey Temerkhanov 16532ffd87d3SSergey Temerkhanov /** 16542ffd87d3SSergey Temerkhanov * ice_aq_get_pkg_info_list 16552ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 16562ffd87d3SSergey Temerkhanov * @pkg_info: the buffer which will receive the information list 16572ffd87d3SSergey Temerkhanov * @buf_size: the size of the pkg_info information buffer 16582ffd87d3SSergey Temerkhanov * @cd: pointer to command details structure or NULL 16592ffd87d3SSergey Temerkhanov * 16602ffd87d3SSergey Temerkhanov * Get Package Info List (0x0C43) 16612ffd87d3SSergey Temerkhanov */ 16622ffd87d3SSergey Temerkhanov static int ice_aq_get_pkg_info_list(struct ice_hw *hw, 16632ffd87d3SSergey Temerkhanov struct ice_aqc_get_pkg_info_resp *pkg_info, 16642ffd87d3SSergey Temerkhanov u16 buf_size, struct ice_sq_cd *cd) 16652ffd87d3SSergey Temerkhanov { 16662ffd87d3SSergey Temerkhanov struct ice_aq_desc desc; 16672ffd87d3SSergey Temerkhanov 16682ffd87d3SSergey Temerkhanov ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list); 16692ffd87d3SSergey Temerkhanov 16702ffd87d3SSergey Temerkhanov return ice_aq_send_cmd(hw, &desc, pkg_info, buf_size, cd); 16712ffd87d3SSergey Temerkhanov } 16722ffd87d3SSergey Temerkhanov 16732ffd87d3SSergey Temerkhanov /** 16742ffd87d3SSergey Temerkhanov * ice_aq_update_pkg 16752ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 16762ffd87d3SSergey Temerkhanov * @pkg_buf: the package cmd buffer 16772ffd87d3SSergey Temerkhanov * @buf_size: the size of the package cmd buffer 16782ffd87d3SSergey Temerkhanov * @last_buf: last buffer indicator 16792ffd87d3SSergey Temerkhanov * @error_offset: returns error offset 16802ffd87d3SSergey Temerkhanov * @error_info: returns error information 16812ffd87d3SSergey Temerkhanov * @cd: pointer to command details structure or NULL 16822ffd87d3SSergey Temerkhanov * 16832ffd87d3SSergey Temerkhanov * Update Package (0x0C42) 16842ffd87d3SSergey Temerkhanov */ 16852ffd87d3SSergey Temerkhanov static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 16862ffd87d3SSergey Temerkhanov u16 buf_size, bool last_buf, u32 *error_offset, 16872ffd87d3SSergey Temerkhanov u32 *error_info, struct ice_sq_cd *cd) 16882ffd87d3SSergey Temerkhanov { 16892ffd87d3SSergey Temerkhanov struct ice_aqc_download_pkg *cmd; 16902ffd87d3SSergey Temerkhanov struct ice_aq_desc desc; 16912ffd87d3SSergey Temerkhanov int status; 16922ffd87d3SSergey Temerkhanov 16932ffd87d3SSergey Temerkhanov if (error_offset) 16942ffd87d3SSergey Temerkhanov *error_offset = 0; 16952ffd87d3SSergey Temerkhanov if (error_info) 16962ffd87d3SSergey Temerkhanov *error_info = 0; 16972ffd87d3SSergey Temerkhanov 16982ffd87d3SSergey Temerkhanov cmd = &desc.params.download_pkg; 16992ffd87d3SSergey Temerkhanov ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg); 17002ffd87d3SSergey Temerkhanov desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 17012ffd87d3SSergey Temerkhanov 17022ffd87d3SSergey Temerkhanov if (last_buf) 17032ffd87d3SSergey Temerkhanov cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF; 17042ffd87d3SSergey Temerkhanov 17052ffd87d3SSergey Temerkhanov status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd); 17062ffd87d3SSergey Temerkhanov if (status == -EIO) { 17072ffd87d3SSergey Temerkhanov /* Read error from buffer only when the FW returned an error */ 17082ffd87d3SSergey Temerkhanov struct ice_aqc_download_pkg_resp *resp; 17092ffd87d3SSergey Temerkhanov 17102ffd87d3SSergey Temerkhanov resp = (struct ice_aqc_download_pkg_resp *)pkg_buf; 17112ffd87d3SSergey Temerkhanov if (error_offset) 17122ffd87d3SSergey Temerkhanov *error_offset = le32_to_cpu(resp->error_offset); 17132ffd87d3SSergey Temerkhanov if (error_info) 17142ffd87d3SSergey Temerkhanov *error_info = le32_to_cpu(resp->error_info); 17152ffd87d3SSergey Temerkhanov } 17162ffd87d3SSergey Temerkhanov 17172ffd87d3SSergey Temerkhanov return status; 17182ffd87d3SSergey Temerkhanov } 17192ffd87d3SSergey Temerkhanov 17202ffd87d3SSergey Temerkhanov /** 1721708b352fSJan Sokolowski * ice_aq_upload_section 1722708b352fSJan Sokolowski * @hw: pointer to the hardware structure 1723708b352fSJan Sokolowski * @pkg_buf: the package buffer which will receive the section 1724708b352fSJan Sokolowski * @buf_size: the size of the package buffer 1725708b352fSJan Sokolowski * @cd: pointer to command details structure or NULL 1726708b352fSJan Sokolowski * 1727708b352fSJan Sokolowski * Upload Section (0x0C41) 1728708b352fSJan Sokolowski */ 1729708b352fSJan Sokolowski int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 1730708b352fSJan Sokolowski u16 buf_size, struct ice_sq_cd *cd) 1731708b352fSJan Sokolowski { 1732708b352fSJan Sokolowski struct ice_aq_desc desc; 1733708b352fSJan Sokolowski 1734708b352fSJan Sokolowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section); 1735708b352fSJan Sokolowski desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 1736708b352fSJan Sokolowski 1737708b352fSJan Sokolowski return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd); 1738708b352fSJan Sokolowski } 1739708b352fSJan Sokolowski 1740708b352fSJan Sokolowski /** 17412ffd87d3SSergey Temerkhanov * ice_update_pkg_no_lock 17422ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 17432ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers 17442ffd87d3SSergey Temerkhanov * @count: the number of buffers in the array 17452ffd87d3SSergey Temerkhanov */ 17462ffd87d3SSergey Temerkhanov int ice_update_pkg_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 count) 17472ffd87d3SSergey Temerkhanov { 17482ffd87d3SSergey Temerkhanov int status = 0; 17492ffd87d3SSergey Temerkhanov u32 i; 17502ffd87d3SSergey Temerkhanov 17512ffd87d3SSergey Temerkhanov for (i = 0; i < count; i++) { 17522ffd87d3SSergey Temerkhanov struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i); 17532ffd87d3SSergey Temerkhanov bool last = ((i + 1) == count); 17542ffd87d3SSergey Temerkhanov u32 offset, info; 17552ffd87d3SSergey Temerkhanov 17562ffd87d3SSergey Temerkhanov status = ice_aq_update_pkg(hw, bh, le16_to_cpu(bh->data_end), 17572ffd87d3SSergey Temerkhanov last, &offset, &info, NULL); 17582ffd87d3SSergey Temerkhanov 17592ffd87d3SSergey Temerkhanov if (status) { 17602ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, 17612ffd87d3SSergey Temerkhanov "Update pkg failed: err %d off %d inf %d\n", 17622ffd87d3SSergey Temerkhanov status, offset, info); 17632ffd87d3SSergey Temerkhanov break; 17642ffd87d3SSergey Temerkhanov } 17652ffd87d3SSergey Temerkhanov } 17662ffd87d3SSergey Temerkhanov 17672ffd87d3SSergey Temerkhanov return status; 17682ffd87d3SSergey Temerkhanov } 17692ffd87d3SSergey Temerkhanov 17702ffd87d3SSergey Temerkhanov /** 17712ffd87d3SSergey Temerkhanov * ice_update_pkg 17722ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 17732ffd87d3SSergey Temerkhanov * @bufs: pointer to an array of buffers 17742ffd87d3SSergey Temerkhanov * @count: the number of buffers in the array 17752ffd87d3SSergey Temerkhanov * 17762ffd87d3SSergey Temerkhanov * Obtains change lock and updates package. 17772ffd87d3SSergey Temerkhanov */ 17782ffd87d3SSergey Temerkhanov int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count) 17792ffd87d3SSergey Temerkhanov { 17802ffd87d3SSergey Temerkhanov int status; 17812ffd87d3SSergey Temerkhanov 17822ffd87d3SSergey Temerkhanov status = ice_acquire_change_lock(hw, ICE_RES_WRITE); 17832ffd87d3SSergey Temerkhanov if (status) 17842ffd87d3SSergey Temerkhanov return status; 17852ffd87d3SSergey Temerkhanov 17862ffd87d3SSergey Temerkhanov status = ice_update_pkg_no_lock(hw, bufs, count); 17872ffd87d3SSergey Temerkhanov 17882ffd87d3SSergey Temerkhanov ice_release_change_lock(hw); 17892ffd87d3SSergey Temerkhanov 17902ffd87d3SSergey Temerkhanov return status; 17912ffd87d3SSergey Temerkhanov } 17922ffd87d3SSergey Temerkhanov 17932ffd87d3SSergey Temerkhanov /** 17942ffd87d3SSergey Temerkhanov * ice_find_seg_in_pkg 17952ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 17962ffd87d3SSergey Temerkhanov * @seg_type: the segment type to search for (i.e., SEGMENT_TYPE_CPK) 17972ffd87d3SSergey Temerkhanov * @pkg_hdr: pointer to the package header to be searched 17982ffd87d3SSergey Temerkhanov * 17992ffd87d3SSergey Temerkhanov * This function searches a package file for a particular segment type. On 18002ffd87d3SSergey Temerkhanov * success it returns a pointer to the segment header, otherwise it will 18012ffd87d3SSergey Temerkhanov * return NULL. 18022ffd87d3SSergey Temerkhanov */ 1803708b352fSJan Sokolowski static struct ice_generic_seg_hdr * 1804708b352fSJan Sokolowski ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type, 18052ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg_hdr) 18062ffd87d3SSergey Temerkhanov { 18072ffd87d3SSergey Temerkhanov u32 i; 18082ffd87d3SSergey Temerkhanov 18092ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n", 18102ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor, 18112ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.update, 18122ffd87d3SSergey Temerkhanov pkg_hdr->pkg_format_ver.draft); 18132ffd87d3SSergey Temerkhanov 18142ffd87d3SSergey Temerkhanov /* Search all package segments for the requested segment type */ 18152ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { 18162ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg; 18172ffd87d3SSergey Temerkhanov 18182ffd87d3SSergey Temerkhanov seg = (struct ice_generic_seg_hdr 18192ffd87d3SSergey Temerkhanov *)((u8 *)pkg_hdr + 18202ffd87d3SSergey Temerkhanov le32_to_cpu(pkg_hdr->seg_offset[i])); 18212ffd87d3SSergey Temerkhanov 18222ffd87d3SSergey Temerkhanov if (le32_to_cpu(seg->seg_type) == seg_type) 18232ffd87d3SSergey Temerkhanov return seg; 18242ffd87d3SSergey Temerkhanov } 18252ffd87d3SSergey Temerkhanov 18262ffd87d3SSergey Temerkhanov return NULL; 18272ffd87d3SSergey Temerkhanov } 18282ffd87d3SSergey Temerkhanov 18292ffd87d3SSergey Temerkhanov /** 18303cbdb034SDan Nowlin * ice_has_signing_seg - determine if package has a signing segment 18313cbdb034SDan Nowlin * @hw: pointer to the hardware structure 18323cbdb034SDan Nowlin * @pkg_hdr: pointer to the driver's package hdr 18333cbdb034SDan Nowlin */ 18343cbdb034SDan Nowlin static bool ice_has_signing_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) 18353cbdb034SDan Nowlin { 18363cbdb034SDan Nowlin struct ice_generic_seg_hdr *seg_hdr; 18373cbdb034SDan Nowlin 18383cbdb034SDan Nowlin seg_hdr = (struct ice_generic_seg_hdr *) 18393cbdb034SDan Nowlin ice_find_seg_in_pkg(hw, SEGMENT_TYPE_SIGNING, pkg_hdr); 18403cbdb034SDan Nowlin 18413cbdb034SDan Nowlin return seg_hdr ? true : false; 18423cbdb034SDan Nowlin } 18433cbdb034SDan Nowlin 18443cbdb034SDan Nowlin /** 18453cbdb034SDan Nowlin * ice_get_pkg_segment_id - get correct package segment id, based on device 18463cbdb034SDan Nowlin * @mac_type: MAC type of the device 18473cbdb034SDan Nowlin */ 18483cbdb034SDan Nowlin static u32 ice_get_pkg_segment_id(enum ice_mac_type mac_type) 18493cbdb034SDan Nowlin { 18503cbdb034SDan Nowlin u32 seg_id; 18513cbdb034SDan Nowlin 18523cbdb034SDan Nowlin switch (mac_type) { 18533cbdb034SDan Nowlin case ICE_MAC_E830: 18543cbdb034SDan Nowlin seg_id = SEGMENT_TYPE_ICE_E830; 18553cbdb034SDan Nowlin break; 18563cbdb034SDan Nowlin case ICE_MAC_GENERIC: 1857372e27deSGrzegorz Nitka case ICE_MAC_GENERIC_3K_E825: 18583cbdb034SDan Nowlin default: 18593cbdb034SDan Nowlin seg_id = SEGMENT_TYPE_ICE_E810; 18603cbdb034SDan Nowlin break; 18613cbdb034SDan Nowlin } 18623cbdb034SDan Nowlin 18633cbdb034SDan Nowlin return seg_id; 18643cbdb034SDan Nowlin } 18653cbdb034SDan Nowlin 18663cbdb034SDan Nowlin /** 18673cbdb034SDan Nowlin * ice_get_pkg_sign_type - get package segment sign type, based on device 18683cbdb034SDan Nowlin * @mac_type: MAC type of the device 18693cbdb034SDan Nowlin */ 18703cbdb034SDan Nowlin static u32 ice_get_pkg_sign_type(enum ice_mac_type mac_type) 18713cbdb034SDan Nowlin { 18723cbdb034SDan Nowlin u32 sign_type; 18733cbdb034SDan Nowlin 18743cbdb034SDan Nowlin switch (mac_type) { 18753cbdb034SDan Nowlin case ICE_MAC_E830: 18763cbdb034SDan Nowlin sign_type = SEGMENT_SIGN_TYPE_RSA3K_SBB; 18773cbdb034SDan Nowlin break; 1878372e27deSGrzegorz Nitka case ICE_MAC_GENERIC_3K_E825: 1879372e27deSGrzegorz Nitka sign_type = SEGMENT_SIGN_TYPE_RSA3K_E825; 1880372e27deSGrzegorz Nitka break; 18813cbdb034SDan Nowlin case ICE_MAC_GENERIC: 18823cbdb034SDan Nowlin default: 18833cbdb034SDan Nowlin sign_type = SEGMENT_SIGN_TYPE_RSA2K; 18843cbdb034SDan Nowlin break; 18853cbdb034SDan Nowlin } 18863cbdb034SDan Nowlin 18873cbdb034SDan Nowlin return sign_type; 18883cbdb034SDan Nowlin } 18893cbdb034SDan Nowlin 18903cbdb034SDan Nowlin /** 18913cbdb034SDan Nowlin * ice_get_signing_req - get correct package requirements, based on device 18923cbdb034SDan Nowlin * @hw: pointer to the hardware structure 18933cbdb034SDan Nowlin */ 18943cbdb034SDan Nowlin static void ice_get_signing_req(struct ice_hw *hw) 18953cbdb034SDan Nowlin { 18963cbdb034SDan Nowlin hw->pkg_seg_id = ice_get_pkg_segment_id(hw->mac_type); 18973cbdb034SDan Nowlin hw->pkg_sign_type = ice_get_pkg_sign_type(hw->mac_type); 18983cbdb034SDan Nowlin } 18993cbdb034SDan Nowlin 19003cbdb034SDan Nowlin /** 19012ffd87d3SSergey Temerkhanov * ice_init_pkg_info 19022ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 19032ffd87d3SSergey Temerkhanov * @pkg_hdr: pointer to the driver's package hdr 19042ffd87d3SSergey Temerkhanov * 19052ffd87d3SSergey Temerkhanov * Saves off the package details into the HW structure. 19062ffd87d3SSergey Temerkhanov */ 19072ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_init_pkg_info(struct ice_hw *hw, 19082ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg_hdr) 19092ffd87d3SSergey Temerkhanov { 19102ffd87d3SSergey Temerkhanov struct ice_generic_seg_hdr *seg_hdr; 19112ffd87d3SSergey Temerkhanov 19122ffd87d3SSergey Temerkhanov if (!pkg_hdr) 19132ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 19142ffd87d3SSergey Temerkhanov 19153cbdb034SDan Nowlin hw->pkg_has_signing_seg = ice_has_signing_seg(hw, pkg_hdr); 19163cbdb034SDan Nowlin ice_get_signing_req(hw); 19173cbdb034SDan Nowlin 19183cbdb034SDan Nowlin ice_debug(hw, ICE_DBG_INIT, "Pkg using segment id: 0x%08X\n", 19193cbdb034SDan Nowlin hw->pkg_seg_id); 19203cbdb034SDan Nowlin 19213cbdb034SDan Nowlin seg_hdr = (struct ice_generic_seg_hdr *) 19223cbdb034SDan Nowlin ice_find_seg_in_pkg(hw, hw->pkg_seg_id, pkg_hdr); 19232ffd87d3SSergey Temerkhanov if (seg_hdr) { 19242ffd87d3SSergey Temerkhanov struct ice_meta_sect *meta; 19252ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 19262ffd87d3SSergey Temerkhanov 19272ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 19282ffd87d3SSergey Temerkhanov 19292ffd87d3SSergey Temerkhanov /* Get package information from the Metadata Section */ 19302ffd87d3SSergey Temerkhanov meta = ice_pkg_enum_section((struct ice_seg *)seg_hdr, &state, 19312ffd87d3SSergey Temerkhanov ICE_SID_METADATA); 19322ffd87d3SSergey Temerkhanov if (!meta) { 19332ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 19342ffd87d3SSergey Temerkhanov "Did not find ice metadata section in package\n"); 19352ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 19362ffd87d3SSergey Temerkhanov } 19372ffd87d3SSergey Temerkhanov 19382ffd87d3SSergey Temerkhanov hw->pkg_ver = meta->ver; 19392ffd87d3SSergey Temerkhanov memcpy(hw->pkg_name, meta->name, sizeof(meta->name)); 19402ffd87d3SSergey Temerkhanov 19412ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Pkg: %d.%d.%d.%d, %s\n", 19422ffd87d3SSergey Temerkhanov meta->ver.major, meta->ver.minor, meta->ver.update, 19432ffd87d3SSergey Temerkhanov meta->ver.draft, meta->name); 19442ffd87d3SSergey Temerkhanov 19452ffd87d3SSergey Temerkhanov hw->ice_seg_fmt_ver = seg_hdr->seg_format_ver; 19462ffd87d3SSergey Temerkhanov memcpy(hw->ice_seg_id, seg_hdr->seg_id, sizeof(hw->ice_seg_id)); 19472ffd87d3SSergey Temerkhanov 19482ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n", 19492ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.major, 19502ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.minor, 19512ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.update, 19522ffd87d3SSergey Temerkhanov seg_hdr->seg_format_ver.draft, seg_hdr->seg_id); 19532ffd87d3SSergey Temerkhanov } else { 19542ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 19552ffd87d3SSergey Temerkhanov "Did not find ice segment in driver package\n"); 19562ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 19572ffd87d3SSergey Temerkhanov } 19582ffd87d3SSergey Temerkhanov 19592ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_SUCCESS; 19602ffd87d3SSergey Temerkhanov } 19612ffd87d3SSergey Temerkhanov 19622ffd87d3SSergey Temerkhanov /** 19632ffd87d3SSergey Temerkhanov * ice_get_pkg_info 19642ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 19652ffd87d3SSergey Temerkhanov * 19662ffd87d3SSergey Temerkhanov * Store details of the package currently loaded in HW into the HW structure. 19672ffd87d3SSergey Temerkhanov */ 19682ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw) 19692ffd87d3SSergey Temerkhanov { 1970d8e45f29SKees Cook DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg_info, pkg_info, 1971230064baSPrzemek Kitszel ICE_PKG_CNT); 1972230064baSPrzemek Kitszel u16 size = __struct_size(pkg_info); 19732ffd87d3SSergey Temerkhanov u32 i; 19742ffd87d3SSergey Temerkhanov 1975230064baSPrzemek Kitszel if (ice_aq_get_pkg_info_list(hw, pkg_info, size, NULL)) 19762ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 19772ffd87d3SSergey Temerkhanov 19782ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg_info->count); i++) { 19792ffd87d3SSergey Temerkhanov #define ICE_PKG_FLAG_COUNT 4 19802ffd87d3SSergey Temerkhanov char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 }; 19812ffd87d3SSergey Temerkhanov u8 place = 0; 19822ffd87d3SSergey Temerkhanov 19832ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_active) { 19842ffd87d3SSergey Temerkhanov flags[place++] = 'A'; 19852ffd87d3SSergey Temerkhanov hw->active_pkg_ver = pkg_info->pkg_info[i].ver; 19862ffd87d3SSergey Temerkhanov hw->active_track_id = 19872ffd87d3SSergey Temerkhanov le32_to_cpu(pkg_info->pkg_info[i].track_id); 19882ffd87d3SSergey Temerkhanov memcpy(hw->active_pkg_name, pkg_info->pkg_info[i].name, 19892ffd87d3SSergey Temerkhanov sizeof(pkg_info->pkg_info[i].name)); 19902ffd87d3SSergey Temerkhanov hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm; 19912ffd87d3SSergey Temerkhanov } 19922ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_active_at_boot) 19932ffd87d3SSergey Temerkhanov flags[place++] = 'B'; 19942ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_modified) 19952ffd87d3SSergey Temerkhanov flags[place++] = 'M'; 19962ffd87d3SSergey Temerkhanov if (pkg_info->pkg_info[i].is_in_nvm) 19972ffd87d3SSergey Temerkhanov flags[place++] = 'N'; 19982ffd87d3SSergey Temerkhanov 19992ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_PKG, "Pkg[%d]: %d.%d.%d.%d,%s,%s\n", i, 20002ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.major, 20012ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.minor, 20022ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.update, 20032ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].ver.draft, 20042ffd87d3SSergey Temerkhanov pkg_info->pkg_info[i].name, flags); 20052ffd87d3SSergey Temerkhanov } 20062ffd87d3SSergey Temerkhanov 2007230064baSPrzemek Kitszel return ICE_DDP_PKG_SUCCESS; 20082ffd87d3SSergey Temerkhanov } 20092ffd87d3SSergey Temerkhanov 20102ffd87d3SSergey Temerkhanov /** 20112ffd87d3SSergey Temerkhanov * ice_chk_pkg_compat 20122ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 20132ffd87d3SSergey Temerkhanov * @ospkg: pointer to the package hdr 20142ffd87d3SSergey Temerkhanov * @seg: pointer to the package segment hdr 20152ffd87d3SSergey Temerkhanov * 20162ffd87d3SSergey Temerkhanov * This function checks the package version compatibility with driver and NVM 20172ffd87d3SSergey Temerkhanov */ 20182ffd87d3SSergey Temerkhanov static enum ice_ddp_state ice_chk_pkg_compat(struct ice_hw *hw, 20192ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *ospkg, 20202ffd87d3SSergey Temerkhanov struct ice_seg **seg) 20212ffd87d3SSergey Temerkhanov { 2022d8e45f29SKees Cook DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg, pkg_info, 2023230064baSPrzemek Kitszel ICE_PKG_CNT); 2024230064baSPrzemek Kitszel u16 size = __struct_size(pkg); 20252ffd87d3SSergey Temerkhanov enum ice_ddp_state state; 20262ffd87d3SSergey Temerkhanov u32 i; 20272ffd87d3SSergey Temerkhanov 20282ffd87d3SSergey Temerkhanov /* Check package version compatibility */ 20292ffd87d3SSergey Temerkhanov state = ice_chk_pkg_version(&hw->pkg_ver); 20302ffd87d3SSergey Temerkhanov if (state) { 20312ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n"); 20322ffd87d3SSergey Temerkhanov return state; 20332ffd87d3SSergey Temerkhanov } 20342ffd87d3SSergey Temerkhanov 20352ffd87d3SSergey Temerkhanov /* find ICE segment in given package */ 20363cbdb034SDan Nowlin *seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, hw->pkg_seg_id, 20372ffd87d3SSergey Temerkhanov ospkg); 20382ffd87d3SSergey Temerkhanov if (!*seg) { 20392ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n"); 20402ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_INVALID_FILE; 20412ffd87d3SSergey Temerkhanov } 20422ffd87d3SSergey Temerkhanov 20432ffd87d3SSergey Temerkhanov /* Check if FW is compatible with the OS package */ 2044230064baSPrzemek Kitszel if (ice_aq_get_pkg_info_list(hw, pkg, size, NULL)) 2045230064baSPrzemek Kitszel return ICE_DDP_PKG_LOAD_ERROR; 20462ffd87d3SSergey Temerkhanov 20472ffd87d3SSergey Temerkhanov for (i = 0; i < le32_to_cpu(pkg->count); i++) { 20482ffd87d3SSergey Temerkhanov /* loop till we find the NVM package */ 20492ffd87d3SSergey Temerkhanov if (!pkg->pkg_info[i].is_in_nvm) 20502ffd87d3SSergey Temerkhanov continue; 20512ffd87d3SSergey Temerkhanov if ((*seg)->hdr.seg_format_ver.major != 20522ffd87d3SSergey Temerkhanov pkg->pkg_info[i].ver.major || 20532ffd87d3SSergey Temerkhanov (*seg)->hdr.seg_format_ver.minor > 20542ffd87d3SSergey Temerkhanov pkg->pkg_info[i].ver.minor) { 20552ffd87d3SSergey Temerkhanov state = ICE_DDP_PKG_FW_MISMATCH; 20562ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 20572ffd87d3SSergey Temerkhanov "OS package is not compatible with NVM.\n"); 20582ffd87d3SSergey Temerkhanov } 20592ffd87d3SSergey Temerkhanov /* done processing NVM package so break */ 20602ffd87d3SSergey Temerkhanov break; 20612ffd87d3SSergey Temerkhanov } 2062230064baSPrzemek Kitszel 20632ffd87d3SSergey Temerkhanov return state; 20642ffd87d3SSergey Temerkhanov } 20652ffd87d3SSergey Temerkhanov 20662ffd87d3SSergey Temerkhanov /** 20672ffd87d3SSergey Temerkhanov * ice_init_pkg_hints 20682ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 20692ffd87d3SSergey Temerkhanov * @ice_seg: pointer to the segment of the package scan (non-NULL) 20702ffd87d3SSergey Temerkhanov * 20712ffd87d3SSergey Temerkhanov * This function will scan the package and save off relevant information 20722ffd87d3SSergey Temerkhanov * (hints or metadata) for driver use. The ice_seg parameter must not be NULL 20732ffd87d3SSergey Temerkhanov * since the first call to ice_enum_labels requires a pointer to an actual 20742ffd87d3SSergey Temerkhanov * ice_seg structure. 20752ffd87d3SSergey Temerkhanov */ 20762ffd87d3SSergey Temerkhanov static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg) 20772ffd87d3SSergey Temerkhanov { 20782ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 20792ffd87d3SSergey Temerkhanov char *label_name; 20802ffd87d3SSergey Temerkhanov u16 val; 20812ffd87d3SSergey Temerkhanov int i; 20822ffd87d3SSergey Temerkhanov 20832ffd87d3SSergey Temerkhanov memset(&hw->tnl, 0, sizeof(hw->tnl)); 20842ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 20852ffd87d3SSergey Temerkhanov 20862ffd87d3SSergey Temerkhanov if (!ice_seg) 20872ffd87d3SSergey Temerkhanov return; 20882ffd87d3SSergey Temerkhanov 20892ffd87d3SSergey Temerkhanov label_name = ice_enum_labels(ice_seg, ICE_SID_LBL_RXPARSER_TMEM, &state, 20902ffd87d3SSergey Temerkhanov &val); 20912ffd87d3SSergey Temerkhanov 20922ffd87d3SSergey Temerkhanov while (label_name) { 20932ffd87d3SSergey Temerkhanov if (!strncmp(label_name, ICE_TNL_PRE, strlen(ICE_TNL_PRE))) 20942ffd87d3SSergey Temerkhanov /* check for a tunnel entry */ 20952ffd87d3SSergey Temerkhanov ice_add_tunnel_hint(hw, label_name, val); 20962ffd87d3SSergey Temerkhanov 20972ffd87d3SSergey Temerkhanov /* check for a dvm mode entry */ 20982ffd87d3SSergey Temerkhanov else if (!strncmp(label_name, ICE_DVM_PRE, strlen(ICE_DVM_PRE))) 20992ffd87d3SSergey Temerkhanov ice_add_dvm_hint(hw, val, true); 21002ffd87d3SSergey Temerkhanov 21012ffd87d3SSergey Temerkhanov /* check for a svm mode entry */ 21022ffd87d3SSergey Temerkhanov else if (!strncmp(label_name, ICE_SVM_PRE, strlen(ICE_SVM_PRE))) 21032ffd87d3SSergey Temerkhanov ice_add_dvm_hint(hw, val, false); 21042ffd87d3SSergey Temerkhanov 21052ffd87d3SSergey Temerkhanov label_name = ice_enum_labels(NULL, 0, &state, &val); 21062ffd87d3SSergey Temerkhanov } 21072ffd87d3SSergey Temerkhanov 21082ffd87d3SSergey Temerkhanov /* Cache the appropriate boost TCAM entry pointers for tunnels */ 21092ffd87d3SSergey Temerkhanov for (i = 0; i < hw->tnl.count; i++) { 21102ffd87d3SSergey Temerkhanov ice_find_boost_entry(ice_seg, hw->tnl.tbl[i].boost_addr, 21112ffd87d3SSergey Temerkhanov &hw->tnl.tbl[i].boost_entry); 21122ffd87d3SSergey Temerkhanov if (hw->tnl.tbl[i].boost_entry) { 21132ffd87d3SSergey Temerkhanov hw->tnl.tbl[i].valid = true; 21142ffd87d3SSergey Temerkhanov if (hw->tnl.tbl[i].type < __TNL_TYPE_CNT) 21152ffd87d3SSergey Temerkhanov hw->tnl.valid_count[hw->tnl.tbl[i].type]++; 21162ffd87d3SSergey Temerkhanov } 21172ffd87d3SSergey Temerkhanov } 21182ffd87d3SSergey Temerkhanov 21192ffd87d3SSergey Temerkhanov /* Cache the appropriate boost TCAM entry pointers for DVM and SVM */ 21202ffd87d3SSergey Temerkhanov for (i = 0; i < hw->dvm_upd.count; i++) 21212ffd87d3SSergey Temerkhanov ice_find_boost_entry(ice_seg, hw->dvm_upd.tbl[i].boost_addr, 21222ffd87d3SSergey Temerkhanov &hw->dvm_upd.tbl[i].boost_entry); 21232ffd87d3SSergey Temerkhanov } 21242ffd87d3SSergey Temerkhanov 21252ffd87d3SSergey Temerkhanov /** 21262ffd87d3SSergey Temerkhanov * ice_fill_hw_ptype - fill the enabled PTYPE bit information 21272ffd87d3SSergey Temerkhanov * @hw: pointer to the HW structure 21282ffd87d3SSergey Temerkhanov */ 21292ffd87d3SSergey Temerkhanov static void ice_fill_hw_ptype(struct ice_hw *hw) 21302ffd87d3SSergey Temerkhanov { 21312ffd87d3SSergey Temerkhanov struct ice_marker_ptype_tcam_entry *tcam; 21322ffd87d3SSergey Temerkhanov struct ice_seg *seg = hw->seg; 21332ffd87d3SSergey Temerkhanov struct ice_pkg_enum state; 21342ffd87d3SSergey Temerkhanov 21352ffd87d3SSergey Temerkhanov bitmap_zero(hw->hw_ptype, ICE_FLOW_PTYPE_MAX); 21362ffd87d3SSergey Temerkhanov if (!seg) 21372ffd87d3SSergey Temerkhanov return; 21382ffd87d3SSergey Temerkhanov 21392ffd87d3SSergey Temerkhanov memset(&state, 0, sizeof(state)); 21402ffd87d3SSergey Temerkhanov 21412ffd87d3SSergey Temerkhanov do { 21422ffd87d3SSergey Temerkhanov tcam = ice_pkg_enum_entry(seg, &state, 21432ffd87d3SSergey Temerkhanov ICE_SID_RXPARSER_MARKER_PTYPE, NULL, 21442ffd87d3SSergey Temerkhanov ice_marker_ptype_tcam_handler); 21452ffd87d3SSergey Temerkhanov if (tcam && 21462ffd87d3SSergey Temerkhanov le16_to_cpu(tcam->addr) < ICE_MARKER_PTYPE_TCAM_ADDR_MAX && 21472ffd87d3SSergey Temerkhanov le16_to_cpu(tcam->ptype) < ICE_FLOW_PTYPE_MAX) 21482ffd87d3SSergey Temerkhanov set_bit(le16_to_cpu(tcam->ptype), hw->hw_ptype); 21492ffd87d3SSergey Temerkhanov 21502ffd87d3SSergey Temerkhanov seg = NULL; 21512ffd87d3SSergey Temerkhanov } while (tcam); 21522ffd87d3SSergey Temerkhanov } 21532ffd87d3SSergey Temerkhanov 21542ffd87d3SSergey Temerkhanov /** 21552ffd87d3SSergey Temerkhanov * ice_init_pkg - initialize/download package 21562ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 21572ffd87d3SSergey Temerkhanov * @buf: pointer to the package buffer 21582ffd87d3SSergey Temerkhanov * @len: size of the package buffer 21592ffd87d3SSergey Temerkhanov * 21602ffd87d3SSergey Temerkhanov * This function initializes a package. The package contains HW tables 21612ffd87d3SSergey Temerkhanov * required to do packet processing. First, the function extracts package 21622ffd87d3SSergey Temerkhanov * information such as version. Then it finds the ice configuration segment 21632ffd87d3SSergey Temerkhanov * within the package; this function then saves a copy of the segment pointer 21642ffd87d3SSergey Temerkhanov * within the supplied package buffer. Next, the function will cache any hints 21652ffd87d3SSergey Temerkhanov * from the package, followed by downloading the package itself. Note, that if 21662ffd87d3SSergey Temerkhanov * a previous PF driver has already downloaded the package successfully, then 21672ffd87d3SSergey Temerkhanov * the current driver will not have to download the package again. 21682ffd87d3SSergey Temerkhanov * 21692ffd87d3SSergey Temerkhanov * The local package contents will be used to query default behavior and to 21702ffd87d3SSergey Temerkhanov * update specific sections of the HW's version of the package (e.g. to update 21712ffd87d3SSergey Temerkhanov * the parse graph to understand new protocols). 21722ffd87d3SSergey Temerkhanov * 21732ffd87d3SSergey Temerkhanov * This function stores a pointer to the package buffer memory, and it is 21742ffd87d3SSergey Temerkhanov * expected that the supplied buffer will not be freed immediately. If the 21752ffd87d3SSergey Temerkhanov * package buffer needs to be freed, such as when read from a file, use 21762ffd87d3SSergey Temerkhanov * ice_copy_and_init_pkg() instead of directly calling ice_init_pkg() in this 21772ffd87d3SSergey Temerkhanov * case. 21782ffd87d3SSergey Temerkhanov */ 21792ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len) 21802ffd87d3SSergey Temerkhanov { 21812ffd87d3SSergey Temerkhanov bool already_loaded = false; 21822ffd87d3SSergey Temerkhanov enum ice_ddp_state state; 21832ffd87d3SSergey Temerkhanov struct ice_pkg_hdr *pkg; 21842ffd87d3SSergey Temerkhanov struct ice_seg *seg; 21852ffd87d3SSergey Temerkhanov 21862ffd87d3SSergey Temerkhanov if (!buf || !len) 21872ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 21882ffd87d3SSergey Temerkhanov 21892ffd87d3SSergey Temerkhanov pkg = (struct ice_pkg_hdr *)buf; 21902ffd87d3SSergey Temerkhanov state = ice_verify_pkg(pkg, len); 21912ffd87d3SSergey Temerkhanov if (state) { 21922ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n", 21932ffd87d3SSergey Temerkhanov state); 21942ffd87d3SSergey Temerkhanov return state; 21952ffd87d3SSergey Temerkhanov } 21962ffd87d3SSergey Temerkhanov 21972ffd87d3SSergey Temerkhanov /* initialize package info */ 21982ffd87d3SSergey Temerkhanov state = ice_init_pkg_info(hw, pkg); 21992ffd87d3SSergey Temerkhanov if (state) 22002ffd87d3SSergey Temerkhanov return state; 22012ffd87d3SSergey Temerkhanov 22023cbdb034SDan Nowlin /* must be a matching segment */ 22033cbdb034SDan Nowlin if (hw->pkg_has_signing_seg && 22043cbdb034SDan Nowlin !ice_match_signing_seg(pkg, hw->pkg_seg_id, hw->pkg_sign_type)) 22053cbdb034SDan Nowlin return ICE_DDP_PKG_ERR; 22063cbdb034SDan Nowlin 22072ffd87d3SSergey Temerkhanov /* before downloading the package, check package version for 22082ffd87d3SSergey Temerkhanov * compatibility with driver 22092ffd87d3SSergey Temerkhanov */ 22102ffd87d3SSergey Temerkhanov state = ice_chk_pkg_compat(hw, pkg, &seg); 22112ffd87d3SSergey Temerkhanov if (state) 22122ffd87d3SSergey Temerkhanov return state; 22132ffd87d3SSergey Temerkhanov 22142ffd87d3SSergey Temerkhanov /* initialize package hints and then download package */ 22152ffd87d3SSergey Temerkhanov ice_init_pkg_hints(hw, seg); 2216a778616eSDan Nowlin state = ice_download_pkg(hw, pkg, seg); 22172ffd87d3SSergey Temerkhanov if (state == ICE_DDP_PKG_ALREADY_LOADED) { 22182ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, 22192ffd87d3SSergey Temerkhanov "package previously loaded - no work.\n"); 22202ffd87d3SSergey Temerkhanov already_loaded = true; 22212ffd87d3SSergey Temerkhanov } 22222ffd87d3SSergey Temerkhanov 22232ffd87d3SSergey Temerkhanov /* Get information on the package currently loaded in HW, then make sure 22242ffd87d3SSergey Temerkhanov * the driver is compatible with this version. 22252ffd87d3SSergey Temerkhanov */ 22262ffd87d3SSergey Temerkhanov if (!state || state == ICE_DDP_PKG_ALREADY_LOADED) { 22272ffd87d3SSergey Temerkhanov state = ice_get_pkg_info(hw); 22282ffd87d3SSergey Temerkhanov if (!state) 22292ffd87d3SSergey Temerkhanov state = ice_get_ddp_pkg_state(hw, already_loaded); 22302ffd87d3SSergey Temerkhanov } 22312ffd87d3SSergey Temerkhanov 22322ffd87d3SSergey Temerkhanov if (ice_is_init_pkg_successful(state)) { 22332ffd87d3SSergey Temerkhanov hw->seg = seg; 22342ffd87d3SSergey Temerkhanov /* on successful package download update other required 22352ffd87d3SSergey Temerkhanov * registers to support the package and fill HW tables 22362ffd87d3SSergey Temerkhanov * with package content. 22372ffd87d3SSergey Temerkhanov */ 22382ffd87d3SSergey Temerkhanov ice_init_pkg_regs(hw); 22392ffd87d3SSergey Temerkhanov ice_fill_blk_tbls(hw); 22402ffd87d3SSergey Temerkhanov ice_fill_hw_ptype(hw); 22412ffd87d3SSergey Temerkhanov ice_get_prof_index_max(hw); 22422ffd87d3SSergey Temerkhanov } else { 22432ffd87d3SSergey Temerkhanov ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n", state); 22442ffd87d3SSergey Temerkhanov } 22452ffd87d3SSergey Temerkhanov 22462ffd87d3SSergey Temerkhanov return state; 22472ffd87d3SSergey Temerkhanov } 22482ffd87d3SSergey Temerkhanov 22492ffd87d3SSergey Temerkhanov /** 22502ffd87d3SSergey Temerkhanov * ice_copy_and_init_pkg - initialize/download a copy of the package 22512ffd87d3SSergey Temerkhanov * @hw: pointer to the hardware structure 22522ffd87d3SSergey Temerkhanov * @buf: pointer to the package buffer 22532ffd87d3SSergey Temerkhanov * @len: size of the package buffer 22542ffd87d3SSergey Temerkhanov * 22552ffd87d3SSergey Temerkhanov * This function copies the package buffer, and then calls ice_init_pkg() to 22562ffd87d3SSergey Temerkhanov * initialize the copied package contents. 22572ffd87d3SSergey Temerkhanov * 22582ffd87d3SSergey Temerkhanov * The copying is necessary if the package buffer supplied is constant, or if 22592ffd87d3SSergey Temerkhanov * the memory may disappear shortly after calling this function. 22602ffd87d3SSergey Temerkhanov * 22612ffd87d3SSergey Temerkhanov * If the package buffer resides in the data segment and can be modified, the 22622ffd87d3SSergey Temerkhanov * caller is free to use ice_init_pkg() instead of ice_copy_and_init_pkg(). 22632ffd87d3SSergey Temerkhanov * 22642ffd87d3SSergey Temerkhanov * However, if the package buffer needs to be copied first, such as when being 22652ffd87d3SSergey Temerkhanov * read from a file, the caller should use ice_copy_and_init_pkg(). 22662ffd87d3SSergey Temerkhanov * 22672ffd87d3SSergey Temerkhanov * This function will first copy the package buffer, before calling 22682ffd87d3SSergey Temerkhanov * ice_init_pkg(). The caller is free to immediately destroy the original 22692ffd87d3SSergey Temerkhanov * package buffer, as the new copy will be managed by this function and 22702ffd87d3SSergey Temerkhanov * related routines. 22712ffd87d3SSergey Temerkhanov */ 22722ffd87d3SSergey Temerkhanov enum ice_ddp_state ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, 22732ffd87d3SSergey Temerkhanov u32 len) 22742ffd87d3SSergey Temerkhanov { 22752ffd87d3SSergey Temerkhanov enum ice_ddp_state state; 22762ffd87d3SSergey Temerkhanov u8 *buf_copy; 22772ffd87d3SSergey Temerkhanov 22782ffd87d3SSergey Temerkhanov if (!buf || !len) 22792ffd87d3SSergey Temerkhanov return ICE_DDP_PKG_ERR; 22802ffd87d3SSergey Temerkhanov 22812ffd87d3SSergey Temerkhanov buf_copy = devm_kmemdup(ice_hw_to_dev(hw), buf, len, GFP_KERNEL); 22822ffd87d3SSergey Temerkhanov 22832ffd87d3SSergey Temerkhanov state = ice_init_pkg(hw, buf_copy, len); 22842ffd87d3SSergey Temerkhanov if (!ice_is_init_pkg_successful(state)) { 22852ffd87d3SSergey Temerkhanov /* Free the copy, since we failed to initialize the package */ 22862ffd87d3SSergey Temerkhanov devm_kfree(ice_hw_to_dev(hw), buf_copy); 22872ffd87d3SSergey Temerkhanov } else { 22882ffd87d3SSergey Temerkhanov /* Track the copied pkg so we can free it later */ 22892ffd87d3SSergey Temerkhanov hw->pkg_copy = buf_copy; 22902ffd87d3SSergey Temerkhanov hw->pkg_size = len; 22912ffd87d3SSergey Temerkhanov } 22922ffd87d3SSergey Temerkhanov 22932ffd87d3SSergey Temerkhanov return state; 22942ffd87d3SSergey Temerkhanov } 229591427e6dSRaj Victor 229691427e6dSRaj Victor /** 229791427e6dSRaj Victor * ice_get_set_tx_topo - get or set Tx topology 229891427e6dSRaj Victor * @hw: pointer to the HW struct 229991427e6dSRaj Victor * @buf: pointer to Tx topology buffer 230091427e6dSRaj Victor * @buf_size: buffer size 230191427e6dSRaj Victor * @cd: pointer to command details structure or NULL 230291427e6dSRaj Victor * @flags: pointer to descriptor flags 230391427e6dSRaj Victor * @set: 0-get, 1-set topology 230491427e6dSRaj Victor * 230591427e6dSRaj Victor * The function will get or set Tx topology 230691427e6dSRaj Victor * 230791427e6dSRaj Victor * Return: zero when set was successful, negative values otherwise. 230891427e6dSRaj Victor */ 230991427e6dSRaj Victor static int 231091427e6dSRaj Victor ice_get_set_tx_topo(struct ice_hw *hw, u8 *buf, u16 buf_size, 231191427e6dSRaj Victor struct ice_sq_cd *cd, u8 *flags, bool set) 231291427e6dSRaj Victor { 231391427e6dSRaj Victor struct ice_aqc_get_set_tx_topo *cmd; 231491427e6dSRaj Victor struct ice_aq_desc desc; 231591427e6dSRaj Victor int status; 231691427e6dSRaj Victor 231791427e6dSRaj Victor cmd = &desc.params.get_set_tx_topo; 231891427e6dSRaj Victor if (set) { 231991427e6dSRaj Victor ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_tx_topo); 232091427e6dSRaj Victor cmd->set_flags = ICE_AQC_TX_TOPO_FLAGS_ISSUED; 232191427e6dSRaj Victor /* requested to update a new topology, not a default topology */ 232291427e6dSRaj Victor if (buf) 232391427e6dSRaj Victor cmd->set_flags |= ICE_AQC_TX_TOPO_FLAGS_SRC_RAM | 232491427e6dSRaj Victor ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW; 232591427e6dSRaj Victor 232691427e6dSRaj Victor if (ice_is_e825c(hw)) 232791427e6dSRaj Victor desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 232891427e6dSRaj Victor } else { 232991427e6dSRaj Victor ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_tx_topo); 233091427e6dSRaj Victor cmd->get_flags = ICE_AQC_TX_TOPO_GET_RAM; 233191427e6dSRaj Victor } 233291427e6dSRaj Victor 233391427e6dSRaj Victor if (!ice_is_e825c(hw)) 233491427e6dSRaj Victor desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 233591427e6dSRaj Victor 233691427e6dSRaj Victor status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 233791427e6dSRaj Victor if (status) 233891427e6dSRaj Victor return status; 233991427e6dSRaj Victor /* read the return flag values (first byte) for get operation */ 234091427e6dSRaj Victor if (!set && flags) 234191427e6dSRaj Victor *flags = desc.params.get_set_tx_topo.set_flags; 234291427e6dSRaj Victor 234391427e6dSRaj Victor return 0; 234491427e6dSRaj Victor } 234591427e6dSRaj Victor 234691427e6dSRaj Victor /** 234791427e6dSRaj Victor * ice_cfg_tx_topo - Initialize new Tx topology if available 234891427e6dSRaj Victor * @hw: pointer to the HW struct 234991427e6dSRaj Victor * @buf: pointer to Tx topology buffer 235091427e6dSRaj Victor * @len: buffer size 235191427e6dSRaj Victor * 235291427e6dSRaj Victor * The function will apply the new Tx topology from the package buffer 235391427e6dSRaj Victor * if available. 235491427e6dSRaj Victor * 235591427e6dSRaj Victor * Return: zero when update was successful, negative values otherwise. 235691427e6dSRaj Victor */ 235791427e6dSRaj Victor int ice_cfg_tx_topo(struct ice_hw *hw, u8 *buf, u32 len) 235891427e6dSRaj Victor { 235991427e6dSRaj Victor u8 *current_topo, *new_topo = NULL; 236091427e6dSRaj Victor struct ice_run_time_cfg_seg *seg; 236191427e6dSRaj Victor struct ice_buf_hdr *section; 236291427e6dSRaj Victor struct ice_pkg_hdr *pkg_hdr; 236391427e6dSRaj Victor enum ice_ddp_state state; 236491427e6dSRaj Victor u16 offset, size = 0; 236591427e6dSRaj Victor u32 reg = 0; 236691427e6dSRaj Victor int status; 236791427e6dSRaj Victor u8 flags; 236891427e6dSRaj Victor 236991427e6dSRaj Victor if (!buf || !len) 237091427e6dSRaj Victor return -EINVAL; 237191427e6dSRaj Victor 237291427e6dSRaj Victor /* Does FW support new Tx topology mode ? */ 237391427e6dSRaj Victor if (!hw->func_caps.common_cap.tx_sched_topo_comp_mode_en) { 237491427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "FW doesn't support compatibility mode\n"); 237591427e6dSRaj Victor return -EOPNOTSUPP; 237691427e6dSRaj Victor } 237791427e6dSRaj Victor 237891427e6dSRaj Victor current_topo = kzalloc(ICE_AQ_MAX_BUF_LEN, GFP_KERNEL); 237991427e6dSRaj Victor if (!current_topo) 238091427e6dSRaj Victor return -ENOMEM; 238191427e6dSRaj Victor 238291427e6dSRaj Victor /* Get the current Tx topology */ 238391427e6dSRaj Victor status = ice_get_set_tx_topo(hw, current_topo, ICE_AQ_MAX_BUF_LEN, NULL, 238491427e6dSRaj Victor &flags, false); 238591427e6dSRaj Victor 238691427e6dSRaj Victor kfree(current_topo); 238791427e6dSRaj Victor 238891427e6dSRaj Victor if (status) { 238991427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "Get current topology is failed\n"); 239091427e6dSRaj Victor return status; 239191427e6dSRaj Victor } 239291427e6dSRaj Victor 239391427e6dSRaj Victor /* Is default topology already applied ? */ 239491427e6dSRaj Victor if (!(flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) && 239591427e6dSRaj Victor hw->num_tx_sched_layers == ICE_SCHED_9_LAYERS) { 239691427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "Default topology already applied\n"); 239791427e6dSRaj Victor return -EEXIST; 239891427e6dSRaj Victor } 239991427e6dSRaj Victor 240091427e6dSRaj Victor /* Is new topology already applied ? */ 240191427e6dSRaj Victor if ((flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) && 240291427e6dSRaj Victor hw->num_tx_sched_layers == ICE_SCHED_5_LAYERS) { 240391427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "New topology already applied\n"); 240491427e6dSRaj Victor return -EEXIST; 240591427e6dSRaj Victor } 240691427e6dSRaj Victor 240791427e6dSRaj Victor /* Setting topology already issued? */ 240891427e6dSRaj Victor if (flags & ICE_AQC_TX_TOPO_FLAGS_ISSUED) { 240991427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "Update Tx topology was done by another PF\n"); 241091427e6dSRaj Victor /* Add a small delay before exiting */ 241191427e6dSRaj Victor msleep(2000); 241291427e6dSRaj Victor return -EEXIST; 241391427e6dSRaj Victor } 241491427e6dSRaj Victor 241591427e6dSRaj Victor /* Change the topology from new to default (5 to 9) */ 241691427e6dSRaj Victor if (!(flags & ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW) && 241791427e6dSRaj Victor hw->num_tx_sched_layers == ICE_SCHED_5_LAYERS) { 241891427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "Change topology from 5 to 9 layers\n"); 241991427e6dSRaj Victor goto update_topo; 242091427e6dSRaj Victor } 242191427e6dSRaj Victor 242291427e6dSRaj Victor pkg_hdr = (struct ice_pkg_hdr *)buf; 242391427e6dSRaj Victor state = ice_verify_pkg(pkg_hdr, len); 242491427e6dSRaj Victor if (state) { 242591427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "Failed to verify pkg (err: %d)\n", 242691427e6dSRaj Victor state); 242791427e6dSRaj Victor return -EIO; 242891427e6dSRaj Victor } 242991427e6dSRaj Victor 243091427e6dSRaj Victor /* Find runtime configuration segment */ 243191427e6dSRaj Victor seg = (struct ice_run_time_cfg_seg *) 243291427e6dSRaj Victor ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE_RUN_TIME_CFG, pkg_hdr); 243391427e6dSRaj Victor if (!seg) { 243491427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "5 layer topology segment is missing\n"); 243591427e6dSRaj Victor return -EIO; 243691427e6dSRaj Victor } 243791427e6dSRaj Victor 243891427e6dSRaj Victor if (le32_to_cpu(seg->buf_table.buf_count) < ICE_MIN_S_COUNT) { 243991427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "5 layer topology segment count(%d) is wrong\n", 244091427e6dSRaj Victor seg->buf_table.buf_count); 244191427e6dSRaj Victor return -EIO; 244291427e6dSRaj Victor } 244391427e6dSRaj Victor 244491427e6dSRaj Victor section = ice_pkg_val_buf(seg->buf_table.buf_array); 244591427e6dSRaj Victor if (!section || le32_to_cpu(section->section_entry[0].type) != 244691427e6dSRaj Victor ICE_SID_TX_5_LAYER_TOPO) { 244791427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "5 layer topology section type is wrong\n"); 244891427e6dSRaj Victor return -EIO; 244991427e6dSRaj Victor } 245091427e6dSRaj Victor 245191427e6dSRaj Victor size = le16_to_cpu(section->section_entry[0].size); 245291427e6dSRaj Victor offset = le16_to_cpu(section->section_entry[0].offset); 245391427e6dSRaj Victor if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ) { 245491427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "5 layer topology section size is wrong\n"); 245591427e6dSRaj Victor return -EIO; 245691427e6dSRaj Victor } 245791427e6dSRaj Victor 245891427e6dSRaj Victor /* Make sure the section fits in the buffer */ 245991427e6dSRaj Victor if (offset + size > ICE_PKG_BUF_SIZE) { 246091427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "5 layer topology buffer > 4K\n"); 246191427e6dSRaj Victor return -EIO; 246291427e6dSRaj Victor } 246391427e6dSRaj Victor 246491427e6dSRaj Victor /* Get the new topology buffer */ 246591427e6dSRaj Victor new_topo = ((u8 *)section) + offset; 246691427e6dSRaj Victor 246791427e6dSRaj Victor update_topo: 246891427e6dSRaj Victor /* Acquire global lock to make sure that set topology issued 246991427e6dSRaj Victor * by one PF. 247091427e6dSRaj Victor */ 247191427e6dSRaj Victor status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, ICE_RES_WRITE, 247291427e6dSRaj Victor ICE_GLOBAL_CFG_LOCK_TIMEOUT); 247391427e6dSRaj Victor if (status) { 247491427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "Failed to acquire global lock\n"); 247591427e6dSRaj Victor return status; 247691427e6dSRaj Victor } 247791427e6dSRaj Victor 247891427e6dSRaj Victor /* Check if reset was triggered already. */ 247991427e6dSRaj Victor reg = rd32(hw, GLGEN_RSTAT); 248091427e6dSRaj Victor if (reg & GLGEN_RSTAT_DEVSTATE_M) { 248191427e6dSRaj Victor /* Reset is in progress, re-init the HW again */ 248291427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "Reset is in progress. Layer topology might be applied already\n"); 248391427e6dSRaj Victor ice_check_reset(hw); 248491427e6dSRaj Victor return 0; 248591427e6dSRaj Victor } 248691427e6dSRaj Victor 248791427e6dSRaj Victor /* Set new topology */ 248891427e6dSRaj Victor status = ice_get_set_tx_topo(hw, new_topo, size, NULL, NULL, true); 248991427e6dSRaj Victor if (status) { 249091427e6dSRaj Victor ice_debug(hw, ICE_DBG_INIT, "Failed setting Tx topology\n"); 249191427e6dSRaj Victor return status; 249291427e6dSRaj Victor } 249391427e6dSRaj Victor 249491427e6dSRaj Victor /* New topology is updated, delay 1 second before issuing the CORER */ 249591427e6dSRaj Victor msleep(1000); 249691427e6dSRaj Victor ice_reset(hw, ICE_RESET_CORER); 249791427e6dSRaj Victor /* CORER will clear the global lock, so no explicit call 249891427e6dSRaj Victor * required for release. 249991427e6dSRaj Victor */ 250091427e6dSRaj Victor 250191427e6dSRaj Victor return 0; 250291427e6dSRaj Victor } 2503