156a62fc8SJesse Brandeburg /******************************************************************************* 256a62fc8SJesse Brandeburg * 356a62fc8SJesse Brandeburg * Intel Ethernet Controller XL710 Family Linux Driver 4dc641b73SGreg Rose * Copyright(c) 2013 - 2014 Intel Corporation. 556a62fc8SJesse Brandeburg * 656a62fc8SJesse Brandeburg * This program is free software; you can redistribute it and/or modify it 756a62fc8SJesse Brandeburg * under the terms and conditions of the GNU General Public License, 856a62fc8SJesse Brandeburg * version 2, as published by the Free Software Foundation. 956a62fc8SJesse Brandeburg * 1056a62fc8SJesse Brandeburg * This program is distributed in the hope it will be useful, but WITHOUT 1156a62fc8SJesse Brandeburg * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1256a62fc8SJesse Brandeburg * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1356a62fc8SJesse Brandeburg * more details. 1456a62fc8SJesse Brandeburg * 15dc641b73SGreg Rose * You should have received a copy of the GNU General Public License along 16dc641b73SGreg Rose * with this program. If not, see <http://www.gnu.org/licenses/>. 1756a62fc8SJesse Brandeburg * 1856a62fc8SJesse Brandeburg * The full GNU General Public License is included in this distribution in 1956a62fc8SJesse Brandeburg * the file called "COPYING". 2056a62fc8SJesse Brandeburg * 2156a62fc8SJesse Brandeburg * Contact Information: 2256a62fc8SJesse Brandeburg * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> 2356a62fc8SJesse Brandeburg * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 2456a62fc8SJesse Brandeburg * 2556a62fc8SJesse Brandeburg ******************************************************************************/ 2656a62fc8SJesse Brandeburg 2756a62fc8SJesse Brandeburg #include "i40e_prototype.h" 2856a62fc8SJesse Brandeburg 2956a62fc8SJesse Brandeburg /** 303e26186dSShannon Nelson * i40e_init_nvm_ops - Initialize NVM function pointers 313e26186dSShannon Nelson * @hw: pointer to the HW structure 3256a62fc8SJesse Brandeburg * 333e26186dSShannon Nelson * Setup the function pointers and the NVM info structure. Should be called 3456a62fc8SJesse Brandeburg * once per NVM initialization, e.g. inside the i40e_init_shared_code(). 3556a62fc8SJesse Brandeburg * Please notice that the NVM term is used here (& in all methods covered 3656a62fc8SJesse Brandeburg * in this file) as an equivalent of the FLASH part mapped into the SR. 3756a62fc8SJesse Brandeburg * We are accessing FLASH always thru the Shadow RAM. 3856a62fc8SJesse Brandeburg **/ 3956a62fc8SJesse Brandeburg i40e_status i40e_init_nvm(struct i40e_hw *hw) 4056a62fc8SJesse Brandeburg { 4156a62fc8SJesse Brandeburg struct i40e_nvm_info *nvm = &hw->nvm; 4256a62fc8SJesse Brandeburg i40e_status ret_code = 0; 4356a62fc8SJesse Brandeburg u32 fla, gens; 4456a62fc8SJesse Brandeburg u8 sr_size; 4556a62fc8SJesse Brandeburg 4656a62fc8SJesse Brandeburg /* The SR size is stored regardless of the nvm programming mode 4756a62fc8SJesse Brandeburg * as the blank mode may be used in the factory line. 4856a62fc8SJesse Brandeburg */ 4956a62fc8SJesse Brandeburg gens = rd32(hw, I40E_GLNVM_GENS); 5056a62fc8SJesse Brandeburg sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >> 5156a62fc8SJesse Brandeburg I40E_GLNVM_GENS_SR_SIZE_SHIFT); 523e26186dSShannon Nelson /* Switching to words (sr_size contains power of 2KB) */ 5356a62fc8SJesse Brandeburg nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB; 5456a62fc8SJesse Brandeburg 553e26186dSShannon Nelson /* Check if we are in the normal or blank NVM programming mode */ 5656a62fc8SJesse Brandeburg fla = rd32(hw, I40E_GLNVM_FLA); 573e26186dSShannon Nelson if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */ 583e26186dSShannon Nelson /* Max NVM timeout */ 5956a62fc8SJesse Brandeburg nvm->timeout = I40E_MAX_NVM_TIMEOUT; 6056a62fc8SJesse Brandeburg nvm->blank_nvm_mode = false; 613e26186dSShannon Nelson } else { /* Blank programming mode */ 6256a62fc8SJesse Brandeburg nvm->blank_nvm_mode = true; 6356a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_BLANK_MODE; 6474d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "NVM init error: unsupported blank mode.\n"); 6556a62fc8SJesse Brandeburg } 6656a62fc8SJesse Brandeburg 6756a62fc8SJesse Brandeburg return ret_code; 6856a62fc8SJesse Brandeburg } 6956a62fc8SJesse Brandeburg 7056a62fc8SJesse Brandeburg /** 713e26186dSShannon Nelson * i40e_acquire_nvm - Generic request for acquiring the NVM ownership 723e26186dSShannon Nelson * @hw: pointer to the HW structure 733e26186dSShannon Nelson * @access: NVM access type (read or write) 7456a62fc8SJesse Brandeburg * 7556a62fc8SJesse Brandeburg * This function will request NVM ownership for reading 7656a62fc8SJesse Brandeburg * via the proper Admin Command. 7756a62fc8SJesse Brandeburg **/ 7856a62fc8SJesse Brandeburg i40e_status i40e_acquire_nvm(struct i40e_hw *hw, 7956a62fc8SJesse Brandeburg enum i40e_aq_resource_access_type access) 8056a62fc8SJesse Brandeburg { 8156a62fc8SJesse Brandeburg i40e_status ret_code = 0; 8256a62fc8SJesse Brandeburg u64 gtime, timeout; 83c509c1deSShannon Nelson u64 time_left = 0; 8456a62fc8SJesse Brandeburg 8556a62fc8SJesse Brandeburg if (hw->nvm.blank_nvm_mode) 8656a62fc8SJesse Brandeburg goto i40e_i40e_acquire_nvm_exit; 8756a62fc8SJesse Brandeburg 8856a62fc8SJesse Brandeburg ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access, 89c509c1deSShannon Nelson 0, &time_left, NULL); 903e26186dSShannon Nelson /* Reading the Global Device Timer */ 9156a62fc8SJesse Brandeburg gtime = rd32(hw, I40E_GLVFGEN_TIMER); 9256a62fc8SJesse Brandeburg 933e26186dSShannon Nelson /* Store the timeout */ 94c509c1deSShannon Nelson hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime; 9556a62fc8SJesse Brandeburg 96a3f0b381SShannon Nelson if (ret_code) 97a3f0b381SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 98a3f0b381SShannon Nelson "NVM acquire type %d failed time_left=%llu ret=%d aq_err=%d\n", 99a3f0b381SShannon Nelson access, time_left, ret_code, hw->aq.asq_last_status); 100a3f0b381SShannon Nelson 101a3f0b381SShannon Nelson if (ret_code && time_left) { 1023e26186dSShannon Nelson /* Poll until the current NVM owner timeouts */ 103c509c1deSShannon Nelson timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime; 104a3f0b381SShannon Nelson while ((gtime < timeout) && time_left) { 10556a62fc8SJesse Brandeburg usleep_range(10000, 20000); 106c509c1deSShannon Nelson gtime = rd32(hw, I40E_GLVFGEN_TIMER); 10756a62fc8SJesse Brandeburg ret_code = i40e_aq_request_resource(hw, 10856a62fc8SJesse Brandeburg I40E_NVM_RESOURCE_ID, 109c509c1deSShannon Nelson access, 0, &time_left, 11056a62fc8SJesse Brandeburg NULL); 11156a62fc8SJesse Brandeburg if (!ret_code) { 11256a62fc8SJesse Brandeburg hw->nvm.hw_semaphore_timeout = 113c509c1deSShannon Nelson I40E_MS_TO_GTIME(time_left) + gtime; 11456a62fc8SJesse Brandeburg break; 11556a62fc8SJesse Brandeburg } 11656a62fc8SJesse Brandeburg } 11756a62fc8SJesse Brandeburg if (ret_code) { 11856a62fc8SJesse Brandeburg hw->nvm.hw_semaphore_timeout = 0; 11974d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 120a3f0b381SShannon Nelson "NVM acquire timed out, wait %llu ms before trying again. status=%d aq_err=%d\n", 121a3f0b381SShannon Nelson time_left, ret_code, hw->aq.asq_last_status); 12256a62fc8SJesse Brandeburg } 12356a62fc8SJesse Brandeburg } 12456a62fc8SJesse Brandeburg 12556a62fc8SJesse Brandeburg i40e_i40e_acquire_nvm_exit: 12656a62fc8SJesse Brandeburg return ret_code; 12756a62fc8SJesse Brandeburg } 12856a62fc8SJesse Brandeburg 12956a62fc8SJesse Brandeburg /** 1303e26186dSShannon Nelson * i40e_release_nvm - Generic request for releasing the NVM ownership 1313e26186dSShannon Nelson * @hw: pointer to the HW structure 13256a62fc8SJesse Brandeburg * 13356a62fc8SJesse Brandeburg * This function will release NVM resource via the proper Admin Command. 13456a62fc8SJesse Brandeburg **/ 13556a62fc8SJesse Brandeburg void i40e_release_nvm(struct i40e_hw *hw) 13656a62fc8SJesse Brandeburg { 13756a62fc8SJesse Brandeburg if (!hw->nvm.blank_nvm_mode) 13856a62fc8SJesse Brandeburg i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL); 13956a62fc8SJesse Brandeburg } 14056a62fc8SJesse Brandeburg 14156a62fc8SJesse Brandeburg /** 1423e26186dSShannon Nelson * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit 1433e26186dSShannon Nelson * @hw: pointer to the HW structure 14456a62fc8SJesse Brandeburg * 14556a62fc8SJesse Brandeburg * Polls the SRCTL Shadow RAM register done bit. 14656a62fc8SJesse Brandeburg **/ 14756a62fc8SJesse Brandeburg static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) 14856a62fc8SJesse Brandeburg { 14956a62fc8SJesse Brandeburg i40e_status ret_code = I40E_ERR_TIMEOUT; 15056a62fc8SJesse Brandeburg u32 srctl, wait_cnt; 15156a62fc8SJesse Brandeburg 1523e26186dSShannon Nelson /* Poll the I40E_GLNVM_SRCTL until the done bit is set */ 15356a62fc8SJesse Brandeburg for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) { 15456a62fc8SJesse Brandeburg srctl = rd32(hw, I40E_GLNVM_SRCTL); 15556a62fc8SJesse Brandeburg if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) { 15656a62fc8SJesse Brandeburg ret_code = 0; 15756a62fc8SJesse Brandeburg break; 15856a62fc8SJesse Brandeburg } 15956a62fc8SJesse Brandeburg udelay(5); 16056a62fc8SJesse Brandeburg } 16156a62fc8SJesse Brandeburg if (ret_code == I40E_ERR_TIMEOUT) 16274d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set"); 16356a62fc8SJesse Brandeburg return ret_code; 16456a62fc8SJesse Brandeburg } 16556a62fc8SJesse Brandeburg 16656a62fc8SJesse Brandeburg /** 167a4bcfbb7SShannon Nelson * i40e_read_nvm_word - Reads Shadow RAM 1683e26186dSShannon Nelson * @hw: pointer to the HW structure 1693e26186dSShannon Nelson * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 1703e26186dSShannon Nelson * @data: word read from the Shadow RAM 17156a62fc8SJesse Brandeburg * 1723e26186dSShannon Nelson * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. 17356a62fc8SJesse Brandeburg **/ 174a4bcfbb7SShannon Nelson i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, 17556a62fc8SJesse Brandeburg u16 *data) 17656a62fc8SJesse Brandeburg { 17756a62fc8SJesse Brandeburg i40e_status ret_code = I40E_ERR_TIMEOUT; 17856a62fc8SJesse Brandeburg u32 sr_reg; 17956a62fc8SJesse Brandeburg 18056a62fc8SJesse Brandeburg if (offset >= hw->nvm.sr_size) { 18174d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 18274d0d0edSShannon Nelson "NVM read error: offset %d beyond Shadow RAM limit %d\n", 18374d0d0edSShannon Nelson offset, hw->nvm.sr_size); 18456a62fc8SJesse Brandeburg ret_code = I40E_ERR_PARAM; 18556a62fc8SJesse Brandeburg goto read_nvm_exit; 18656a62fc8SJesse Brandeburg } 18756a62fc8SJesse Brandeburg 1883e26186dSShannon Nelson /* Poll the done bit first */ 18956a62fc8SJesse Brandeburg ret_code = i40e_poll_sr_srctl_done_bit(hw); 19056a62fc8SJesse Brandeburg if (!ret_code) { 1913e26186dSShannon Nelson /* Write the address and start reading */ 19256a62fc8SJesse Brandeburg sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | 19356a62fc8SJesse Brandeburg (1 << I40E_GLNVM_SRCTL_START_SHIFT); 19456a62fc8SJesse Brandeburg wr32(hw, I40E_GLNVM_SRCTL, sr_reg); 19556a62fc8SJesse Brandeburg 1963e26186dSShannon Nelson /* Poll I40E_GLNVM_SRCTL until the done bit is set */ 19756a62fc8SJesse Brandeburg ret_code = i40e_poll_sr_srctl_done_bit(hw); 19856a62fc8SJesse Brandeburg if (!ret_code) { 19956a62fc8SJesse Brandeburg sr_reg = rd32(hw, I40E_GLNVM_SRDATA); 20056a62fc8SJesse Brandeburg *data = (u16)((sr_reg & 20156a62fc8SJesse Brandeburg I40E_GLNVM_SRDATA_RDDATA_MASK) 20256a62fc8SJesse Brandeburg >> I40E_GLNVM_SRDATA_RDDATA_SHIFT); 20356a62fc8SJesse Brandeburg } 20456a62fc8SJesse Brandeburg } 20556a62fc8SJesse Brandeburg if (ret_code) 20674d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 20774d0d0edSShannon Nelson "NVM read error: Couldn't access Shadow RAM address: 0x%x\n", 20856a62fc8SJesse Brandeburg offset); 20956a62fc8SJesse Brandeburg 21056a62fc8SJesse Brandeburg read_nvm_exit: 21156a62fc8SJesse Brandeburg return ret_code; 21256a62fc8SJesse Brandeburg } 21356a62fc8SJesse Brandeburg 21456a62fc8SJesse Brandeburg /** 2153e26186dSShannon Nelson * i40e_read_nvm_buffer - Reads Shadow RAM buffer 2163e26186dSShannon Nelson * @hw: pointer to the HW structure 21756a62fc8SJesse Brandeburg * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 2183e26186dSShannon Nelson * @words: (in) number of words to read; (out) number of words actually read 2193e26186dSShannon Nelson * @data: words read from the Shadow RAM 22056a62fc8SJesse Brandeburg * 22156a62fc8SJesse Brandeburg * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() 22256a62fc8SJesse Brandeburg * method. The buffer read is preceded by the NVM ownership take 22356a62fc8SJesse Brandeburg * and followed by the release. 22456a62fc8SJesse Brandeburg **/ 22556a62fc8SJesse Brandeburg i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, 22656a62fc8SJesse Brandeburg u16 *words, u16 *data) 22756a62fc8SJesse Brandeburg { 22856a62fc8SJesse Brandeburg i40e_status ret_code = 0; 22956a62fc8SJesse Brandeburg u16 index, word; 23056a62fc8SJesse Brandeburg 2313e26186dSShannon Nelson /* Loop thru the selected region */ 23256a62fc8SJesse Brandeburg for (word = 0; word < *words; word++) { 23356a62fc8SJesse Brandeburg index = offset + word; 234a4bcfbb7SShannon Nelson ret_code = i40e_read_nvm_word(hw, index, &data[word]); 23556a62fc8SJesse Brandeburg if (ret_code) 23656a62fc8SJesse Brandeburg break; 23756a62fc8SJesse Brandeburg } 238a4bcfbb7SShannon Nelson 2393e26186dSShannon Nelson /* Update the number of words read from the Shadow RAM */ 24056a62fc8SJesse Brandeburg *words = word; 24156a62fc8SJesse Brandeburg 24256a62fc8SJesse Brandeburg return ret_code; 24356a62fc8SJesse Brandeburg } 24456a62fc8SJesse Brandeburg 24556a62fc8SJesse Brandeburg /** 246cd552cb4SShannon Nelson * i40e_write_nvm_aq - Writes Shadow RAM. 247cd552cb4SShannon Nelson * @hw: pointer to the HW structure. 248cd552cb4SShannon Nelson * @module_pointer: module pointer location in words from the NVM beginning 249cd552cb4SShannon Nelson * @offset: offset in words from module start 250cd552cb4SShannon Nelson * @words: number of words to write 251cd552cb4SShannon Nelson * @data: buffer with words to write to the Shadow RAM 252cd552cb4SShannon Nelson * @last_command: tells the AdminQ that this is the last command 253cd552cb4SShannon Nelson * 254cd552cb4SShannon Nelson * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 255cd552cb4SShannon Nelson **/ 256952d9639SWei Yongjun static i40e_status i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer, 257cd552cb4SShannon Nelson u32 offset, u16 words, void *data, 258cd552cb4SShannon Nelson bool last_command) 259cd552cb4SShannon Nelson { 260cd552cb4SShannon Nelson i40e_status ret_code = I40E_ERR_NVM; 261cd552cb4SShannon Nelson 262cd552cb4SShannon Nelson /* Here we are checking the SR limit only for the flat memory model. 263cd552cb4SShannon Nelson * We cannot do it for the module-based model, as we did not acquire 264cd552cb4SShannon Nelson * the NVM resource yet (we cannot get the module pointer value). 265cd552cb4SShannon Nelson * Firmware will check the module-based model. 266cd552cb4SShannon Nelson */ 267cd552cb4SShannon Nelson if ((offset + words) > hw->nvm.sr_size) 26874d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 26974d0d0edSShannon Nelson "NVM write error: offset %d beyond Shadow RAM limit %d\n", 27074d0d0edSShannon Nelson (offset + words), hw->nvm.sr_size); 271cd552cb4SShannon Nelson else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) 272cd552cb4SShannon Nelson /* We can write only up to 4KB (one sector), in one AQ write */ 27374d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 27474d0d0edSShannon Nelson "NVM write fail error: tried to write %d words, limit is %d.\n", 27574d0d0edSShannon Nelson words, I40E_SR_SECTOR_SIZE_IN_WORDS); 276cd552cb4SShannon Nelson else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) 277cd552cb4SShannon Nelson != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) 278cd552cb4SShannon Nelson /* A single write cannot spread over two sectors */ 27974d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 28074d0d0edSShannon Nelson "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n", 28174d0d0edSShannon Nelson offset, words); 282cd552cb4SShannon Nelson else 283cd552cb4SShannon Nelson ret_code = i40e_aq_update_nvm(hw, module_pointer, 284cd552cb4SShannon Nelson 2 * offset, /*bytes*/ 285cd552cb4SShannon Nelson 2 * words, /*bytes*/ 286cd552cb4SShannon Nelson data, last_command, NULL); 287cd552cb4SShannon Nelson 288cd552cb4SShannon Nelson return ret_code; 289cd552cb4SShannon Nelson } 290cd552cb4SShannon Nelson 291cd552cb4SShannon Nelson /** 29256a62fc8SJesse Brandeburg * i40e_calc_nvm_checksum - Calculates and returns the checksum 29356a62fc8SJesse Brandeburg * @hw: pointer to hardware structure 29498d44381SJeff Kirsher * @checksum: pointer to the checksum 29556a62fc8SJesse Brandeburg * 2963e26186dSShannon Nelson * This function calculates SW Checksum that covers the whole 64kB shadow RAM 29756a62fc8SJesse Brandeburg * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD 29856a62fc8SJesse Brandeburg * is customer specific and unknown. Therefore, this function skips all maximum 29956a62fc8SJesse Brandeburg * possible size of VPD (1kB). 30056a62fc8SJesse Brandeburg **/ 30156a62fc8SJesse Brandeburg static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw, 30256a62fc8SJesse Brandeburg u16 *checksum) 30356a62fc8SJesse Brandeburg { 30456a62fc8SJesse Brandeburg i40e_status ret_code = 0; 30556a62fc8SJesse Brandeburg u16 pcie_alt_module = 0; 30656a62fc8SJesse Brandeburg u16 checksum_local = 0; 30756a62fc8SJesse Brandeburg u16 vpd_module = 0; 30856a62fc8SJesse Brandeburg u16 word = 0; 30956a62fc8SJesse Brandeburg u32 i = 0; 31056a62fc8SJesse Brandeburg 31156a62fc8SJesse Brandeburg /* read pointer to VPD area */ 312a4bcfbb7SShannon Nelson ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module); 31356a62fc8SJesse Brandeburg if (ret_code) { 31456a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 31556a62fc8SJesse Brandeburg goto i40e_calc_nvm_checksum_exit; 31656a62fc8SJesse Brandeburg } 31756a62fc8SJesse Brandeburg 31856a62fc8SJesse Brandeburg /* read pointer to PCIe Alt Auto-load module */ 319a4bcfbb7SShannon Nelson ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR, 32056a62fc8SJesse Brandeburg &pcie_alt_module); 32156a62fc8SJesse Brandeburg if (ret_code) { 32256a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 32356a62fc8SJesse Brandeburg goto i40e_calc_nvm_checksum_exit; 32456a62fc8SJesse Brandeburg } 32556a62fc8SJesse Brandeburg 32656a62fc8SJesse Brandeburg /* Calculate SW checksum that covers the whole 64kB shadow RAM 32756a62fc8SJesse Brandeburg * except the VPD and PCIe ALT Auto-load modules 32856a62fc8SJesse Brandeburg */ 32956a62fc8SJesse Brandeburg for (i = 0; i < hw->nvm.sr_size; i++) { 33056a62fc8SJesse Brandeburg /* Skip Checksum word */ 33156a62fc8SJesse Brandeburg if (i == I40E_SR_SW_CHECKSUM_WORD) 33256a62fc8SJesse Brandeburg i++; 33356a62fc8SJesse Brandeburg /* Skip VPD module (convert byte size to word count) */ 33456a62fc8SJesse Brandeburg if (i == (u32)vpd_module) { 33556a62fc8SJesse Brandeburg i += (I40E_SR_VPD_MODULE_MAX_SIZE / 2); 33656a62fc8SJesse Brandeburg if (i >= hw->nvm.sr_size) 33756a62fc8SJesse Brandeburg break; 33856a62fc8SJesse Brandeburg } 33956a62fc8SJesse Brandeburg /* Skip PCIe ALT module (convert byte size to word count) */ 34056a62fc8SJesse Brandeburg if (i == (u32)pcie_alt_module) { 34156a62fc8SJesse Brandeburg i += (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2); 34256a62fc8SJesse Brandeburg if (i >= hw->nvm.sr_size) 34356a62fc8SJesse Brandeburg break; 34456a62fc8SJesse Brandeburg } 34556a62fc8SJesse Brandeburg 346a4bcfbb7SShannon Nelson ret_code = i40e_read_nvm_word(hw, (u16)i, &word); 34756a62fc8SJesse Brandeburg if (ret_code) { 34856a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 34956a62fc8SJesse Brandeburg goto i40e_calc_nvm_checksum_exit; 35056a62fc8SJesse Brandeburg } 35156a62fc8SJesse Brandeburg checksum_local += word; 35256a62fc8SJesse Brandeburg } 35356a62fc8SJesse Brandeburg 35456a62fc8SJesse Brandeburg *checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local; 35556a62fc8SJesse Brandeburg 35656a62fc8SJesse Brandeburg i40e_calc_nvm_checksum_exit: 35756a62fc8SJesse Brandeburg return ret_code; 35856a62fc8SJesse Brandeburg } 35956a62fc8SJesse Brandeburg 36056a62fc8SJesse Brandeburg /** 361cd552cb4SShannon Nelson * i40e_update_nvm_checksum - Updates the NVM checksum 362cd552cb4SShannon Nelson * @hw: pointer to hardware structure 363cd552cb4SShannon Nelson * 364cd552cb4SShannon Nelson * NVM ownership must be acquired before calling this function and released 365cd552cb4SShannon Nelson * on ARQ completion event reception by caller. 366cd552cb4SShannon Nelson * This function will commit SR to NVM. 367cd552cb4SShannon Nelson **/ 368cd552cb4SShannon Nelson i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw) 369cd552cb4SShannon Nelson { 370cd552cb4SShannon Nelson i40e_status ret_code = 0; 371cd552cb4SShannon Nelson u16 checksum; 372cd552cb4SShannon Nelson 373cd552cb4SShannon Nelson ret_code = i40e_calc_nvm_checksum(hw, &checksum); 374cd552cb4SShannon Nelson if (!ret_code) 375cd552cb4SShannon Nelson ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD, 376cd552cb4SShannon Nelson 1, &checksum, true); 377cd552cb4SShannon Nelson 378cd552cb4SShannon Nelson return ret_code; 379cd552cb4SShannon Nelson } 380cd552cb4SShannon Nelson 381cd552cb4SShannon Nelson /** 38256a62fc8SJesse Brandeburg * i40e_validate_nvm_checksum - Validate EEPROM checksum 38356a62fc8SJesse Brandeburg * @hw: pointer to hardware structure 38456a62fc8SJesse Brandeburg * @checksum: calculated checksum 38556a62fc8SJesse Brandeburg * 38656a62fc8SJesse Brandeburg * Performs checksum calculation and validates the NVM SW checksum. If the 38756a62fc8SJesse Brandeburg * caller does not need checksum, the value can be NULL. 38856a62fc8SJesse Brandeburg **/ 38956a62fc8SJesse Brandeburg i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, 39056a62fc8SJesse Brandeburg u16 *checksum) 39156a62fc8SJesse Brandeburg { 39256a62fc8SJesse Brandeburg i40e_status ret_code = 0; 39356a62fc8SJesse Brandeburg u16 checksum_sr = 0; 394e15c9fa0SJesse Brandeburg u16 checksum_local = 0; 39556a62fc8SJesse Brandeburg 39656a62fc8SJesse Brandeburg ret_code = i40e_calc_nvm_checksum(hw, &checksum_local); 39756a62fc8SJesse Brandeburg if (ret_code) 3987a208e83SKamil Krawczyk goto i40e_validate_nvm_checksum_exit; 39956a62fc8SJesse Brandeburg 40056a62fc8SJesse Brandeburg /* Do not use i40e_read_nvm_word() because we do not want to take 40156a62fc8SJesse Brandeburg * the synchronization semaphores twice here. 40256a62fc8SJesse Brandeburg */ 403a4bcfbb7SShannon Nelson i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr); 40456a62fc8SJesse Brandeburg 40556a62fc8SJesse Brandeburg /* Verify read checksum from EEPROM is the same as 40656a62fc8SJesse Brandeburg * calculated checksum 40756a62fc8SJesse Brandeburg */ 40856a62fc8SJesse Brandeburg if (checksum_local != checksum_sr) 40956a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 41056a62fc8SJesse Brandeburg 41156a62fc8SJesse Brandeburg /* If the user cares, return the calculated checksum */ 41256a62fc8SJesse Brandeburg if (checksum) 41356a62fc8SJesse Brandeburg *checksum = checksum_local; 41456a62fc8SJesse Brandeburg 41556a62fc8SJesse Brandeburg i40e_validate_nvm_checksum_exit: 41656a62fc8SJesse Brandeburg return ret_code; 41756a62fc8SJesse Brandeburg } 418cd552cb4SShannon Nelson 419cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw, 420cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 421cd552cb4SShannon Nelson u8 *bytes, int *errno); 422cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw, 423cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 424cd552cb4SShannon Nelson u8 *bytes, int *errno); 425cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw, 426cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 427cd552cb4SShannon Nelson u8 *bytes, int *errno); 428cd552cb4SShannon Nelson static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, 429cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 430cd552cb4SShannon Nelson int *errno); 431cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw, 432cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 433cd552cb4SShannon Nelson int *errno); 434cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw, 435cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 436cd552cb4SShannon Nelson u8 *bytes, int *errno); 437cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw, 438cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 439cd552cb4SShannon Nelson u8 *bytes, int *errno); 440cd552cb4SShannon Nelson static inline u8 i40e_nvmupd_get_module(u32 val) 441cd552cb4SShannon Nelson { 442cd552cb4SShannon Nelson return (u8)(val & I40E_NVM_MOD_PNT_MASK); 443cd552cb4SShannon Nelson } 444cd552cb4SShannon Nelson static inline u8 i40e_nvmupd_get_transaction(u32 val) 445cd552cb4SShannon Nelson { 446cd552cb4SShannon Nelson return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT); 447cd552cb4SShannon Nelson } 448cd552cb4SShannon Nelson 44974d0d0edSShannon Nelson static char *i40e_nvm_update_state_str[] = { 45074d0d0edSShannon Nelson "I40E_NVMUPD_INVALID", 45174d0d0edSShannon Nelson "I40E_NVMUPD_READ_CON", 45274d0d0edSShannon Nelson "I40E_NVMUPD_READ_SNT", 45374d0d0edSShannon Nelson "I40E_NVMUPD_READ_LCB", 45474d0d0edSShannon Nelson "I40E_NVMUPD_READ_SA", 45574d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_ERA", 45674d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_CON", 45774d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_SNT", 45874d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_LCB", 45974d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_SA", 46074d0d0edSShannon Nelson "I40E_NVMUPD_CSUM_CON", 46174d0d0edSShannon Nelson "I40E_NVMUPD_CSUM_SA", 46274d0d0edSShannon Nelson "I40E_NVMUPD_CSUM_LCB", 46374d0d0edSShannon Nelson }; 46474d0d0edSShannon Nelson 465cd552cb4SShannon Nelson /** 466cd552cb4SShannon Nelson * i40e_nvmupd_command - Process an NVM update command 467cd552cb4SShannon Nelson * @hw: pointer to hardware structure 468cd552cb4SShannon Nelson * @cmd: pointer to nvm update command 469cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 470cd552cb4SShannon Nelson * @errno: pointer to return error code 471cd552cb4SShannon Nelson * 472cd552cb4SShannon Nelson * Dispatches command depending on what update state is current 473cd552cb4SShannon Nelson **/ 474cd552cb4SShannon Nelson i40e_status i40e_nvmupd_command(struct i40e_hw *hw, 475cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 476cd552cb4SShannon Nelson u8 *bytes, int *errno) 477cd552cb4SShannon Nelson { 478cd552cb4SShannon Nelson i40e_status status; 479cd552cb4SShannon Nelson 480cd552cb4SShannon Nelson /* assume success */ 481cd552cb4SShannon Nelson *errno = 0; 482cd552cb4SShannon Nelson 483cd552cb4SShannon Nelson switch (hw->nvmupd_state) { 484cd552cb4SShannon Nelson case I40E_NVMUPD_STATE_INIT: 485cd552cb4SShannon Nelson status = i40e_nvmupd_state_init(hw, cmd, bytes, errno); 486cd552cb4SShannon Nelson break; 487cd552cb4SShannon Nelson 488cd552cb4SShannon Nelson case I40E_NVMUPD_STATE_READING: 489cd552cb4SShannon Nelson status = i40e_nvmupd_state_reading(hw, cmd, bytes, errno); 490cd552cb4SShannon Nelson break; 491cd552cb4SShannon Nelson 492cd552cb4SShannon Nelson case I40E_NVMUPD_STATE_WRITING: 493cd552cb4SShannon Nelson status = i40e_nvmupd_state_writing(hw, cmd, bytes, errno); 494cd552cb4SShannon Nelson break; 495cd552cb4SShannon Nelson 496cd552cb4SShannon Nelson default: 497cd552cb4SShannon Nelson /* invalid state, should never happen */ 49874d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 49974d0d0edSShannon Nelson "NVMUPD: no such state %d\n", hw->nvmupd_state); 500cd552cb4SShannon Nelson status = I40E_NOT_SUPPORTED; 501cd552cb4SShannon Nelson *errno = -ESRCH; 502cd552cb4SShannon Nelson break; 503cd552cb4SShannon Nelson } 504cd552cb4SShannon Nelson return status; 505cd552cb4SShannon Nelson } 506cd552cb4SShannon Nelson 507cd552cb4SShannon Nelson /** 508cd552cb4SShannon Nelson * i40e_nvmupd_state_init - Handle NVM update state Init 509cd552cb4SShannon Nelson * @hw: pointer to hardware structure 510cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 511cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 512cd552cb4SShannon Nelson * @errno: pointer to return error code 513cd552cb4SShannon Nelson * 514cd552cb4SShannon Nelson * Process legitimate commands of the Init state and conditionally set next 515cd552cb4SShannon Nelson * state. Reject all other commands. 516cd552cb4SShannon Nelson **/ 517cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw, 518cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 519cd552cb4SShannon Nelson u8 *bytes, int *errno) 520cd552cb4SShannon Nelson { 521cd552cb4SShannon Nelson i40e_status status = 0; 522cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 523cd552cb4SShannon Nelson 524cd552cb4SShannon Nelson upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); 525cd552cb4SShannon Nelson 526cd552cb4SShannon Nelson switch (upd_cmd) { 527cd552cb4SShannon Nelson case I40E_NVMUPD_READ_SA: 528cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 529cd552cb4SShannon Nelson if (status) { 530cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 531cd552cb4SShannon Nelson } else { 532cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); 533cd552cb4SShannon Nelson i40e_release_nvm(hw); 534cd552cb4SShannon Nelson } 535cd552cb4SShannon Nelson break; 536cd552cb4SShannon Nelson 537cd552cb4SShannon Nelson case I40E_NVMUPD_READ_SNT: 538cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 539cd552cb4SShannon Nelson if (status) { 540cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 541cd552cb4SShannon Nelson } else { 542cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); 5430fdd052cSShannon Nelson if (status) 5440fdd052cSShannon Nelson i40e_release_nvm(hw); 5450fdd052cSShannon Nelson else 546cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_READING; 547cd552cb4SShannon Nelson } 548cd552cb4SShannon Nelson break; 549cd552cb4SShannon Nelson 550cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_ERA: 551cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 552cd552cb4SShannon Nelson if (status) { 553cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 554cd552cb4SShannon Nelson } else { 555cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_erase(hw, cmd, errno); 556cd552cb4SShannon Nelson if (status) 557cd552cb4SShannon Nelson i40e_release_nvm(hw); 558cd552cb4SShannon Nelson else 559cd552cb4SShannon Nelson hw->aq.nvm_release_on_done = true; 560cd552cb4SShannon Nelson } 561cd552cb4SShannon Nelson break; 562cd552cb4SShannon Nelson 563cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_SA: 564cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 565cd552cb4SShannon Nelson if (status) { 566cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 567cd552cb4SShannon Nelson } else { 568cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); 569cd552cb4SShannon Nelson if (status) 570cd552cb4SShannon Nelson i40e_release_nvm(hw); 571cd552cb4SShannon Nelson else 572cd552cb4SShannon Nelson hw->aq.nvm_release_on_done = true; 573cd552cb4SShannon Nelson } 574cd552cb4SShannon Nelson break; 575cd552cb4SShannon Nelson 576cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_SNT: 577cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 578cd552cb4SShannon Nelson if (status) { 579cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 580cd552cb4SShannon Nelson } else { 581cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); 5820fdd052cSShannon Nelson if (status) 5830fdd052cSShannon Nelson i40e_release_nvm(hw); 5840fdd052cSShannon Nelson else 585cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING; 586cd552cb4SShannon Nelson } 587cd552cb4SShannon Nelson break; 588cd552cb4SShannon Nelson 589cd552cb4SShannon Nelson case I40E_NVMUPD_CSUM_SA: 590cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 591cd552cb4SShannon Nelson if (status) { 592cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 593cd552cb4SShannon Nelson } else { 594cd552cb4SShannon Nelson status = i40e_update_nvm_checksum(hw); 595cd552cb4SShannon Nelson if (status) { 596cd552cb4SShannon Nelson *errno = hw->aq.asq_last_status ? 597cd552cb4SShannon Nelson i40e_aq_rc_to_posix(hw->aq.asq_last_status) : 598cd552cb4SShannon Nelson -EIO; 599cd552cb4SShannon Nelson i40e_release_nvm(hw); 600cd552cb4SShannon Nelson } else { 601cd552cb4SShannon Nelson hw->aq.nvm_release_on_done = true; 602cd552cb4SShannon Nelson } 603cd552cb4SShannon Nelson } 604cd552cb4SShannon Nelson break; 605cd552cb4SShannon Nelson 606cd552cb4SShannon Nelson default: 60774d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 60874d0d0edSShannon Nelson "NVMUPD: bad cmd %s in init state\n", 60974d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 610cd552cb4SShannon Nelson status = I40E_ERR_NVM; 611cd552cb4SShannon Nelson *errno = -ESRCH; 612cd552cb4SShannon Nelson break; 613cd552cb4SShannon Nelson } 614cd552cb4SShannon Nelson return status; 615cd552cb4SShannon Nelson } 616cd552cb4SShannon Nelson 617cd552cb4SShannon Nelson /** 618cd552cb4SShannon Nelson * i40e_nvmupd_state_reading - Handle NVM update state Reading 619cd552cb4SShannon Nelson * @hw: pointer to hardware structure 620cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 621cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 622cd552cb4SShannon Nelson * @errno: pointer to return error code 623cd552cb4SShannon Nelson * 624cd552cb4SShannon Nelson * NVM ownership is already held. Process legitimate commands and set any 625cd552cb4SShannon Nelson * change in state; reject all other commands. 626cd552cb4SShannon Nelson **/ 627cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw, 628cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 629cd552cb4SShannon Nelson u8 *bytes, int *errno) 630cd552cb4SShannon Nelson { 631cd552cb4SShannon Nelson i40e_status status; 632cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 633cd552cb4SShannon Nelson 634cd552cb4SShannon Nelson upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); 635cd552cb4SShannon Nelson 636cd552cb4SShannon Nelson switch (upd_cmd) { 637cd552cb4SShannon Nelson case I40E_NVMUPD_READ_SA: 638cd552cb4SShannon Nelson case I40E_NVMUPD_READ_CON: 639cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); 640cd552cb4SShannon Nelson break; 641cd552cb4SShannon Nelson 642cd552cb4SShannon Nelson case I40E_NVMUPD_READ_LCB: 643cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); 644cd552cb4SShannon Nelson i40e_release_nvm(hw); 645cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 646cd552cb4SShannon Nelson break; 647cd552cb4SShannon Nelson 648cd552cb4SShannon Nelson default: 64974d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 65074d0d0edSShannon Nelson "NVMUPD: bad cmd %s in reading state.\n", 65174d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 652cd552cb4SShannon Nelson status = I40E_NOT_SUPPORTED; 653cd552cb4SShannon Nelson *errno = -ESRCH; 654cd552cb4SShannon Nelson break; 655cd552cb4SShannon Nelson } 656cd552cb4SShannon Nelson return status; 657cd552cb4SShannon Nelson } 658cd552cb4SShannon Nelson 659cd552cb4SShannon Nelson /** 660cd552cb4SShannon Nelson * i40e_nvmupd_state_writing - Handle NVM update state Writing 661cd552cb4SShannon Nelson * @hw: pointer to hardware structure 662cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 663cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 664cd552cb4SShannon Nelson * @errno: pointer to return error code 665cd552cb4SShannon Nelson * 666cd552cb4SShannon Nelson * NVM ownership is already held. Process legitimate commands and set any 667cd552cb4SShannon Nelson * change in state; reject all other commands 668cd552cb4SShannon Nelson **/ 669cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw, 670cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 671cd552cb4SShannon Nelson u8 *bytes, int *errno) 672cd552cb4SShannon Nelson { 673cd552cb4SShannon Nelson i40e_status status; 674cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 675cd552cb4SShannon Nelson 676cd552cb4SShannon Nelson upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); 677cd552cb4SShannon Nelson 678cd552cb4SShannon Nelson switch (upd_cmd) { 679cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_CON: 680cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); 681cd552cb4SShannon Nelson break; 682cd552cb4SShannon Nelson 683cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_LCB: 684cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); 6850fdd052cSShannon Nelson if (!status) 686cd552cb4SShannon Nelson hw->aq.nvm_release_on_done = true; 687cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 688cd552cb4SShannon Nelson break; 689cd552cb4SShannon Nelson 690cd552cb4SShannon Nelson case I40E_NVMUPD_CSUM_CON: 691cd552cb4SShannon Nelson status = i40e_update_nvm_checksum(hw); 692cd552cb4SShannon Nelson if (status) { 693cd552cb4SShannon Nelson *errno = hw->aq.asq_last_status ? 694cd552cb4SShannon Nelson i40e_aq_rc_to_posix(hw->aq.asq_last_status) : 695cd552cb4SShannon Nelson -EIO; 696cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 697cd552cb4SShannon Nelson } 698cd552cb4SShannon Nelson break; 699cd552cb4SShannon Nelson 7000fdd052cSShannon Nelson case I40E_NVMUPD_CSUM_LCB: 7010fdd052cSShannon Nelson status = i40e_update_nvm_checksum(hw); 7020fdd052cSShannon Nelson if (status) 7030fdd052cSShannon Nelson *errno = hw->aq.asq_last_status ? 7040fdd052cSShannon Nelson i40e_aq_rc_to_posix(hw->aq.asq_last_status) : 7050fdd052cSShannon Nelson -EIO; 7060fdd052cSShannon Nelson else 7070fdd052cSShannon Nelson hw->aq.nvm_release_on_done = true; 7080fdd052cSShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 7090fdd052cSShannon Nelson break; 7100fdd052cSShannon Nelson 711cd552cb4SShannon Nelson default: 71274d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 71374d0d0edSShannon Nelson "NVMUPD: bad cmd %s in writing state.\n", 71474d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 715cd552cb4SShannon Nelson status = I40E_NOT_SUPPORTED; 716cd552cb4SShannon Nelson *errno = -ESRCH; 717cd552cb4SShannon Nelson break; 718cd552cb4SShannon Nelson } 719cd552cb4SShannon Nelson return status; 720cd552cb4SShannon Nelson } 721cd552cb4SShannon Nelson 722cd552cb4SShannon Nelson /** 723cd552cb4SShannon Nelson * i40e_nvmupd_validate_command - Validate given command 724cd552cb4SShannon Nelson * @hw: pointer to hardware structure 725cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 726cd552cb4SShannon Nelson * @errno: pointer to return error code 727cd552cb4SShannon Nelson * 728cd552cb4SShannon Nelson * Return one of the valid command types or I40E_NVMUPD_INVALID 729cd552cb4SShannon Nelson **/ 730cd552cb4SShannon Nelson static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, 731cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 732cd552cb4SShannon Nelson int *errno) 733cd552cb4SShannon Nelson { 734cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 735cd552cb4SShannon Nelson u8 transaction, module; 736cd552cb4SShannon Nelson 737cd552cb4SShannon Nelson /* anything that doesn't match a recognized case is an error */ 738cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_INVALID; 739cd552cb4SShannon Nelson 740cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 741cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 742cd552cb4SShannon Nelson 743cd552cb4SShannon Nelson /* limits on data size */ 744cd552cb4SShannon Nelson if ((cmd->data_size < 1) || 745cd552cb4SShannon Nelson (cmd->data_size > I40E_NVMUPD_MAX_DATA)) { 74674d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 74774d0d0edSShannon Nelson "i40e_nvmupd_validate_command data_size %d\n", 748cd552cb4SShannon Nelson cmd->data_size); 749cd552cb4SShannon Nelson *errno = -EFAULT; 750cd552cb4SShannon Nelson return I40E_NVMUPD_INVALID; 751cd552cb4SShannon Nelson } 752cd552cb4SShannon Nelson 753cd552cb4SShannon Nelson switch (cmd->command) { 754cd552cb4SShannon Nelson case I40E_NVM_READ: 755cd552cb4SShannon Nelson switch (transaction) { 756cd552cb4SShannon Nelson case I40E_NVM_CON: 757cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_CON; 758cd552cb4SShannon Nelson break; 759cd552cb4SShannon Nelson case I40E_NVM_SNT: 760cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_SNT; 761cd552cb4SShannon Nelson break; 762cd552cb4SShannon Nelson case I40E_NVM_LCB: 763cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_LCB; 764cd552cb4SShannon Nelson break; 765cd552cb4SShannon Nelson case I40E_NVM_SA: 766cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_SA; 767cd552cb4SShannon Nelson break; 768cd552cb4SShannon Nelson } 769cd552cb4SShannon Nelson break; 770cd552cb4SShannon Nelson 771cd552cb4SShannon Nelson case I40E_NVM_WRITE: 772cd552cb4SShannon Nelson switch (transaction) { 773cd552cb4SShannon Nelson case I40E_NVM_CON: 774cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_CON; 775cd552cb4SShannon Nelson break; 776cd552cb4SShannon Nelson case I40E_NVM_SNT: 777cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_SNT; 778cd552cb4SShannon Nelson break; 779cd552cb4SShannon Nelson case I40E_NVM_LCB: 780cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_LCB; 781cd552cb4SShannon Nelson break; 782cd552cb4SShannon Nelson case I40E_NVM_SA: 783cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_SA; 784cd552cb4SShannon Nelson break; 785cd552cb4SShannon Nelson case I40E_NVM_ERA: 786cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_ERA; 787cd552cb4SShannon Nelson break; 788cd552cb4SShannon Nelson case I40E_NVM_CSUM: 789cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_CSUM_CON; 790cd552cb4SShannon Nelson break; 791cd552cb4SShannon Nelson case (I40E_NVM_CSUM|I40E_NVM_SA): 792cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_CSUM_SA; 793cd552cb4SShannon Nelson break; 794cd552cb4SShannon Nelson case (I40E_NVM_CSUM|I40E_NVM_LCB): 795cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_CSUM_LCB; 796cd552cb4SShannon Nelson break; 797cd552cb4SShannon Nelson } 798cd552cb4SShannon Nelson break; 799cd552cb4SShannon Nelson } 80074d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "%s\n", 80174d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 802cd552cb4SShannon Nelson 803cd552cb4SShannon Nelson if (upd_cmd == I40E_NVMUPD_INVALID) { 804cd552cb4SShannon Nelson *errno = -EFAULT; 80574d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 80674d0d0edSShannon Nelson "i40e_nvmupd_validate_command returns %d errno %d\n", 807cd552cb4SShannon Nelson upd_cmd, *errno); 808cd552cb4SShannon Nelson } 809cd552cb4SShannon Nelson return upd_cmd; 810cd552cb4SShannon Nelson } 811cd552cb4SShannon Nelson 812cd552cb4SShannon Nelson /** 813cd552cb4SShannon Nelson * i40e_nvmupd_nvm_read - Read NVM 814cd552cb4SShannon Nelson * @hw: pointer to hardware structure 815cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 816cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 817cd552cb4SShannon Nelson * @errno: pointer to return error code 818cd552cb4SShannon Nelson * 819cd552cb4SShannon Nelson * cmd structure contains identifiers and data buffer 820cd552cb4SShannon Nelson **/ 821cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw, 822cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 823cd552cb4SShannon Nelson u8 *bytes, int *errno) 824cd552cb4SShannon Nelson { 825cd552cb4SShannon Nelson i40e_status status; 826cd552cb4SShannon Nelson u8 module, transaction; 827cd552cb4SShannon Nelson bool last; 828cd552cb4SShannon Nelson 829cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 830cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 831cd552cb4SShannon Nelson last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA); 832cd552cb4SShannon Nelson 833cd552cb4SShannon Nelson status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size, 834cd552cb4SShannon Nelson bytes, last, NULL); 83574d0d0edSShannon Nelson if (status) { 83674d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 83774d0d0edSShannon Nelson "i40e_nvmupd_nvm_read mod 0x%x off 0x%x len 0x%x\n", 83874d0d0edSShannon Nelson module, cmd->offset, cmd->data_size); 83974d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 84074d0d0edSShannon Nelson "i40e_nvmupd_nvm_read status %d aq %d\n", 84174d0d0edSShannon Nelson status, hw->aq.asq_last_status); 842cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 84374d0d0edSShannon Nelson } 844cd552cb4SShannon Nelson 845cd552cb4SShannon Nelson return status; 846cd552cb4SShannon Nelson } 847cd552cb4SShannon Nelson 848cd552cb4SShannon Nelson /** 849cd552cb4SShannon Nelson * i40e_nvmupd_nvm_erase - Erase an NVM module 850cd552cb4SShannon Nelson * @hw: pointer to hardware structure 851cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 852cd552cb4SShannon Nelson * @errno: pointer to return error code 853cd552cb4SShannon Nelson * 854cd552cb4SShannon Nelson * module, offset, data_size and data are in cmd structure 855cd552cb4SShannon Nelson **/ 856cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw, 857cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 858cd552cb4SShannon Nelson int *errno) 859cd552cb4SShannon Nelson { 860cd552cb4SShannon Nelson i40e_status status = 0; 861cd552cb4SShannon Nelson u8 module, transaction; 862cd552cb4SShannon Nelson bool last; 863cd552cb4SShannon Nelson 864cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 865cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 866cd552cb4SShannon Nelson last = (transaction & I40E_NVM_LCB); 867cd552cb4SShannon Nelson status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size, 868cd552cb4SShannon Nelson last, NULL); 86974d0d0edSShannon Nelson if (status) { 87074d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 87174d0d0edSShannon Nelson "i40e_nvmupd_nvm_erase mod 0x%x off 0x%x len 0x%x\n", 87274d0d0edSShannon Nelson module, cmd->offset, cmd->data_size); 87374d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 87474d0d0edSShannon Nelson "i40e_nvmupd_nvm_erase status %d aq %d\n", 87574d0d0edSShannon Nelson status, hw->aq.asq_last_status); 876cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 87774d0d0edSShannon Nelson } 878cd552cb4SShannon Nelson 879cd552cb4SShannon Nelson return status; 880cd552cb4SShannon Nelson } 881cd552cb4SShannon Nelson 882cd552cb4SShannon Nelson /** 883cd552cb4SShannon Nelson * i40e_nvmupd_nvm_write - Write NVM 884cd552cb4SShannon Nelson * @hw: pointer to hardware structure 885cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 886cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 887cd552cb4SShannon Nelson * @errno: pointer to return error code 888cd552cb4SShannon Nelson * 889cd552cb4SShannon Nelson * module, offset, data_size and data are in cmd structure 890cd552cb4SShannon Nelson **/ 891cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw, 892cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 893cd552cb4SShannon Nelson u8 *bytes, int *errno) 894cd552cb4SShannon Nelson { 895cd552cb4SShannon Nelson i40e_status status = 0; 896cd552cb4SShannon Nelson u8 module, transaction; 897cd552cb4SShannon Nelson bool last; 898cd552cb4SShannon Nelson 899cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 900cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 901cd552cb4SShannon Nelson last = (transaction & I40E_NVM_LCB); 90274d0d0edSShannon Nelson 903cd552cb4SShannon Nelson status = i40e_aq_update_nvm(hw, module, cmd->offset, 904cd552cb4SShannon Nelson (u16)cmd->data_size, bytes, last, NULL); 90574d0d0edSShannon Nelson if (status) { 90674d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 90774d0d0edSShannon Nelson "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n", 90874d0d0edSShannon Nelson module, cmd->offset, cmd->data_size); 90974d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 91074d0d0edSShannon Nelson "i40e_nvmupd_nvm_write status %d aq %d\n", 91174d0d0edSShannon Nelson status, hw->aq.asq_last_status); 912cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 91374d0d0edSShannon Nelson } 914cd552cb4SShannon Nelson 915cd552cb4SShannon Nelson return status; 916cd552cb4SShannon Nelson } 917