161ae650dSJack F Vogel /****************************************************************************** 261ae650dSJack F Vogel 3be771cdaSJack F Vogel Copyright (c) 2013-2015, 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 37f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset, 38f247dc25SJack F Vogel u16 *data); 39f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset, 40f247dc25SJack F Vogel u16 *data); 41f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset, 42f247dc25SJack F Vogel u16 *words, u16 *data); 43f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset, 44f247dc25SJack F Vogel u16 *words, u16 *data); 45f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer, 46f247dc25SJack F Vogel u32 offset, u16 words, void *data, 47f247dc25SJack F Vogel bool last_command); 48f247dc25SJack 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) */ 75be771cdaSJack F Vogel nvm->sr_size = BIT(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; 86f247dc25SJack 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; 105f247dc25SJack 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, 113f247dc25SJack 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 */ 118f247dc25SJack F Vogel hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime; 11961ae650dSJack F Vogel 120f247dc25SJack F Vogel if (ret_code) 121f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 122f247dc25SJack F Vogel "NVM acquire type %d failed time_left=%llu ret=%d aq_err=%d\n", 123f247dc25SJack F Vogel access, time_left, ret_code, hw->aq.asq_last_status); 124f247dc25SJack F Vogel 125f247dc25SJack F Vogel if (ret_code && time_left) { 12661ae650dSJack F Vogel /* Poll until the current NVM owner timeouts */ 127f247dc25SJack F Vogel timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime; 128f247dc25SJack F Vogel while ((gtime < timeout) && time_left) { 12961ae650dSJack F Vogel i40e_msec_delay(10); 130f247dc25SJack 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, 133f247dc25SJack 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 = 137f247dc25SJack 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; 143f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 144f247dc25SJack F Vogel "NVM acquire timed out, wait %llu ms before trying again. status=%d aq_err=%d\n", 145f247dc25SJack 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 { 161be771cdaSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 162be771cdaSJack F Vogel u32 total_delay = 0; 163be771cdaSJack F Vogel 16461ae650dSJack F Vogel DEBUGFUNC("i40e_release_nvm"); 16561ae650dSJack F Vogel 166be771cdaSJack F Vogel if (hw->nvm.blank_nvm_mode) 167be771cdaSJack F Vogel return; 168be771cdaSJack F Vogel 169be771cdaSJack F Vogel ret_code = i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL); 170be771cdaSJack F Vogel 171be771cdaSJack F Vogel /* there are some rare cases when trying to release the resource 172be771cdaSJack F Vogel * results in an admin Q timeout, so handle them correctly 173be771cdaSJack F Vogel */ 174be771cdaSJack F Vogel while ((ret_code == I40E_ERR_ADMIN_QUEUE_TIMEOUT) && 175be771cdaSJack F Vogel (total_delay < hw->aq.asq_cmd_timeout)) { 176be771cdaSJack F Vogel i40e_msec_delay(1); 177be771cdaSJack F Vogel ret_code = i40e_aq_release_resource(hw, 178be771cdaSJack F Vogel I40E_NVM_RESOURCE_ID, 0, NULL); 179be771cdaSJack F Vogel total_delay++; 180be771cdaSJack F Vogel } 18161ae650dSJack F Vogel } 18261ae650dSJack F Vogel 18361ae650dSJack F Vogel /** 18461ae650dSJack F Vogel * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit 18561ae650dSJack F Vogel * @hw: pointer to the HW structure 18661ae650dSJack F Vogel * 18761ae650dSJack F Vogel * Polls the SRCTL Shadow RAM register done bit. 18861ae650dSJack F Vogel **/ 18961ae650dSJack F Vogel static enum i40e_status_code i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) 19061ae650dSJack F Vogel { 19161ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; 19261ae650dSJack F Vogel u32 srctl, wait_cnt; 19361ae650dSJack F Vogel 19461ae650dSJack F Vogel DEBUGFUNC("i40e_poll_sr_srctl_done_bit"); 19561ae650dSJack F Vogel 19661ae650dSJack F Vogel /* Poll the I40E_GLNVM_SRCTL until the done bit is set */ 19761ae650dSJack F Vogel for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) { 19861ae650dSJack F Vogel srctl = rd32(hw, I40E_GLNVM_SRCTL); 19961ae650dSJack F Vogel if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) { 20061ae650dSJack F Vogel ret_code = I40E_SUCCESS; 20161ae650dSJack F Vogel break; 20261ae650dSJack F Vogel } 20361ae650dSJack F Vogel i40e_usec_delay(5); 20461ae650dSJack F Vogel } 20561ae650dSJack F Vogel if (ret_code == I40E_ERR_TIMEOUT) 206f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set"); 20761ae650dSJack F Vogel return ret_code; 20861ae650dSJack F Vogel } 20961ae650dSJack F Vogel 21061ae650dSJack F Vogel /** 21161ae650dSJack F Vogel * i40e_read_nvm_word - Reads Shadow RAM 21261ae650dSJack F Vogel * @hw: pointer to the HW structure 21361ae650dSJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 21461ae650dSJack F Vogel * @data: word read from the Shadow RAM 21561ae650dSJack F Vogel * 21661ae650dSJack F Vogel * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. 21761ae650dSJack F Vogel **/ 21861ae650dSJack F Vogel enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, 21961ae650dSJack F Vogel u16 *data) 22061ae650dSJack F Vogel { 221*223d846dSEric Joyner enum i40e_status_code ret_code = I40E_SUCCESS; 222*223d846dSEric Joyner 223*223d846dSEric Joyner ret_code = i40e_read_nvm_word_srctl(hw, offset, data); 224*223d846dSEric Joyner return ret_code; 225f247dc25SJack F Vogel } 226f247dc25SJack F Vogel 227f247dc25SJack F Vogel /** 228f247dc25SJack F Vogel * i40e_read_nvm_word_srctl - Reads Shadow RAM via SRCTL register 229f247dc25SJack F Vogel * @hw: pointer to the HW structure 230f247dc25SJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 231f247dc25SJack F Vogel * @data: word read from the Shadow RAM 232f247dc25SJack F Vogel * 233f247dc25SJack F Vogel * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. 234f247dc25SJack F Vogel **/ 235f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset, 236f247dc25SJack F Vogel u16 *data) 237f247dc25SJack F Vogel { 23861ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; 23961ae650dSJack F Vogel u32 sr_reg; 24061ae650dSJack F Vogel 241f247dc25SJack F Vogel DEBUGFUNC("i40e_read_nvm_word_srctl"); 24261ae650dSJack F Vogel 24361ae650dSJack F Vogel if (offset >= hw->nvm.sr_size) { 244f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 245f247dc25SJack F Vogel "NVM read error: Offset %d beyond Shadow RAM limit %d\n", 246f247dc25SJack F Vogel offset, hw->nvm.sr_size); 24761ae650dSJack F Vogel ret_code = I40E_ERR_PARAM; 24861ae650dSJack F Vogel goto read_nvm_exit; 24961ae650dSJack F Vogel } 25061ae650dSJack F Vogel 25161ae650dSJack F Vogel /* Poll the done bit first */ 25261ae650dSJack F Vogel ret_code = i40e_poll_sr_srctl_done_bit(hw); 25361ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) { 25461ae650dSJack F Vogel /* Write the address and start reading */ 255be771cdaSJack F Vogel sr_reg = ((u32)offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | 256be771cdaSJack F Vogel BIT(I40E_GLNVM_SRCTL_START_SHIFT); 25761ae650dSJack F Vogel wr32(hw, I40E_GLNVM_SRCTL, sr_reg); 25861ae650dSJack F Vogel 25961ae650dSJack F Vogel /* Poll I40E_GLNVM_SRCTL until the done bit is set */ 26061ae650dSJack F Vogel ret_code = i40e_poll_sr_srctl_done_bit(hw); 26161ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) { 26261ae650dSJack F Vogel sr_reg = rd32(hw, I40E_GLNVM_SRDATA); 26361ae650dSJack F Vogel *data = (u16)((sr_reg & 26461ae650dSJack F Vogel I40E_GLNVM_SRDATA_RDDATA_MASK) 26561ae650dSJack F Vogel >> I40E_GLNVM_SRDATA_RDDATA_SHIFT); 26661ae650dSJack F Vogel } 26761ae650dSJack F Vogel } 26861ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) 269f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 270f247dc25SJack F Vogel "NVM read error: Couldn't access Shadow RAM address: 0x%x\n", 27161ae650dSJack F Vogel offset); 27261ae650dSJack F Vogel 27361ae650dSJack F Vogel read_nvm_exit: 27461ae650dSJack F Vogel return ret_code; 27561ae650dSJack F Vogel } 27661ae650dSJack F Vogel 27761ae650dSJack F Vogel /** 278f247dc25SJack F Vogel * i40e_read_nvm_word_aq - Reads Shadow RAM via AQ 279f247dc25SJack F Vogel * @hw: pointer to the HW structure 280f247dc25SJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 281f247dc25SJack F Vogel * @data: word read from the Shadow RAM 282f247dc25SJack F Vogel * 283f247dc25SJack F Vogel * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. 284f247dc25SJack F Vogel **/ 285f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset, 286f247dc25SJack F Vogel u16 *data) 287f247dc25SJack F Vogel { 288f247dc25SJack F Vogel enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; 289f247dc25SJack F Vogel 290f247dc25SJack F Vogel DEBUGFUNC("i40e_read_nvm_word_aq"); 291f247dc25SJack F Vogel 292f247dc25SJack F Vogel ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, TRUE); 293f247dc25SJack F Vogel *data = LE16_TO_CPU(*(__le16 *)data); 294f247dc25SJack F Vogel 295f247dc25SJack F Vogel return ret_code; 296f247dc25SJack F Vogel } 297f247dc25SJack F Vogel 298f247dc25SJack F Vogel /** 29961ae650dSJack F Vogel * i40e_read_nvm_buffer - Reads Shadow RAM buffer 30061ae650dSJack F Vogel * @hw: pointer to the HW structure 30161ae650dSJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 30261ae650dSJack F Vogel * @words: (in) number of words to read; (out) number of words actually read 30361ae650dSJack F Vogel * @data: words read from the Shadow RAM 30461ae650dSJack F Vogel * 30561ae650dSJack F Vogel * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() 30661ae650dSJack F Vogel * method. The buffer read is preceded by the NVM ownership take 30761ae650dSJack F Vogel * and followed by the release. 30861ae650dSJack F Vogel **/ 30961ae650dSJack F Vogel enum i40e_status_code i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, 31061ae650dSJack F Vogel u16 *words, u16 *data) 31161ae650dSJack F Vogel { 312*223d846dSEric Joyner enum i40e_status_code ret_code = I40E_SUCCESS; 313*223d846dSEric Joyner 314*223d846dSEric Joyner ret_code = i40e_read_nvm_buffer_srctl(hw, offset, words, data); 315*223d846dSEric Joyner return ret_code; 316f247dc25SJack F Vogel } 317f247dc25SJack F Vogel 318f247dc25SJack F Vogel /** 319f247dc25SJack F Vogel * i40e_read_nvm_buffer_srctl - Reads Shadow RAM buffer via SRCTL register 320f247dc25SJack F Vogel * @hw: pointer to the HW structure 321f247dc25SJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 322f247dc25SJack F Vogel * @words: (in) number of words to read; (out) number of words actually read 323f247dc25SJack F Vogel * @data: words read from the Shadow RAM 324f247dc25SJack F Vogel * 325f247dc25SJack F Vogel * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() 326f247dc25SJack F Vogel * method. The buffer read is preceded by the NVM ownership take 327f247dc25SJack F Vogel * and followed by the release. 328f247dc25SJack F Vogel **/ 329f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset, 330f247dc25SJack F Vogel u16 *words, u16 *data) 331f247dc25SJack F Vogel { 33261ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 33361ae650dSJack F Vogel u16 index, word; 33461ae650dSJack F Vogel 335f247dc25SJack F Vogel DEBUGFUNC("i40e_read_nvm_buffer_srctl"); 33661ae650dSJack F Vogel 33761ae650dSJack F Vogel /* Loop thru the selected region */ 33861ae650dSJack F Vogel for (word = 0; word < *words; word++) { 33961ae650dSJack F Vogel index = offset + word; 340f247dc25SJack F Vogel ret_code = i40e_read_nvm_word_srctl(hw, index, &data[word]); 34161ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) 34261ae650dSJack F Vogel break; 34361ae650dSJack F Vogel } 34461ae650dSJack F Vogel 34561ae650dSJack F Vogel /* Update the number of words read from the Shadow RAM */ 34661ae650dSJack F Vogel *words = word; 34761ae650dSJack F Vogel 34861ae650dSJack F Vogel return ret_code; 34961ae650dSJack F Vogel } 350f247dc25SJack F Vogel 351f247dc25SJack F Vogel /** 352f247dc25SJack F Vogel * i40e_read_nvm_buffer_aq - Reads Shadow RAM buffer via AQ 353f247dc25SJack F Vogel * @hw: pointer to the HW structure 354f247dc25SJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 355f247dc25SJack F Vogel * @words: (in) number of words to read; (out) number of words actually read 356f247dc25SJack F Vogel * @data: words read from the Shadow RAM 357f247dc25SJack F Vogel * 358f247dc25SJack F Vogel * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_aq() 359f247dc25SJack F Vogel * method. The buffer read is preceded by the NVM ownership take 360f247dc25SJack F Vogel * and followed by the release. 361f247dc25SJack F Vogel **/ 362f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset, 363f247dc25SJack F Vogel u16 *words, u16 *data) 364f247dc25SJack F Vogel { 365f247dc25SJack F Vogel enum i40e_status_code ret_code; 366f247dc25SJack F Vogel u16 read_size = *words; 367f247dc25SJack F Vogel bool last_cmd = FALSE; 368f247dc25SJack F Vogel u16 words_read = 0; 369f247dc25SJack F Vogel u16 i = 0; 370f247dc25SJack F Vogel 371f247dc25SJack F Vogel DEBUGFUNC("i40e_read_nvm_buffer_aq"); 372f247dc25SJack F Vogel 373f247dc25SJack F Vogel do { 374f247dc25SJack F Vogel /* Calculate number of bytes we should read in this step. 375f247dc25SJack F Vogel * FVL AQ do not allow to read more than one page at a time or 376f247dc25SJack F Vogel * to cross page boundaries. 377f247dc25SJack F Vogel */ 378f247dc25SJack F Vogel if (offset % I40E_SR_SECTOR_SIZE_IN_WORDS) 379f247dc25SJack F Vogel read_size = min(*words, 380f247dc25SJack F Vogel (u16)(I40E_SR_SECTOR_SIZE_IN_WORDS - 381f247dc25SJack F Vogel (offset % I40E_SR_SECTOR_SIZE_IN_WORDS))); 382f247dc25SJack F Vogel else 383f247dc25SJack F Vogel read_size = min((*words - words_read), 384f247dc25SJack F Vogel I40E_SR_SECTOR_SIZE_IN_WORDS); 385f247dc25SJack F Vogel 386f247dc25SJack F Vogel /* Check if this is last command, if so set proper flag */ 387f247dc25SJack F Vogel if ((words_read + read_size) >= *words) 388f247dc25SJack F Vogel last_cmd = TRUE; 389f247dc25SJack F Vogel 390f247dc25SJack F Vogel ret_code = i40e_read_nvm_aq(hw, 0x0, offset, read_size, 391f247dc25SJack F Vogel data + words_read, last_cmd); 392f247dc25SJack F Vogel if (ret_code != I40E_SUCCESS) 393f247dc25SJack F Vogel goto read_nvm_buffer_aq_exit; 394f247dc25SJack F Vogel 395f247dc25SJack F Vogel /* Increment counter for words already read and move offset to 396f247dc25SJack F Vogel * new read location 397f247dc25SJack F Vogel */ 398f247dc25SJack F Vogel words_read += read_size; 399f247dc25SJack F Vogel offset += read_size; 400f247dc25SJack F Vogel } while (words_read < *words); 401f247dc25SJack F Vogel 402f247dc25SJack F Vogel for (i = 0; i < *words; i++) 403f247dc25SJack F Vogel data[i] = LE16_TO_CPU(((__le16 *)data)[i]); 404f247dc25SJack F Vogel 405f247dc25SJack F Vogel read_nvm_buffer_aq_exit: 406f247dc25SJack F Vogel *words = words_read; 407f247dc25SJack F Vogel return ret_code; 408f247dc25SJack F Vogel } 409f247dc25SJack F Vogel 410f247dc25SJack F Vogel /** 411f247dc25SJack F Vogel * i40e_read_nvm_aq - Read Shadow RAM. 412f247dc25SJack F Vogel * @hw: pointer to the HW structure. 413f247dc25SJack F Vogel * @module_pointer: module pointer location in words from the NVM beginning 414f247dc25SJack F Vogel * @offset: offset in words from module start 415f247dc25SJack F Vogel * @words: number of words to write 416f247dc25SJack F Vogel * @data: buffer with words to write to the Shadow RAM 417f247dc25SJack F Vogel * @last_command: tells the AdminQ that this is the last command 418f247dc25SJack F Vogel * 419f247dc25SJack F Vogel * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 420f247dc25SJack F Vogel **/ 421f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer, 422f247dc25SJack F Vogel u32 offset, u16 words, void *data, 423f247dc25SJack F Vogel bool last_command) 424f247dc25SJack F Vogel { 425f247dc25SJack F Vogel enum i40e_status_code ret_code = I40E_ERR_NVM; 426be771cdaSJack F Vogel struct i40e_asq_cmd_details cmd_details; 427f247dc25SJack F Vogel 428f247dc25SJack F Vogel DEBUGFUNC("i40e_read_nvm_aq"); 429f247dc25SJack F Vogel 430be771cdaSJack F Vogel memset(&cmd_details, 0, sizeof(cmd_details)); 431be771cdaSJack F Vogel cmd_details.wb_desc = &hw->nvm_wb_desc; 432be771cdaSJack F Vogel 433f247dc25SJack F Vogel /* Here we are checking the SR limit only for the flat memory model. 434f247dc25SJack F Vogel * We cannot do it for the module-based model, as we did not acquire 435f247dc25SJack F Vogel * the NVM resource yet (we cannot get the module pointer value). 436f247dc25SJack F Vogel * Firmware will check the module-based model. 437f247dc25SJack F Vogel */ 438f247dc25SJack F Vogel if ((offset + words) > hw->nvm.sr_size) 439f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 440f247dc25SJack F Vogel "NVM write error: offset %d beyond Shadow RAM limit %d\n", 441f247dc25SJack F Vogel (offset + words), hw->nvm.sr_size); 442f247dc25SJack F Vogel else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) 443f247dc25SJack F Vogel /* We can write only up to 4KB (one sector), in one AQ write */ 444f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 445f247dc25SJack F Vogel "NVM write fail error: tried to write %d words, limit is %d.\n", 446f247dc25SJack F Vogel words, I40E_SR_SECTOR_SIZE_IN_WORDS); 447f247dc25SJack F Vogel else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) 448f247dc25SJack F Vogel != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) 449f247dc25SJack F Vogel /* A single write cannot spread over two sectors */ 450f247dc25SJack F Vogel i40e_debug(hw, I40E_DEBUG_NVM, 451f247dc25SJack F Vogel "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n", 452f247dc25SJack F Vogel offset, words); 453f247dc25SJack F Vogel else 454f247dc25SJack F Vogel ret_code = i40e_aq_read_nvm(hw, module_pointer, 455f247dc25SJack F Vogel 2 * offset, /*bytes*/ 456f247dc25SJack F Vogel 2 * words, /*bytes*/ 457be771cdaSJack F Vogel data, last_command, &cmd_details); 458f247dc25SJack F Vogel 459f247dc25SJack F Vogel return ret_code; 460f247dc25SJack F Vogel } 461f247dc25SJack F Vogel 46261ae650dSJack F Vogel /** 46361ae650dSJack F Vogel * i40e_write_nvm_aq - Writes Shadow RAM. 46461ae650dSJack F Vogel * @hw: pointer to the HW structure. 46561ae650dSJack F Vogel * @module_pointer: module pointer location in words from the NVM beginning 46661ae650dSJack F Vogel * @offset: offset in words from module start 46761ae650dSJack F Vogel * @words: number of words to write 46861ae650dSJack F Vogel * @data: buffer with words to write to the Shadow RAM 46961ae650dSJack F Vogel * @last_command: tells the AdminQ that this is the last command 47061ae650dSJack F Vogel * 47161ae650dSJack F Vogel * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 47261ae650dSJack F Vogel **/ 47361ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer, 47461ae650dSJack F Vogel u32 offset, u16 words, void *data, 47561ae650dSJack F Vogel bool last_command) 47661ae650dSJack F Vogel { 47761ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_ERR_NVM; 478be771cdaSJack F Vogel struct i40e_asq_cmd_details cmd_details; 47961ae650dSJack F Vogel 48061ae650dSJack F Vogel DEBUGFUNC("i40e_write_nvm_aq"); 48161ae650dSJack F Vogel 482be771cdaSJack F Vogel memset(&cmd_details, 0, sizeof(cmd_details)); 483be771cdaSJack F Vogel cmd_details.wb_desc = &hw->nvm_wb_desc; 484be771cdaSJack F Vogel 48561ae650dSJack F Vogel /* Here we are checking the SR limit only for the flat memory model. 48661ae650dSJack F Vogel * We cannot do it for the module-based model, as we did not acquire 48761ae650dSJack F Vogel * the NVM resource yet (we cannot get the module pointer value). 48861ae650dSJack F Vogel * Firmware will check the module-based model. 48961ae650dSJack F Vogel */ 49061ae650dSJack F Vogel if ((offset + words) > hw->nvm.sr_size) 49161ae650dSJack F Vogel DEBUGOUT("NVM write error: offset beyond Shadow RAM limit.\n"); 49261ae650dSJack F Vogel else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) 49361ae650dSJack F Vogel /* We can write only up to 4KB (one sector), in one AQ write */ 49461ae650dSJack F Vogel DEBUGOUT("NVM write fail error: cannot write more than 4KB in a single write.\n"); 49561ae650dSJack F Vogel else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) 49661ae650dSJack F Vogel != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) 49761ae650dSJack F Vogel /* A single write cannot spread over two sectors */ 49861ae650dSJack F Vogel DEBUGOUT("NVM write error: cannot spread over two sectors in a single write.\n"); 49961ae650dSJack F Vogel else 50061ae650dSJack F Vogel ret_code = i40e_aq_update_nvm(hw, module_pointer, 50161ae650dSJack F Vogel 2 * offset, /*bytes*/ 50261ae650dSJack F Vogel 2 * words, /*bytes*/ 503be771cdaSJack F Vogel data, last_command, &cmd_details); 50461ae650dSJack F Vogel 50561ae650dSJack F Vogel return ret_code; 50661ae650dSJack F Vogel } 50761ae650dSJack F Vogel 50861ae650dSJack F Vogel /** 50961ae650dSJack F Vogel * i40e_write_nvm_word - Writes Shadow RAM word 51061ae650dSJack F Vogel * @hw: pointer to the HW structure 51161ae650dSJack F Vogel * @offset: offset of the Shadow RAM word to write 51261ae650dSJack F Vogel * @data: word to write to the Shadow RAM 51361ae650dSJack F Vogel * 51461ae650dSJack F Vogel * Writes a 16 bit word to the SR using the i40e_write_nvm_aq() method. 51561ae650dSJack F Vogel * NVM ownership have to be acquired and released (on ARQ completion event 51661ae650dSJack F Vogel * reception) by caller. To commit SR to NVM update checksum function 51761ae650dSJack F Vogel * should be called. 51861ae650dSJack F Vogel **/ 51961ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_word(struct i40e_hw *hw, u32 offset, 52061ae650dSJack F Vogel void *data) 52161ae650dSJack F Vogel { 52261ae650dSJack F Vogel DEBUGFUNC("i40e_write_nvm_word"); 52361ae650dSJack F Vogel 524f247dc25SJack F Vogel *((__le16 *)data) = CPU_TO_LE16(*((u16 *)data)); 525f247dc25SJack F Vogel 52661ae650dSJack F Vogel /* Value 0x00 below means that we treat SR as a flat mem */ 52761ae650dSJack F Vogel return i40e_write_nvm_aq(hw, 0x00, offset, 1, data, FALSE); 52861ae650dSJack F Vogel } 52961ae650dSJack F Vogel 53061ae650dSJack F Vogel /** 53161ae650dSJack F Vogel * i40e_write_nvm_buffer - Writes Shadow RAM buffer 53261ae650dSJack F Vogel * @hw: pointer to the HW structure 53361ae650dSJack F Vogel * @module_pointer: module pointer location in words from the NVM beginning 53461ae650dSJack F Vogel * @offset: offset of the Shadow RAM buffer to write 53561ae650dSJack F Vogel * @words: number of words to write 53661ae650dSJack F Vogel * @data: words to write to the Shadow RAM 53761ae650dSJack F Vogel * 53861ae650dSJack F Vogel * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 53961ae650dSJack F Vogel * NVM ownership must be acquired before calling this function and released 54061ae650dSJack F Vogel * on ARQ completion event reception by caller. To commit SR to NVM update 54161ae650dSJack F Vogel * checksum function should be called. 54261ae650dSJack F Vogel **/ 54361ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_buffer(struct i40e_hw *hw, 54461ae650dSJack F Vogel u8 module_pointer, u32 offset, 54561ae650dSJack F Vogel u16 words, void *data) 54661ae650dSJack F Vogel { 547f247dc25SJack F Vogel __le16 *le_word_ptr = (__le16 *)data; 548f247dc25SJack F Vogel u16 *word_ptr = (u16 *)data; 549f247dc25SJack F Vogel u32 i = 0; 550f247dc25SJack F Vogel 55161ae650dSJack F Vogel DEBUGFUNC("i40e_write_nvm_buffer"); 55261ae650dSJack F Vogel 553f247dc25SJack F Vogel for (i = 0; i < words; i++) 554f247dc25SJack F Vogel le_word_ptr[i] = CPU_TO_LE16(word_ptr[i]); 555f247dc25SJack F Vogel 55661ae650dSJack F Vogel /* Here we will only write one buffer as the size of the modules 55761ae650dSJack F Vogel * mirrored in the Shadow RAM is always less than 4K. 55861ae650dSJack F Vogel */ 55961ae650dSJack F Vogel return i40e_write_nvm_aq(hw, module_pointer, offset, words, 56061ae650dSJack F Vogel data, FALSE); 56161ae650dSJack F Vogel } 56261ae650dSJack F Vogel 56361ae650dSJack F Vogel /** 56461ae650dSJack F Vogel * i40e_calc_nvm_checksum - Calculates and returns the checksum 56561ae650dSJack F Vogel * @hw: pointer to hardware structure 56661ae650dSJack F Vogel * @checksum: pointer to the checksum 56761ae650dSJack F Vogel * 56861ae650dSJack F Vogel * This function calculates SW Checksum that covers the whole 64kB shadow RAM 56961ae650dSJack F Vogel * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD 57061ae650dSJack F Vogel * is customer specific and unknown. Therefore, this function skips all maximum 57161ae650dSJack F Vogel * possible size of VPD (1kB). 57261ae650dSJack F Vogel **/ 57361ae650dSJack F Vogel enum i40e_status_code i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum) 57461ae650dSJack F Vogel { 57561ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 576f247dc25SJack F Vogel struct i40e_virt_mem vmem; 57761ae650dSJack F Vogel u16 pcie_alt_module = 0; 57861ae650dSJack F Vogel u16 checksum_local = 0; 57961ae650dSJack F Vogel u16 vpd_module = 0; 580f247dc25SJack F Vogel u16 *data; 581f247dc25SJack F Vogel u16 i = 0; 58261ae650dSJack F Vogel 58361ae650dSJack F Vogel DEBUGFUNC("i40e_calc_nvm_checksum"); 58461ae650dSJack F Vogel 585f247dc25SJack F Vogel ret_code = i40e_allocate_virt_mem(hw, &vmem, 586f247dc25SJack F Vogel I40E_SR_SECTOR_SIZE_IN_WORDS * sizeof(u16)); 587f247dc25SJack F Vogel if (ret_code) 588f247dc25SJack F Vogel goto i40e_calc_nvm_checksum_exit; 589f247dc25SJack F Vogel data = (u16 *)vmem.va; 590f247dc25SJack F Vogel 59161ae650dSJack F Vogel /* read pointer to VPD area */ 59261ae650dSJack F Vogel ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module); 59361ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 59461ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 59561ae650dSJack F Vogel goto i40e_calc_nvm_checksum_exit; 59661ae650dSJack F Vogel } 59761ae650dSJack F Vogel 59861ae650dSJack F Vogel /* read pointer to PCIe Alt Auto-load module */ 59961ae650dSJack F Vogel ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR, 60061ae650dSJack F Vogel &pcie_alt_module); 60161ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 60261ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 60361ae650dSJack F Vogel goto i40e_calc_nvm_checksum_exit; 60461ae650dSJack F Vogel } 60561ae650dSJack F Vogel 60661ae650dSJack F Vogel /* Calculate SW checksum that covers the whole 64kB shadow RAM 60761ae650dSJack F Vogel * except the VPD and PCIe ALT Auto-load modules 60861ae650dSJack F Vogel */ 60961ae650dSJack F Vogel for (i = 0; i < hw->nvm.sr_size; i++) { 610f247dc25SJack F Vogel /* Read SR page */ 611f247dc25SJack F Vogel if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) { 612f247dc25SJack F Vogel u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS; 613be771cdaSJack F Vogel 614f247dc25SJack F Vogel ret_code = i40e_read_nvm_buffer(hw, i, &words, data); 61561ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 61661ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 61761ae650dSJack F Vogel goto i40e_calc_nvm_checksum_exit; 61861ae650dSJack F Vogel } 619f247dc25SJack F Vogel } 620f247dc25SJack F Vogel 621f247dc25SJack F Vogel /* Skip Checksum word */ 622f247dc25SJack F Vogel if (i == I40E_SR_SW_CHECKSUM_WORD) 623f247dc25SJack F Vogel continue; 624f247dc25SJack F Vogel /* Skip VPD module (convert byte size to word count) */ 625f247dc25SJack F Vogel if ((i >= (u32)vpd_module) && 626f247dc25SJack F Vogel (i < ((u32)vpd_module + 627f247dc25SJack F Vogel (I40E_SR_VPD_MODULE_MAX_SIZE / 2)))) { 628f247dc25SJack F Vogel continue; 629f247dc25SJack F Vogel } 630f247dc25SJack F Vogel /* Skip PCIe ALT module (convert byte size to word count) */ 631f247dc25SJack F Vogel if ((i >= (u32)pcie_alt_module) && 632f247dc25SJack F Vogel (i < ((u32)pcie_alt_module + 633f247dc25SJack F Vogel (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2)))) { 634f247dc25SJack F Vogel continue; 635f247dc25SJack F Vogel } 636f247dc25SJack F Vogel 637f247dc25SJack F Vogel checksum_local += data[i % I40E_SR_SECTOR_SIZE_IN_WORDS]; 63861ae650dSJack F Vogel } 63961ae650dSJack F Vogel 64061ae650dSJack F Vogel *checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local; 64161ae650dSJack F Vogel 64261ae650dSJack F Vogel i40e_calc_nvm_checksum_exit: 643f247dc25SJack F Vogel i40e_free_virt_mem(hw, &vmem); 64461ae650dSJack F Vogel return ret_code; 64561ae650dSJack F Vogel } 64661ae650dSJack F Vogel 64761ae650dSJack F Vogel /** 64861ae650dSJack F Vogel * i40e_update_nvm_checksum - Updates the NVM checksum 64961ae650dSJack F Vogel * @hw: pointer to hardware structure 65061ae650dSJack F Vogel * 65161ae650dSJack F Vogel * NVM ownership must be acquired before calling this function and released 65261ae650dSJack F Vogel * on ARQ completion event reception by caller. 65361ae650dSJack F Vogel * This function will commit SR to NVM. 65461ae650dSJack F Vogel **/ 65561ae650dSJack F Vogel enum i40e_status_code i40e_update_nvm_checksum(struct i40e_hw *hw) 65661ae650dSJack F Vogel { 65761ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 65861ae650dSJack F Vogel u16 checksum; 659be771cdaSJack F Vogel __le16 le_sum; 66061ae650dSJack F Vogel 66161ae650dSJack F Vogel DEBUGFUNC("i40e_update_nvm_checksum"); 66261ae650dSJack F Vogel 66361ae650dSJack F Vogel ret_code = i40e_calc_nvm_checksum(hw, &checksum); 664be771cdaSJack F Vogel le_sum = CPU_TO_LE16(checksum); 66561ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) 66661ae650dSJack F Vogel ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD, 667be771cdaSJack F Vogel 1, &le_sum, TRUE); 66861ae650dSJack F Vogel 66961ae650dSJack F Vogel return ret_code; 67061ae650dSJack F Vogel } 67161ae650dSJack F Vogel 67261ae650dSJack F Vogel /** 67361ae650dSJack F Vogel * i40e_validate_nvm_checksum - Validate EEPROM checksum 67461ae650dSJack F Vogel * @hw: pointer to hardware structure 67561ae650dSJack F Vogel * @checksum: calculated checksum 67661ae650dSJack F Vogel * 67761ae650dSJack F Vogel * Performs checksum calculation and validates the NVM SW checksum. If the 67861ae650dSJack F Vogel * caller does not need checksum, the value can be NULL. 67961ae650dSJack F Vogel **/ 68061ae650dSJack F Vogel enum i40e_status_code i40e_validate_nvm_checksum(struct i40e_hw *hw, 68161ae650dSJack F Vogel u16 *checksum) 68261ae650dSJack F Vogel { 68361ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 68461ae650dSJack F Vogel u16 checksum_sr = 0; 68561ae650dSJack F Vogel u16 checksum_local = 0; 68661ae650dSJack F Vogel 68761ae650dSJack F Vogel DEBUGFUNC("i40e_validate_nvm_checksum"); 68861ae650dSJack F Vogel 68961ae650dSJack F Vogel ret_code = i40e_calc_nvm_checksum(hw, &checksum_local); 69061ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) 69161ae650dSJack F Vogel goto i40e_validate_nvm_checksum_exit; 69261ae650dSJack F Vogel 69361ae650dSJack F Vogel /* Do not use i40e_read_nvm_word() because we do not want to take 69461ae650dSJack F Vogel * the synchronization semaphores twice here. 69561ae650dSJack F Vogel */ 69661ae650dSJack F Vogel i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr); 69761ae650dSJack F Vogel 69861ae650dSJack F Vogel /* Verify read checksum from EEPROM is the same as 69961ae650dSJack F Vogel * calculated checksum 70061ae650dSJack F Vogel */ 70161ae650dSJack F Vogel if (checksum_local != checksum_sr) 70261ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 70361ae650dSJack F Vogel 70461ae650dSJack F Vogel /* If the user cares, return the calculated checksum */ 70561ae650dSJack F Vogel if (checksum) 70661ae650dSJack F Vogel *checksum = checksum_local; 70761ae650dSJack F Vogel 70861ae650dSJack F Vogel i40e_validate_nvm_checksum_exit: 70961ae650dSJack F Vogel return ret_code; 71061ae650dSJack F Vogel } 711*223d846dSEric Joyner 712*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw, 713*223d846dSEric Joyner struct i40e_nvm_access *cmd, 714*223d846dSEric Joyner u8 *bytes, int *perrno); 715*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_state_reading(struct i40e_hw *hw, 716*223d846dSEric Joyner struct i40e_nvm_access *cmd, 717*223d846dSEric Joyner u8 *bytes, int *perrno); 718*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_state_writing(struct i40e_hw *hw, 719*223d846dSEric Joyner struct i40e_nvm_access *cmd, 720*223d846dSEric Joyner u8 *bytes, int *perrno); 721*223d846dSEric Joyner static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, 722*223d846dSEric Joyner struct i40e_nvm_access *cmd, 723*223d846dSEric Joyner int *perrno); 724*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_nvm_erase(struct i40e_hw *hw, 725*223d846dSEric Joyner struct i40e_nvm_access *cmd, 726*223d846dSEric Joyner int *perrno); 727*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_nvm_write(struct i40e_hw *hw, 728*223d846dSEric Joyner struct i40e_nvm_access *cmd, 729*223d846dSEric Joyner u8 *bytes, int *perrno); 730*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_nvm_read(struct i40e_hw *hw, 731*223d846dSEric Joyner struct i40e_nvm_access *cmd, 732*223d846dSEric Joyner u8 *bytes, int *perrno); 733*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw, 734*223d846dSEric Joyner struct i40e_nvm_access *cmd, 735*223d846dSEric Joyner u8 *bytes, int *perrno); 736*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_get_aq_result(struct i40e_hw *hw, 737*223d846dSEric Joyner struct i40e_nvm_access *cmd, 738*223d846dSEric Joyner u8 *bytes, int *perrno); 739*223d846dSEric Joyner static INLINE u8 i40e_nvmupd_get_module(u32 val) 740*223d846dSEric Joyner { 741*223d846dSEric Joyner return (u8)(val & I40E_NVM_MOD_PNT_MASK); 742*223d846dSEric Joyner } 743*223d846dSEric Joyner static INLINE u8 i40e_nvmupd_get_transaction(u32 val) 744*223d846dSEric Joyner { 745*223d846dSEric Joyner return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT); 746*223d846dSEric Joyner } 747*223d846dSEric Joyner 748*223d846dSEric Joyner static const char *i40e_nvm_update_state_str[] = { 749*223d846dSEric Joyner "I40E_NVMUPD_INVALID", 750*223d846dSEric Joyner "I40E_NVMUPD_READ_CON", 751*223d846dSEric Joyner "I40E_NVMUPD_READ_SNT", 752*223d846dSEric Joyner "I40E_NVMUPD_READ_LCB", 753*223d846dSEric Joyner "I40E_NVMUPD_READ_SA", 754*223d846dSEric Joyner "I40E_NVMUPD_WRITE_ERA", 755*223d846dSEric Joyner "I40E_NVMUPD_WRITE_CON", 756*223d846dSEric Joyner "I40E_NVMUPD_WRITE_SNT", 757*223d846dSEric Joyner "I40E_NVMUPD_WRITE_LCB", 758*223d846dSEric Joyner "I40E_NVMUPD_WRITE_SA", 759*223d846dSEric Joyner "I40E_NVMUPD_CSUM_CON", 760*223d846dSEric Joyner "I40E_NVMUPD_CSUM_SA", 761*223d846dSEric Joyner "I40E_NVMUPD_CSUM_LCB", 762*223d846dSEric Joyner "I40E_NVMUPD_STATUS", 763*223d846dSEric Joyner "I40E_NVMUPD_EXEC_AQ", 764*223d846dSEric Joyner "I40E_NVMUPD_GET_AQ_RESULT", 765*223d846dSEric Joyner }; 766*223d846dSEric Joyner 767*223d846dSEric Joyner /** 768*223d846dSEric Joyner * i40e_nvmupd_command - Process an NVM update command 769*223d846dSEric Joyner * @hw: pointer to hardware structure 770*223d846dSEric Joyner * @cmd: pointer to nvm update command 771*223d846dSEric Joyner * @bytes: pointer to the data buffer 772*223d846dSEric Joyner * @perrno: pointer to return error code 773*223d846dSEric Joyner * 774*223d846dSEric Joyner * Dispatches command depending on what update state is current 775*223d846dSEric Joyner **/ 776*223d846dSEric Joyner enum i40e_status_code i40e_nvmupd_command(struct i40e_hw *hw, 777*223d846dSEric Joyner struct i40e_nvm_access *cmd, 778*223d846dSEric Joyner u8 *bytes, int *perrno) 779*223d846dSEric Joyner { 780*223d846dSEric Joyner enum i40e_status_code status; 781*223d846dSEric Joyner enum i40e_nvmupd_cmd upd_cmd; 782*223d846dSEric Joyner 783*223d846dSEric Joyner DEBUGFUNC("i40e_nvmupd_command"); 784*223d846dSEric Joyner 785*223d846dSEric Joyner /* assume success */ 786*223d846dSEric Joyner *perrno = 0; 787*223d846dSEric Joyner 788*223d846dSEric Joyner /* early check for status command and debug msgs */ 789*223d846dSEric Joyner upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno); 790*223d846dSEric Joyner 791*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, "%s state %d nvm_release_on_hold %d\n", 792*223d846dSEric Joyner i40e_nvm_update_state_str[upd_cmd], 793*223d846dSEric Joyner hw->nvmupd_state, 794*223d846dSEric Joyner hw->aq.nvm_release_on_done); 795*223d846dSEric Joyner 796*223d846dSEric Joyner if (upd_cmd == I40E_NVMUPD_INVALID) { 797*223d846dSEric Joyner *perrno = -EFAULT; 798*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 799*223d846dSEric Joyner "i40e_nvmupd_validate_command returns %d errno %d\n", 800*223d846dSEric Joyner upd_cmd, *perrno); 801*223d846dSEric Joyner } 802*223d846dSEric Joyner 803*223d846dSEric Joyner /* a status request returns immediately rather than 804*223d846dSEric Joyner * going into the state machine 805*223d846dSEric Joyner */ 806*223d846dSEric Joyner if (upd_cmd == I40E_NVMUPD_STATUS) { 807*223d846dSEric Joyner bytes[0] = hw->nvmupd_state; 808*223d846dSEric Joyner return I40E_SUCCESS; 809*223d846dSEric Joyner } 810*223d846dSEric Joyner 811*223d846dSEric Joyner switch (hw->nvmupd_state) { 812*223d846dSEric Joyner case I40E_NVMUPD_STATE_INIT: 813*223d846dSEric Joyner status = i40e_nvmupd_state_init(hw, cmd, bytes, perrno); 814*223d846dSEric Joyner break; 815*223d846dSEric Joyner 816*223d846dSEric Joyner case I40E_NVMUPD_STATE_READING: 817*223d846dSEric Joyner status = i40e_nvmupd_state_reading(hw, cmd, bytes, perrno); 818*223d846dSEric Joyner break; 819*223d846dSEric Joyner 820*223d846dSEric Joyner case I40E_NVMUPD_STATE_WRITING: 821*223d846dSEric Joyner status = i40e_nvmupd_state_writing(hw, cmd, bytes, perrno); 822*223d846dSEric Joyner break; 823*223d846dSEric Joyner 824*223d846dSEric Joyner case I40E_NVMUPD_STATE_INIT_WAIT: 825*223d846dSEric Joyner case I40E_NVMUPD_STATE_WRITE_WAIT: 826*223d846dSEric Joyner status = I40E_ERR_NOT_READY; 827*223d846dSEric Joyner *perrno = -EBUSY; 828*223d846dSEric Joyner break; 829*223d846dSEric Joyner 830*223d846dSEric Joyner default: 831*223d846dSEric Joyner /* invalid state, should never happen */ 832*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 833*223d846dSEric Joyner "NVMUPD: no such state %d\n", hw->nvmupd_state); 834*223d846dSEric Joyner status = I40E_NOT_SUPPORTED; 835*223d846dSEric Joyner *perrno = -ESRCH; 836*223d846dSEric Joyner break; 837*223d846dSEric Joyner } 838*223d846dSEric Joyner return status; 839*223d846dSEric Joyner } 840*223d846dSEric Joyner 841*223d846dSEric Joyner /** 842*223d846dSEric Joyner * i40e_nvmupd_state_init - Handle NVM update state Init 843*223d846dSEric Joyner * @hw: pointer to hardware structure 844*223d846dSEric Joyner * @cmd: pointer to nvm update command buffer 845*223d846dSEric Joyner * @bytes: pointer to the data buffer 846*223d846dSEric Joyner * @perrno: pointer to return error code 847*223d846dSEric Joyner * 848*223d846dSEric Joyner * Process legitimate commands of the Init state and conditionally set next 849*223d846dSEric Joyner * state. Reject all other commands. 850*223d846dSEric Joyner **/ 851*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw, 852*223d846dSEric Joyner struct i40e_nvm_access *cmd, 853*223d846dSEric Joyner u8 *bytes, int *perrno) 854*223d846dSEric Joyner { 855*223d846dSEric Joyner enum i40e_status_code status = I40E_SUCCESS; 856*223d846dSEric Joyner enum i40e_nvmupd_cmd upd_cmd; 857*223d846dSEric Joyner 858*223d846dSEric Joyner DEBUGFUNC("i40e_nvmupd_state_init"); 859*223d846dSEric Joyner 860*223d846dSEric Joyner upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno); 861*223d846dSEric Joyner 862*223d846dSEric Joyner switch (upd_cmd) { 863*223d846dSEric Joyner case I40E_NVMUPD_READ_SA: 864*223d846dSEric Joyner status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 865*223d846dSEric Joyner if (status) { 866*223d846dSEric Joyner *perrno = i40e_aq_rc_to_posix(status, 867*223d846dSEric Joyner hw->aq.asq_last_status); 868*223d846dSEric Joyner } else { 869*223d846dSEric Joyner status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno); 870*223d846dSEric Joyner i40e_release_nvm(hw); 871*223d846dSEric Joyner } 872*223d846dSEric Joyner break; 873*223d846dSEric Joyner 874*223d846dSEric Joyner case I40E_NVMUPD_READ_SNT: 875*223d846dSEric Joyner status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 876*223d846dSEric Joyner if (status) { 877*223d846dSEric Joyner *perrno = i40e_aq_rc_to_posix(status, 878*223d846dSEric Joyner hw->aq.asq_last_status); 879*223d846dSEric Joyner } else { 880*223d846dSEric Joyner status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno); 881*223d846dSEric Joyner if (status) 882*223d846dSEric Joyner i40e_release_nvm(hw); 883*223d846dSEric Joyner else 884*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_READING; 885*223d846dSEric Joyner } 886*223d846dSEric Joyner break; 887*223d846dSEric Joyner 888*223d846dSEric Joyner case I40E_NVMUPD_WRITE_ERA: 889*223d846dSEric Joyner status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 890*223d846dSEric Joyner if (status) { 891*223d846dSEric Joyner *perrno = i40e_aq_rc_to_posix(status, 892*223d846dSEric Joyner hw->aq.asq_last_status); 893*223d846dSEric Joyner } else { 894*223d846dSEric Joyner status = i40e_nvmupd_nvm_erase(hw, cmd, perrno); 895*223d846dSEric Joyner if (status) { 896*223d846dSEric Joyner i40e_release_nvm(hw); 897*223d846dSEric Joyner } else { 898*223d846dSEric Joyner hw->aq.nvm_release_on_done = TRUE; 899*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 900*223d846dSEric Joyner } 901*223d846dSEric Joyner } 902*223d846dSEric Joyner break; 903*223d846dSEric Joyner 904*223d846dSEric Joyner case I40E_NVMUPD_WRITE_SA: 905*223d846dSEric Joyner status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 906*223d846dSEric Joyner if (status) { 907*223d846dSEric Joyner *perrno = i40e_aq_rc_to_posix(status, 908*223d846dSEric Joyner hw->aq.asq_last_status); 909*223d846dSEric Joyner } else { 910*223d846dSEric Joyner status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno); 911*223d846dSEric Joyner if (status) { 912*223d846dSEric Joyner i40e_release_nvm(hw); 913*223d846dSEric Joyner } else { 914*223d846dSEric Joyner hw->aq.nvm_release_on_done = TRUE; 915*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 916*223d846dSEric Joyner } 917*223d846dSEric Joyner } 918*223d846dSEric Joyner break; 919*223d846dSEric Joyner 920*223d846dSEric Joyner case I40E_NVMUPD_WRITE_SNT: 921*223d846dSEric Joyner status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 922*223d846dSEric Joyner if (status) { 923*223d846dSEric Joyner *perrno = i40e_aq_rc_to_posix(status, 924*223d846dSEric Joyner hw->aq.asq_last_status); 925*223d846dSEric Joyner } else { 926*223d846dSEric Joyner status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno); 927*223d846dSEric Joyner if (status) 928*223d846dSEric Joyner i40e_release_nvm(hw); 929*223d846dSEric Joyner else 930*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT; 931*223d846dSEric Joyner } 932*223d846dSEric Joyner break; 933*223d846dSEric Joyner 934*223d846dSEric Joyner case I40E_NVMUPD_CSUM_SA: 935*223d846dSEric Joyner status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 936*223d846dSEric Joyner if (status) { 937*223d846dSEric Joyner *perrno = i40e_aq_rc_to_posix(status, 938*223d846dSEric Joyner hw->aq.asq_last_status); 939*223d846dSEric Joyner } else { 940*223d846dSEric Joyner status = i40e_update_nvm_checksum(hw); 941*223d846dSEric Joyner if (status) { 942*223d846dSEric Joyner *perrno = hw->aq.asq_last_status ? 943*223d846dSEric Joyner i40e_aq_rc_to_posix(status, 944*223d846dSEric Joyner hw->aq.asq_last_status) : 945*223d846dSEric Joyner -EIO; 946*223d846dSEric Joyner i40e_release_nvm(hw); 947*223d846dSEric Joyner } else { 948*223d846dSEric Joyner hw->aq.nvm_release_on_done = TRUE; 949*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 950*223d846dSEric Joyner } 951*223d846dSEric Joyner } 952*223d846dSEric Joyner break; 953*223d846dSEric Joyner 954*223d846dSEric Joyner case I40E_NVMUPD_EXEC_AQ: 955*223d846dSEric Joyner status = i40e_nvmupd_exec_aq(hw, cmd, bytes, perrno); 956*223d846dSEric Joyner break; 957*223d846dSEric Joyner 958*223d846dSEric Joyner case I40E_NVMUPD_GET_AQ_RESULT: 959*223d846dSEric Joyner status = i40e_nvmupd_get_aq_result(hw, cmd, bytes, perrno); 960*223d846dSEric Joyner break; 961*223d846dSEric Joyner 962*223d846dSEric Joyner default: 963*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 964*223d846dSEric Joyner "NVMUPD: bad cmd %s in init state\n", 965*223d846dSEric Joyner i40e_nvm_update_state_str[upd_cmd]); 966*223d846dSEric Joyner status = I40E_ERR_NVM; 967*223d846dSEric Joyner *perrno = -ESRCH; 968*223d846dSEric Joyner break; 969*223d846dSEric Joyner } 970*223d846dSEric Joyner return status; 971*223d846dSEric Joyner } 972*223d846dSEric Joyner 973*223d846dSEric Joyner /** 974*223d846dSEric Joyner * i40e_nvmupd_state_reading - Handle NVM update state Reading 975*223d846dSEric Joyner * @hw: pointer to hardware structure 976*223d846dSEric Joyner * @cmd: pointer to nvm update command buffer 977*223d846dSEric Joyner * @bytes: pointer to the data buffer 978*223d846dSEric Joyner * @perrno: pointer to return error code 979*223d846dSEric Joyner * 980*223d846dSEric Joyner * NVM ownership is already held. Process legitimate commands and set any 981*223d846dSEric Joyner * change in state; reject all other commands. 982*223d846dSEric Joyner **/ 983*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_state_reading(struct i40e_hw *hw, 984*223d846dSEric Joyner struct i40e_nvm_access *cmd, 985*223d846dSEric Joyner u8 *bytes, int *perrno) 986*223d846dSEric Joyner { 987*223d846dSEric Joyner enum i40e_status_code status = I40E_SUCCESS; 988*223d846dSEric Joyner enum i40e_nvmupd_cmd upd_cmd; 989*223d846dSEric Joyner 990*223d846dSEric Joyner DEBUGFUNC("i40e_nvmupd_state_reading"); 991*223d846dSEric Joyner 992*223d846dSEric Joyner upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno); 993*223d846dSEric Joyner 994*223d846dSEric Joyner switch (upd_cmd) { 995*223d846dSEric Joyner case I40E_NVMUPD_READ_SA: 996*223d846dSEric Joyner case I40E_NVMUPD_READ_CON: 997*223d846dSEric Joyner status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno); 998*223d846dSEric Joyner break; 999*223d846dSEric Joyner 1000*223d846dSEric Joyner case I40E_NVMUPD_READ_LCB: 1001*223d846dSEric Joyner status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno); 1002*223d846dSEric Joyner i40e_release_nvm(hw); 1003*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 1004*223d846dSEric Joyner break; 1005*223d846dSEric Joyner 1006*223d846dSEric Joyner default: 1007*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1008*223d846dSEric Joyner "NVMUPD: bad cmd %s in reading state.\n", 1009*223d846dSEric Joyner i40e_nvm_update_state_str[upd_cmd]); 1010*223d846dSEric Joyner status = I40E_NOT_SUPPORTED; 1011*223d846dSEric Joyner *perrno = -ESRCH; 1012*223d846dSEric Joyner break; 1013*223d846dSEric Joyner } 1014*223d846dSEric Joyner return status; 1015*223d846dSEric Joyner } 1016*223d846dSEric Joyner 1017*223d846dSEric Joyner /** 1018*223d846dSEric Joyner * i40e_nvmupd_state_writing - Handle NVM update state Writing 1019*223d846dSEric Joyner * @hw: pointer to hardware structure 1020*223d846dSEric Joyner * @cmd: pointer to nvm update command buffer 1021*223d846dSEric Joyner * @bytes: pointer to the data buffer 1022*223d846dSEric Joyner * @perrno: pointer to return error code 1023*223d846dSEric Joyner * 1024*223d846dSEric Joyner * NVM ownership is already held. Process legitimate commands and set any 1025*223d846dSEric Joyner * change in state; reject all other commands 1026*223d846dSEric Joyner **/ 1027*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_state_writing(struct i40e_hw *hw, 1028*223d846dSEric Joyner struct i40e_nvm_access *cmd, 1029*223d846dSEric Joyner u8 *bytes, int *perrno) 1030*223d846dSEric Joyner { 1031*223d846dSEric Joyner enum i40e_status_code status = I40E_SUCCESS; 1032*223d846dSEric Joyner enum i40e_nvmupd_cmd upd_cmd; 1033*223d846dSEric Joyner bool retry_attempt = FALSE; 1034*223d846dSEric Joyner 1035*223d846dSEric Joyner DEBUGFUNC("i40e_nvmupd_state_writing"); 1036*223d846dSEric Joyner 1037*223d846dSEric Joyner upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno); 1038*223d846dSEric Joyner 1039*223d846dSEric Joyner retry: 1040*223d846dSEric Joyner switch (upd_cmd) { 1041*223d846dSEric Joyner case I40E_NVMUPD_WRITE_CON: 1042*223d846dSEric Joyner status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno); 1043*223d846dSEric Joyner if (!status) 1044*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT; 1045*223d846dSEric Joyner break; 1046*223d846dSEric Joyner 1047*223d846dSEric Joyner case I40E_NVMUPD_WRITE_LCB: 1048*223d846dSEric Joyner status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno); 1049*223d846dSEric Joyner if (status) { 1050*223d846dSEric Joyner *perrno = hw->aq.asq_last_status ? 1051*223d846dSEric Joyner i40e_aq_rc_to_posix(status, 1052*223d846dSEric Joyner hw->aq.asq_last_status) : 1053*223d846dSEric Joyner -EIO; 1054*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 1055*223d846dSEric Joyner } else { 1056*223d846dSEric Joyner hw->aq.nvm_release_on_done = TRUE; 1057*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 1058*223d846dSEric Joyner } 1059*223d846dSEric Joyner break; 1060*223d846dSEric Joyner 1061*223d846dSEric Joyner case I40E_NVMUPD_CSUM_CON: 1062*223d846dSEric Joyner status = i40e_update_nvm_checksum(hw); 1063*223d846dSEric Joyner if (status) { 1064*223d846dSEric Joyner *perrno = hw->aq.asq_last_status ? 1065*223d846dSEric Joyner i40e_aq_rc_to_posix(status, 1066*223d846dSEric Joyner hw->aq.asq_last_status) : 1067*223d846dSEric Joyner -EIO; 1068*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 1069*223d846dSEric Joyner } else { 1070*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT; 1071*223d846dSEric Joyner } 1072*223d846dSEric Joyner break; 1073*223d846dSEric Joyner 1074*223d846dSEric Joyner case I40E_NVMUPD_CSUM_LCB: 1075*223d846dSEric Joyner status = i40e_update_nvm_checksum(hw); 1076*223d846dSEric Joyner if (status) { 1077*223d846dSEric Joyner *perrno = hw->aq.asq_last_status ? 1078*223d846dSEric Joyner i40e_aq_rc_to_posix(status, 1079*223d846dSEric Joyner hw->aq.asq_last_status) : 1080*223d846dSEric Joyner -EIO; 1081*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 1082*223d846dSEric Joyner } else { 1083*223d846dSEric Joyner hw->aq.nvm_release_on_done = TRUE; 1084*223d846dSEric Joyner hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 1085*223d846dSEric Joyner } 1086*223d846dSEric Joyner break; 1087*223d846dSEric Joyner 1088*223d846dSEric Joyner default: 1089*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1090*223d846dSEric Joyner "NVMUPD: bad cmd %s in writing state.\n", 1091*223d846dSEric Joyner i40e_nvm_update_state_str[upd_cmd]); 1092*223d846dSEric Joyner status = I40E_NOT_SUPPORTED; 1093*223d846dSEric Joyner *perrno = -ESRCH; 1094*223d846dSEric Joyner break; 1095*223d846dSEric Joyner } 1096*223d846dSEric Joyner 1097*223d846dSEric Joyner /* In some circumstances, a multi-write transaction takes longer 1098*223d846dSEric Joyner * than the default 3 minute timeout on the write semaphore. If 1099*223d846dSEric Joyner * the write failed with an EBUSY status, this is likely the problem, 1100*223d846dSEric Joyner * so here we try to reacquire the semaphore then retry the write. 1101*223d846dSEric Joyner * We only do one retry, then give up. 1102*223d846dSEric Joyner */ 1103*223d846dSEric Joyner if (status && (hw->aq.asq_last_status == I40E_AQ_RC_EBUSY) && 1104*223d846dSEric Joyner !retry_attempt) { 1105*223d846dSEric Joyner enum i40e_status_code old_status = status; 1106*223d846dSEric Joyner u32 old_asq_status = hw->aq.asq_last_status; 1107*223d846dSEric Joyner u32 gtime; 1108*223d846dSEric Joyner 1109*223d846dSEric Joyner gtime = rd32(hw, I40E_GLVFGEN_TIMER); 1110*223d846dSEric Joyner if (gtime >= hw->nvm.hw_semaphore_timeout) { 1111*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_ALL, 1112*223d846dSEric Joyner "NVMUPD: write semaphore expired (%d >= %lld), retrying\n", 1113*223d846dSEric Joyner gtime, hw->nvm.hw_semaphore_timeout); 1114*223d846dSEric Joyner i40e_release_nvm(hw); 1115*223d846dSEric Joyner status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 1116*223d846dSEric Joyner if (status) { 1117*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_ALL, 1118*223d846dSEric Joyner "NVMUPD: write semaphore reacquire failed aq_err = %d\n", 1119*223d846dSEric Joyner hw->aq.asq_last_status); 1120*223d846dSEric Joyner status = old_status; 1121*223d846dSEric Joyner hw->aq.asq_last_status = old_asq_status; 1122*223d846dSEric Joyner } else { 1123*223d846dSEric Joyner retry_attempt = TRUE; 1124*223d846dSEric Joyner goto retry; 1125*223d846dSEric Joyner } 1126*223d846dSEric Joyner } 1127*223d846dSEric Joyner } 1128*223d846dSEric Joyner 1129*223d846dSEric Joyner return status; 1130*223d846dSEric Joyner } 1131*223d846dSEric Joyner 1132*223d846dSEric Joyner /** 1133*223d846dSEric Joyner * i40e_nvmupd_validate_command - Validate given command 1134*223d846dSEric Joyner * @hw: pointer to hardware structure 1135*223d846dSEric Joyner * @cmd: pointer to nvm update command buffer 1136*223d846dSEric Joyner * @perrno: pointer to return error code 1137*223d846dSEric Joyner * 1138*223d846dSEric Joyner * Return one of the valid command types or I40E_NVMUPD_INVALID 1139*223d846dSEric Joyner **/ 1140*223d846dSEric Joyner static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, 1141*223d846dSEric Joyner struct i40e_nvm_access *cmd, 1142*223d846dSEric Joyner int *perrno) 1143*223d846dSEric Joyner { 1144*223d846dSEric Joyner enum i40e_nvmupd_cmd upd_cmd; 1145*223d846dSEric Joyner u8 module, transaction; 1146*223d846dSEric Joyner 1147*223d846dSEric Joyner DEBUGFUNC("i40e_nvmupd_validate_command\n"); 1148*223d846dSEric Joyner 1149*223d846dSEric Joyner /* anything that doesn't match a recognized case is an error */ 1150*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_INVALID; 1151*223d846dSEric Joyner 1152*223d846dSEric Joyner transaction = i40e_nvmupd_get_transaction(cmd->config); 1153*223d846dSEric Joyner module = i40e_nvmupd_get_module(cmd->config); 1154*223d846dSEric Joyner 1155*223d846dSEric Joyner /* limits on data size */ 1156*223d846dSEric Joyner if ((cmd->data_size < 1) || 1157*223d846dSEric Joyner (cmd->data_size > I40E_NVMUPD_MAX_DATA)) { 1158*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1159*223d846dSEric Joyner "i40e_nvmupd_validate_command data_size %d\n", 1160*223d846dSEric Joyner cmd->data_size); 1161*223d846dSEric Joyner *perrno = -EFAULT; 1162*223d846dSEric Joyner return I40E_NVMUPD_INVALID; 1163*223d846dSEric Joyner } 1164*223d846dSEric Joyner 1165*223d846dSEric Joyner switch (cmd->command) { 1166*223d846dSEric Joyner case I40E_NVM_READ: 1167*223d846dSEric Joyner switch (transaction) { 1168*223d846dSEric Joyner case I40E_NVM_CON: 1169*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_READ_CON; 1170*223d846dSEric Joyner break; 1171*223d846dSEric Joyner case I40E_NVM_SNT: 1172*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_READ_SNT; 1173*223d846dSEric Joyner break; 1174*223d846dSEric Joyner case I40E_NVM_LCB: 1175*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_READ_LCB; 1176*223d846dSEric Joyner break; 1177*223d846dSEric Joyner case I40E_NVM_SA: 1178*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_READ_SA; 1179*223d846dSEric Joyner break; 1180*223d846dSEric Joyner case I40E_NVM_EXEC: 1181*223d846dSEric Joyner if (module == 0xf) 1182*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_STATUS; 1183*223d846dSEric Joyner else if (module == 0) 1184*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_GET_AQ_RESULT; 1185*223d846dSEric Joyner break; 1186*223d846dSEric Joyner } 1187*223d846dSEric Joyner break; 1188*223d846dSEric Joyner 1189*223d846dSEric Joyner case I40E_NVM_WRITE: 1190*223d846dSEric Joyner switch (transaction) { 1191*223d846dSEric Joyner case I40E_NVM_CON: 1192*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_WRITE_CON; 1193*223d846dSEric Joyner break; 1194*223d846dSEric Joyner case I40E_NVM_SNT: 1195*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_WRITE_SNT; 1196*223d846dSEric Joyner break; 1197*223d846dSEric Joyner case I40E_NVM_LCB: 1198*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_WRITE_LCB; 1199*223d846dSEric Joyner break; 1200*223d846dSEric Joyner case I40E_NVM_SA: 1201*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_WRITE_SA; 1202*223d846dSEric Joyner break; 1203*223d846dSEric Joyner case I40E_NVM_ERA: 1204*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_WRITE_ERA; 1205*223d846dSEric Joyner break; 1206*223d846dSEric Joyner case I40E_NVM_CSUM: 1207*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_CSUM_CON; 1208*223d846dSEric Joyner break; 1209*223d846dSEric Joyner case (I40E_NVM_CSUM|I40E_NVM_SA): 1210*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_CSUM_SA; 1211*223d846dSEric Joyner break; 1212*223d846dSEric Joyner case (I40E_NVM_CSUM|I40E_NVM_LCB): 1213*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_CSUM_LCB; 1214*223d846dSEric Joyner break; 1215*223d846dSEric Joyner case I40E_NVM_EXEC: 1216*223d846dSEric Joyner if (module == 0) 1217*223d846dSEric Joyner upd_cmd = I40E_NVMUPD_EXEC_AQ; 1218*223d846dSEric Joyner break; 1219*223d846dSEric Joyner } 1220*223d846dSEric Joyner break; 1221*223d846dSEric Joyner } 1222*223d846dSEric Joyner 1223*223d846dSEric Joyner return upd_cmd; 1224*223d846dSEric Joyner } 1225*223d846dSEric Joyner 1226*223d846dSEric Joyner /** 1227*223d846dSEric Joyner * i40e_nvmupd_exec_aq - Run an AQ command 1228*223d846dSEric Joyner * @hw: pointer to hardware structure 1229*223d846dSEric Joyner * @cmd: pointer to nvm update command buffer 1230*223d846dSEric Joyner * @bytes: pointer to the data buffer 1231*223d846dSEric Joyner * @perrno: pointer to return error code 1232*223d846dSEric Joyner * 1233*223d846dSEric Joyner * cmd structure contains identifiers and data buffer 1234*223d846dSEric Joyner **/ 1235*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw, 1236*223d846dSEric Joyner struct i40e_nvm_access *cmd, 1237*223d846dSEric Joyner u8 *bytes, int *perrno) 1238*223d846dSEric Joyner { 1239*223d846dSEric Joyner struct i40e_asq_cmd_details cmd_details; 1240*223d846dSEric Joyner enum i40e_status_code status; 1241*223d846dSEric Joyner struct i40e_aq_desc *aq_desc; 1242*223d846dSEric Joyner u32 buff_size = 0; 1243*223d846dSEric Joyner u8 *buff = NULL; 1244*223d846dSEric Joyner u32 aq_desc_len; 1245*223d846dSEric Joyner u32 aq_data_len; 1246*223d846dSEric Joyner 1247*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__); 1248*223d846dSEric Joyner memset(&cmd_details, 0, sizeof(cmd_details)); 1249*223d846dSEric Joyner cmd_details.wb_desc = &hw->nvm_wb_desc; 1250*223d846dSEric Joyner 1251*223d846dSEric Joyner aq_desc_len = sizeof(struct i40e_aq_desc); 1252*223d846dSEric Joyner memset(&hw->nvm_wb_desc, 0, aq_desc_len); 1253*223d846dSEric Joyner 1254*223d846dSEric Joyner /* get the aq descriptor */ 1255*223d846dSEric Joyner if (cmd->data_size < aq_desc_len) { 1256*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1257*223d846dSEric Joyner "NVMUPD: not enough aq desc bytes for exec, size %d < %d\n", 1258*223d846dSEric Joyner cmd->data_size, aq_desc_len); 1259*223d846dSEric Joyner *perrno = -EINVAL; 1260*223d846dSEric Joyner return I40E_ERR_PARAM; 1261*223d846dSEric Joyner } 1262*223d846dSEric Joyner aq_desc = (struct i40e_aq_desc *)bytes; 1263*223d846dSEric Joyner 1264*223d846dSEric Joyner /* if data buffer needed, make sure it's ready */ 1265*223d846dSEric Joyner aq_data_len = cmd->data_size - aq_desc_len; 1266*223d846dSEric Joyner buff_size = max(aq_data_len, (u32)LE16_TO_CPU(aq_desc->datalen)); 1267*223d846dSEric Joyner if (buff_size) { 1268*223d846dSEric Joyner if (!hw->nvm_buff.va) { 1269*223d846dSEric Joyner status = i40e_allocate_virt_mem(hw, &hw->nvm_buff, 1270*223d846dSEric Joyner hw->aq.asq_buf_size); 1271*223d846dSEric Joyner if (status) 1272*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1273*223d846dSEric Joyner "NVMUPD: i40e_allocate_virt_mem for exec buff failed, %d\n", 1274*223d846dSEric Joyner status); 1275*223d846dSEric Joyner } 1276*223d846dSEric Joyner 1277*223d846dSEric Joyner if (hw->nvm_buff.va) { 1278*223d846dSEric Joyner buff = hw->nvm_buff.va; 1279*223d846dSEric Joyner memcpy(buff, &bytes[aq_desc_len], aq_data_len); 1280*223d846dSEric Joyner } 1281*223d846dSEric Joyner } 1282*223d846dSEric Joyner 1283*223d846dSEric Joyner /* and away we go! */ 1284*223d846dSEric Joyner status = i40e_asq_send_command(hw, aq_desc, buff, 1285*223d846dSEric Joyner buff_size, &cmd_details); 1286*223d846dSEric Joyner if (status) { 1287*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1288*223d846dSEric Joyner "i40e_nvmupd_exec_aq err %s aq_err %s\n", 1289*223d846dSEric Joyner i40e_stat_str(hw, status), 1290*223d846dSEric Joyner i40e_aq_str(hw, hw->aq.asq_last_status)); 1291*223d846dSEric Joyner *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status); 1292*223d846dSEric Joyner } 1293*223d846dSEric Joyner 1294*223d846dSEric Joyner return status; 1295*223d846dSEric Joyner } 1296*223d846dSEric Joyner 1297*223d846dSEric Joyner /** 1298*223d846dSEric Joyner * i40e_nvmupd_get_aq_result - Get the results from the previous exec_aq 1299*223d846dSEric Joyner * @hw: pointer to hardware structure 1300*223d846dSEric Joyner * @cmd: pointer to nvm update command buffer 1301*223d846dSEric Joyner * @bytes: pointer to the data buffer 1302*223d846dSEric Joyner * @perrno: pointer to return error code 1303*223d846dSEric Joyner * 1304*223d846dSEric Joyner * cmd structure contains identifiers and data buffer 1305*223d846dSEric Joyner **/ 1306*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_get_aq_result(struct i40e_hw *hw, 1307*223d846dSEric Joyner struct i40e_nvm_access *cmd, 1308*223d846dSEric Joyner u8 *bytes, int *perrno) 1309*223d846dSEric Joyner { 1310*223d846dSEric Joyner u32 aq_total_len; 1311*223d846dSEric Joyner u32 aq_desc_len; 1312*223d846dSEric Joyner int remainder; 1313*223d846dSEric Joyner u8 *buff; 1314*223d846dSEric Joyner 1315*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__); 1316*223d846dSEric Joyner 1317*223d846dSEric Joyner aq_desc_len = sizeof(struct i40e_aq_desc); 1318*223d846dSEric Joyner aq_total_len = aq_desc_len + LE16_TO_CPU(hw->nvm_wb_desc.datalen); 1319*223d846dSEric Joyner 1320*223d846dSEric Joyner /* check offset range */ 1321*223d846dSEric Joyner if (cmd->offset > aq_total_len) { 1322*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, "%s: offset too big %d > %d\n", 1323*223d846dSEric Joyner __func__, cmd->offset, aq_total_len); 1324*223d846dSEric Joyner *perrno = -EINVAL; 1325*223d846dSEric Joyner return I40E_ERR_PARAM; 1326*223d846dSEric Joyner } 1327*223d846dSEric Joyner 1328*223d846dSEric Joyner /* check copylength range */ 1329*223d846dSEric Joyner if (cmd->data_size > (aq_total_len - cmd->offset)) { 1330*223d846dSEric Joyner int new_len = aq_total_len - cmd->offset; 1331*223d846dSEric Joyner 1332*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, "%s: copy length %d too big, trimming to %d\n", 1333*223d846dSEric Joyner __func__, cmd->data_size, new_len); 1334*223d846dSEric Joyner cmd->data_size = new_len; 1335*223d846dSEric Joyner } 1336*223d846dSEric Joyner 1337*223d846dSEric Joyner remainder = cmd->data_size; 1338*223d846dSEric Joyner if (cmd->offset < aq_desc_len) { 1339*223d846dSEric Joyner u32 len = aq_desc_len - cmd->offset; 1340*223d846dSEric Joyner 1341*223d846dSEric Joyner len = min(len, cmd->data_size); 1342*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, "%s: aq_desc bytes %d to %d\n", 1343*223d846dSEric Joyner __func__, cmd->offset, cmd->offset + len); 1344*223d846dSEric Joyner 1345*223d846dSEric Joyner buff = ((u8 *)&hw->nvm_wb_desc) + cmd->offset; 1346*223d846dSEric Joyner memcpy(bytes, buff, len); 1347*223d846dSEric Joyner 1348*223d846dSEric Joyner bytes += len; 1349*223d846dSEric Joyner remainder -= len; 1350*223d846dSEric Joyner buff = hw->nvm_buff.va; 1351*223d846dSEric Joyner } else { 1352*223d846dSEric Joyner buff = (u8 *)hw->nvm_buff.va + (cmd->offset - aq_desc_len); 1353*223d846dSEric Joyner } 1354*223d846dSEric Joyner 1355*223d846dSEric Joyner if (remainder > 0) { 1356*223d846dSEric Joyner int start_byte = buff - (u8 *)hw->nvm_buff.va; 1357*223d846dSEric Joyner 1358*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, "%s: databuf bytes %d to %d\n", 1359*223d846dSEric Joyner __func__, start_byte, start_byte + remainder); 1360*223d846dSEric Joyner memcpy(bytes, buff, remainder); 1361*223d846dSEric Joyner } 1362*223d846dSEric Joyner 1363*223d846dSEric Joyner return I40E_SUCCESS; 1364*223d846dSEric Joyner } 1365*223d846dSEric Joyner 1366*223d846dSEric Joyner /** 1367*223d846dSEric Joyner * i40e_nvmupd_nvm_read - Read NVM 1368*223d846dSEric Joyner * @hw: pointer to hardware structure 1369*223d846dSEric Joyner * @cmd: pointer to nvm update command buffer 1370*223d846dSEric Joyner * @bytes: pointer to the data buffer 1371*223d846dSEric Joyner * @perrno: pointer to return error code 1372*223d846dSEric Joyner * 1373*223d846dSEric Joyner * cmd structure contains identifiers and data buffer 1374*223d846dSEric Joyner **/ 1375*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_nvm_read(struct i40e_hw *hw, 1376*223d846dSEric Joyner struct i40e_nvm_access *cmd, 1377*223d846dSEric Joyner u8 *bytes, int *perrno) 1378*223d846dSEric Joyner { 1379*223d846dSEric Joyner struct i40e_asq_cmd_details cmd_details; 1380*223d846dSEric Joyner enum i40e_status_code status; 1381*223d846dSEric Joyner u8 module, transaction; 1382*223d846dSEric Joyner bool last; 1383*223d846dSEric Joyner 1384*223d846dSEric Joyner transaction = i40e_nvmupd_get_transaction(cmd->config); 1385*223d846dSEric Joyner module = i40e_nvmupd_get_module(cmd->config); 1386*223d846dSEric Joyner last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA); 1387*223d846dSEric Joyner 1388*223d846dSEric Joyner memset(&cmd_details, 0, sizeof(cmd_details)); 1389*223d846dSEric Joyner cmd_details.wb_desc = &hw->nvm_wb_desc; 1390*223d846dSEric Joyner 1391*223d846dSEric Joyner status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size, 1392*223d846dSEric Joyner bytes, last, &cmd_details); 1393*223d846dSEric Joyner if (status) { 1394*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1395*223d846dSEric Joyner "i40e_nvmupd_nvm_read mod 0x%x off 0x%x len 0x%x\n", 1396*223d846dSEric Joyner module, cmd->offset, cmd->data_size); 1397*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1398*223d846dSEric Joyner "i40e_nvmupd_nvm_read status %d aq %d\n", 1399*223d846dSEric Joyner status, hw->aq.asq_last_status); 1400*223d846dSEric Joyner *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status); 1401*223d846dSEric Joyner } 1402*223d846dSEric Joyner 1403*223d846dSEric Joyner return status; 1404*223d846dSEric Joyner } 1405*223d846dSEric Joyner 1406*223d846dSEric Joyner /** 1407*223d846dSEric Joyner * i40e_nvmupd_nvm_erase - Erase an NVM module 1408*223d846dSEric Joyner * @hw: pointer to hardware structure 1409*223d846dSEric Joyner * @cmd: pointer to nvm update command buffer 1410*223d846dSEric Joyner * @perrno: pointer to return error code 1411*223d846dSEric Joyner * 1412*223d846dSEric Joyner * module, offset, data_size and data are in cmd structure 1413*223d846dSEric Joyner **/ 1414*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_nvm_erase(struct i40e_hw *hw, 1415*223d846dSEric Joyner struct i40e_nvm_access *cmd, 1416*223d846dSEric Joyner int *perrno) 1417*223d846dSEric Joyner { 1418*223d846dSEric Joyner enum i40e_status_code status = I40E_SUCCESS; 1419*223d846dSEric Joyner struct i40e_asq_cmd_details cmd_details; 1420*223d846dSEric Joyner u8 module, transaction; 1421*223d846dSEric Joyner bool last; 1422*223d846dSEric Joyner 1423*223d846dSEric Joyner transaction = i40e_nvmupd_get_transaction(cmd->config); 1424*223d846dSEric Joyner module = i40e_nvmupd_get_module(cmd->config); 1425*223d846dSEric Joyner last = (transaction & I40E_NVM_LCB); 1426*223d846dSEric Joyner 1427*223d846dSEric Joyner memset(&cmd_details, 0, sizeof(cmd_details)); 1428*223d846dSEric Joyner cmd_details.wb_desc = &hw->nvm_wb_desc; 1429*223d846dSEric Joyner 1430*223d846dSEric Joyner status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size, 1431*223d846dSEric Joyner last, &cmd_details); 1432*223d846dSEric Joyner if (status) { 1433*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1434*223d846dSEric Joyner "i40e_nvmupd_nvm_erase mod 0x%x off 0x%x len 0x%x\n", 1435*223d846dSEric Joyner module, cmd->offset, cmd->data_size); 1436*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1437*223d846dSEric Joyner "i40e_nvmupd_nvm_erase status %d aq %d\n", 1438*223d846dSEric Joyner status, hw->aq.asq_last_status); 1439*223d846dSEric Joyner *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status); 1440*223d846dSEric Joyner } 1441*223d846dSEric Joyner 1442*223d846dSEric Joyner return status; 1443*223d846dSEric Joyner } 1444*223d846dSEric Joyner 1445*223d846dSEric Joyner /** 1446*223d846dSEric Joyner * i40e_nvmupd_nvm_write - Write NVM 1447*223d846dSEric Joyner * @hw: pointer to hardware structure 1448*223d846dSEric Joyner * @cmd: pointer to nvm update command buffer 1449*223d846dSEric Joyner * @bytes: pointer to the data buffer 1450*223d846dSEric Joyner * @perrno: pointer to return error code 1451*223d846dSEric Joyner * 1452*223d846dSEric Joyner * module, offset, data_size and data are in cmd structure 1453*223d846dSEric Joyner **/ 1454*223d846dSEric Joyner static enum i40e_status_code i40e_nvmupd_nvm_write(struct i40e_hw *hw, 1455*223d846dSEric Joyner struct i40e_nvm_access *cmd, 1456*223d846dSEric Joyner u8 *bytes, int *perrno) 1457*223d846dSEric Joyner { 1458*223d846dSEric Joyner enum i40e_status_code status = I40E_SUCCESS; 1459*223d846dSEric Joyner struct i40e_asq_cmd_details cmd_details; 1460*223d846dSEric Joyner u8 module, transaction; 1461*223d846dSEric Joyner bool last; 1462*223d846dSEric Joyner 1463*223d846dSEric Joyner transaction = i40e_nvmupd_get_transaction(cmd->config); 1464*223d846dSEric Joyner module = i40e_nvmupd_get_module(cmd->config); 1465*223d846dSEric Joyner last = (transaction & I40E_NVM_LCB); 1466*223d846dSEric Joyner 1467*223d846dSEric Joyner memset(&cmd_details, 0, sizeof(cmd_details)); 1468*223d846dSEric Joyner cmd_details.wb_desc = &hw->nvm_wb_desc; 1469*223d846dSEric Joyner 1470*223d846dSEric Joyner status = i40e_aq_update_nvm(hw, module, cmd->offset, 1471*223d846dSEric Joyner (u16)cmd->data_size, bytes, last, 1472*223d846dSEric Joyner &cmd_details); 1473*223d846dSEric Joyner if (status) { 1474*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1475*223d846dSEric Joyner "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n", 1476*223d846dSEric Joyner module, cmd->offset, cmd->data_size); 1477*223d846dSEric Joyner i40e_debug(hw, I40E_DEBUG_NVM, 1478*223d846dSEric Joyner "i40e_nvmupd_nvm_write status %d aq %d\n", 1479*223d846dSEric Joyner status, hw->aq.asq_last_status); 1480*223d846dSEric Joyner *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status); 1481*223d846dSEric Joyner } 1482*223d846dSEric Joyner 1483*223d846dSEric Joyner return status; 1484*223d846dSEric Joyner } 1485