Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ice/ice_nvm.c
Show First 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
* @hw: pointer to the HW struct | * @hw: pointer to the HW struct | ||||
* @offset: offset from beginning of NVM | * @offset: offset from beginning of NVM | ||||
* @length: (in) number of bytes to read; (out) number of bytes actually read | * @length: (in) number of bytes to read; (out) number of bytes actually read | ||||
* @data: buffer to return data in (sized to fit the specified length) | * @data: buffer to return data in (sized to fit the specified length) | ||||
* @read_shadow_ram: if true, read from shadow RAM instead of NVM | * @read_shadow_ram: if true, read from shadow RAM instead of NVM | ||||
* | * | ||||
* Reads a portion of the NVM, as a flat memory space. This function correctly | * Reads a portion of the NVM, as a flat memory space. This function correctly | ||||
* breaks read requests across Shadow RAM sectors and ensures that no single | * breaks read requests across Shadow RAM sectors and ensures that no single | ||||
* read request exceeds the maximum 4Kb read for a single AdminQ command. | * read request exceeds the maximum 4KB read for a single AdminQ command. | ||||
* | * | ||||
* Returns a status code on failure. Note that the data pointer may be | * Returns a status code on failure. Note that the data pointer may be | ||||
* partially updated if some reads succeed before a failure. | * partially updated if some reads succeed before a failure. | ||||
*/ | */ | ||||
enum ice_status | enum ice_status | ||||
ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data, | ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data, | ||||
bool read_shadow_ram) | bool read_shadow_ram) | ||||
{ | { | ||||
enum ice_status status; | enum ice_status status; | ||||
u32 inlen = *length; | u32 inlen = *length; | ||||
u32 bytes_read = 0; | u32 bytes_read = 0; | ||||
bool last_cmd; | bool last_cmd; | ||||
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); | ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); | ||||
*length = 0; | *length = 0; | ||||
/* Verify the length of the read if this is for the Shadow RAM */ | /* Verify the length of the read if this is for the Shadow RAM */ | ||||
if (read_shadow_ram && ((offset + inlen) > (hw->nvm.sr_words * 2u))) { | if (read_shadow_ram && ((offset + inlen) > (hw->nvm.sr_words * 2u))) { | ||||
ice_debug(hw, ICE_DBG_NVM, | ice_debug(hw, ICE_DBG_NVM, "NVM error: requested data is beyond Shadow RAM limit\n"); | ||||
"NVM error: requested data is beyond Shadow RAM limit\n"); | |||||
return ICE_ERR_PARAM; | return ICE_ERR_PARAM; | ||||
} | } | ||||
do { | do { | ||||
u32 read_size, sector_offset; | u32 read_size, sector_offset; | ||||
/* ice_aq_read_nvm cannot read more than 4Kb at a time. | /* ice_aq_read_nvm cannot read more than 4KB at a time. | ||||
* Additionally, a read from the Shadow RAM may not cross over | * Additionally, a read from the Shadow RAM may not cross over | ||||
* a sector boundary. Conveniently, the sector size is also | * a sector boundary. Conveniently, the sector size is also | ||||
* 4Kb. | * 4KB. | ||||
*/ | */ | ||||
sector_offset = offset % ICE_AQ_MAX_BUF_LEN; | sector_offset = offset % ICE_AQ_MAX_BUF_LEN; | ||||
read_size = MIN_T(u32, ICE_AQ_MAX_BUF_LEN - sector_offset, | read_size = MIN_T(u32, ICE_AQ_MAX_BUF_LEN - sector_offset, | ||||
inlen - bytes_read); | inlen - bytes_read); | ||||
last_cmd = !(bytes_read + read_size < inlen); | last_cmd = !(bytes_read + read_size < inlen); | ||||
/* ice_aq_read_nvm takes the length as a u16. Our read_size is | /* ice_aq_read_nvm takes the length as a u16. Our read_size is | ||||
Show All 23 Lines | |||||
* @length: length of the section to be written (in bytes from the offset) | * @length: length of the section to be written (in bytes from the offset) | ||||
* @data: command buffer (size [bytes] = length) | * @data: command buffer (size [bytes] = length) | ||||
* @last_command: tells if this is the last command in a series | * @last_command: tells if this is the last command in a series | ||||
* @command_flags: command parameters | * @command_flags: command parameters | ||||
* @cd: pointer to command details structure or NULL | * @cd: pointer to command details structure or NULL | ||||
* | * | ||||
* Update the NVM using the admin queue commands (0x0703) | * Update the NVM using the admin queue commands (0x0703) | ||||
*/ | */ | ||||
static enum ice_status | enum ice_status | ||||
ice_aq_update_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, | ice_aq_update_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, | ||||
u16 length, void *data, bool last_command, u8 command_flags, | u16 length, void *data, bool last_command, u8 command_flags, | ||||
struct ice_sq_cd *cd) | struct ice_sq_cd *cd) | ||||
{ | { | ||||
struct ice_aq_desc desc; | struct ice_aq_desc desc; | ||||
struct ice_aqc_nvm *cmd; | struct ice_aqc_nvm *cmd; | ||||
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); | ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); | ||||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | |||||
* @hw: pointer to the HW structure | * @hw: pointer to the HW structure | ||||
* @offset: offset in words from module start | * @offset: offset in words from module start | ||||
* @words: number of words to access | * @words: number of words to access | ||||
*/ | */ | ||||
static enum ice_status | static enum ice_status | ||||
ice_check_sr_access_params(struct ice_hw *hw, u32 offset, u16 words) | ice_check_sr_access_params(struct ice_hw *hw, u32 offset, u16 words) | ||||
{ | { | ||||
if ((offset + words) > hw->nvm.sr_words) { | if ((offset + words) > hw->nvm.sr_words) { | ||||
ice_debug(hw, ICE_DBG_NVM, | ice_debug(hw, ICE_DBG_NVM, "NVM error: offset beyond SR lmt.\n"); | ||||
"NVM error: offset beyond SR lmt.\n"); | |||||
return ICE_ERR_PARAM; | return ICE_ERR_PARAM; | ||||
} | } | ||||
if (words > ICE_SR_SECTOR_SIZE_IN_WORDS) { | if (words > ICE_SR_SECTOR_SIZE_IN_WORDS) { | ||||
/* We can access only up to 4KB (one sector), in one AQ write */ | /* We can access only up to 4KB (one sector), in one AQ write */ | ||||
ice_debug(hw, ICE_DBG_NVM, | ice_debug(hw, ICE_DBG_NVM, "NVM error: tried to access %d words, limit is %d.\n", | ||||
"NVM error: tried to access %d words, limit is %d.\n", | |||||
words, ICE_SR_SECTOR_SIZE_IN_WORDS); | words, ICE_SR_SECTOR_SIZE_IN_WORDS); | ||||
return ICE_ERR_PARAM; | return ICE_ERR_PARAM; | ||||
} | } | ||||
if (((offset + (words - 1)) / ICE_SR_SECTOR_SIZE_IN_WORDS) != | if (((offset + (words - 1)) / ICE_SR_SECTOR_SIZE_IN_WORDS) != | ||||
(offset / ICE_SR_SECTOR_SIZE_IN_WORDS)) { | (offset / ICE_SR_SECTOR_SIZE_IN_WORDS)) { | ||||
/* A single access cannot spread over two sectors */ | /* A single access cannot spread over two sectors */ | ||||
ice_debug(hw, ICE_DBG_NVM, | ice_debug(hw, ICE_DBG_NVM, "NVM error: cannot spread over two sectors.\n"); | ||||
"NVM error: cannot spread over two sectors.\n"); | |||||
return ICE_ERR_PARAM; | return ICE_ERR_PARAM; | ||||
} | } | ||||
return ICE_SUCCESS; | return ICE_SUCCESS; | ||||
} | } | ||||
/** | /** | ||||
* ice_read_sr_word_aq - Reads Shadow RAM via AQ | * ice_read_sr_word_aq - Reads Shadow RAM via AQ | ||||
* @hw: pointer to the HW structure | * @hw: pointer to the HW structure | ||||
* @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) | * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) | ||||
* @data: word read from the Shadow RAM | * @data: word read from the Shadow RAM | ||||
* | * | ||||
* Reads one 16 bit word from the Shadow RAM using ice_read_flat_nvm. | * Reads one 16 bit word from the Shadow RAM using ice_read_flat_nvm. | ||||
*/ | */ | ||||
enum ice_status | enum ice_status ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data) | ||||
ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data) | |||||
{ | { | ||||
u32 bytes = sizeof(u16); | u32 bytes = sizeof(u16); | ||||
enum ice_status status; | enum ice_status status; | ||||
__le16 data_local; | __le16 data_local; | ||||
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); | ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); | ||||
/* Note that ice_read_flat_nvm checks if the read is past the Shadow | /* Note that ice_read_flat_nvm checks if the read is past the Shadow | ||||
* RAM size, and ensures we don't read across a Shadow RAM sector | * RAM size, and ensures we don't read across a Shadow RAM sector | ||||
* boundary | * boundary | ||||
*/ | */ | ||||
status = ice_read_flat_nvm(hw, offset * sizeof(u16), &bytes, | status = ice_read_flat_nvm(hw, offset * sizeof(u16), &bytes, | ||||
(u8 *)&data_local, true); | (_FORCE_ u8 *)&data_local, true); | ||||
if (status) | if (status) | ||||
return status; | return status; | ||||
*data = LE16_TO_CPU(data_local); | *data = LE16_TO_CPU(data_local); | ||||
return ICE_SUCCESS; | return ICE_SUCCESS; | ||||
} | } | ||||
/** | /** | ||||
Show All 35 Lines | |||||
static enum ice_status | static enum ice_status | ||||
ice_read_sr_buf_aq(struct ice_hw *hw, u16 offset, u16 *words, u16 *data) | ice_read_sr_buf_aq(struct ice_hw *hw, u16 offset, u16 *words, u16 *data) | ||||
{ | { | ||||
u32 bytes = *words * 2, i; | u32 bytes = *words * 2, i; | ||||
enum ice_status status; | enum ice_status status; | ||||
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); | ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); | ||||
/* ice_read_flat_nvm takes into account the 4Kb AdminQ and Shadow RAM | /* ice_read_flat_nvm takes into account the 4KB AdminQ and Shadow RAM | ||||
* sector restrictions necessary when reading from the NVM. | * sector restrictions necessary when reading from the NVM. | ||||
*/ | */ | ||||
status = ice_read_flat_nvm(hw, offset * 2, &bytes, (u8 *)data, true); | status = ice_read_flat_nvm(hw, offset * 2, &bytes, (u8 *)data, true); | ||||
/* Report the number of words successfully read */ | /* Report the number of words successfully read */ | ||||
*words = bytes / 2; | *words = bytes / 2; | ||||
/* Byte swap the words up to the amount we actually read */ | /* Byte swap the words up to the amount we actually read */ | ||||
▲ Show 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | if (pba_tlv_len < pba_size) { | ||||
return ICE_ERR_INVAL_SIZE; | return ICE_ERR_INVAL_SIZE; | ||||
} | } | ||||
/* Subtract one to get PBA word count (PBA Size word is included in | /* Subtract one to get PBA word count (PBA Size word is included in | ||||
* total size) | * total size) | ||||
*/ | */ | ||||
pba_size--; | pba_size--; | ||||
if (pba_num_size < (((u32)pba_size * 2) + 1)) { | if (pba_num_size < (((u32)pba_size * 2) + 1)) { | ||||
ice_debug(hw, ICE_DBG_INIT, | ice_debug(hw, ICE_DBG_INIT, "Buffer too small for PBA data.\n"); | ||||
"Buffer too small for PBA data.\n"); | |||||
return ICE_ERR_PARAM; | return ICE_ERR_PARAM; | ||||
} | } | ||||
for (i = 0; i < pba_size; i++) { | for (i = 0; i < pba_size; i++) { | ||||
status = ice_read_sr_word(hw, (pba_tlv + 2 + 1) + i, &pba_word); | status = ice_read_sr_word(hw, (pba_tlv + 2 + 1) + i, &pba_word); | ||||
if (status != ICE_SUCCESS) { | if (status != ICE_SUCCESS) { | ||||
ice_debug(hw, ICE_DBG_INIT, | ice_debug(hw, ICE_DBG_INIT, "Failed to read PBA Block word %d.\n", i); | ||||
"Failed to read PBA Block word %d.\n", i); | |||||
return status; | return status; | ||||
} | } | ||||
pba_num[(i * 2)] = (pba_word >> 8) & 0xFF; | pba_num[(i * 2)] = (pba_word >> 8) & 0xFF; | ||||
pba_num[(i * 2) + 1] = pba_word & 0xFF; | pba_num[(i * 2) + 1] = pba_word & 0xFF; | ||||
} | } | ||||
pba_num[(pba_size * 2)] = '\0'; | pba_num[(pba_size * 2)] = '\0'; | ||||
Show All 12 Lines | static enum ice_status ice_get_orom_ver_info(struct ice_hw *hw) | ||||
u16 combo_hi, combo_lo, boot_cfg_tlv, boot_cfg_tlv_len; | u16 combo_hi, combo_lo, boot_cfg_tlv, boot_cfg_tlv_len; | ||||
struct ice_orom_info *orom = &hw->nvm.orom; | struct ice_orom_info *orom = &hw->nvm.orom; | ||||
enum ice_status status; | enum ice_status status; | ||||
u32 combo_ver; | u32 combo_ver; | ||||
status = ice_get_pfa_module_tlv(hw, &boot_cfg_tlv, &boot_cfg_tlv_len, | status = ice_get_pfa_module_tlv(hw, &boot_cfg_tlv, &boot_cfg_tlv_len, | ||||
ICE_SR_BOOT_CFG_PTR); | ICE_SR_BOOT_CFG_PTR); | ||||
if (status) { | if (status) { | ||||
ice_debug(hw, ICE_DBG_INIT, | ice_debug(hw, ICE_DBG_INIT, "Failed to read Boot Configuration Block TLV.\n"); | ||||
"Failed to read Boot Configuration Block TLV.\n"); | |||||
return status; | return status; | ||||
} | } | ||||
/* Boot Configuration Block must have length at least 2 words | /* Boot Configuration Block must have length at least 2 words | ||||
* (Combo Image Version High and Combo Image Version Low) | * (Combo Image Version High and Combo Image Version Low) | ||||
*/ | */ | ||||
if (boot_cfg_tlv_len < 2) { | if (boot_cfg_tlv_len < 2) { | ||||
ice_debug(hw, ICE_DBG_INIT, | ice_debug(hw, ICE_DBG_INIT, "Invalid Boot Configuration Block TLV size.\n"); | ||||
"Invalid Boot Configuration Block TLV size.\n"); | |||||
return ICE_ERR_INVAL_SIZE; | return ICE_ERR_INVAL_SIZE; | ||||
} | } | ||||
status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OROM_VER_OFF), | status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OROM_VER_OFF), | ||||
&combo_hi); | &combo_hi); | ||||
if (status) { | if (status) { | ||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read OROM_VER hi.\n"); | ice_debug(hw, ICE_DBG_INIT, "Failed to read OROM_VER hi.\n"); | ||||
return status; | return status; | ||||
Show All 13 Lines | static enum ice_status ice_get_orom_ver_info(struct ice_hw *hw) | ||||
orom->patch = (u8)(combo_ver & ICE_OROM_VER_PATCH_MASK); | orom->patch = (u8)(combo_ver & ICE_OROM_VER_PATCH_MASK); | ||||
orom->build = (u16)((combo_ver & ICE_OROM_VER_BUILD_MASK) >> | orom->build = (u16)((combo_ver & ICE_OROM_VER_BUILD_MASK) >> | ||||
ICE_OROM_VER_BUILD_SHIFT); | ICE_OROM_VER_BUILD_SHIFT); | ||||
return ICE_SUCCESS; | return ICE_SUCCESS; | ||||
} | } | ||||
/** | /** | ||||
* ice_get_netlist_ver_info | |||||
* @hw: pointer to the HW struct | |||||
* | |||||
* Get the netlist version information | |||||
*/ | |||||
enum ice_status ice_get_netlist_ver_info(struct ice_hw *hw) | |||||
{ | |||||
struct ice_netlist_ver_info *ver = &hw->netlist_ver; | |||||
enum ice_status ret; | |||||
u32 id_blk_start; | |||||
__le16 raw_data; | |||||
u16 data, i; | |||||
u16 *buff; | |||||
ret = ice_acquire_nvm(hw, ICE_RES_READ); | |||||
if (ret) | |||||
return ret; | |||||
buff = (u16 *)ice_calloc(hw, ICE_AQC_NVM_NETLIST_ID_BLK_LEN, | |||||
sizeof(*buff)); | |||||
if (!buff) { | |||||
ret = ICE_ERR_NO_MEMORY; | |||||
goto exit_no_mem; | |||||
} | |||||
/* read module length */ | |||||
ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID, | |||||
ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN_OFFSET * 2, | |||||
ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN, &raw_data, | |||||
false, false, NULL); | |||||
if (ret) | |||||
goto exit_error; | |||||
data = LE16_TO_CPU(raw_data); | |||||
/* exit if length is = 0 */ | |||||
if (!data) | |||||
goto exit_error; | |||||
/* read node count */ | |||||
ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID, | |||||
ICE_AQC_NVM_NETLIST_NODE_COUNT_OFFSET * 2, | |||||
ICE_AQC_NVM_NETLIST_NODE_COUNT_LEN, &raw_data, | |||||
false, false, NULL); | |||||
if (ret) | |||||
goto exit_error; | |||||
data = LE16_TO_CPU(raw_data) & ICE_AQC_NVM_NETLIST_NODE_COUNT_M; | |||||
/* netlist ID block starts from offset 4 + node count * 2 */ | |||||
id_blk_start = ICE_AQC_NVM_NETLIST_ID_BLK_START_OFFSET + data * 2; | |||||
/* read the entire netlist ID block */ | |||||
ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID, | |||||
id_blk_start * 2, | |||||
ICE_AQC_NVM_NETLIST_ID_BLK_LEN * 2, buff, false, | |||||
false, NULL); | |||||
if (ret) | |||||
goto exit_error; | |||||
for (i = 0; i < ICE_AQC_NVM_NETLIST_ID_BLK_LEN; i++) | |||||
buff[i] = LE16_TO_CPU(((_FORCE_ __le16 *)buff)[i]); | |||||
ver->major = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_HIGH] << 16) | | |||||
buff[ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_LOW]; | |||||
ver->minor = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_HIGH] << 16) | | |||||
buff[ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_LOW]; | |||||
ver->type = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_HIGH] << 16) | | |||||
buff[ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_LOW]; | |||||
ver->rev = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_REV_HIGH] << 16) | | |||||
buff[ICE_AQC_NVM_NETLIST_ID_BLK_REV_LOW]; | |||||
ver->cust_ver = buff[ICE_AQC_NVM_NETLIST_ID_BLK_CUST_VER]; | |||||
/* Read the left most 4 bytes of SHA */ | |||||
ver->hash = buff[ICE_AQC_NVM_NETLIST_ID_BLK_SHA_HASH + 15] << 16 | | |||||
buff[ICE_AQC_NVM_NETLIST_ID_BLK_SHA_HASH + 14]; | |||||
exit_error: | |||||
ice_free(hw, buff); | |||||
exit_no_mem: | |||||
ice_release_nvm(hw); | |||||
return ret; | |||||
} | |||||
/** | |||||
* ice_discover_flash_size - Discover the available flash size. | * ice_discover_flash_size - Discover the available flash size. | ||||
* @hw: pointer to the HW struct | * @hw: pointer to the HW struct | ||||
* | * | ||||
* The device flash could be up to 16MB in size. However, it is possible that | * The device flash could be up to 16MB in size. However, it is possible that | ||||
* the actual size is smaller. Use bisection to determine the accessible size | * the actual size is smaller. Use bisection to determine the accessible size | ||||
* of flash memory. | * of flash memory. | ||||
*/ | */ | ||||
static enum ice_status ice_discover_flash_size(struct ice_hw *hw) | static enum ice_status ice_discover_flash_size(struct ice_hw *hw) | ||||
Show All 10 Lines | static enum ice_status ice_discover_flash_size(struct ice_hw *hw) | ||||
while ((max_size - min_size) > 1) { | while ((max_size - min_size) > 1) { | ||||
u32 offset = (max_size + min_size) / 2; | u32 offset = (max_size + min_size) / 2; | ||||
u32 len = 1; | u32 len = 1; | ||||
u8 data; | u8 data; | ||||
status = ice_read_flat_nvm(hw, offset, &len, &data, false); | status = ice_read_flat_nvm(hw, offset, &len, &data, false); | ||||
if (status == ICE_ERR_AQ_ERROR && | if (status == ICE_ERR_AQ_ERROR && | ||||
hw->adminq.sq_last_status == ICE_AQ_RC_EINVAL) { | hw->adminq.sq_last_status == ICE_AQ_RC_EINVAL) { | ||||
ice_debug(hw, ICE_DBG_NVM, | ice_debug(hw, ICE_DBG_NVM, "%s: New upper bound of %u bytes\n", | ||||
"%s: New upper bound of %u bytes\n", | |||||
__func__, offset); | __func__, offset); | ||||
status = ICE_SUCCESS; | status = ICE_SUCCESS; | ||||
max_size = offset; | max_size = offset; | ||||
} else if (!status) { | } else if (!status) { | ||||
ice_debug(hw, ICE_DBG_NVM, | ice_debug(hw, ICE_DBG_NVM, "%s: New lower bound of %u bytes\n", | ||||
"%s: New lower bound of %u bytes\n", | |||||
__func__, offset); | __func__, offset); | ||||
min_size = offset; | min_size = offset; | ||||
} else { | } else { | ||||
/* an unexpected error occurred */ | /* an unexpected error occurred */ | ||||
goto err_read_flat_nvm; | goto err_read_flat_nvm; | ||||
} | } | ||||
} | } | ||||
ice_debug(hw, ICE_DBG_NVM, | ice_debug(hw, ICE_DBG_NVM, "Predicted flash size is %u bytes\n", max_size); | ||||
"Predicted flash size is %u bytes\n", max_size); | |||||
hw->nvm.flash_size = max_size; | hw->nvm.flash_size = max_size; | ||||
err_read_flat_nvm: | err_read_flat_nvm: | ||||
ice_release_nvm(hw); | ice_release_nvm(hw); | ||||
return status; | return status; | ||||
} | } | ||||
Show All 26 Lines | enum ice_status ice_init_nvm(struct ice_hw *hw) | ||||
/* Check if we are in the normal or blank NVM programming mode */ | /* Check if we are in the normal or blank NVM programming mode */ | ||||
fla = rd32(hw, GLNVM_FLA); | fla = rd32(hw, GLNVM_FLA); | ||||
if (fla & GLNVM_FLA_LOCKED_M) { /* Normal programming mode */ | if (fla & GLNVM_FLA_LOCKED_M) { /* Normal programming mode */ | ||||
nvm->blank_nvm_mode = false; | nvm->blank_nvm_mode = false; | ||||
} else { | } else { | ||||
/* Blank programming mode */ | /* Blank programming mode */ | ||||
nvm->blank_nvm_mode = true; | nvm->blank_nvm_mode = true; | ||||
ice_debug(hw, ICE_DBG_NVM, | ice_debug(hw, ICE_DBG_NVM, "NVM init error: unsupported blank mode.\n"); | ||||
"NVM init error: unsupported blank mode.\n"); | |||||
return ICE_ERR_NVM_BLANK_MODE; | return ICE_ERR_NVM_BLANK_MODE; | ||||
} | } | ||||
status = ice_read_sr_word(hw, ICE_SR_NVM_DEV_STARTER_VER, &ver); | status = ice_read_sr_word(hw, ICE_SR_NVM_DEV_STARTER_VER, &ver); | ||||
if (status) { | if (status) { | ||||
ice_debug(hw, ICE_DBG_INIT, | ice_debug(hw, ICE_DBG_INIT, "Failed to read DEV starter version.\n"); | ||||
"Failed to read DEV starter version.\n"); | |||||
return status; | return status; | ||||
} | } | ||||
nvm->major_ver = (ver & ICE_NVM_VER_HI_MASK) >> ICE_NVM_VER_HI_SHIFT; | nvm->major_ver = (ver & ICE_NVM_VER_HI_MASK) >> ICE_NVM_VER_HI_SHIFT; | ||||
nvm->minor_ver = (ver & ICE_NVM_VER_LO_MASK) >> ICE_NVM_VER_LO_SHIFT; | nvm->minor_ver = (ver & ICE_NVM_VER_LO_MASK) >> ICE_NVM_VER_LO_SHIFT; | ||||
status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_LO, &eetrack_lo); | status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_LO, &eetrack_lo); | ||||
if (status) { | if (status) { | ||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK lo.\n"); | ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK lo.\n"); | ||||
return status; | return status; | ||||
} | } | ||||
status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_HI, &eetrack_hi); | status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_HI, &eetrack_hi); | ||||
if (status) { | if (status) { | ||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK hi.\n"); | ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK hi.\n"); | ||||
return status; | return status; | ||||
} | } | ||||
nvm->eetrack = (eetrack_hi << 16) | eetrack_lo; | nvm->eetrack = (eetrack_hi << 16) | eetrack_lo; | ||||
status = ice_discover_flash_size(hw); | status = ice_discover_flash_size(hw); | ||||
if (status) { | if (status) { | ||||
ice_debug(hw, ICE_DBG_NVM, | ice_debug(hw, ICE_DBG_NVM, "NVM init error: failed to discover flash size.\n"); | ||||
"NVM init error: failed to discover flash size.\n"); | |||||
return status; | return status; | ||||
} | } | ||||
switch (hw->device_id) { | |||||
/* the following devices do not have boot_cfg_tlv yet */ | |||||
case ICE_DEV_ID_E822C_BACKPLANE: | |||||
case ICE_DEV_ID_E822C_QSFP: | |||||
case ICE_DEV_ID_E822C_10G_BASE_T: | |||||
case ICE_DEV_ID_E822C_SGMII: | |||||
case ICE_DEV_ID_E822C_SFP: | |||||
case ICE_DEV_ID_E822L_BACKPLANE: | |||||
case ICE_DEV_ID_E822L_SFP: | |||||
case ICE_DEV_ID_E822L_10G_BASE_T: | |||||
case ICE_DEV_ID_E822L_SGMII: | |||||
case ICE_DEV_ID_E823L_BACKPLANE: | |||||
case ICE_DEV_ID_E823L_SFP: | |||||
case ICE_DEV_ID_E823L_10G_BASE_T: | |||||
case ICE_DEV_ID_E823L_1GBE: | |||||
case ICE_DEV_ID_E823L_QSFP: | |||||
return status; | |||||
default: | |||||
break; | |||||
} | |||||
status = ice_get_orom_ver_info(hw); | status = ice_get_orom_ver_info(hw); | ||||
if (status) { | if (status) { | ||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read Option ROM info.\n"); | ice_debug(hw, ICE_DBG_INIT, "Failed to read Option ROM info.\n"); | ||||
return status; | return status; | ||||
} | } | ||||
/* read the netlist version information */ | /* read the netlist version information */ | ||||
status = ice_get_netlist_ver_info(hw); | status = ice_get_netlist_ver_info(hw); | ||||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | if ((i % ICE_SR_SECTOR_SIZE_IN_WORDS) == 0) { | ||||
if (status != ICE_SUCCESS) | if (status != ICE_SUCCESS) | ||||
goto ice_calc_sr_checksum_exit; | goto ice_calc_sr_checksum_exit; | ||||
} | } | ||||
/* Skip Checksum word */ | /* Skip Checksum word */ | ||||
if (i == ICE_SR_SW_CHECKSUM_WORD) | if (i == ICE_SR_SW_CHECKSUM_WORD) | ||||
continue; | continue; | ||||
/* Skip VPD module (convert byte size to word count) */ | /* Skip VPD module (convert byte size to word count) */ | ||||
if ((i >= (u32)vpd_module) && | if (i >= (u32)vpd_module && | ||||
(i < ((u32)vpd_module + ICE_SR_VPD_SIZE_WORDS))) | i < ((u32)vpd_module + ICE_SR_VPD_SIZE_WORDS)) | ||||
continue; | continue; | ||||
/* Skip PCIe ALT module (convert byte size to word count) */ | /* Skip PCIe ALT module (convert byte size to word count) */ | ||||
if ((i >= (u32)pcie_alt_module) && | if (i >= (u32)pcie_alt_module && | ||||
(i < ((u32)pcie_alt_module + ICE_SR_PCIE_ALT_SIZE_WORDS))) | i < ((u32)pcie_alt_module + ICE_SR_PCIE_ALT_SIZE_WORDS)) | ||||
continue; | continue; | ||||
checksum_local += data[i % ICE_SR_SECTOR_SIZE_IN_WORDS]; | checksum_local += data[i % ICE_SR_SECTOR_SIZE_IN_WORDS]; | ||||
} | } | ||||
*checksum = (u16)ICE_SR_SW_CHECKSUM_BASE - checksum_local; | *checksum = (u16)ICE_SR_SW_CHECKSUM_BASE - checksum_local; | ||||
ice_calc_sr_checksum_exit: | ice_calc_sr_checksum_exit: | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | |||||
* features structure. | * features structure. | ||||
*/ | */ | ||||
enum ice_status | enum ice_status | ||||
ice_nvm_access_get_features(struct ice_nvm_access_cmd *cmd, | ice_nvm_access_get_features(struct ice_nvm_access_cmd *cmd, | ||||
union ice_nvm_access_data *data) | union ice_nvm_access_data *data) | ||||
{ | { | ||||
/* The provided data_size must be at least as large as our NVM | /* The provided data_size must be at least as large as our NVM | ||||
* features structure. A larger size should not be treated as an | * features structure. A larger size should not be treated as an | ||||
* error, to allow future extensions to to the features structure to | * error, to allow future extensions to the features structure to | ||||
* work on older drivers. | * work on older drivers. | ||||
*/ | */ | ||||
if (cmd->data_size < sizeof(struct ice_nvm_features)) | if (cmd->data_size < sizeof(struct ice_nvm_features)) | ||||
return ICE_ERR_NO_MEMORY; | return ICE_ERR_NO_MEMORY; | ||||
/* Initialize the data buffer to zeros */ | /* Initialize the data buffer to zeros */ | ||||
ice_memset(data, 0, cmd->data_size, ICE_NONDMA_MEM); | ice_memset(data, 0, cmd->data_size, ICE_NONDMA_MEM); | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | ice_nvm_access_write(struct ice_hw *hw, struct ice_nvm_access_cmd *cmd, | ||||
switch (cmd->offset) { | switch (cmd->offset) { | ||||
case GL_HICR_EN: | case GL_HICR_EN: | ||||
case GLGEN_RSTAT: | case GLGEN_RSTAT: | ||||
return ICE_ERR_OUT_OF_RANGE; | return ICE_ERR_OUT_OF_RANGE; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
ice_debug(hw, ICE_DBG_NVM, | ice_debug(hw, ICE_DBG_NVM, "NVM access: writing register %08x with value %08x\n", | ||||
"NVM access: writing register %08x with value %08x\n", | |||||
cmd->offset, data->regval); | cmd->offset, data->regval); | ||||
/* Write the data field to the specified register */ | /* Write the data field to the specified register */ | ||||
wr32(hw, cmd->offset, data->regval); | wr32(hw, cmd->offset, data->regval); | ||||
return ICE_SUCCESS; | return ICE_SUCCESS; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 52 Lines • Show Last 20 Lines |