18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "ice_common.h" 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci/** 78c2ecf20Sopenharmony_ci * ice_aq_read_nvm 88c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 98c2ecf20Sopenharmony_ci * @module_typeid: module pointer location in words from the NVM beginning 108c2ecf20Sopenharmony_ci * @offset: byte offset from the module beginning 118c2ecf20Sopenharmony_ci * @length: length of the section to be read (in bytes from the offset) 128c2ecf20Sopenharmony_ci * @data: command buffer (size [bytes] = length) 138c2ecf20Sopenharmony_ci * @last_command: tells if this is the last command in a series 148c2ecf20Sopenharmony_ci * @read_shadow_ram: tell if this is a shadow RAM read 158c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Read the NVM using the admin queue commands (0x0701) 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_cistatic enum ice_status 208c2ecf20Sopenharmony_ciice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, u16 length, 218c2ecf20Sopenharmony_ci void *data, bool last_command, bool read_shadow_ram, 228c2ecf20Sopenharmony_ci struct ice_sq_cd *cd) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct ice_aq_desc desc; 258c2ecf20Sopenharmony_ci struct ice_aqc_nvm *cmd; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci cmd = &desc.params.nvm; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (offset > ICE_AQC_NVM_MAX_OFFSET) 308c2ecf20Sopenharmony_ci return ICE_ERR_PARAM; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_read); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (!read_shadow_ram && module_typeid == ICE_AQC_NVM_START_POINT) 358c2ecf20Sopenharmony_ci cmd->cmd_flags |= ICE_AQC_NVM_FLASH_ONLY; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci /* If this is the last command in a series, set the proper flag. */ 388c2ecf20Sopenharmony_ci if (last_command) 398c2ecf20Sopenharmony_ci cmd->cmd_flags |= ICE_AQC_NVM_LAST_CMD; 408c2ecf20Sopenharmony_ci cmd->module_typeid = cpu_to_le16(module_typeid); 418c2ecf20Sopenharmony_ci cmd->offset_low = cpu_to_le16(offset & 0xFFFF); 428c2ecf20Sopenharmony_ci cmd->offset_high = (offset >> 16) & 0xFF; 438c2ecf20Sopenharmony_ci cmd->length = cpu_to_le16(length); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return ice_aq_send_cmd(hw, &desc, data, length, cd); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/** 498c2ecf20Sopenharmony_ci * ice_read_flat_nvm - Read portion of NVM by flat offset 508c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 518c2ecf20Sopenharmony_ci * @offset: offset from beginning of NVM 528c2ecf20Sopenharmony_ci * @length: (in) number of bytes to read; (out) number of bytes actually read 538c2ecf20Sopenharmony_ci * @data: buffer to return data in (sized to fit the specified length) 548c2ecf20Sopenharmony_ci * @read_shadow_ram: if true, read from shadow RAM instead of NVM 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * Reads a portion of the NVM, as a flat memory space. This function correctly 578c2ecf20Sopenharmony_ci * breaks read requests across Shadow RAM sectors and ensures that no single 588c2ecf20Sopenharmony_ci * read request exceeds the maximum 4Kb read for a single AdminQ command. 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * Returns a status code on failure. Note that the data pointer may be 618c2ecf20Sopenharmony_ci * partially updated if some reads succeed before a failure. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_cienum ice_status 648c2ecf20Sopenharmony_ciice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data, 658c2ecf20Sopenharmony_ci bool read_shadow_ram) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci enum ice_status status; 688c2ecf20Sopenharmony_ci u32 inlen = *length; 698c2ecf20Sopenharmony_ci u32 bytes_read = 0; 708c2ecf20Sopenharmony_ci bool last_cmd; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci *length = 0; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Verify the length of the read if this is for the Shadow RAM */ 758c2ecf20Sopenharmony_ci if (read_shadow_ram && ((offset + inlen) > (hw->nvm.sr_words * 2u))) { 768c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_NVM, 778c2ecf20Sopenharmony_ci "NVM error: requested offset is beyond Shadow RAM limit\n"); 788c2ecf20Sopenharmony_ci return ICE_ERR_PARAM; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci do { 828c2ecf20Sopenharmony_ci u32 read_size, sector_offset; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* ice_aq_read_nvm cannot read more than 4Kb at a time. 858c2ecf20Sopenharmony_ci * Additionally, a read from the Shadow RAM may not cross over 868c2ecf20Sopenharmony_ci * a sector boundary. Conveniently, the sector size is also 878c2ecf20Sopenharmony_ci * 4Kb. 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci sector_offset = offset % ICE_AQ_MAX_BUF_LEN; 908c2ecf20Sopenharmony_ci read_size = min_t(u32, ICE_AQ_MAX_BUF_LEN - sector_offset, 918c2ecf20Sopenharmony_ci inlen - bytes_read); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci last_cmd = !(bytes_read + read_size < inlen); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci status = ice_aq_read_nvm(hw, ICE_AQC_NVM_START_POINT, 968c2ecf20Sopenharmony_ci offset, read_size, 978c2ecf20Sopenharmony_ci data + bytes_read, last_cmd, 988c2ecf20Sopenharmony_ci read_shadow_ram, NULL); 998c2ecf20Sopenharmony_ci if (status) 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci bytes_read += read_size; 1038c2ecf20Sopenharmony_ci offset += read_size; 1048c2ecf20Sopenharmony_ci } while (!last_cmd); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci *length = bytes_read; 1078c2ecf20Sopenharmony_ci return status; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/** 1118c2ecf20Sopenharmony_ci * ice_aq_update_nvm 1128c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 1138c2ecf20Sopenharmony_ci * @module_typeid: module pointer location in words from the NVM beginning 1148c2ecf20Sopenharmony_ci * @offset: byte offset from the module beginning 1158c2ecf20Sopenharmony_ci * @length: length of the section to be written (in bytes from the offset) 1168c2ecf20Sopenharmony_ci * @data: command buffer (size [bytes] = length) 1178c2ecf20Sopenharmony_ci * @last_command: tells if this is the last command in a series 1188c2ecf20Sopenharmony_ci * @command_flags: command parameters 1198c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL 1208c2ecf20Sopenharmony_ci * 1218c2ecf20Sopenharmony_ci * Update the NVM using the admin queue commands (0x0703) 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_cienum ice_status 1248c2ecf20Sopenharmony_ciice_aq_update_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, 1258c2ecf20Sopenharmony_ci u16 length, void *data, bool last_command, u8 command_flags, 1268c2ecf20Sopenharmony_ci struct ice_sq_cd *cd) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct ice_aq_desc desc; 1298c2ecf20Sopenharmony_ci struct ice_aqc_nvm *cmd; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci cmd = &desc.params.nvm; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* In offset the highest byte must be zeroed. */ 1348c2ecf20Sopenharmony_ci if (offset & 0xFF000000) 1358c2ecf20Sopenharmony_ci return ICE_ERR_PARAM; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_write); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci cmd->cmd_flags |= command_flags; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* If this is the last command in a series, set the proper flag. */ 1428c2ecf20Sopenharmony_ci if (last_command) 1438c2ecf20Sopenharmony_ci cmd->cmd_flags |= ICE_AQC_NVM_LAST_CMD; 1448c2ecf20Sopenharmony_ci cmd->module_typeid = cpu_to_le16(module_typeid); 1458c2ecf20Sopenharmony_ci cmd->offset_low = cpu_to_le16(offset & 0xFFFF); 1468c2ecf20Sopenharmony_ci cmd->offset_high = (offset >> 16) & 0xFF; 1478c2ecf20Sopenharmony_ci cmd->length = cpu_to_le16(length); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return ice_aq_send_cmd(hw, &desc, data, length, cd); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/** 1558c2ecf20Sopenharmony_ci * ice_aq_erase_nvm 1568c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 1578c2ecf20Sopenharmony_ci * @module_typeid: module pointer location in words from the NVM beginning 1588c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL 1598c2ecf20Sopenharmony_ci * 1608c2ecf20Sopenharmony_ci * Erase the NVM sector using the admin queue commands (0x0702) 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_cienum ice_status 1638c2ecf20Sopenharmony_ciice_aq_erase_nvm(struct ice_hw *hw, u16 module_typeid, struct ice_sq_cd *cd) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct ice_aq_desc desc; 1668c2ecf20Sopenharmony_ci struct ice_aqc_nvm *cmd; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci cmd = &desc.params.nvm; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_erase); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci cmd->module_typeid = cpu_to_le16(module_typeid); 1738c2ecf20Sopenharmony_ci cmd->length = cpu_to_le16(ICE_AQC_NVM_ERASE_LEN); 1748c2ecf20Sopenharmony_ci cmd->offset_low = 0; 1758c2ecf20Sopenharmony_ci cmd->offset_high = 0; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return ice_aq_send_cmd(hw, &desc, NULL, 0, cd); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/** 1818c2ecf20Sopenharmony_ci * ice_read_sr_word_aq - Reads Shadow RAM via AQ 1828c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 1838c2ecf20Sopenharmony_ci * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 1848c2ecf20Sopenharmony_ci * @data: word read from the Shadow RAM 1858c2ecf20Sopenharmony_ci * 1868c2ecf20Sopenharmony_ci * Reads one 16 bit word from the Shadow RAM using ice_read_flat_nvm. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_cistatic enum ice_status 1898c2ecf20Sopenharmony_ciice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci u32 bytes = sizeof(u16); 1928c2ecf20Sopenharmony_ci enum ice_status status; 1938c2ecf20Sopenharmony_ci __le16 data_local; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* Note that ice_read_flat_nvm takes into account the 4Kb AdminQ and 1968c2ecf20Sopenharmony_ci * Shadow RAM sector restrictions necessary when reading from the NVM. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci status = ice_read_flat_nvm(hw, offset * sizeof(u16), &bytes, 1998c2ecf20Sopenharmony_ci (u8 *)&data_local, true); 2008c2ecf20Sopenharmony_ci if (status) 2018c2ecf20Sopenharmony_ci return status; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci *data = le16_to_cpu(data_local); 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/** 2088c2ecf20Sopenharmony_ci * ice_acquire_nvm - Generic request for acquiring the NVM ownership 2098c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 2108c2ecf20Sopenharmony_ci * @access: NVM access type (read or write) 2118c2ecf20Sopenharmony_ci * 2128c2ecf20Sopenharmony_ci * This function will request NVM ownership. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_cienum ice_status 2158c2ecf20Sopenharmony_ciice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci if (hw->nvm.blank_nvm_mode) 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return ice_acquire_res(hw, ICE_NVM_RES_ID, access, ICE_NVM_TIMEOUT); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/** 2248c2ecf20Sopenharmony_ci * ice_release_nvm - Generic request for releasing the NVM ownership 2258c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 2268c2ecf20Sopenharmony_ci * 2278c2ecf20Sopenharmony_ci * This function will release NVM ownership. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_civoid ice_release_nvm(struct ice_hw *hw) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci if (hw->nvm.blank_nvm_mode) 2328c2ecf20Sopenharmony_ci return; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ice_release_res(hw, ICE_NVM_RES_ID); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/** 2388c2ecf20Sopenharmony_ci * ice_read_sr_word - Reads Shadow RAM word and acquire NVM if necessary 2398c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 2408c2ecf20Sopenharmony_ci * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 2418c2ecf20Sopenharmony_ci * @data: word read from the Shadow RAM 2428c2ecf20Sopenharmony_ci * 2438c2ecf20Sopenharmony_ci * Reads one 16 bit word from the Shadow RAM using the ice_read_sr_word_aq. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_cienum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci enum ice_status status; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci status = ice_acquire_nvm(hw, ICE_RES_READ); 2508c2ecf20Sopenharmony_ci if (!status) { 2518c2ecf20Sopenharmony_ci status = ice_read_sr_word_aq(hw, offset, data); 2528c2ecf20Sopenharmony_ci ice_release_nvm(hw); 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return status; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/** 2598c2ecf20Sopenharmony_ci * ice_get_pfa_module_tlv - Reads sub module TLV from NVM PFA 2608c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 2618c2ecf20Sopenharmony_ci * @module_tlv: pointer to module TLV to return 2628c2ecf20Sopenharmony_ci * @module_tlv_len: pointer to module TLV length to return 2638c2ecf20Sopenharmony_ci * @module_type: module type requested 2648c2ecf20Sopenharmony_ci * 2658c2ecf20Sopenharmony_ci * Finds the requested sub module TLV type from the Preserved Field 2668c2ecf20Sopenharmony_ci * Area (PFA) and returns the TLV pointer and length. The caller can 2678c2ecf20Sopenharmony_ci * use these to read the variable length TLV value. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_cienum ice_status 2708c2ecf20Sopenharmony_ciice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len, 2718c2ecf20Sopenharmony_ci u16 module_type) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci enum ice_status status; 2748c2ecf20Sopenharmony_ci u16 pfa_len, pfa_ptr; 2758c2ecf20Sopenharmony_ci u16 next_tlv; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, ICE_SR_PFA_PTR, &pfa_ptr); 2788c2ecf20Sopenharmony_ci if (status) { 2798c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Preserved Field Array pointer.\n"); 2808c2ecf20Sopenharmony_ci return status; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, pfa_ptr, &pfa_len); 2838c2ecf20Sopenharmony_ci if (status) { 2848c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read PFA length.\n"); 2858c2ecf20Sopenharmony_ci return status; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci /* Starting with first TLV after PFA length, iterate through the list 2888c2ecf20Sopenharmony_ci * of TLVs to find the requested one. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci next_tlv = pfa_ptr + 1; 2918c2ecf20Sopenharmony_ci while (next_tlv < pfa_ptr + pfa_len) { 2928c2ecf20Sopenharmony_ci u16 tlv_sub_module_type; 2938c2ecf20Sopenharmony_ci u16 tlv_len; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Read TLV type */ 2968c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, next_tlv, &tlv_sub_module_type); 2978c2ecf20Sopenharmony_ci if (status) { 2988c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV type.\n"); 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci /* Read TLV length */ 3028c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, next_tlv + 1, &tlv_len); 3038c2ecf20Sopenharmony_ci if (status) { 3048c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV length.\n"); 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci if (tlv_sub_module_type == module_type) { 3088c2ecf20Sopenharmony_ci if (tlv_len) { 3098c2ecf20Sopenharmony_ci *module_tlv = next_tlv; 3108c2ecf20Sopenharmony_ci *module_tlv_len = tlv_len; 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci return ICE_ERR_INVAL_SIZE; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci /* Check next TLV, i.e. current TLV pointer + length + 2 words 3168c2ecf20Sopenharmony_ci * (for current TLV's type and length) 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci next_tlv = next_tlv + tlv_len + 2; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci /* Module does not exist */ 3218c2ecf20Sopenharmony_ci return ICE_ERR_DOES_NOT_EXIST; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/** 3258c2ecf20Sopenharmony_ci * ice_read_pba_string - Reads part number string from NVM 3268c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 3278c2ecf20Sopenharmony_ci * @pba_num: stores the part number string from the NVM 3288c2ecf20Sopenharmony_ci * @pba_num_size: part number string buffer length 3298c2ecf20Sopenharmony_ci * 3308c2ecf20Sopenharmony_ci * Reads the part number string from the NVM. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_cienum ice_status 3338c2ecf20Sopenharmony_ciice_read_pba_string(struct ice_hw *hw, u8 *pba_num, u32 pba_num_size) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci u16 pba_tlv, pba_tlv_len; 3368c2ecf20Sopenharmony_ci enum ice_status status; 3378c2ecf20Sopenharmony_ci u16 pba_word, pba_size; 3388c2ecf20Sopenharmony_ci u16 i; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci status = ice_get_pfa_module_tlv(hw, &pba_tlv, &pba_tlv_len, 3418c2ecf20Sopenharmony_ci ICE_SR_PBA_BLOCK_PTR); 3428c2ecf20Sopenharmony_ci if (status) { 3438c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read PBA Block TLV.\n"); 3448c2ecf20Sopenharmony_ci return status; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* pba_size is the next word */ 3488c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, (pba_tlv + 2), &pba_size); 3498c2ecf20Sopenharmony_ci if (status) { 3508c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read PBA Section size.\n"); 3518c2ecf20Sopenharmony_ci return status; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (pba_tlv_len < pba_size) { 3558c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Invalid PBA Block TLV size.\n"); 3568c2ecf20Sopenharmony_ci return ICE_ERR_INVAL_SIZE; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* Subtract one to get PBA word count (PBA Size word is included in 3608c2ecf20Sopenharmony_ci * total size) 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci pba_size--; 3638c2ecf20Sopenharmony_ci if (pba_num_size < (((u32)pba_size * 2) + 1)) { 3648c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Buffer too small for PBA data.\n"); 3658c2ecf20Sopenharmony_ci return ICE_ERR_PARAM; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci for (i = 0; i < pba_size; i++) { 3698c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, (pba_tlv + 2 + 1) + i, &pba_word); 3708c2ecf20Sopenharmony_ci if (status) { 3718c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read PBA Block word %d.\n", i); 3728c2ecf20Sopenharmony_ci return status; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci pba_num[(i * 2)] = (pba_word >> 8) & 0xFF; 3768c2ecf20Sopenharmony_ci pba_num[(i * 2) + 1] = pba_word & 0xFF; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci pba_num[(pba_size * 2)] = '\0'; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return status; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/** 3848c2ecf20Sopenharmony_ci * ice_get_orom_ver_info - Read Option ROM version information 3858c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 3868c2ecf20Sopenharmony_ci * 3878c2ecf20Sopenharmony_ci * Read the Combo Image version data from the Boot Configuration TLV and fill 3888c2ecf20Sopenharmony_ci * in the option ROM version data. 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_cistatic enum ice_status ice_get_orom_ver_info(struct ice_hw *hw) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci u16 combo_hi, combo_lo, boot_cfg_tlv, boot_cfg_tlv_len; 3938c2ecf20Sopenharmony_ci struct ice_orom_info *orom = &hw->nvm.orom; 3948c2ecf20Sopenharmony_ci enum ice_status status; 3958c2ecf20Sopenharmony_ci u32 combo_ver; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci status = ice_get_pfa_module_tlv(hw, &boot_cfg_tlv, &boot_cfg_tlv_len, 3988c2ecf20Sopenharmony_ci ICE_SR_BOOT_CFG_PTR); 3998c2ecf20Sopenharmony_ci if (status) { 4008c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, 4018c2ecf20Sopenharmony_ci "Failed to read Boot Configuration Block TLV.\n"); 4028c2ecf20Sopenharmony_ci return status; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* Boot Configuration Block must have length at least 2 words 4068c2ecf20Sopenharmony_ci * (Combo Image Version High and Combo Image Version Low) 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci if (boot_cfg_tlv_len < 2) { 4098c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, 4108c2ecf20Sopenharmony_ci "Invalid Boot Configuration Block TLV size.\n"); 4118c2ecf20Sopenharmony_ci return ICE_ERR_INVAL_SIZE; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OROM_VER_OFF), 4158c2ecf20Sopenharmony_ci &combo_hi); 4168c2ecf20Sopenharmony_ci if (status) { 4178c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read OROM_VER hi.\n"); 4188c2ecf20Sopenharmony_ci return status; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OROM_VER_OFF + 1), 4228c2ecf20Sopenharmony_ci &combo_lo); 4238c2ecf20Sopenharmony_ci if (status) { 4248c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read OROM_VER lo.\n"); 4258c2ecf20Sopenharmony_ci return status; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci combo_ver = ((u32)combo_hi << 16) | combo_lo; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci orom->major = (u8)((combo_ver & ICE_OROM_VER_MASK) >> 4318c2ecf20Sopenharmony_ci ICE_OROM_VER_SHIFT); 4328c2ecf20Sopenharmony_ci orom->patch = (u8)(combo_ver & ICE_OROM_VER_PATCH_MASK); 4338c2ecf20Sopenharmony_ci orom->build = (u16)((combo_ver & ICE_OROM_VER_BUILD_MASK) >> 4348c2ecf20Sopenharmony_ci ICE_OROM_VER_BUILD_SHIFT); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/** 4408c2ecf20Sopenharmony_ci * ice_get_netlist_ver_info 4418c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 4428c2ecf20Sopenharmony_ci * 4438c2ecf20Sopenharmony_ci * Get the netlist version information 4448c2ecf20Sopenharmony_ci */ 4458c2ecf20Sopenharmony_cistatic enum ice_status ice_get_netlist_ver_info(struct ice_hw *hw) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct ice_netlist_ver_info *ver = &hw->netlist_ver; 4488c2ecf20Sopenharmony_ci enum ice_status ret; 4498c2ecf20Sopenharmony_ci u32 id_blk_start; 4508c2ecf20Sopenharmony_ci __le16 raw_data; 4518c2ecf20Sopenharmony_ci u16 data, i; 4528c2ecf20Sopenharmony_ci u16 *buff; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci ret = ice_acquire_nvm(hw, ICE_RES_READ); 4558c2ecf20Sopenharmony_ci if (ret) 4568c2ecf20Sopenharmony_ci return ret; 4578c2ecf20Sopenharmony_ci buff = kcalloc(ICE_AQC_NVM_NETLIST_ID_BLK_LEN, sizeof(*buff), 4588c2ecf20Sopenharmony_ci GFP_KERNEL); 4598c2ecf20Sopenharmony_ci if (!buff) { 4608c2ecf20Sopenharmony_ci ret = ICE_ERR_NO_MEMORY; 4618c2ecf20Sopenharmony_ci goto exit_no_mem; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* read module length */ 4658c2ecf20Sopenharmony_ci ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID, 4668c2ecf20Sopenharmony_ci ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN_OFFSET * 2, 4678c2ecf20Sopenharmony_ci ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN, &raw_data, 4688c2ecf20Sopenharmony_ci false, false, NULL); 4698c2ecf20Sopenharmony_ci if (ret) 4708c2ecf20Sopenharmony_ci goto exit_error; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci data = le16_to_cpu(raw_data); 4738c2ecf20Sopenharmony_ci /* exit if length is = 0 */ 4748c2ecf20Sopenharmony_ci if (!data) 4758c2ecf20Sopenharmony_ci goto exit_error; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* read node count */ 4788c2ecf20Sopenharmony_ci ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID, 4798c2ecf20Sopenharmony_ci ICE_AQC_NVM_NETLIST_NODE_COUNT_OFFSET * 2, 4808c2ecf20Sopenharmony_ci ICE_AQC_NVM_NETLIST_NODE_COUNT_LEN, &raw_data, 4818c2ecf20Sopenharmony_ci false, false, NULL); 4828c2ecf20Sopenharmony_ci if (ret) 4838c2ecf20Sopenharmony_ci goto exit_error; 4848c2ecf20Sopenharmony_ci data = le16_to_cpu(raw_data) & ICE_AQC_NVM_NETLIST_NODE_COUNT_M; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* netlist ID block starts from offset 4 + node count * 2 */ 4878c2ecf20Sopenharmony_ci id_blk_start = ICE_AQC_NVM_NETLIST_ID_BLK_START_OFFSET + data * 2; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* read the entire netlist ID block */ 4908c2ecf20Sopenharmony_ci ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID, 4918c2ecf20Sopenharmony_ci id_blk_start * 2, 4928c2ecf20Sopenharmony_ci ICE_AQC_NVM_NETLIST_ID_BLK_LEN * 2, buff, false, 4938c2ecf20Sopenharmony_ci false, NULL); 4948c2ecf20Sopenharmony_ci if (ret) 4958c2ecf20Sopenharmony_ci goto exit_error; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci for (i = 0; i < ICE_AQC_NVM_NETLIST_ID_BLK_LEN; i++) 4988c2ecf20Sopenharmony_ci buff[i] = le16_to_cpu(((__force __le16 *)buff)[i]); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci ver->major = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_HIGH] << 16) | 5018c2ecf20Sopenharmony_ci buff[ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_LOW]; 5028c2ecf20Sopenharmony_ci ver->minor = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_HIGH] << 16) | 5038c2ecf20Sopenharmony_ci buff[ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_LOW]; 5048c2ecf20Sopenharmony_ci ver->type = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_HIGH] << 16) | 5058c2ecf20Sopenharmony_ci buff[ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_LOW]; 5068c2ecf20Sopenharmony_ci ver->rev = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_REV_HIGH] << 16) | 5078c2ecf20Sopenharmony_ci buff[ICE_AQC_NVM_NETLIST_ID_BLK_REV_LOW]; 5088c2ecf20Sopenharmony_ci ver->cust_ver = buff[ICE_AQC_NVM_NETLIST_ID_BLK_CUST_VER]; 5098c2ecf20Sopenharmony_ci /* Read the left most 4 bytes of SHA */ 5108c2ecf20Sopenharmony_ci ver->hash = buff[ICE_AQC_NVM_NETLIST_ID_BLK_SHA_HASH + 15] << 16 | 5118c2ecf20Sopenharmony_ci buff[ICE_AQC_NVM_NETLIST_ID_BLK_SHA_HASH + 14]; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ciexit_error: 5148c2ecf20Sopenharmony_ci kfree(buff); 5158c2ecf20Sopenharmony_ciexit_no_mem: 5168c2ecf20Sopenharmony_ci ice_release_nvm(hw); 5178c2ecf20Sopenharmony_ci return ret; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/** 5218c2ecf20Sopenharmony_ci * ice_discover_flash_size - Discover the available flash size. 5228c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 5238c2ecf20Sopenharmony_ci * 5248c2ecf20Sopenharmony_ci * The device flash could be up to 16MB in size. However, it is possible that 5258c2ecf20Sopenharmony_ci * the actual size is smaller. Use bisection to determine the accessible size 5268c2ecf20Sopenharmony_ci * of flash memory. 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_cistatic enum ice_status ice_discover_flash_size(struct ice_hw *hw) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci u32 min_size = 0, max_size = ICE_AQC_NVM_MAX_OFFSET + 1; 5318c2ecf20Sopenharmony_ci enum ice_status status; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci status = ice_acquire_nvm(hw, ICE_RES_READ); 5348c2ecf20Sopenharmony_ci if (status) 5358c2ecf20Sopenharmony_ci return status; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci while ((max_size - min_size) > 1) { 5388c2ecf20Sopenharmony_ci u32 offset = (max_size + min_size) / 2; 5398c2ecf20Sopenharmony_ci u32 len = 1; 5408c2ecf20Sopenharmony_ci u8 data; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci status = ice_read_flat_nvm(hw, offset, &len, &data, false); 5438c2ecf20Sopenharmony_ci if (status == ICE_ERR_AQ_ERROR && 5448c2ecf20Sopenharmony_ci hw->adminq.sq_last_status == ICE_AQ_RC_EINVAL) { 5458c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_NVM, 5468c2ecf20Sopenharmony_ci "%s: New upper bound of %u bytes\n", 5478c2ecf20Sopenharmony_ci __func__, offset); 5488c2ecf20Sopenharmony_ci status = 0; 5498c2ecf20Sopenharmony_ci max_size = offset; 5508c2ecf20Sopenharmony_ci } else if (!status) { 5518c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_NVM, 5528c2ecf20Sopenharmony_ci "%s: New lower bound of %u bytes\n", 5538c2ecf20Sopenharmony_ci __func__, offset); 5548c2ecf20Sopenharmony_ci min_size = offset; 5558c2ecf20Sopenharmony_ci } else { 5568c2ecf20Sopenharmony_ci /* an unexpected error occurred */ 5578c2ecf20Sopenharmony_ci goto err_read_flat_nvm; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_NVM, 5628c2ecf20Sopenharmony_ci "Predicted flash size is %u bytes\n", max_size); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci hw->nvm.flash_size = max_size; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cierr_read_flat_nvm: 5678c2ecf20Sopenharmony_ci ice_release_nvm(hw); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return status; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci/** 5738c2ecf20Sopenharmony_ci * ice_init_nvm - initializes NVM setting 5748c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 5758c2ecf20Sopenharmony_ci * 5768c2ecf20Sopenharmony_ci * This function reads and populates NVM settings such as Shadow RAM size, 5778c2ecf20Sopenharmony_ci * max_timeout, and blank_nvm_mode 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_cienum ice_status ice_init_nvm(struct ice_hw *hw) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct ice_nvm_info *nvm = &hw->nvm; 5828c2ecf20Sopenharmony_ci u16 eetrack_lo, eetrack_hi, ver; 5838c2ecf20Sopenharmony_ci enum ice_status status; 5848c2ecf20Sopenharmony_ci u32 fla, gens_stat; 5858c2ecf20Sopenharmony_ci u8 sr_size; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* The SR size is stored regardless of the NVM programming mode 5888c2ecf20Sopenharmony_ci * as the blank mode may be used in the factory line. 5898c2ecf20Sopenharmony_ci */ 5908c2ecf20Sopenharmony_ci gens_stat = rd32(hw, GLNVM_GENS); 5918c2ecf20Sopenharmony_ci sr_size = (gens_stat & GLNVM_GENS_SR_SIZE_M) >> GLNVM_GENS_SR_SIZE_S; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* Switching to words (sr_size contains power of 2) */ 5948c2ecf20Sopenharmony_ci nvm->sr_words = BIT(sr_size) * ICE_SR_WORDS_IN_1KB; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* Check if we are in the normal or blank NVM programming mode */ 5978c2ecf20Sopenharmony_ci fla = rd32(hw, GLNVM_FLA); 5988c2ecf20Sopenharmony_ci if (fla & GLNVM_FLA_LOCKED_M) { /* Normal programming mode */ 5998c2ecf20Sopenharmony_ci nvm->blank_nvm_mode = false; 6008c2ecf20Sopenharmony_ci } else { 6018c2ecf20Sopenharmony_ci /* Blank programming mode */ 6028c2ecf20Sopenharmony_ci nvm->blank_nvm_mode = true; 6038c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_NVM, 6048c2ecf20Sopenharmony_ci "NVM init error: unsupported blank mode.\n"); 6058c2ecf20Sopenharmony_ci return ICE_ERR_NVM_BLANK_MODE; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, ICE_SR_NVM_DEV_STARTER_VER, &ver); 6098c2ecf20Sopenharmony_ci if (status) { 6108c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, 6118c2ecf20Sopenharmony_ci "Failed to read DEV starter version.\n"); 6128c2ecf20Sopenharmony_ci return status; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci nvm->major_ver = (ver & ICE_NVM_VER_HI_MASK) >> ICE_NVM_VER_HI_SHIFT; 6158c2ecf20Sopenharmony_ci nvm->minor_ver = (ver & ICE_NVM_VER_LO_MASK) >> ICE_NVM_VER_LO_SHIFT; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_LO, &eetrack_lo); 6188c2ecf20Sopenharmony_ci if (status) { 6198c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK lo.\n"); 6208c2ecf20Sopenharmony_ci return status; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_HI, &eetrack_hi); 6238c2ecf20Sopenharmony_ci if (status) { 6248c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK hi.\n"); 6258c2ecf20Sopenharmony_ci return status; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci nvm->eetrack = (eetrack_hi << 16) | eetrack_lo; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci status = ice_discover_flash_size(hw); 6318c2ecf20Sopenharmony_ci if (status) { 6328c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_NVM, 6338c2ecf20Sopenharmony_ci "NVM init error: failed to discover flash size.\n"); 6348c2ecf20Sopenharmony_ci return status; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci switch (hw->device_id) { 6388c2ecf20Sopenharmony_ci /* the following devices do not have boot_cfg_tlv yet */ 6398c2ecf20Sopenharmony_ci case ICE_DEV_ID_E823C_BACKPLANE: 6408c2ecf20Sopenharmony_ci case ICE_DEV_ID_E823C_QSFP: 6418c2ecf20Sopenharmony_ci case ICE_DEV_ID_E823C_SFP: 6428c2ecf20Sopenharmony_ci case ICE_DEV_ID_E823C_10G_BASE_T: 6438c2ecf20Sopenharmony_ci case ICE_DEV_ID_E823C_SGMII: 6448c2ecf20Sopenharmony_ci case ICE_DEV_ID_E822C_BACKPLANE: 6458c2ecf20Sopenharmony_ci case ICE_DEV_ID_E822C_QSFP: 6468c2ecf20Sopenharmony_ci case ICE_DEV_ID_E822C_10G_BASE_T: 6478c2ecf20Sopenharmony_ci case ICE_DEV_ID_E822C_SGMII: 6488c2ecf20Sopenharmony_ci case ICE_DEV_ID_E822C_SFP: 6498c2ecf20Sopenharmony_ci case ICE_DEV_ID_E822L_BACKPLANE: 6508c2ecf20Sopenharmony_ci case ICE_DEV_ID_E822L_SFP: 6518c2ecf20Sopenharmony_ci case ICE_DEV_ID_E822L_10G_BASE_T: 6528c2ecf20Sopenharmony_ci case ICE_DEV_ID_E822L_SGMII: 6538c2ecf20Sopenharmony_ci case ICE_DEV_ID_E823L_BACKPLANE: 6548c2ecf20Sopenharmony_ci case ICE_DEV_ID_E823L_SFP: 6558c2ecf20Sopenharmony_ci case ICE_DEV_ID_E823L_10G_BASE_T: 6568c2ecf20Sopenharmony_ci case ICE_DEV_ID_E823L_1GBE: 6578c2ecf20Sopenharmony_ci case ICE_DEV_ID_E823L_QSFP: 6588c2ecf20Sopenharmony_ci return status; 6598c2ecf20Sopenharmony_ci default: 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci status = ice_get_orom_ver_info(hw); 6648c2ecf20Sopenharmony_ci if (status) { 6658c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read Option ROM info.\n"); 6668c2ecf20Sopenharmony_ci return status; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* read the netlist version information */ 6708c2ecf20Sopenharmony_ci status = ice_get_netlist_ver_info(hw); 6718c2ecf20Sopenharmony_ci if (status) 6728c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_INIT, "Failed to read netlist info.\n"); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci return 0; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci/** 6788c2ecf20Sopenharmony_ci * ice_nvm_validate_checksum 6798c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 6808c2ecf20Sopenharmony_ci * 6818c2ecf20Sopenharmony_ci * Verify NVM PFA checksum validity (0x0706) 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_cienum ice_status ice_nvm_validate_checksum(struct ice_hw *hw) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct ice_aqc_nvm_checksum *cmd; 6868c2ecf20Sopenharmony_ci struct ice_aq_desc desc; 6878c2ecf20Sopenharmony_ci enum ice_status status; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci status = ice_acquire_nvm(hw, ICE_RES_READ); 6908c2ecf20Sopenharmony_ci if (status) 6918c2ecf20Sopenharmony_ci return status; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci cmd = &desc.params.nvm_checksum; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_checksum); 6968c2ecf20Sopenharmony_ci cmd->flags = ICE_AQC_NVM_CHECKSUM_VERIFY; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 6998c2ecf20Sopenharmony_ci ice_release_nvm(hw); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (!status) 7028c2ecf20Sopenharmony_ci if (le16_to_cpu(cmd->checksum) != ICE_AQC_NVM_CHECKSUM_CORRECT) 7038c2ecf20Sopenharmony_ci status = ICE_ERR_NVM_CHECKSUM; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci return status; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci/** 7098c2ecf20Sopenharmony_ci * ice_nvm_write_activate 7108c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 7118c2ecf20Sopenharmony_ci * @cmd_flags: NVM activate admin command bits (banks to be validated) 7128c2ecf20Sopenharmony_ci * 7138c2ecf20Sopenharmony_ci * Update the control word with the required banks' validity bits 7148c2ecf20Sopenharmony_ci * and dumps the Shadow RAM to flash (0x0707) 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_cienum ice_status ice_nvm_write_activate(struct ice_hw *hw, u8 cmd_flags) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct ice_aqc_nvm *cmd; 7198c2ecf20Sopenharmony_ci struct ice_aq_desc desc; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci cmd = &desc.params.nvm; 7228c2ecf20Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_write_activate); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci cmd->cmd_flags = cmd_flags; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci/** 7308c2ecf20Sopenharmony_ci * ice_aq_nvm_update_empr 7318c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 7328c2ecf20Sopenharmony_ci * 7338c2ecf20Sopenharmony_ci * Update empr (0x0709). This command allows SW to 7348c2ecf20Sopenharmony_ci * request an EMPR to activate new FW. 7358c2ecf20Sopenharmony_ci */ 7368c2ecf20Sopenharmony_cienum ice_status ice_aq_nvm_update_empr(struct ice_hw *hw) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci struct ice_aq_desc desc; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_update_empr); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci/* ice_nvm_set_pkg_data 7468c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 7478c2ecf20Sopenharmony_ci * @del_pkg_data_flag: If is set then the current pkg_data store by FW 7488c2ecf20Sopenharmony_ci * is deleted. 7498c2ecf20Sopenharmony_ci * If bit is set to 1, then buffer should be size 0. 7508c2ecf20Sopenharmony_ci * @data: pointer to buffer 7518c2ecf20Sopenharmony_ci * @length: length of the buffer 7528c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL 7538c2ecf20Sopenharmony_ci * 7548c2ecf20Sopenharmony_ci * Set package data (0x070A). This command is equivalent to the reception 7558c2ecf20Sopenharmony_ci * of a PLDM FW Update GetPackageData cmd. This command should be sent 7568c2ecf20Sopenharmony_ci * as part of the NVM update as the first cmd in the flow. 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_cienum ice_status 7608c2ecf20Sopenharmony_ciice_nvm_set_pkg_data(struct ice_hw *hw, bool del_pkg_data_flag, u8 *data, 7618c2ecf20Sopenharmony_ci u16 length, struct ice_sq_cd *cd) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct ice_aqc_nvm_pkg_data *cmd; 7648c2ecf20Sopenharmony_ci struct ice_aq_desc desc; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (length != 0 && !data) 7678c2ecf20Sopenharmony_ci return ICE_ERR_PARAM; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci cmd = &desc.params.pkg_data; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_pkg_data); 7728c2ecf20Sopenharmony_ci desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (del_pkg_data_flag) 7758c2ecf20Sopenharmony_ci cmd->cmd_flags |= ICE_AQC_NVM_PKG_DELETE; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci return ice_aq_send_cmd(hw, &desc, data, length, cd); 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci/* ice_nvm_pass_component_tbl 7818c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 7828c2ecf20Sopenharmony_ci * @data: pointer to buffer 7838c2ecf20Sopenharmony_ci * @length: length of the buffer 7848c2ecf20Sopenharmony_ci * @transfer_flag: parameter for determining stage of the update 7858c2ecf20Sopenharmony_ci * @comp_response: a pointer to the response from the 0x070B AQC. 7868c2ecf20Sopenharmony_ci * @comp_response_code: a pointer to the response code from the 0x070B AQC. 7878c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL 7888c2ecf20Sopenharmony_ci * 7898c2ecf20Sopenharmony_ci * Pass component table (0x070B). This command is equivalent to the reception 7908c2ecf20Sopenharmony_ci * of a PLDM FW Update PassComponentTable cmd. This command should be sent once 7918c2ecf20Sopenharmony_ci * per component. It can be only sent after Set Package Data cmd and before 7928c2ecf20Sopenharmony_ci * actual update. FW will assume these commands are going to be sent until 7938c2ecf20Sopenharmony_ci * the TransferFlag is set to End or StartAndEnd. 7948c2ecf20Sopenharmony_ci */ 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cienum ice_status 7978c2ecf20Sopenharmony_ciice_nvm_pass_component_tbl(struct ice_hw *hw, u8 *data, u16 length, 7988c2ecf20Sopenharmony_ci u8 transfer_flag, u8 *comp_response, 7998c2ecf20Sopenharmony_ci u8 *comp_response_code, struct ice_sq_cd *cd) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct ice_aqc_nvm_pass_comp_tbl *cmd; 8028c2ecf20Sopenharmony_ci struct ice_aq_desc desc; 8038c2ecf20Sopenharmony_ci enum ice_status status; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (!data || !comp_response || !comp_response_code) 8068c2ecf20Sopenharmony_ci return ICE_ERR_PARAM; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci cmd = &desc.params.pass_comp_tbl; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci ice_fill_dflt_direct_cmd_desc(&desc, 8118c2ecf20Sopenharmony_ci ice_aqc_opc_nvm_pass_component_tbl); 8128c2ecf20Sopenharmony_ci desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci cmd->transfer_flag = transfer_flag; 8158c2ecf20Sopenharmony_ci status = ice_aq_send_cmd(hw, &desc, data, length, cd); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (!status) { 8188c2ecf20Sopenharmony_ci *comp_response = cmd->component_response; 8198c2ecf20Sopenharmony_ci *comp_response_code = cmd->component_response_code; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci return status; 8228c2ecf20Sopenharmony_ci} 823