161ae650dSJack F Vogel /****************************************************************************** 261ae650dSJack F Vogel 361ae650dSJack F Vogel Copyright (c) 2013-2014, Intel Corporation 461ae650dSJack F Vogel All rights reserved. 561ae650dSJack F Vogel 661ae650dSJack F Vogel Redistribution and use in source and binary forms, with or without 761ae650dSJack F Vogel modification, are permitted provided that the following conditions are met: 861ae650dSJack F Vogel 961ae650dSJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 1061ae650dSJack F Vogel this list of conditions and the following disclaimer. 1161ae650dSJack F Vogel 1261ae650dSJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 1361ae650dSJack F Vogel notice, this list of conditions and the following disclaimer in the 1461ae650dSJack F Vogel documentation and/or other materials provided with the distribution. 1561ae650dSJack F Vogel 1661ae650dSJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 1761ae650dSJack F Vogel contributors may be used to endorse or promote products derived from 1861ae650dSJack F Vogel this software without specific prior written permission. 1961ae650dSJack F Vogel 2061ae650dSJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2161ae650dSJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2261ae650dSJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2361ae650dSJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2461ae650dSJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2561ae650dSJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2661ae650dSJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2761ae650dSJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2861ae650dSJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2961ae650dSJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3061ae650dSJack F Vogel POSSIBILITY OF SUCH DAMAGE. 3161ae650dSJack F Vogel 3261ae650dSJack F Vogel ******************************************************************************/ 3361ae650dSJack F Vogel /*$FreeBSD$*/ 3461ae650dSJack F Vogel 3561ae650dSJack F Vogel #include "i40e_prototype.h" 3661ae650dSJack F Vogel 37*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset, 38*f247dc25SJack F Vogel u16 *data); 39*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset, 40*f247dc25SJack F Vogel u16 *data); 41*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset, 42*f247dc25SJack F Vogel u16 *words, u16 *data); 43*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset, 44*f247dc25SJack F Vogel u16 *words, u16 *data); 45*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer, 46*f247dc25SJack F Vogel u32 offset, u16 words, void *data, 47*f247dc25SJack F Vogel bool last_command); 48*f247dc25SJack F Vogel 4961ae650dSJack F Vogel /** 5061ae650dSJack F Vogel * i40e_init_nvm_ops - Initialize NVM function pointers 5161ae650dSJack F Vogel * @hw: pointer to the HW structure 5261ae650dSJack F Vogel * 5361ae650dSJack F Vogel * Setup the function pointers and the NVM info structure. Should be called 5461ae650dSJack F Vogel * once per NVM initialization, e.g. inside the i40e_init_shared_code(). 5561ae650dSJack F Vogel * Please notice that the NVM term is used here (& in all methods covered 5661ae650dSJack F Vogel * in this file) as an equivalent of the FLASH part mapped into the SR. 5761ae650dSJack F Vogel * We are accessing FLASH always thru the Shadow RAM. 5861ae650dSJack F Vogel **/ 5961ae650dSJack F Vogel enum i40e_status_code i40e_init_nvm(struct i40e_hw *hw) 6061ae650dSJack F Vogel { 6161ae650dSJack F Vogel struct i40e_nvm_info *nvm = &hw->nvm; 6261ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 6361ae650dSJack F Vogel u32 fla, gens; 6461ae650dSJack F Vogel u8 sr_size; 6561ae650dSJack F Vogel 6661ae650dSJack F Vogel DEBUGFUNC("i40e_init_nvm"); 6761ae650dSJack F Vogel 6861ae650dSJack F Vogel /* The SR size is stored regardless of the nvm programming mode 6961ae650dSJack F Vogel * as the blank mode may be used in the factory line. 7061ae650dSJack F Vogel */ 7161ae650dSJack F Vogel gens = rd32(hw, I40E_GLNVM_GENS); 7261ae650dSJack F Vogel sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >> 7361ae650dSJack F Vogel I40E_GLNVM_GENS_SR_SIZE_SHIFT); 7461ae650dSJack F Vogel /* Switching to words (sr_size contains power of 2KB) */ 7561ae650dSJack F Vogel nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB; 7661ae650dSJack F Vogel 7761ae650dSJack F Vogel /* Check if we are in the normal or blank NVM programming mode */ 7861ae650dSJack F Vogel fla = rd32(hw, I40E_GLNVM_FLA); 7961ae650dSJack F Vogel if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */ 8061ae650dSJack F Vogel /* Max NVM timeout */ 8161ae650dSJack F Vogel nvm->timeout = I40E_MAX_NVM_TIMEOUT; 8261ae650dSJack F Vogel nvm->blank_nvm_mode = FALSE; 8361ae650dSJack F Vogel } else { /* Blank programming mode */ 8461ae650dSJack F Vogel nvm->blank_nvm_mode = TRUE; 8561ae650dSJack F Vogel ret_code = I40E_ERR_NVM_BLANK_MODE; 86*f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, "NVM init error: unsupported blank mode.\n"); 8761ae650dSJack F Vogel } 8861ae650dSJack F Vogel 8961ae650dSJack F Vogel return ret_code; 9061ae650dSJack F Vogel } 9161ae650dSJack F Vogel 9261ae650dSJack F Vogel /** 9361ae650dSJack F Vogel * i40e_acquire_nvm - Generic request for acquiring the NVM ownership 9461ae650dSJack F Vogel * @hw: pointer to the HW structure 9561ae650dSJack F Vogel * @access: NVM access type (read or write) 9661ae650dSJack F Vogel * 9761ae650dSJack F Vogel * This function will request NVM ownership for reading 9861ae650dSJack F Vogel * via the proper Admin Command. 9961ae650dSJack F Vogel **/ 10061ae650dSJack F Vogel enum i40e_status_code i40e_acquire_nvm(struct i40e_hw *hw, 10161ae650dSJack F Vogel enum i40e_aq_resource_access_type access) 10261ae650dSJack F Vogel { 10361ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 10461ae650dSJack F Vogel u64 gtime, timeout; 105*f247dc25SJack F Vogel u64 time_left = 0; 10661ae650dSJack F Vogel 10761ae650dSJack F Vogel DEBUGFUNC("i40e_acquire_nvm"); 10861ae650dSJack F Vogel 10961ae650dSJack F Vogel if (hw->nvm.blank_nvm_mode) 11061ae650dSJack F Vogel goto i40e_i40e_acquire_nvm_exit; 11161ae650dSJack F Vogel 11261ae650dSJack F Vogel ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access, 113*f247dc25SJack F Vogel 0, &time_left, NULL); 11461ae650dSJack F Vogel /* Reading the Global Device Timer */ 11561ae650dSJack F Vogel gtime = rd32(hw, I40E_GLVFGEN_TIMER); 11661ae650dSJack F Vogel 11761ae650dSJack F Vogel /* Store the timeout */ 118*f247dc25SJack F Vogel hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime; 11961ae650dSJack F Vogel 120*f247dc25SJack F Vogel if (ret_code) 121*f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 122*f247dc25SJack F Vogel "NVM acquire type %d failed time_left=%llu ret=%d aq_err=%d\n", 123*f247dc25SJack F Vogel access, time_left, ret_code, hw->aq.asq_last_status); 124*f247dc25SJack F Vogel 125*f247dc25SJack F Vogel if (ret_code && time_left) { 12661ae650dSJack F Vogel /* Poll until the current NVM owner timeouts */ 127*f247dc25SJack F Vogel timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime; 128*f247dc25SJack F Vogel while ((gtime < timeout) && time_left) { 12961ae650dSJack F Vogel i40e_msec_delay(10); 130*f247dc25SJack F Vogel gtime = rd32(hw, I40E_GLVFGEN_TIMER); 13161ae650dSJack F Vogel ret_code = i40e_aq_request_resource(hw, 13261ae650dSJack F Vogel I40E_NVM_RESOURCE_ID, 133*f247dc25SJack F Vogel access, 0, &time_left, 13461ae650dSJack F Vogel NULL); 13561ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) { 13661ae650dSJack F Vogel hw->nvm.hw_semaphore_timeout = 137*f247dc25SJack F Vogel I40E_MS_TO_GTIME(time_left) + gtime; 13861ae650dSJack F Vogel break; 13961ae650dSJack F Vogel } 14061ae650dSJack F Vogel } 14161ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 14261ae650dSJack F Vogel hw->nvm.hw_semaphore_timeout = 0; 143*f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 144*f247dc25SJack F Vogel "NVM acquire timed out, wait %llu ms before trying again. status=%d aq_err=%d\n", 145*f247dc25SJack F Vogel time_left, ret_code, hw->aq.asq_last_status); 14661ae650dSJack F Vogel } 14761ae650dSJack F Vogel } 14861ae650dSJack F Vogel 14961ae650dSJack F Vogel i40e_i40e_acquire_nvm_exit: 15061ae650dSJack F Vogel return ret_code; 15161ae650dSJack F Vogel } 15261ae650dSJack F Vogel 15361ae650dSJack F Vogel /** 15461ae650dSJack F Vogel * i40e_release_nvm - Generic request for releasing the NVM ownership 15561ae650dSJack F Vogel * @hw: pointer to the HW structure 15661ae650dSJack F Vogel * 15761ae650dSJack F Vogel * This function will release NVM resource via the proper Admin Command. 15861ae650dSJack F Vogel **/ 15961ae650dSJack F Vogel void i40e_release_nvm(struct i40e_hw *hw) 16061ae650dSJack F Vogel { 16161ae650dSJack F Vogel DEBUGFUNC("i40e_release_nvm"); 16261ae650dSJack F Vogel 16361ae650dSJack F Vogel if (!hw->nvm.blank_nvm_mode) 16461ae650dSJack F Vogel i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL); 16561ae650dSJack F Vogel } 16661ae650dSJack F Vogel 16761ae650dSJack F Vogel /** 16861ae650dSJack F Vogel * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit 16961ae650dSJack F Vogel * @hw: pointer to the HW structure 17061ae650dSJack F Vogel * 17161ae650dSJack F Vogel * Polls the SRCTL Shadow RAM register done bit. 17261ae650dSJack F Vogel **/ 17361ae650dSJack F Vogel static enum i40e_status_code i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) 17461ae650dSJack F Vogel { 17561ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; 17661ae650dSJack F Vogel u32 srctl, wait_cnt; 17761ae650dSJack F Vogel 17861ae650dSJack F Vogel DEBUGFUNC("i40e_poll_sr_srctl_done_bit"); 17961ae650dSJack F Vogel 18061ae650dSJack F Vogel /* Poll the I40E_GLNVM_SRCTL until the done bit is set */ 18161ae650dSJack F Vogel for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) { 18261ae650dSJack F Vogel srctl = rd32(hw, I40E_GLNVM_SRCTL); 18361ae650dSJack F Vogel if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) { 18461ae650dSJack F Vogel ret_code = I40E_SUCCESS; 18561ae650dSJack F Vogel break; 18661ae650dSJack F Vogel } 18761ae650dSJack F Vogel i40e_usec_delay(5); 18861ae650dSJack F Vogel } 18961ae650dSJack F Vogel if (ret_code == I40E_ERR_TIMEOUT) 190*f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set"); 19161ae650dSJack F Vogel return ret_code; 19261ae650dSJack F Vogel } 19361ae650dSJack F Vogel 19461ae650dSJack F Vogel /** 19561ae650dSJack F Vogel * i40e_read_nvm_word - Reads Shadow RAM 19661ae650dSJack F Vogel * @hw: pointer to the HW structure 19761ae650dSJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 19861ae650dSJack F Vogel * @data: word read from the Shadow RAM 19961ae650dSJack F Vogel * 20061ae650dSJack F Vogel * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. 20161ae650dSJack F Vogel **/ 20261ae650dSJack F Vogel enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, 20361ae650dSJack F Vogel u16 *data) 20461ae650dSJack F Vogel { 205*f247dc25SJack F Vogel return i40e_read_nvm_word_srctl(hw, offset, data); 206*f247dc25SJack F Vogel } 207*f247dc25SJack F Vogel 208*f247dc25SJack F Vogel /** 209*f247dc25SJack F Vogel * i40e_read_nvm_word_srctl - Reads Shadow RAM via SRCTL register 210*f247dc25SJack F Vogel * @hw: pointer to the HW structure 211*f247dc25SJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 212*f247dc25SJack F Vogel * @data: word read from the Shadow RAM 213*f247dc25SJack F Vogel * 214*f247dc25SJack F Vogel * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. 215*f247dc25SJack F Vogel **/ 216*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset, 217*f247dc25SJack F Vogel u16 *data) 218*f247dc25SJack F Vogel { 21961ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; 22061ae650dSJack F Vogel u32 sr_reg; 22161ae650dSJack F Vogel 222*f247dc25SJack F Vogel DEBUGFUNC("i40e_read_nvm_word_srctl"); 22361ae650dSJack F Vogel 22461ae650dSJack F Vogel if (offset >= hw->nvm.sr_size) { 225*f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 226*f247dc25SJack F Vogel "NVM read error: Offset %d beyond Shadow RAM limit %d\n", 227*f247dc25SJack F Vogel offset, hw->nvm.sr_size); 22861ae650dSJack F Vogel ret_code = I40E_ERR_PARAM; 22961ae650dSJack F Vogel goto read_nvm_exit; 23061ae650dSJack F Vogel } 23161ae650dSJack F Vogel 23261ae650dSJack F Vogel /* Poll the done bit first */ 23361ae650dSJack F Vogel ret_code = i40e_poll_sr_srctl_done_bit(hw); 23461ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) { 23561ae650dSJack F Vogel /* Write the address and start reading */ 23661ae650dSJack F Vogel sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | 23761ae650dSJack F Vogel (1 << I40E_GLNVM_SRCTL_START_SHIFT); 23861ae650dSJack F Vogel wr32(hw, I40E_GLNVM_SRCTL, sr_reg); 23961ae650dSJack F Vogel 24061ae650dSJack F Vogel /* Poll I40E_GLNVM_SRCTL until the done bit is set */ 24161ae650dSJack F Vogel ret_code = i40e_poll_sr_srctl_done_bit(hw); 24261ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) { 24361ae650dSJack F Vogel sr_reg = rd32(hw, I40E_GLNVM_SRDATA); 24461ae650dSJack F Vogel *data = (u16)((sr_reg & 24561ae650dSJack F Vogel I40E_GLNVM_SRDATA_RDDATA_MASK) 24661ae650dSJack F Vogel >> I40E_GLNVM_SRDATA_RDDATA_SHIFT); 24761ae650dSJack F Vogel } 24861ae650dSJack F Vogel } 24961ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) 250*f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 251*f247dc25SJack F Vogel "NVM read error: Couldn't access Shadow RAM address: 0x%x\n", 25261ae650dSJack F Vogel offset); 25361ae650dSJack F Vogel 25461ae650dSJack F Vogel read_nvm_exit: 25561ae650dSJack F Vogel return ret_code; 25661ae650dSJack F Vogel } 25761ae650dSJack F Vogel 25861ae650dSJack F Vogel /** 259*f247dc25SJack F Vogel * i40e_read_nvm_word_aq - Reads Shadow RAM via AQ 260*f247dc25SJack F Vogel * @hw: pointer to the HW structure 261*f247dc25SJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 262*f247dc25SJack F Vogel * @data: word read from the Shadow RAM 263*f247dc25SJack F Vogel * 264*f247dc25SJack F Vogel * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. 265*f247dc25SJack F Vogel **/ 266*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset, 267*f247dc25SJack F Vogel u16 *data) 268*f247dc25SJack F Vogel { 269*f247dc25SJack F Vogel enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; 270*f247dc25SJack F Vogel 271*f247dc25SJack F Vogel DEBUGFUNC("i40e_read_nvm_word_aq"); 272*f247dc25SJack F Vogel 273*f247dc25SJack F Vogel ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, TRUE); 274*f247dc25SJack F Vogel *data = LE16_TO_CPU(*(__le16 *)data); 275*f247dc25SJack F Vogel 276*f247dc25SJack F Vogel return ret_code; 277*f247dc25SJack F Vogel } 278*f247dc25SJack F Vogel 279*f247dc25SJack F Vogel /** 28061ae650dSJack F Vogel * i40e_read_nvm_buffer - Reads Shadow RAM buffer 28161ae650dSJack F Vogel * @hw: pointer to the HW structure 28261ae650dSJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 28361ae650dSJack F Vogel * @words: (in) number of words to read; (out) number of words actually read 28461ae650dSJack F Vogel * @data: words read from the Shadow RAM 28561ae650dSJack F Vogel * 28661ae650dSJack F Vogel * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() 28761ae650dSJack F Vogel * method. The buffer read is preceded by the NVM ownership take 28861ae650dSJack F Vogel * and followed by the release. 28961ae650dSJack F Vogel **/ 29061ae650dSJack F Vogel enum i40e_status_code i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, 29161ae650dSJack F Vogel u16 *words, u16 *data) 29261ae650dSJack F Vogel { 293*f247dc25SJack F Vogel return i40e_read_nvm_buffer_srctl(hw, offset, words, data); 294*f247dc25SJack F Vogel } 295*f247dc25SJack F Vogel 296*f247dc25SJack F Vogel /** 297*f247dc25SJack F Vogel * i40e_read_nvm_buffer_srctl - Reads Shadow RAM buffer via SRCTL register 298*f247dc25SJack F Vogel * @hw: pointer to the HW structure 299*f247dc25SJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 300*f247dc25SJack F Vogel * @words: (in) number of words to read; (out) number of words actually read 301*f247dc25SJack F Vogel * @data: words read from the Shadow RAM 302*f247dc25SJack F Vogel * 303*f247dc25SJack F Vogel * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() 304*f247dc25SJack F Vogel * method. The buffer read is preceded by the NVM ownership take 305*f247dc25SJack F Vogel * and followed by the release. 306*f247dc25SJack F Vogel **/ 307*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset, 308*f247dc25SJack F Vogel u16 *words, u16 *data) 309*f247dc25SJack F Vogel { 31061ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 31161ae650dSJack F Vogel u16 index, word; 31261ae650dSJack F Vogel 313*f247dc25SJack F Vogel DEBUGFUNC("i40e_read_nvm_buffer_srctl"); 31461ae650dSJack F Vogel 31561ae650dSJack F Vogel /* Loop thru the selected region */ 31661ae650dSJack F Vogel for (word = 0; word < *words; word++) { 31761ae650dSJack F Vogel index = offset + word; 318*f247dc25SJack F Vogel ret_code = i40e_read_nvm_word_srctl(hw, index, &data[word]); 31961ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) 32061ae650dSJack F Vogel break; 32161ae650dSJack F Vogel } 32261ae650dSJack F Vogel 32361ae650dSJack F Vogel /* Update the number of words read from the Shadow RAM */ 32461ae650dSJack F Vogel *words = word; 32561ae650dSJack F Vogel 32661ae650dSJack F Vogel return ret_code; 32761ae650dSJack F Vogel } 328*f247dc25SJack F Vogel 329*f247dc25SJack F Vogel /** 330*f247dc25SJack F Vogel * i40e_read_nvm_buffer_aq - Reads Shadow RAM buffer via AQ 331*f247dc25SJack F Vogel * @hw: pointer to the HW structure 332*f247dc25SJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 333*f247dc25SJack F Vogel * @words: (in) number of words to read; (out) number of words actually read 334*f247dc25SJack F Vogel * @data: words read from the Shadow RAM 335*f247dc25SJack F Vogel * 336*f247dc25SJack F Vogel * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_aq() 337*f247dc25SJack F Vogel * method. The buffer read is preceded by the NVM ownership take 338*f247dc25SJack F Vogel * and followed by the release. 339*f247dc25SJack F Vogel **/ 340*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset, 341*f247dc25SJack F Vogel u16 *words, u16 *data) 342*f247dc25SJack F Vogel { 343*f247dc25SJack F Vogel enum i40e_status_code ret_code; 344*f247dc25SJack F Vogel u16 read_size = *words; 345*f247dc25SJack F Vogel bool last_cmd = FALSE; 346*f247dc25SJack F Vogel u16 words_read = 0; 347*f247dc25SJack F Vogel u16 i = 0; 348*f247dc25SJack F Vogel 349*f247dc25SJack F Vogel DEBUGFUNC("i40e_read_nvm_buffer_aq"); 350*f247dc25SJack F Vogel 351*f247dc25SJack F Vogel do { 352*f247dc25SJack F Vogel /* Calculate number of bytes we should read in this step. 353*f247dc25SJack F Vogel * FVL AQ do not allow to read more than one page at a time or 354*f247dc25SJack F Vogel * to cross page boundaries. 355*f247dc25SJack F Vogel */ 356*f247dc25SJack F Vogel if (offset % I40E_SR_SECTOR_SIZE_IN_WORDS) 357*f247dc25SJack F Vogel read_size = min(*words, 358*f247dc25SJack F Vogel (u16)(I40E_SR_SECTOR_SIZE_IN_WORDS - 359*f247dc25SJack F Vogel (offset % I40E_SR_SECTOR_SIZE_IN_WORDS))); 360*f247dc25SJack F Vogel else 361*f247dc25SJack F Vogel read_size = min((*words - words_read), 362*f247dc25SJack F Vogel I40E_SR_SECTOR_SIZE_IN_WORDS); 363*f247dc25SJack F Vogel 364*f247dc25SJack F Vogel /* Check if this is last command, if so set proper flag */ 365*f247dc25SJack F Vogel if ((words_read + read_size) >= *words) 366*f247dc25SJack F Vogel last_cmd = TRUE; 367*f247dc25SJack F Vogel 368*f247dc25SJack F Vogel ret_code = i40e_read_nvm_aq(hw, 0x0, offset, read_size, 369*f247dc25SJack F Vogel data + words_read, last_cmd); 370*f247dc25SJack F Vogel if (ret_code != I40E_SUCCESS) 371*f247dc25SJack F Vogel goto read_nvm_buffer_aq_exit; 372*f247dc25SJack F Vogel 373*f247dc25SJack F Vogel /* Increment counter for words already read and move offset to 374*f247dc25SJack F Vogel * new read location 375*f247dc25SJack F Vogel */ 376*f247dc25SJack F Vogel words_read += read_size; 377*f247dc25SJack F Vogel offset += read_size; 378*f247dc25SJack F Vogel } while (words_read < *words); 379*f247dc25SJack F Vogel 380*f247dc25SJack F Vogel for (i = 0; i < *words; i++) 381*f247dc25SJack F Vogel data[i] = LE16_TO_CPU(((__le16 *)data)[i]); 382*f247dc25SJack F Vogel 383*f247dc25SJack F Vogel read_nvm_buffer_aq_exit: 384*f247dc25SJack F Vogel *words = words_read; 385*f247dc25SJack F Vogel return ret_code; 386*f247dc25SJack F Vogel } 387*f247dc25SJack F Vogel 388*f247dc25SJack F Vogel /** 389*f247dc25SJack F Vogel * i40e_read_nvm_aq - Read Shadow RAM. 390*f247dc25SJack F Vogel * @hw: pointer to the HW structure. 391*f247dc25SJack F Vogel * @module_pointer: module pointer location in words from the NVM beginning 392*f247dc25SJack F Vogel * @offset: offset in words from module start 393*f247dc25SJack F Vogel * @words: number of words to write 394*f247dc25SJack F Vogel * @data: buffer with words to write to the Shadow RAM 395*f247dc25SJack F Vogel * @last_command: tells the AdminQ that this is the last command 396*f247dc25SJack F Vogel * 397*f247dc25SJack F Vogel * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 398*f247dc25SJack F Vogel **/ 399*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer, 400*f247dc25SJack F Vogel u32 offset, u16 words, void *data, 401*f247dc25SJack F Vogel bool last_command) 402*f247dc25SJack F Vogel { 403*f247dc25SJack F Vogel enum i40e_status_code ret_code = I40E_ERR_NVM; 404*f247dc25SJack F Vogel 405*f247dc25SJack F Vogel DEBUGFUNC("i40e_read_nvm_aq"); 406*f247dc25SJack F Vogel 407*f247dc25SJack F Vogel /* Here we are checking the SR limit only for the flat memory model. 408*f247dc25SJack F Vogel * We cannot do it for the module-based model, as we did not acquire 409*f247dc25SJack F Vogel * the NVM resource yet (we cannot get the module pointer value). 410*f247dc25SJack F Vogel * Firmware will check the module-based model. 411*f247dc25SJack F Vogel */ 412*f247dc25SJack F Vogel if ((offset + words) > hw->nvm.sr_size) 413*f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 414*f247dc25SJack F Vogel "NVM write error: offset %d beyond Shadow RAM limit %d\n", 415*f247dc25SJack F Vogel (offset + words), hw->nvm.sr_size); 416*f247dc25SJack F Vogel else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) 417*f247dc25SJack F Vogel /* We can write only up to 4KB (one sector), in one AQ write */ 418*f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 419*f247dc25SJack F Vogel "NVM write fail error: tried to write %d words, limit is %d.\n", 420*f247dc25SJack F Vogel words, I40E_SR_SECTOR_SIZE_IN_WORDS); 421*f247dc25SJack F Vogel else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) 422*f247dc25SJack F Vogel != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) 423*f247dc25SJack F Vogel /* A single write cannot spread over two sectors */ 424*f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 425*f247dc25SJack F Vogel "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n", 426*f247dc25SJack F Vogel offset, words); 427*f247dc25SJack F Vogel else 428*f247dc25SJack F Vogel ret_code = i40e_aq_read_nvm(hw, module_pointer, 429*f247dc25SJack F Vogel 2 * offset, /*bytes*/ 430*f247dc25SJack F Vogel 2 * words, /*bytes*/ 431*f247dc25SJack F Vogel data, last_command, NULL); 432*f247dc25SJack F Vogel 433*f247dc25SJack F Vogel return ret_code; 434*f247dc25SJack F Vogel } 435*f247dc25SJack F Vogel 43661ae650dSJack F Vogel /** 43761ae650dSJack F Vogel * i40e_write_nvm_aq - Writes Shadow RAM. 43861ae650dSJack F Vogel * @hw: pointer to the HW structure. 43961ae650dSJack F Vogel * @module_pointer: module pointer location in words from the NVM beginning 44061ae650dSJack F Vogel * @offset: offset in words from module start 44161ae650dSJack F Vogel * @words: number of words to write 44261ae650dSJack F Vogel * @data: buffer with words to write to the Shadow RAM 44361ae650dSJack F Vogel * @last_command: tells the AdminQ that this is the last command 44461ae650dSJack F Vogel * 44561ae650dSJack F Vogel * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 44661ae650dSJack F Vogel **/ 44761ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer, 44861ae650dSJack F Vogel u32 offset, u16 words, void *data, 44961ae650dSJack F Vogel bool last_command) 45061ae650dSJack F Vogel { 45161ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_ERR_NVM; 45261ae650dSJack F Vogel 45361ae650dSJack F Vogel DEBUGFUNC("i40e_write_nvm_aq"); 45461ae650dSJack F Vogel 45561ae650dSJack F Vogel /* Here we are checking the SR limit only for the flat memory model. 45661ae650dSJack F Vogel * We cannot do it for the module-based model, as we did not acquire 45761ae650dSJack F Vogel * the NVM resource yet (we cannot get the module pointer value). 45861ae650dSJack F Vogel * Firmware will check the module-based model. 45961ae650dSJack F Vogel */ 46061ae650dSJack F Vogel if ((offset + words) > hw->nvm.sr_size) 46161ae650dSJack F Vogel DEBUGOUT("NVM write error: offset beyond Shadow RAM limit.\n"); 46261ae650dSJack F Vogel else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) 46361ae650dSJack F Vogel /* We can write only up to 4KB (one sector), in one AQ write */ 46461ae650dSJack F Vogel DEBUGOUT("NVM write fail error: cannot write more than 4KB in a single write.\n"); 46561ae650dSJack F Vogel else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) 46661ae650dSJack F Vogel != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) 46761ae650dSJack F Vogel /* A single write cannot spread over two sectors */ 46861ae650dSJack F Vogel DEBUGOUT("NVM write error: cannot spread over two sectors in a single write.\n"); 46961ae650dSJack F Vogel else 47061ae650dSJack F Vogel ret_code = i40e_aq_update_nvm(hw, module_pointer, 47161ae650dSJack F Vogel 2 * offset, /*bytes*/ 47261ae650dSJack F Vogel 2 * words, /*bytes*/ 47361ae650dSJack F Vogel data, last_command, NULL); 47461ae650dSJack F Vogel 47561ae650dSJack F Vogel return ret_code; 47661ae650dSJack F Vogel } 47761ae650dSJack F Vogel 47861ae650dSJack F Vogel /** 47961ae650dSJack F Vogel * i40e_write_nvm_word - Writes Shadow RAM word 48061ae650dSJack F Vogel * @hw: pointer to the HW structure 48161ae650dSJack F Vogel * @offset: offset of the Shadow RAM word to write 48261ae650dSJack F Vogel * @data: word to write to the Shadow RAM 48361ae650dSJack F Vogel * 48461ae650dSJack F Vogel * Writes a 16 bit word to the SR using the i40e_write_nvm_aq() method. 48561ae650dSJack F Vogel * NVM ownership have to be acquired and released (on ARQ completion event 48661ae650dSJack F Vogel * reception) by caller. To commit SR to NVM update checksum function 48761ae650dSJack F Vogel * should be called. 48861ae650dSJack F Vogel **/ 48961ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_word(struct i40e_hw *hw, u32 offset, 49061ae650dSJack F Vogel void *data) 49161ae650dSJack F Vogel { 49261ae650dSJack F Vogel DEBUGFUNC("i40e_write_nvm_word"); 49361ae650dSJack F Vogel 494*f247dc25SJack F Vogel *((__le16 *)data) = CPU_TO_LE16(*((u16 *)data)); 495*f247dc25SJack F Vogel 49661ae650dSJack F Vogel /* Value 0x00 below means that we treat SR as a flat mem */ 49761ae650dSJack F Vogel return i40e_write_nvm_aq(hw, 0x00, offset, 1, data, FALSE); 49861ae650dSJack F Vogel } 49961ae650dSJack F Vogel 50061ae650dSJack F Vogel /** 50161ae650dSJack F Vogel * i40e_write_nvm_buffer - Writes Shadow RAM buffer 50261ae650dSJack F Vogel * @hw: pointer to the HW structure 50361ae650dSJack F Vogel * @module_pointer: module pointer location in words from the NVM beginning 50461ae650dSJack F Vogel * @offset: offset of the Shadow RAM buffer to write 50561ae650dSJack F Vogel * @words: number of words to write 50661ae650dSJack F Vogel * @data: words to write to the Shadow RAM 50761ae650dSJack F Vogel * 50861ae650dSJack F Vogel * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 50961ae650dSJack F Vogel * NVM ownership must be acquired before calling this function and released 51061ae650dSJack F Vogel * on ARQ completion event reception by caller. To commit SR to NVM update 51161ae650dSJack F Vogel * checksum function should be called. 51261ae650dSJack F Vogel **/ 51361ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_buffer(struct i40e_hw *hw, 51461ae650dSJack F Vogel u8 module_pointer, u32 offset, 51561ae650dSJack F Vogel u16 words, void *data) 51661ae650dSJack F Vogel { 517*f247dc25SJack F Vogel __le16 *le_word_ptr = (__le16 *)data; 518*f247dc25SJack F Vogel u16 *word_ptr = (u16 *)data; 519*f247dc25SJack F Vogel u32 i = 0; 520*f247dc25SJack F Vogel 52161ae650dSJack F Vogel DEBUGFUNC("i40e_write_nvm_buffer"); 52261ae650dSJack F Vogel 523*f247dc25SJack F Vogel for (i = 0; i < words; i++) 524*f247dc25SJack F Vogel le_word_ptr[i] = CPU_TO_LE16(word_ptr[i]); 525*f247dc25SJack F Vogel 52661ae650dSJack F Vogel /* Here we will only write one buffer as the size of the modules 52761ae650dSJack F Vogel * mirrored in the Shadow RAM is always less than 4K. 52861ae650dSJack F Vogel */ 52961ae650dSJack F Vogel return i40e_write_nvm_aq(hw, module_pointer, offset, words, 53061ae650dSJack F Vogel data, FALSE); 53161ae650dSJack F Vogel } 53261ae650dSJack F Vogel 53361ae650dSJack F Vogel /** 53461ae650dSJack F Vogel * i40e_calc_nvm_checksum - Calculates and returns the checksum 53561ae650dSJack F Vogel * @hw: pointer to hardware structure 53661ae650dSJack F Vogel * @checksum: pointer to the checksum 53761ae650dSJack F Vogel * 53861ae650dSJack F Vogel * This function calculates SW Checksum that covers the whole 64kB shadow RAM 53961ae650dSJack F Vogel * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD 54061ae650dSJack F Vogel * is customer specific and unknown. Therefore, this function skips all maximum 54161ae650dSJack F Vogel * possible size of VPD (1kB). 54261ae650dSJack F Vogel **/ 54361ae650dSJack F Vogel enum i40e_status_code i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum) 54461ae650dSJack F Vogel { 54561ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 546*f247dc25SJack F Vogel struct i40e_virt_mem vmem; 54761ae650dSJack F Vogel u16 pcie_alt_module = 0; 54861ae650dSJack F Vogel u16 checksum_local = 0; 54961ae650dSJack F Vogel u16 vpd_module = 0; 550*f247dc25SJack F Vogel u16 *data; 551*f247dc25SJack F Vogel u16 i = 0; 55261ae650dSJack F Vogel 55361ae650dSJack F Vogel DEBUGFUNC("i40e_calc_nvm_checksum"); 55461ae650dSJack F Vogel 555*f247dc25SJack F Vogel ret_code = i40e_allocate_virt_mem(hw, &vmem, 556*f247dc25SJack F Vogel I40E_SR_SECTOR_SIZE_IN_WORDS * sizeof(u16)); 557*f247dc25SJack F Vogel if (ret_code) 558*f247dc25SJack F Vogel goto i40e_calc_nvm_checksum_exit; 559*f247dc25SJack F Vogel data = (u16 *)vmem.va; 560*f247dc25SJack F Vogel 56161ae650dSJack F Vogel /* read pointer to VPD area */ 56261ae650dSJack F Vogel ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module); 56361ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 56461ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 56561ae650dSJack F Vogel goto i40e_calc_nvm_checksum_exit; 56661ae650dSJack F Vogel } 56761ae650dSJack F Vogel 56861ae650dSJack F Vogel /* read pointer to PCIe Alt Auto-load module */ 56961ae650dSJack F Vogel ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR, 57061ae650dSJack F Vogel &pcie_alt_module); 57161ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 57261ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 57361ae650dSJack F Vogel goto i40e_calc_nvm_checksum_exit; 57461ae650dSJack F Vogel } 57561ae650dSJack F Vogel 57661ae650dSJack F Vogel /* Calculate SW checksum that covers the whole 64kB shadow RAM 57761ae650dSJack F Vogel * except the VPD and PCIe ALT Auto-load modules 57861ae650dSJack F Vogel */ 57961ae650dSJack F Vogel for (i = 0; i < hw->nvm.sr_size; i++) { 580*f247dc25SJack F Vogel /* Read SR page */ 581*f247dc25SJack F Vogel if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) { 582*f247dc25SJack F Vogel u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS; 583*f247dc25SJack F Vogel ret_code = i40e_read_nvm_buffer(hw, i, &words, data); 58461ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 58561ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 58661ae650dSJack F Vogel goto i40e_calc_nvm_checksum_exit; 58761ae650dSJack F Vogel } 588*f247dc25SJack F Vogel } 589*f247dc25SJack F Vogel 590*f247dc25SJack F Vogel /* Skip Checksum word */ 591*f247dc25SJack F Vogel if (i == I40E_SR_SW_CHECKSUM_WORD) 592*f247dc25SJack F Vogel continue; 593*f247dc25SJack F Vogel /* Skip VPD module (convert byte size to word count) */ 594*f247dc25SJack F Vogel if ((i >= (u32)vpd_module) && 595*f247dc25SJack F Vogel (i < ((u32)vpd_module + 596*f247dc25SJack F Vogel (I40E_SR_VPD_MODULE_MAX_SIZE / 2)))) { 597*f247dc25SJack F Vogel continue; 598*f247dc25SJack F Vogel } 599*f247dc25SJack F Vogel /* Skip PCIe ALT module (convert byte size to word count) */ 600*f247dc25SJack F Vogel if ((i >= (u32)pcie_alt_module) && 601*f247dc25SJack F Vogel (i < ((u32)pcie_alt_module + 602*f247dc25SJack F Vogel (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2)))) { 603*f247dc25SJack F Vogel continue; 604*f247dc25SJack F Vogel } 605*f247dc25SJack F Vogel 606*f247dc25SJack F Vogel checksum_local += data[i % I40E_SR_SECTOR_SIZE_IN_WORDS]; 60761ae650dSJack F Vogel } 60861ae650dSJack F Vogel 60961ae650dSJack F Vogel *checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local; 61061ae650dSJack F Vogel 61161ae650dSJack F Vogel i40e_calc_nvm_checksum_exit: 612*f247dc25SJack F Vogel i40e_free_virt_mem(hw, &vmem); 61361ae650dSJack F Vogel return ret_code; 61461ae650dSJack F Vogel } 61561ae650dSJack F Vogel 61661ae650dSJack F Vogel /** 61761ae650dSJack F Vogel * i40e_update_nvm_checksum - Updates the NVM checksum 61861ae650dSJack F Vogel * @hw: pointer to hardware structure 61961ae650dSJack F Vogel * 62061ae650dSJack F Vogel * NVM ownership must be acquired before calling this function and released 62161ae650dSJack F Vogel * on ARQ completion event reception by caller. 62261ae650dSJack F Vogel * This function will commit SR to NVM. 62361ae650dSJack F Vogel **/ 62461ae650dSJack F Vogel enum i40e_status_code i40e_update_nvm_checksum(struct i40e_hw *hw) 62561ae650dSJack F Vogel { 62661ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 62761ae650dSJack F Vogel u16 checksum; 62861ae650dSJack F Vogel 62961ae650dSJack F Vogel DEBUGFUNC("i40e_update_nvm_checksum"); 63061ae650dSJack F Vogel 63161ae650dSJack F Vogel ret_code = i40e_calc_nvm_checksum(hw, &checksum); 63261ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) 63361ae650dSJack F Vogel ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD, 63461ae650dSJack F Vogel 1, &checksum, TRUE); 63561ae650dSJack F Vogel 63661ae650dSJack F Vogel return ret_code; 63761ae650dSJack F Vogel } 63861ae650dSJack F Vogel 63961ae650dSJack F Vogel /** 64061ae650dSJack F Vogel * i40e_validate_nvm_checksum - Validate EEPROM checksum 64161ae650dSJack F Vogel * @hw: pointer to hardware structure 64261ae650dSJack F Vogel * @checksum: calculated checksum 64361ae650dSJack F Vogel * 64461ae650dSJack F Vogel * Performs checksum calculation and validates the NVM SW checksum. If the 64561ae650dSJack F Vogel * caller does not need checksum, the value can be NULL. 64661ae650dSJack F Vogel **/ 64761ae650dSJack F Vogel enum i40e_status_code i40e_validate_nvm_checksum(struct i40e_hw *hw, 64861ae650dSJack F Vogel u16 *checksum) 64961ae650dSJack F Vogel { 65061ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 65161ae650dSJack F Vogel u16 checksum_sr = 0; 65261ae650dSJack F Vogel u16 checksum_local = 0; 65361ae650dSJack F Vogel 65461ae650dSJack F Vogel DEBUGFUNC("i40e_validate_nvm_checksum"); 65561ae650dSJack F Vogel 65661ae650dSJack F Vogel ret_code = i40e_calc_nvm_checksum(hw, &checksum_local); 65761ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) 65861ae650dSJack F Vogel goto i40e_validate_nvm_checksum_exit; 65961ae650dSJack F Vogel 66061ae650dSJack F Vogel /* Do not use i40e_read_nvm_word() because we do not want to take 66161ae650dSJack F Vogel * the synchronization semaphores twice here. 66261ae650dSJack F Vogel */ 66361ae650dSJack F Vogel i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr); 66461ae650dSJack F Vogel 66561ae650dSJack F Vogel /* Verify read checksum from EEPROM is the same as 66661ae650dSJack F Vogel * calculated checksum 66761ae650dSJack F Vogel */ 66861ae650dSJack F Vogel if (checksum_local != checksum_sr) 66961ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 67061ae650dSJack F Vogel 67161ae650dSJack F Vogel /* If the user cares, return the calculated checksum */ 67261ae650dSJack F Vogel if (checksum) 67361ae650dSJack F Vogel *checksum = checksum_local; 67461ae650dSJack F Vogel 67561ae650dSJack F Vogel i40e_validate_nvm_checksum_exit: 67661ae650dSJack F Vogel return ret_code; 67761ae650dSJack F Vogel } 678