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