#include "ice_common.h"
#define GL_MNG_DEF_DEVID 0x000B611C
int
ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, u16 length,
void *data, bool last_command, bool read_shadow_ram,
struct ice_sq_cd *cd)
{
struct ice_aq_desc desc;
struct ice_aqc_nvm *cmd;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
cmd = &desc.params.nvm;
if (offset > ICE_AQC_NVM_MAX_OFFSET)
return ICE_ERR_PARAM;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_read);
if (!read_shadow_ram && module_typeid == ICE_AQC_NVM_START_POINT)
cmd->cmd_flags |= ICE_AQC_NVM_FLASH_ONLY;
if (last_command)
cmd->cmd_flags |= ICE_AQC_NVM_LAST_CMD;
cmd->module_typeid = CPU_TO_LE16(module_typeid);
cmd->offset_low = CPU_TO_LE16(offset & 0xFFFF);
cmd->offset_high = (offset >> 16) & 0xFF;
cmd->length = CPU_TO_LE16(length);
return ice_aq_send_cmd(hw, &desc, data, length, cd);
}
int
ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
bool read_shadow_ram)
{
u32 inlen = *length;
u32 bytes_read = 0;
bool last_cmd;
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
*length = 0;
if (read_shadow_ram && ((offset + inlen) > (hw->flash.sr_words * 2u))) {
ice_debug(hw, ICE_DBG_NVM, "NVM error: requested data is beyond Shadow RAM limit\n");
return ICE_ERR_PARAM;
}
do {
u32 read_size, sector_offset;
sector_offset = offset % ICE_AQ_MAX_BUF_LEN;
read_size = MIN_T(u32, ICE_AQ_MAX_BUF_LEN - sector_offset,
inlen - bytes_read);
last_cmd = !(bytes_read + read_size < inlen);
status = ice_aq_read_nvm(hw, ICE_AQC_NVM_START_POINT,
offset, (u16)read_size,
data + bytes_read, last_cmd,
read_shadow_ram, NULL);
if (status)
break;
bytes_read += read_size;
offset += read_size;
} while (!last_cmd);
*length = bytes_read;
return status;
}
int
ice_aq_update_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset,
u16 length, void *data, bool last_command, u8 command_flags,
struct ice_sq_cd *cd)
{
struct ice_aq_desc desc;
struct ice_aqc_nvm *cmd;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
cmd = &desc.params.nvm;
if (offset & 0xFF000000)
return ICE_ERR_PARAM;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_write);
cmd->cmd_flags |= command_flags;
if (last_command)
cmd->cmd_flags |= ICE_AQC_NVM_LAST_CMD;
cmd->module_typeid = CPU_TO_LE16(module_typeid);
cmd->offset_low = CPU_TO_LE16(offset & 0xFFFF);
cmd->offset_high = (offset >> 16) & 0xFF;
cmd->length = CPU_TO_LE16(length);
desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
return ice_aq_send_cmd(hw, &desc, data, length, cd);
}
int ice_aq_erase_nvm(struct ice_hw *hw, u16 module_typeid, struct ice_sq_cd *cd)
{
struct ice_aq_desc desc;
struct ice_aqc_nvm *cmd;
int status;
__le16 len;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
status = ice_aq_read_nvm(hw, 0, 2 * module_typeid + 2, 2, &len, true,
true, NULL);
if (status)
return status;
cmd = &desc.params.nvm;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_erase);
cmd->module_typeid = CPU_TO_LE16(module_typeid);
cmd->length = len;
cmd->offset_low = 0;
cmd->offset_high = 0;
return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
}
int
ice_aq_read_nvm_cfg(struct ice_hw *hw, u8 cmd_flags, u16 field_id, void *data,
u16 buf_size, u16 *elem_count, struct ice_sq_cd *cd)
{
struct ice_aqc_nvm_cfg *cmd;
struct ice_aq_desc desc;
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
cmd = &desc.params.nvm_cfg;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_cfg_read);
cmd->cmd_flags = cmd_flags;
cmd->id = CPU_TO_LE16(field_id);
status = ice_aq_send_cmd(hw, &desc, data, buf_size, cd);
if (!status && elem_count)
*elem_count = LE16_TO_CPU(cmd->count);
return status;
}
int
ice_aq_write_nvm_cfg(struct ice_hw *hw, u8 cmd_flags, void *data, u16 buf_size,
u16 elem_count, struct ice_sq_cd *cd)
{
struct ice_aqc_nvm_cfg *cmd;
struct ice_aq_desc desc;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
cmd = &desc.params.nvm_cfg;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_cfg_write);
desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
cmd->count = CPU_TO_LE16(elem_count);
cmd->cmd_flags = cmd_flags;
return ice_aq_send_cmd(hw, &desc, data, buf_size, cd);
}
static int
ice_check_sr_access_params(struct ice_hw *hw, u32 offset, u16 words)
{
if ((offset + words) > hw->flash.sr_words) {
ice_debug(hw, ICE_DBG_NVM, "NVM error: offset beyond SR lmt.\n");
return ICE_ERR_PARAM;
}
if (words > ICE_SR_SECTOR_SIZE_IN_WORDS) {
ice_debug(hw, ICE_DBG_NVM, "NVM error: tried to access %d words, limit is %d.\n",
words, ICE_SR_SECTOR_SIZE_IN_WORDS);
return ICE_ERR_PARAM;
}
if (((offset + (words - 1)) / ICE_SR_SECTOR_SIZE_IN_WORDS) !=
(offset / ICE_SR_SECTOR_SIZE_IN_WORDS)) {
ice_debug(hw, ICE_DBG_NVM, "NVM error: cannot spread over two sectors.\n");
return ICE_ERR_PARAM;
}
return 0;
}
int ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data)
{
u32 bytes = sizeof(u16);
__le16 data_local;
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
status = ice_read_flat_nvm(hw, offset * sizeof(u16), &bytes,
(_FORCE_ u8 *)&data_local, true);
if (status)
return status;
*data = LE16_TO_CPU(data_local);
return 0;
}
static int
ice_write_sr_aq(struct ice_hw *hw, u32 offset, u16 words, __le16 *data,
bool last_command)
{
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
status = ice_check_sr_access_params(hw, offset, words);
if (!status)
status = ice_aq_update_nvm(hw, 0, 2 * offset, 2 * words, data,
last_command, 0, NULL);
return status;
}
static int
ice_read_sr_buf_aq(struct ice_hw *hw, u16 offset, u16 *words, u16 *data)
{
u32 bytes = *words * 2, i;
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
status = ice_read_flat_nvm(hw, offset * 2, &bytes, (u8 *)data, true);
*words = (u16)(bytes / 2);
for (i = 0; i < *words; i++)
data[i] = LE16_TO_CPU(((_FORCE_ __le16 *)data)[i]);
return status;
}
int ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access)
{
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
if (hw->flash.blank_nvm_mode)
return 0;
return ice_acquire_res(hw, ICE_NVM_RES_ID, access, ICE_NVM_TIMEOUT);
}
void ice_release_nvm(struct ice_hw *hw)
{
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
if (hw->flash.blank_nvm_mode)
return;
ice_release_res(hw, ICE_NVM_RES_ID);
}
static u32 ice_get_flash_bank_offset(struct ice_hw *hw, enum ice_bank_select bank, u16 module)
{
struct ice_bank_info *banks = &hw->flash.banks;
enum ice_flash_bank active_bank;
bool second_bank_active;
u32 offset, size;
switch (module) {
case ICE_SR_1ST_NVM_BANK_PTR:
offset = banks->nvm_ptr;
size = banks->nvm_size;
active_bank = banks->nvm_bank;
break;
case ICE_SR_1ST_OROM_BANK_PTR:
offset = banks->orom_ptr;
size = banks->orom_size;
active_bank = banks->orom_bank;
break;
case ICE_SR_NETLIST_BANK_PTR:
offset = banks->netlist_ptr;
size = banks->netlist_size;
active_bank = banks->netlist_bank;
break;
default:
ice_debug(hw, ICE_DBG_NVM, "Unexpected value for flash module: 0x%04x\n", module);
return 0;
}
switch (active_bank) {
case ICE_1ST_FLASH_BANK:
second_bank_active = false;
break;
case ICE_2ND_FLASH_BANK:
second_bank_active = true;
break;
default:
ice_debug(hw, ICE_DBG_NVM, "Unexpected value for active flash bank: %u\n",
active_bank);
return 0;
}
switch (bank) {
case ICE_ACTIVE_FLASH_BANK:
return offset + (second_bank_active ? size : 0);
case ICE_INACTIVE_FLASH_BANK:
return offset + (second_bank_active ? 0 : size);
}
ice_debug(hw, ICE_DBG_NVM, "Unexpected value for flash bank selection: %u\n", bank);
return 0;
}
static int
ice_read_flash_module(struct ice_hw *hw, enum ice_bank_select bank, u16 module,
u32 offset, u8 *data, u32 length)
{
int status;
u32 start;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
start = ice_get_flash_bank_offset(hw, bank, module);
if (!start) {
ice_debug(hw, ICE_DBG_NVM, "Unable to calculate flash bank offset for module 0x%04x\n",
module);
return ICE_ERR_PARAM;
}
status = ice_acquire_nvm(hw, ICE_RES_READ);
if (status)
return status;
status = ice_read_flat_nvm(hw, start + offset, &length, data, false);
ice_release_nvm(hw);
return status;
}
static int
ice_read_nvm_module(struct ice_hw *hw, enum ice_bank_select bank, u32 offset, u16 *data)
{
__le16 data_local;
int status;
status = ice_read_flash_module(hw, bank, ICE_SR_1ST_NVM_BANK_PTR, offset * sizeof(u16),
(_FORCE_ u8 *)&data_local, sizeof(u16));
if (!status)
*data = LE16_TO_CPU(data_local);
return status;
}
static int
ice_get_nvm_css_hdr_len(struct ice_hw *hw, enum ice_bank_select bank,
u32 *hdr_len)
{
u16 hdr_len_l, hdr_len_h;
u32 hdr_len_dword;
int status;
status = ice_read_nvm_module(hw, bank, ICE_NVM_CSS_HDR_LEN_L,
&hdr_len_l);
if (status)
return status;
status = ice_read_nvm_module(hw, bank, ICE_NVM_CSS_HDR_LEN_H,
&hdr_len_h);
if (status)
return status;
hdr_len_dword = hdr_len_h << 16 | hdr_len_l;
*hdr_len = (hdr_len_dword * 2) + ICE_NVM_AUTH_HEADER_LEN;
return 0;
}
static int
ice_read_nvm_sr_copy(struct ice_hw *hw, enum ice_bank_select bank, u32 offset, u16 *data)
{
u32 hdr_len;
int status;
status = ice_get_nvm_css_hdr_len(hw, bank, &hdr_len);
if (status)
return status;
hdr_len = ROUND_UP(hdr_len, 32);
return ice_read_nvm_module(hw, bank, hdr_len + offset, data);
}
static int
ice_read_orom_module(struct ice_hw *hw, enum ice_bank_select bank, u32 offset, u16 *data)
{
__le16 data_local;
int status;
status = ice_read_flash_module(hw, bank, ICE_SR_1ST_OROM_BANK_PTR, offset * sizeof(u16),
(_FORCE_ u8 *)&data_local, sizeof(u16));
if (!status)
*data = LE16_TO_CPU(data_local);
return status;
}
static int
ice_read_netlist_module(struct ice_hw *hw, enum ice_bank_select bank, u32 offset, u16 *data)
{
__le16 data_local;
int status;
status = ice_read_flash_module(hw, bank, ICE_SR_NETLIST_BANK_PTR, offset * sizeof(u16),
(_FORCE_ u8 *)&data_local, sizeof(u16));
if (!status)
*data = LE16_TO_CPU(data_local);
return status;
}
int ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
{
int status;
status = ice_acquire_nvm(hw, ICE_RES_READ);
if (!status) {
status = ice_read_sr_word_aq(hw, offset, data);
ice_release_nvm(hw);
}
return status;
}
#define check_add_overflow __builtin_add_overflow
int
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
u16 module_type)
{
u16 pfa_len, pfa_ptr, next_tlv, max_tlv;
int status;
status = ice_read_sr_word(hw, ICE_SR_PFA_PTR, &pfa_ptr);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Preserved Field Array pointer.\n");
return status;
}
status = ice_read_sr_word(hw, pfa_ptr, &pfa_len);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read PFA length.\n");
return status;
}
if (check_add_overflow(pfa_ptr, (u16)(pfa_len - 1), &max_tlv)) {
ice_debug(hw, ICE_DBG_INIT, "PFA starts at offset %u. PFA length of %u caused 16-bit arithmetic overflow.\n",
pfa_ptr, pfa_len);
return ICE_ERR_INVAL_SIZE;
}
next_tlv = pfa_ptr + 1;
while (next_tlv < max_tlv) {
u16 tlv_sub_module_type;
u16 tlv_len;
status = ice_read_sr_word(hw, (u16)next_tlv,
&tlv_sub_module_type);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV type.\n");
break;
}
status = ice_read_sr_word(hw, (u16)(next_tlv + 1), &tlv_len);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV length.\n");
break;
}
if (tlv_sub_module_type == module_type) {
if (tlv_len) {
*module_tlv = (u16)next_tlv;
*module_tlv_len = tlv_len;
return 0;
}
return ICE_ERR_INVAL_SIZE;
}
if (check_add_overflow(next_tlv, (u16)2, &next_tlv) ||
check_add_overflow(next_tlv, tlv_len, &next_tlv)) {
ice_debug(hw, ICE_DBG_INIT, "TLV of type %u and length 0x%04x caused 16-bit arithmetic overflow. The PFA starts at 0x%04x and has length of 0x%04x\n",
tlv_sub_module_type, tlv_len, pfa_ptr, pfa_len);
return ICE_ERR_INVAL_SIZE;
}
}
return ICE_ERR_DOES_NOT_EXIST;
}
int ice_read_pba_string(struct ice_hw *hw, u8 *pba_num, u32 pba_num_size)
{
u16 pba_tlv, pba_tlv_len;
u16 pba_word, pba_size;
int status;
u16 i;
status = ice_get_pfa_module_tlv(hw, &pba_tlv, &pba_tlv_len,
ICE_SR_PBA_BLOCK_PTR);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read PBA Block TLV.\n");
return status;
}
status = ice_read_sr_word(hw, (pba_tlv + 2), &pba_size);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read PBA Section size.\n");
return status;
}
if (pba_tlv_len < pba_size) {
ice_debug(hw, ICE_DBG_INIT, "Invalid PBA Block TLV size.\n");
return ICE_ERR_INVAL_SIZE;
}
pba_size--;
if (pba_num_size < (((u32)pba_size * 2) + 1)) {
ice_debug(hw, ICE_DBG_INIT, "Buffer too small for PBA data.\n");
return ICE_ERR_PARAM;
}
for (i = 0; i < pba_size; i++) {
status = ice_read_sr_word(hw, (pba_tlv + 2 + 1) + i, &pba_word);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read PBA Block word %d.\n", i);
return status;
}
pba_num[(i * 2)] = (pba_word >> 8) & 0xFF;
pba_num[(i * 2) + 1] = pba_word & 0xFF;
}
pba_num[(pba_size * 2)] = '\0';
return status;
}
static int ice_get_nvm_srev(struct ice_hw *hw, enum ice_bank_select bank, u32 *srev)
{
u16 srev_l, srev_h;
int status;
status = ice_read_nvm_module(hw, bank, ICE_NVM_CSS_SREV_L, &srev_l);
if (status)
return status;
status = ice_read_nvm_module(hw, bank, ICE_NVM_CSS_SREV_H, &srev_h);
if (status)
return status;
*srev = srev_h << 16 | srev_l;
return 0;
}
static int
ice_get_nvm_ver_info(struct ice_hw *hw, enum ice_bank_select bank, struct ice_nvm_info *nvm)
{
u16 eetrack_lo, eetrack_hi, ver;
int status;
status = ice_read_nvm_sr_copy(hw, bank, ICE_SR_NVM_DEV_STARTER_VER, &ver);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read DEV starter version.\n");
return status;
}
nvm->major = (ver & ICE_NVM_VER_HI_MASK) >> ICE_NVM_VER_HI_SHIFT;
nvm->minor = (ver & ICE_NVM_VER_LO_MASK) >> ICE_NVM_VER_LO_SHIFT;
status = ice_read_nvm_sr_copy(hw, bank, ICE_SR_NVM_EETRACK_LO, &eetrack_lo);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read EETRACK lo.\n");
return status;
}
status = ice_read_nvm_sr_copy(hw, bank, ICE_SR_NVM_EETRACK_HI, &eetrack_hi);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read EETRACK hi.\n");
return status;
}
nvm->eetrack = (eetrack_hi << 16) | eetrack_lo;
status = ice_get_nvm_srev(hw, bank, &nvm->srev);
if (status)
ice_debug(hw, ICE_DBG_NVM, "Failed to read NVM security revision.\n");
return 0;
}
int ice_get_inactive_nvm_ver(struct ice_hw *hw, struct ice_nvm_info *nvm)
{
return ice_get_nvm_ver_info(hw, ICE_INACTIVE_FLASH_BANK, nvm);
}
static int ice_get_orom_srev(struct ice_hw *hw, enum ice_bank_select bank, u32 *srev)
{
u32 orom_size_word = hw->flash.banks.orom_size / 2;
u16 srev_l, srev_h;
u32 css_start;
u32 hdr_len;
int status;
status = ice_get_nvm_css_hdr_len(hw, bank, &hdr_len);
if (status)
return status;
if (orom_size_word < hdr_len) {
ice_debug(hw, ICE_DBG_NVM, "Unexpected Option ROM Size of %u\n",
hw->flash.banks.orom_size);
return ICE_ERR_CFG;
}
css_start = orom_size_word - hdr_len;
status = ice_read_orom_module(hw, bank, css_start + ICE_NVM_CSS_SREV_L, &srev_l);
if (status)
return status;
status = ice_read_orom_module(hw, bank, css_start + ICE_NVM_CSS_SREV_H, &srev_h);
if (status)
return status;
*srev = srev_h << 16 | srev_l;
return 0;
}
static int
ice_get_orom_civd_data(struct ice_hw *hw, enum ice_bank_select bank,
struct ice_orom_civd_info *civd)
{
struct ice_orom_civd_info civd_data_section;
int status;
u32 offset;
u32 tmp;
for (offset = 0; (offset + 512) <= hw->flash.banks.orom_size; offset += 512) {
u8 sum = 0, i;
status = ice_read_flash_module(hw, bank, ICE_SR_1ST_OROM_BANK_PTR,
offset, (u8 *)&tmp, sizeof(tmp));
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Unable to read Option ROM data\n");
return status;
}
if (memcmp("$CIV", &tmp, sizeof(tmp)) != 0)
continue;
ice_debug(hw, ICE_DBG_NVM, "Found CIVD section at offset %u\n",
offset);
status = ice_read_flash_module(hw, bank, ICE_SR_1ST_OROM_BANK_PTR,
offset, (u8 *)&civd_data_section,
sizeof(civd_data_section));
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Unable to read CIVD data\n");
goto exit_error;
}
for (i = 0; i < sizeof(civd_data_section); i++)
sum += ((u8 *)&civd_data_section)[i];
if (sum) {
ice_debug(hw, ICE_DBG_NVM, "Found CIVD data with invalid checksum of %u\n",
sum);
status = ICE_ERR_NVM;
goto exit_error;
}
*civd = civd_data_section;
return 0;
}
status = ICE_ERR_NVM;
ice_debug(hw, ICE_DBG_NVM, "Unable to locate CIVD data within the Option ROM\n");
exit_error:
return status;
}
static int
ice_get_orom_ver_info(struct ice_hw *hw, enum ice_bank_select bank, struct ice_orom_info *orom)
{
struct ice_orom_civd_info civd;
u32 combo_ver;
int status;
status = ice_get_orom_civd_data(hw, bank, &civd);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to locate valid Option ROM CIVD data\n");
return status;
}
combo_ver = LE32_TO_CPU(civd.combo_ver);
orom->major = (u8)((combo_ver & ICE_OROM_VER_MASK) >> ICE_OROM_VER_SHIFT);
orom->patch = (u8)(combo_ver & ICE_OROM_VER_PATCH_MASK);
orom->build = (u16)((combo_ver & ICE_OROM_VER_BUILD_MASK) >> ICE_OROM_VER_BUILD_SHIFT);
status = ice_get_orom_srev(hw, bank, &orom->srev);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read Option ROM security revision.\n");
return status;
}
return 0;
}
int ice_get_inactive_orom_ver(struct ice_hw *hw, struct ice_orom_info *orom)
{
return ice_get_orom_ver_info(hw, ICE_INACTIVE_FLASH_BANK, orom);
}
static int
ice_get_netlist_info(struct ice_hw *hw, enum ice_bank_select bank,
struct ice_netlist_info *netlist)
{
u16 module_id, length, node_count, i;
u16 *id_blk;
int status;
status = ice_read_netlist_module(hw, bank, ICE_NETLIST_TYPE_OFFSET, &module_id);
if (status)
return status;
if (module_id != ICE_NETLIST_LINK_TOPO_MOD_ID) {
ice_debug(hw, ICE_DBG_NVM, "Expected netlist module_id ID of 0x%04x, but got 0x%04x\n",
ICE_NETLIST_LINK_TOPO_MOD_ID, module_id);
return ICE_ERR_NVM;
}
status = ice_read_netlist_module(hw, bank, ICE_LINK_TOPO_MODULE_LEN, &length);
if (status)
return status;
if (length < ICE_NETLIST_ID_BLK_SIZE) {
ice_debug(hw, ICE_DBG_NVM, "Netlist Link Topology module too small. Expected at least %u words, but got %u words.\n",
ICE_NETLIST_ID_BLK_SIZE, length);
return ICE_ERR_NVM;
}
status = ice_read_netlist_module(hw, bank, ICE_LINK_TOPO_NODE_COUNT, &node_count);
if (status)
return status;
node_count &= ICE_LINK_TOPO_NODE_COUNT_M;
id_blk = (u16 *)ice_calloc(hw, ICE_NETLIST_ID_BLK_SIZE, sizeof(*id_blk));
if (!id_blk)
return ICE_ERR_NO_MEMORY;
status = ice_read_flash_module(hw, bank, ICE_SR_NETLIST_BANK_PTR,
ICE_NETLIST_ID_BLK_OFFSET(node_count) * sizeof(u16),
(u8 *)id_blk, ICE_NETLIST_ID_BLK_SIZE * sizeof(u16));
if (status)
goto exit_error;
for (i = 0; i < ICE_NETLIST_ID_BLK_SIZE; i++)
id_blk[i] = LE16_TO_CPU(((_FORCE_ __le16 *)id_blk)[i]);
netlist->major = id_blk[ICE_NETLIST_ID_BLK_MAJOR_VER_HIGH] << 16 |
id_blk[ICE_NETLIST_ID_BLK_MAJOR_VER_LOW];
netlist->minor = id_blk[ICE_NETLIST_ID_BLK_MINOR_VER_HIGH] << 16 |
id_blk[ICE_NETLIST_ID_BLK_MINOR_VER_LOW];
netlist->type = id_blk[ICE_NETLIST_ID_BLK_TYPE_HIGH] << 16 |
id_blk[ICE_NETLIST_ID_BLK_TYPE_LOW];
netlist->rev = id_blk[ICE_NETLIST_ID_BLK_REV_HIGH] << 16 |
id_blk[ICE_NETLIST_ID_BLK_REV_LOW];
netlist->cust_ver = id_blk[ICE_NETLIST_ID_BLK_CUST_VER];
netlist->hash = id_blk[ICE_NETLIST_ID_BLK_SHA_HASH_WORD(15)] << 16 |
id_blk[ICE_NETLIST_ID_BLK_SHA_HASH_WORD(14)];
exit_error:
ice_free(hw, id_blk);
return status;
}
int ice_get_netlist_ver_info(struct ice_hw *hw, struct ice_netlist_info *netlist)
{
return ice_get_netlist_info(hw, ICE_ACTIVE_FLASH_BANK, netlist);
}
int ice_get_inactive_netlist_ver(struct ice_hw *hw, struct ice_netlist_info *netlist)
{
return ice_get_netlist_info(hw, ICE_INACTIVE_FLASH_BANK, netlist);
}
static int ice_discover_flash_size(struct ice_hw *hw)
{
u32 min_size = 0, max_size = ICE_AQC_NVM_MAX_OFFSET + 1;
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
status = ice_acquire_nvm(hw, ICE_RES_READ);
if (status)
return status;
while ((max_size - min_size) > 1) {
u32 offset = (max_size + min_size) / 2;
u32 len = 1;
u8 data;
status = ice_read_flat_nvm(hw, offset, &len, &data, false);
if (status == ICE_ERR_AQ_ERROR &&
hw->adminq.sq_last_status == ICE_AQ_RC_EINVAL) {
ice_debug(hw, ICE_DBG_NVM, "%s: New upper bound of %u bytes\n",
__func__, offset);
status = 0;
max_size = offset;
} else if (!status) {
ice_debug(hw, ICE_DBG_NVM, "%s: New lower bound of %u bytes\n",
__func__, offset);
min_size = offset;
} else {
goto err_read_flat_nvm;
}
}
ice_debug(hw, ICE_DBG_NVM, "Predicted flash size is %u bytes\n", max_size);
hw->flash.flash_size = max_size;
err_read_flat_nvm:
ice_release_nvm(hw);
return status;
}
static int ice_read_sr_pointer(struct ice_hw *hw, u16 offset, u32 *pointer)
{
int status;
u16 value;
status = ice_read_sr_word(hw, offset, &value);
if (status)
return status;
if (value & ICE_SR_NVM_PTR_4KB_UNITS)
*pointer = (value & ~ICE_SR_NVM_PTR_4KB_UNITS) * 4 * 1024;
else
*pointer = value * 2;
return 0;
}
static int ice_read_sr_area_size(struct ice_hw *hw, u16 offset, u32 *size)
{
int status;
u16 value;
status = ice_read_sr_word(hw, offset, &value);
if (status)
return status;
*size = value * 4 * 1024;
return 0;
}
static int ice_determine_active_flash_banks(struct ice_hw *hw)
{
struct ice_bank_info *banks = &hw->flash.banks;
u16 ctrl_word;
int status;
status = ice_read_sr_word(hw, ICE_SR_NVM_CTRL_WORD, &ctrl_word);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read the Shadow RAM control word\n");
return status;
}
if ((ctrl_word & ICE_SR_CTRL_WORD_1_M) >> ICE_SR_CTRL_WORD_1_S != ICE_SR_CTRL_WORD_VALID) {
ice_debug(hw, ICE_DBG_NVM, "Shadow RAM control word is invalid\n");
return ICE_ERR_CFG;
}
if (!(ctrl_word & ICE_SR_CTRL_WORD_NVM_BANK))
banks->nvm_bank = ICE_1ST_FLASH_BANK;
else
banks->nvm_bank = ICE_2ND_FLASH_BANK;
if (!(ctrl_word & ICE_SR_CTRL_WORD_OROM_BANK))
banks->orom_bank = ICE_1ST_FLASH_BANK;
else
banks->orom_bank = ICE_2ND_FLASH_BANK;
if (!(ctrl_word & ICE_SR_CTRL_WORD_NETLIST_BANK))
banks->netlist_bank = ICE_1ST_FLASH_BANK;
else
banks->netlist_bank = ICE_2ND_FLASH_BANK;
status = ice_read_sr_pointer(hw, ICE_SR_1ST_NVM_BANK_PTR, &banks->nvm_ptr);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read NVM bank pointer\n");
return status;
}
status = ice_read_sr_area_size(hw, ICE_SR_NVM_BANK_SIZE, &banks->nvm_size);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read NVM bank area size\n");
return status;
}
status = ice_read_sr_pointer(hw, ICE_SR_1ST_OROM_BANK_PTR, &banks->orom_ptr);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read OROM bank pointer\n");
return status;
}
status = ice_read_sr_area_size(hw, ICE_SR_OROM_BANK_SIZE, &banks->orom_size);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read OROM bank area size\n");
return status;
}
status = ice_read_sr_pointer(hw, ICE_SR_NETLIST_BANK_PTR, &banks->netlist_ptr);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read Netlist bank pointer\n");
return status;
}
status = ice_read_sr_area_size(hw, ICE_SR_NETLIST_BANK_SIZE, &banks->netlist_size);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read Netlist bank area size\n");
return status;
}
return 0;
}
int ice_init_nvm(struct ice_hw *hw)
{
struct ice_flash_info *flash = &hw->flash;
u32 fla, gens_stat;
u8 sr_size;
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
gens_stat = rd32(hw, GLNVM_GENS);
sr_size = (gens_stat & GLNVM_GENS_SR_SIZE_M) >> GLNVM_GENS_SR_SIZE_S;
flash->sr_words = BIT(sr_size) * ICE_SR_WORDS_IN_1KB;
fla = rd32(hw, GLNVM_FLA);
if (fla & GLNVM_FLA_LOCKED_M) {
flash->blank_nvm_mode = false;
} else {
flash->blank_nvm_mode = true;
ice_debug(hw, ICE_DBG_NVM, "NVM init error: unsupported blank mode.\n");
return ICE_ERR_NVM_BLANK_MODE;
}
status = ice_discover_flash_size(hw);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "NVM init error: failed to discover flash size.\n");
return status;
}
status = ice_determine_active_flash_banks(hw);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to determine active flash banks.\n");
return status;
}
status = ice_get_nvm_ver_info(hw, ICE_ACTIVE_FLASH_BANK, &flash->nvm);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read NVM info.\n");
return status;
}
status = ice_get_orom_ver_info(hw, ICE_ACTIVE_FLASH_BANK, &flash->orom);
if (status)
ice_debug(hw, ICE_DBG_INIT, "Failed to read Option ROM info.\n");
status = ice_get_netlist_info(hw, ICE_ACTIVE_FLASH_BANK, &flash->netlist);
if (status)
ice_debug(hw, ICE_DBG_INIT, "Failed to read netlist info.\n");
return 0;
}
int
ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, u16 *data)
{
int status;
status = ice_acquire_nvm(hw, ICE_RES_READ);
if (!status) {
status = ice_read_sr_buf_aq(hw, offset, words, data);
ice_release_nvm(hw);
}
return status;
}
int
__ice_write_sr_word(struct ice_hw *hw, u32 offset, const u16 *data)
{
__le16 data_local = CPU_TO_LE16(*data);
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
return ice_write_sr_aq(hw, offset, 1, &data_local, false);
}
int
__ice_write_sr_buf(struct ice_hw *hw, u32 offset, u16 words, const u16 *data)
{
__le16 *data_local;
int status;
void *vmem;
u32 i;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
vmem = ice_calloc(hw, words, sizeof(u16));
if (!vmem)
return ICE_ERR_NO_MEMORY;
data_local = (_FORCE_ __le16 *)vmem;
for (i = 0; i < words; i++)
data_local[i] = CPU_TO_LE16(data[i]);
status = ice_write_sr_aq(hw, offset, words, data_local, false);
ice_free(hw, vmem);
return status;
}
static int ice_calc_sr_checksum(struct ice_hw *hw, u16 *checksum)
{
u16 pcie_alt_module = 0;
u16 checksum_local = 0;
u16 vpd_module;
int status = 0;
void *vmem;
u16 *data;
u16 i;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
vmem = ice_calloc(hw, ICE_SR_SECTOR_SIZE_IN_WORDS, sizeof(u16));
if (!vmem)
return ICE_ERR_NO_MEMORY;
data = (u16 *)vmem;
status = ice_read_sr_word_aq(hw, ICE_SR_VPD_PTR, &vpd_module);
if (status)
goto ice_calc_sr_checksum_exit;
status = ice_read_sr_word_aq(hw, ICE_SR_PCIE_ALT_AUTO_LOAD_PTR,
&pcie_alt_module);
if (status)
goto ice_calc_sr_checksum_exit;
for (i = 0; i < hw->flash.sr_words; i++) {
if ((i % ICE_SR_SECTOR_SIZE_IN_WORDS) == 0) {
u16 words = ICE_SR_SECTOR_SIZE_IN_WORDS;
status = ice_read_sr_buf_aq(hw, i, &words, data);
if (status)
goto ice_calc_sr_checksum_exit;
}
if (i == ICE_SR_SW_CHECKSUM_WORD)
continue;
if (i >= (u32)vpd_module &&
i < ((u32)vpd_module + ICE_SR_VPD_SIZE_WORDS))
continue;
if (i >= (u32)pcie_alt_module &&
i < ((u32)pcie_alt_module + ICE_SR_PCIE_ALT_SIZE_WORDS))
continue;
checksum_local += data[i % ICE_SR_SECTOR_SIZE_IN_WORDS];
}
*checksum = (u16)ICE_SR_SW_CHECKSUM_BASE - checksum_local;
ice_calc_sr_checksum_exit:
ice_free(hw, vmem);
return status;
}
int ice_update_sr_checksum(struct ice_hw *hw)
{
__le16 le_sum;
u16 checksum;
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
status = ice_calc_sr_checksum(hw, &checksum);
if (!status) {
le_sum = CPU_TO_LE16(checksum);
status = ice_write_sr_aq(hw, ICE_SR_SW_CHECKSUM_WORD, 1,
&le_sum, true);
}
return status;
}
int ice_validate_sr_checksum(struct ice_hw *hw, u16 *checksum)
{
u16 checksum_local;
u16 checksum_sr;
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
status = ice_acquire_nvm(hw, ICE_RES_READ);
if (!status) {
status = ice_calc_sr_checksum(hw, &checksum_local);
ice_release_nvm(hw);
if (status)
return status;
} else {
return status;
}
ice_read_sr_word(hw, ICE_SR_SW_CHECKSUM_WORD, &checksum_sr);
if (checksum_local != checksum_sr)
status = ICE_ERR_NVM_CHECKSUM;
if (checksum)
*checksum = checksum_local;
return status;
}
int ice_nvm_validate_checksum(struct ice_hw *hw)
{
struct ice_aqc_nvm_checksum *cmd;
struct ice_aq_desc desc;
int status;
status = ice_acquire_nvm(hw, ICE_RES_READ);
if (status)
return status;
cmd = &desc.params.nvm_checksum;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_checksum);
cmd->flags = ICE_AQC_NVM_CHECKSUM_VERIFY;
status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
ice_release_nvm(hw);
if (!status)
if (LE16_TO_CPU(cmd->checksum) != ICE_AQC_NVM_CHECKSUM_CORRECT)
status = ICE_ERR_NVM_CHECKSUM;
return status;
}
int ice_nvm_recalculate_checksum(struct ice_hw *hw)
{
struct ice_aqc_nvm_checksum *cmd;
struct ice_aq_desc desc;
int status;
status = ice_acquire_nvm(hw, ICE_RES_READ);
if (status)
return status;
cmd = &desc.params.nvm_checksum;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_checksum);
cmd->flags = ICE_AQC_NVM_CHECKSUM_RECALC;
status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
ice_release_nvm(hw);
return status;
}
int ice_nvm_write_activate(struct ice_hw *hw, u16 cmd_flags, u8 *response_flags)
{
struct ice_aqc_nvm *cmd;
struct ice_aq_desc desc;
int err;
cmd = &desc.params.nvm;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_write_activate);
cmd->cmd_flags = (u8)(cmd_flags & 0xFF);
cmd->offset_high = (u8)((cmd_flags >> 8) & 0xFF);
err = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
if (!err && response_flags)
*response_flags = cmd->cmd_flags;
return err;
}
int
ice_get_nvm_minsrevs(struct ice_hw *hw, struct ice_minsrev_info *minsrevs)
{
struct ice_aqc_nvm_minsrev data;
int status;
u16 valid;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
status = ice_acquire_nvm(hw, ICE_RES_READ);
if (status)
return status;
status = ice_aq_read_nvm(hw, ICE_AQC_NVM_MINSREV_MOD_ID, 0, sizeof(data),
&data, true, false, NULL);
ice_release_nvm(hw);
if (status)
return status;
valid = LE16_TO_CPU(data.validity);
if (valid & ICE_AQC_NVM_MINSREV_NVM_VALID) {
u16 minsrev_l, minsrev_h;
minsrev_l = LE16_TO_CPU(data.nvm_minsrev_l);
minsrev_h = LE16_TO_CPU(data.nvm_minsrev_h);
minsrevs->nvm = minsrev_h << 16 | minsrev_l;
minsrevs->nvm_valid = true;
}
if (valid & ICE_AQC_NVM_MINSREV_OROM_VALID) {
u16 minsrev_l, minsrev_h;
minsrev_l = LE16_TO_CPU(data.orom_minsrev_l);
minsrev_h = LE16_TO_CPU(data.orom_minsrev_h);
minsrevs->orom = minsrev_h << 16 | minsrev_l;
minsrevs->orom_valid = true;
}
return 0;
}
int
ice_update_nvm_minsrevs(struct ice_hw *hw, struct ice_minsrev_info *minsrevs)
{
struct ice_aqc_nvm_minsrev data;
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
if (!minsrevs->nvm_valid && !minsrevs->orom_valid) {
ice_debug(hw, ICE_DBG_NVM, "At least one of NVM and OROM MinSrev must be valid");
return ICE_ERR_PARAM;
}
status = ice_acquire_nvm(hw, ICE_RES_WRITE);
if (status)
return status;
status = ice_aq_read_nvm(hw, ICE_AQC_NVM_MINSREV_MOD_ID, 0, sizeof(data),
&data, true, false, NULL);
if (status)
goto exit_release_res;
if (minsrevs->nvm_valid) {
data.nvm_minsrev_l = CPU_TO_LE16(minsrevs->nvm & 0xFFFF);
data.nvm_minsrev_h = CPU_TO_LE16(minsrevs->nvm >> 16);
data.validity |= CPU_TO_LE16(ICE_AQC_NVM_MINSREV_NVM_VALID);
}
if (minsrevs->orom_valid) {
data.orom_minsrev_l = CPU_TO_LE16(minsrevs->orom & 0xFFFF);
data.orom_minsrev_h = CPU_TO_LE16(minsrevs->orom >> 16);
data.validity |= CPU_TO_LE16(ICE_AQC_NVM_MINSREV_OROM_VALID);
}
status = ice_aq_update_nvm(hw, ICE_AQC_NVM_MINSREV_MOD_ID, 0, sizeof(data), &data,
false, ICE_AQC_NVM_SPECIAL_UPDATE, NULL);
if (status)
goto exit_release_res;
status = ice_nvm_write_activate(hw, 0, NULL);
exit_release_res:
ice_release_nvm(hw);
return status;
}
int
ice_nvm_access_get_features(struct ice_nvm_access_cmd *cmd,
union ice_nvm_access_data *data)
{
if (cmd->data_size < sizeof(struct ice_nvm_features))
return ICE_ERR_NO_MEMORY;
ice_memset(data, 0, cmd->data_size, ICE_NONDMA_MEM);
data->drv_features.major = ICE_NVM_ACCESS_MAJOR_VER;
data->drv_features.minor = ICE_NVM_ACCESS_MINOR_VER;
data->drv_features.size = sizeof(struct ice_nvm_features);
data->drv_features.features[0] = ICE_NVM_FEATURES_0_REG_ACCESS;
return 0;
}
u32 ice_nvm_access_get_module(struct ice_nvm_access_cmd *cmd)
{
return ((cmd->config & ICE_NVM_CFG_MODULE_M) >> ICE_NVM_CFG_MODULE_S);
}
u32 ice_nvm_access_get_flags(struct ice_nvm_access_cmd *cmd)
{
return ((cmd->config & ICE_NVM_CFG_FLAGS_M) >> ICE_NVM_CFG_FLAGS_S);
}
u32 ice_nvm_access_get_adapter(struct ice_nvm_access_cmd *cmd)
{
return ((cmd->config & ICE_NVM_CFG_ADAPTER_INFO_M) >>
ICE_NVM_CFG_ADAPTER_INFO_S);
}
static int
ice_validate_nvm_rw_reg(struct ice_nvm_access_cmd *cmd)
{
u32 module, flags, offset;
u16 i;
module = ice_nvm_access_get_module(cmd);
flags = ice_nvm_access_get_flags(cmd);
offset = cmd->offset;
if (module != ICE_NVM_REG_RW_MODULE ||
flags != ICE_NVM_REG_RW_FLAGS ||
cmd->data_size != FIELD_SIZEOF(union ice_nvm_access_data, regval))
return ICE_ERR_PARAM;
switch (offset) {
case GL_HICR:
case GL_HICR_EN:
case GL_FWSTS:
case GL_MNG_FWSM:
case GLGEN_CSR_DEBUG_C:
case GLGEN_RSTAT:
case GLPCI_LBARCTRL:
case GL_MNG_DEF_DEVID:
case GLNVM_GENS:
case GLNVM_FLA:
case PF_FUNC_RID:
return 0;
default:
break;
}
for (i = 0; i <= GL_HIDA_MAX_INDEX; i++)
if (offset == (u32)GL_HIDA(i))
return 0;
for (i = 0; i <= GL_HIBA_MAX_INDEX; i++)
if (offset == (u32)GL_HIBA(i))
return 0;
return ICE_ERR_OUT_OF_RANGE;
}
int
ice_nvm_access_read(struct ice_hw *hw, struct ice_nvm_access_cmd *cmd,
union ice_nvm_access_data *data)
{
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
ice_memset(data, 0, cmd->data_size, ICE_NONDMA_MEM);
status = ice_validate_nvm_rw_reg(cmd);
if (status)
return status;
ice_debug(hw, ICE_DBG_NVM, "NVM access: reading register %08x\n",
cmd->offset);
data->regval = rd32(hw, cmd->offset);
return 0;
}
int
ice_nvm_access_write(struct ice_hw *hw, struct ice_nvm_access_cmd *cmd,
union ice_nvm_access_data *data)
{
int status;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
status = ice_validate_nvm_rw_reg(cmd);
if (status)
return status;
if (hw->mac_type == ICE_MAC_E830) {
if (cmd->offset == E830_GL_HICR_EN)
return ICE_ERR_OUT_OF_RANGE;
} else {
if (cmd->offset == GL_HICR_EN)
return ICE_ERR_OUT_OF_RANGE;
}
if (cmd->offset == GLGEN_RSTAT)
return ICE_ERR_OUT_OF_RANGE;
ice_debug(hw, ICE_DBG_NVM, "NVM access: writing register %08x with value %08x\n",
cmd->offset, data->regval);
wr32(hw, cmd->offset, data->regval);
return 0;
}
int
ice_handle_nvm_access(struct ice_hw *hw, struct ice_nvm_access_cmd *cmd,
union ice_nvm_access_data *data)
{
u32 module, flags, adapter_info;
ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
if ((cmd->config & ICE_NVM_CFG_EXT_FLAGS_M) != 0)
return ICE_ERR_PARAM;
adapter_info = ice_nvm_access_get_adapter(cmd);
if (adapter_info != hw->device_id)
return ICE_ERR_PARAM;
switch (cmd->command) {
case ICE_NVM_CMD_READ:
module = ice_nvm_access_get_module(cmd);
flags = ice_nvm_access_get_flags(cmd);
if (module == ICE_NVM_GET_FEATURES_MODULE &&
flags == ICE_NVM_GET_FEATURES_FLAGS &&
cmd->offset == 0)
return ice_nvm_access_get_features(cmd, data);
else
return ice_nvm_access_read(hw, cmd, data);
case ICE_NVM_CMD_WRITE:
return ice_nvm_access_write(hw, cmd, data);
default:
return ICE_ERR_PARAM;
}
}
s32 ice_nvm_sanitize_operate(struct ice_hw *hw)
{
s32 status;
u8 values;
u8 cmd_flags = ICE_AQ_NVM_SANITIZE_REQ_OPERATE |
ICE_AQ_NVM_SANITIZE_OPERATE_SUBJECT_CLEAR;
status = ice_nvm_sanitize(hw, cmd_flags, &values);
if (status)
return status;
if ((!(values & ICE_AQ_NVM_SANITIZE_OPERATE_HOST_CLEAN_DONE) &&
!(values & ICE_AQ_NVM_SANITIZE_OPERATE_BMC_CLEAN_DONE)) ||
((values & ICE_AQ_NVM_SANITIZE_OPERATE_HOST_CLEAN_DONE) &&
!(values & ICE_AQ_NVM_SANITIZE_OPERATE_HOST_CLEAN_SUCCESS)) ||
((values & ICE_AQ_NVM_SANITIZE_OPERATE_BMC_CLEAN_DONE) &&
!(values & ICE_AQ_NVM_SANITIZE_OPERATE_BMC_CLEAN_SUCCESS)))
return ICE_ERR_AQ_ERROR;
return ICE_SUCCESS;
}
s32 ice_nvm_sanitize(struct ice_hw *hw, u8 cmd_flags, u8 *values)
{
struct ice_aqc_nvm_sanitization *cmd;
struct ice_aq_desc desc;
s32 status;
cmd = &desc.params.sanitization;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_sanitization);
cmd->cmd_flags = cmd_flags;
status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
if (values)
*values = cmd->values;
return status;
}