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 9656a62fc8SJesse Brandeburg if (ret_code) { 973e26186dSShannon Nelson /* Poll until the current NVM owner timeouts */ 98c509c1deSShannon Nelson timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime; 9956a62fc8SJesse Brandeburg while (gtime < timeout) { 10056a62fc8SJesse Brandeburg usleep_range(10000, 20000); 101c509c1deSShannon Nelson gtime = rd32(hw, I40E_GLVFGEN_TIMER); 10256a62fc8SJesse Brandeburg ret_code = i40e_aq_request_resource(hw, 10356a62fc8SJesse Brandeburg I40E_NVM_RESOURCE_ID, 104c509c1deSShannon Nelson access, 0, &time_left, 10556a62fc8SJesse Brandeburg NULL); 10656a62fc8SJesse Brandeburg if (!ret_code) { 10756a62fc8SJesse Brandeburg hw->nvm.hw_semaphore_timeout = 108c509c1deSShannon Nelson I40E_MS_TO_GTIME(time_left) + gtime; 10956a62fc8SJesse Brandeburg break; 11056a62fc8SJesse Brandeburg } 11156a62fc8SJesse Brandeburg } 11256a62fc8SJesse Brandeburg if (ret_code) { 11356a62fc8SJesse Brandeburg hw->nvm.hw_semaphore_timeout = 0; 11474d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 11574d0d0edSShannon Nelson "NVM acquire timed out, wait %llu ms before trying again.\n", 116c509c1deSShannon Nelson time_left); 11756a62fc8SJesse Brandeburg } 11856a62fc8SJesse Brandeburg } 11956a62fc8SJesse Brandeburg 12056a62fc8SJesse Brandeburg i40e_i40e_acquire_nvm_exit: 12156a62fc8SJesse Brandeburg return ret_code; 12256a62fc8SJesse Brandeburg } 12356a62fc8SJesse Brandeburg 12456a62fc8SJesse Brandeburg /** 1253e26186dSShannon Nelson * i40e_release_nvm - Generic request for releasing the NVM ownership 1263e26186dSShannon Nelson * @hw: pointer to the HW structure 12756a62fc8SJesse Brandeburg * 12856a62fc8SJesse Brandeburg * This function will release NVM resource via the proper Admin Command. 12956a62fc8SJesse Brandeburg **/ 13056a62fc8SJesse Brandeburg void i40e_release_nvm(struct i40e_hw *hw) 13156a62fc8SJesse Brandeburg { 13256a62fc8SJesse Brandeburg if (!hw->nvm.blank_nvm_mode) 13356a62fc8SJesse Brandeburg i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL); 13456a62fc8SJesse Brandeburg } 13556a62fc8SJesse Brandeburg 13656a62fc8SJesse Brandeburg /** 1373e26186dSShannon Nelson * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit 1383e26186dSShannon Nelson * @hw: pointer to the HW structure 13956a62fc8SJesse Brandeburg * 14056a62fc8SJesse Brandeburg * Polls the SRCTL Shadow RAM register done bit. 14156a62fc8SJesse Brandeburg **/ 14256a62fc8SJesse Brandeburg static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) 14356a62fc8SJesse Brandeburg { 14456a62fc8SJesse Brandeburg i40e_status ret_code = I40E_ERR_TIMEOUT; 14556a62fc8SJesse Brandeburg u32 srctl, wait_cnt; 14656a62fc8SJesse Brandeburg 1473e26186dSShannon Nelson /* Poll the I40E_GLNVM_SRCTL until the done bit is set */ 14856a62fc8SJesse Brandeburg for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) { 14956a62fc8SJesse Brandeburg srctl = rd32(hw, I40E_GLNVM_SRCTL); 15056a62fc8SJesse Brandeburg if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) { 15156a62fc8SJesse Brandeburg ret_code = 0; 15256a62fc8SJesse Brandeburg break; 15356a62fc8SJesse Brandeburg } 15456a62fc8SJesse Brandeburg udelay(5); 15556a62fc8SJesse Brandeburg } 15656a62fc8SJesse Brandeburg if (ret_code == I40E_ERR_TIMEOUT) 15774d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set"); 15856a62fc8SJesse Brandeburg return ret_code; 15956a62fc8SJesse Brandeburg } 16056a62fc8SJesse Brandeburg 16156a62fc8SJesse Brandeburg /** 162a4bcfbb7SShannon Nelson * i40e_read_nvm_word - Reads Shadow RAM 1633e26186dSShannon Nelson * @hw: pointer to the HW structure 1643e26186dSShannon Nelson * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 1653e26186dSShannon Nelson * @data: word read from the Shadow RAM 16656a62fc8SJesse Brandeburg * 1673e26186dSShannon Nelson * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. 16856a62fc8SJesse Brandeburg **/ 169a4bcfbb7SShannon Nelson i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, 17056a62fc8SJesse Brandeburg u16 *data) 17156a62fc8SJesse Brandeburg { 17256a62fc8SJesse Brandeburg i40e_status ret_code = I40E_ERR_TIMEOUT; 17356a62fc8SJesse Brandeburg u32 sr_reg; 17456a62fc8SJesse Brandeburg 17556a62fc8SJesse Brandeburg if (offset >= hw->nvm.sr_size) { 17674d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 17774d0d0edSShannon Nelson "NVM read error: offset %d beyond Shadow RAM limit %d\n", 17874d0d0edSShannon Nelson offset, hw->nvm.sr_size); 17956a62fc8SJesse Brandeburg ret_code = I40E_ERR_PARAM; 18056a62fc8SJesse Brandeburg goto read_nvm_exit; 18156a62fc8SJesse Brandeburg } 18256a62fc8SJesse Brandeburg 1833e26186dSShannon Nelson /* Poll the done bit first */ 18456a62fc8SJesse Brandeburg ret_code = i40e_poll_sr_srctl_done_bit(hw); 18556a62fc8SJesse Brandeburg if (!ret_code) { 1863e26186dSShannon Nelson /* Write the address and start reading */ 18756a62fc8SJesse Brandeburg sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | 18856a62fc8SJesse Brandeburg (1 << I40E_GLNVM_SRCTL_START_SHIFT); 18956a62fc8SJesse Brandeburg wr32(hw, I40E_GLNVM_SRCTL, sr_reg); 19056a62fc8SJesse Brandeburg 1913e26186dSShannon Nelson /* Poll I40E_GLNVM_SRCTL until the done bit is set */ 19256a62fc8SJesse Brandeburg ret_code = i40e_poll_sr_srctl_done_bit(hw); 19356a62fc8SJesse Brandeburg if (!ret_code) { 19456a62fc8SJesse Brandeburg sr_reg = rd32(hw, I40E_GLNVM_SRDATA); 19556a62fc8SJesse Brandeburg *data = (u16)((sr_reg & 19656a62fc8SJesse Brandeburg I40E_GLNVM_SRDATA_RDDATA_MASK) 19756a62fc8SJesse Brandeburg >> I40E_GLNVM_SRDATA_RDDATA_SHIFT); 19856a62fc8SJesse Brandeburg } 19956a62fc8SJesse Brandeburg } 20056a62fc8SJesse Brandeburg if (ret_code) 20174d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 20274d0d0edSShannon Nelson "NVM read error: Couldn't access Shadow RAM address: 0x%x\n", 20356a62fc8SJesse Brandeburg offset); 20456a62fc8SJesse Brandeburg 20556a62fc8SJesse Brandeburg read_nvm_exit: 20656a62fc8SJesse Brandeburg return ret_code; 20756a62fc8SJesse Brandeburg } 20856a62fc8SJesse Brandeburg 20956a62fc8SJesse Brandeburg /** 2103e26186dSShannon Nelson * i40e_read_nvm_buffer - Reads Shadow RAM buffer 2113e26186dSShannon Nelson * @hw: pointer to the HW structure 21256a62fc8SJesse Brandeburg * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 2133e26186dSShannon Nelson * @words: (in) number of words to read; (out) number of words actually read 2143e26186dSShannon Nelson * @data: words read from the Shadow RAM 21556a62fc8SJesse Brandeburg * 21656a62fc8SJesse Brandeburg * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() 21756a62fc8SJesse Brandeburg * method. The buffer read is preceded by the NVM ownership take 21856a62fc8SJesse Brandeburg * and followed by the release. 21956a62fc8SJesse Brandeburg **/ 22056a62fc8SJesse Brandeburg i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, 22156a62fc8SJesse Brandeburg u16 *words, u16 *data) 22256a62fc8SJesse Brandeburg { 22356a62fc8SJesse Brandeburg i40e_status ret_code = 0; 22456a62fc8SJesse Brandeburg u16 index, word; 22556a62fc8SJesse Brandeburg 2263e26186dSShannon Nelson /* Loop thru the selected region */ 22756a62fc8SJesse Brandeburg for (word = 0; word < *words; word++) { 22856a62fc8SJesse Brandeburg index = offset + word; 229a4bcfbb7SShannon Nelson ret_code = i40e_read_nvm_word(hw, index, &data[word]); 23056a62fc8SJesse Brandeburg if (ret_code) 23156a62fc8SJesse Brandeburg break; 23256a62fc8SJesse Brandeburg } 233a4bcfbb7SShannon Nelson 2343e26186dSShannon Nelson /* Update the number of words read from the Shadow RAM */ 23556a62fc8SJesse Brandeburg *words = word; 23656a62fc8SJesse Brandeburg 23756a62fc8SJesse Brandeburg return ret_code; 23856a62fc8SJesse Brandeburg } 23956a62fc8SJesse Brandeburg 24056a62fc8SJesse Brandeburg /** 241cd552cb4SShannon Nelson * i40e_write_nvm_aq - Writes Shadow RAM. 242cd552cb4SShannon Nelson * @hw: pointer to the HW structure. 243cd552cb4SShannon Nelson * @module_pointer: module pointer location in words from the NVM beginning 244cd552cb4SShannon Nelson * @offset: offset in words from module start 245cd552cb4SShannon Nelson * @words: number of words to write 246cd552cb4SShannon Nelson * @data: buffer with words to write to the Shadow RAM 247cd552cb4SShannon Nelson * @last_command: tells the AdminQ that this is the last command 248cd552cb4SShannon Nelson * 249cd552cb4SShannon Nelson * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 250cd552cb4SShannon Nelson **/ 251952d9639SWei Yongjun static i40e_status i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer, 252cd552cb4SShannon Nelson u32 offset, u16 words, void *data, 253cd552cb4SShannon Nelson bool last_command) 254cd552cb4SShannon Nelson { 255cd552cb4SShannon Nelson i40e_status ret_code = I40E_ERR_NVM; 256cd552cb4SShannon Nelson 257cd552cb4SShannon Nelson /* Here we are checking the SR limit only for the flat memory model. 258cd552cb4SShannon Nelson * We cannot do it for the module-based model, as we did not acquire 259cd552cb4SShannon Nelson * the NVM resource yet (we cannot get the module pointer value). 260cd552cb4SShannon Nelson * Firmware will check the module-based model. 261cd552cb4SShannon Nelson */ 262cd552cb4SShannon Nelson if ((offset + words) > hw->nvm.sr_size) 26374d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 26474d0d0edSShannon Nelson "NVM write error: offset %d beyond Shadow RAM limit %d\n", 26574d0d0edSShannon Nelson (offset + words), hw->nvm.sr_size); 266cd552cb4SShannon Nelson else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) 267cd552cb4SShannon Nelson /* We can write only up to 4KB (one sector), in one AQ write */ 26874d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 26974d0d0edSShannon Nelson "NVM write fail error: tried to write %d words, limit is %d.\n", 27074d0d0edSShannon Nelson words, I40E_SR_SECTOR_SIZE_IN_WORDS); 271cd552cb4SShannon Nelson else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) 272cd552cb4SShannon Nelson != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) 273cd552cb4SShannon Nelson /* A single write cannot spread over two sectors */ 27474d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 27574d0d0edSShannon Nelson "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n", 27674d0d0edSShannon Nelson offset, words); 277cd552cb4SShannon Nelson else 278cd552cb4SShannon Nelson ret_code = i40e_aq_update_nvm(hw, module_pointer, 279cd552cb4SShannon Nelson 2 * offset, /*bytes*/ 280cd552cb4SShannon Nelson 2 * words, /*bytes*/ 281cd552cb4SShannon Nelson data, last_command, NULL); 282cd552cb4SShannon Nelson 283cd552cb4SShannon Nelson return ret_code; 284cd552cb4SShannon Nelson } 285cd552cb4SShannon Nelson 286cd552cb4SShannon Nelson /** 28756a62fc8SJesse Brandeburg * i40e_calc_nvm_checksum - Calculates and returns the checksum 28856a62fc8SJesse Brandeburg * @hw: pointer to hardware structure 28998d44381SJeff Kirsher * @checksum: pointer to the checksum 29056a62fc8SJesse Brandeburg * 2913e26186dSShannon Nelson * This function calculates SW Checksum that covers the whole 64kB shadow RAM 29256a62fc8SJesse Brandeburg * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD 29356a62fc8SJesse Brandeburg * is customer specific and unknown. Therefore, this function skips all maximum 29456a62fc8SJesse Brandeburg * possible size of VPD (1kB). 29556a62fc8SJesse Brandeburg **/ 29656a62fc8SJesse Brandeburg static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw, 29756a62fc8SJesse Brandeburg u16 *checksum) 29856a62fc8SJesse Brandeburg { 29956a62fc8SJesse Brandeburg i40e_status ret_code = 0; 30056a62fc8SJesse Brandeburg u16 pcie_alt_module = 0; 30156a62fc8SJesse Brandeburg u16 checksum_local = 0; 30256a62fc8SJesse Brandeburg u16 vpd_module = 0; 30356a62fc8SJesse Brandeburg u16 word = 0; 30456a62fc8SJesse Brandeburg u32 i = 0; 30556a62fc8SJesse Brandeburg 30656a62fc8SJesse Brandeburg /* read pointer to VPD area */ 307a4bcfbb7SShannon Nelson ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module); 30856a62fc8SJesse Brandeburg if (ret_code) { 30956a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 31056a62fc8SJesse Brandeburg goto i40e_calc_nvm_checksum_exit; 31156a62fc8SJesse Brandeburg } 31256a62fc8SJesse Brandeburg 31356a62fc8SJesse Brandeburg /* read pointer to PCIe Alt Auto-load module */ 314a4bcfbb7SShannon Nelson ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR, 31556a62fc8SJesse Brandeburg &pcie_alt_module); 31656a62fc8SJesse Brandeburg if (ret_code) { 31756a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 31856a62fc8SJesse Brandeburg goto i40e_calc_nvm_checksum_exit; 31956a62fc8SJesse Brandeburg } 32056a62fc8SJesse Brandeburg 32156a62fc8SJesse Brandeburg /* Calculate SW checksum that covers the whole 64kB shadow RAM 32256a62fc8SJesse Brandeburg * except the VPD and PCIe ALT Auto-load modules 32356a62fc8SJesse Brandeburg */ 32456a62fc8SJesse Brandeburg for (i = 0; i < hw->nvm.sr_size; i++) { 32556a62fc8SJesse Brandeburg /* Skip Checksum word */ 32656a62fc8SJesse Brandeburg if (i == I40E_SR_SW_CHECKSUM_WORD) 32756a62fc8SJesse Brandeburg i++; 32856a62fc8SJesse Brandeburg /* Skip VPD module (convert byte size to word count) */ 32956a62fc8SJesse Brandeburg if (i == (u32)vpd_module) { 33056a62fc8SJesse Brandeburg i += (I40E_SR_VPD_MODULE_MAX_SIZE / 2); 33156a62fc8SJesse Brandeburg if (i >= hw->nvm.sr_size) 33256a62fc8SJesse Brandeburg break; 33356a62fc8SJesse Brandeburg } 33456a62fc8SJesse Brandeburg /* Skip PCIe ALT module (convert byte size to word count) */ 33556a62fc8SJesse Brandeburg if (i == (u32)pcie_alt_module) { 33656a62fc8SJesse Brandeburg i += (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2); 33756a62fc8SJesse Brandeburg if (i >= hw->nvm.sr_size) 33856a62fc8SJesse Brandeburg break; 33956a62fc8SJesse Brandeburg } 34056a62fc8SJesse Brandeburg 341a4bcfbb7SShannon Nelson ret_code = i40e_read_nvm_word(hw, (u16)i, &word); 34256a62fc8SJesse Brandeburg if (ret_code) { 34356a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 34456a62fc8SJesse Brandeburg goto i40e_calc_nvm_checksum_exit; 34556a62fc8SJesse Brandeburg } 34656a62fc8SJesse Brandeburg checksum_local += word; 34756a62fc8SJesse Brandeburg } 34856a62fc8SJesse Brandeburg 34956a62fc8SJesse Brandeburg *checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local; 35056a62fc8SJesse Brandeburg 35156a62fc8SJesse Brandeburg i40e_calc_nvm_checksum_exit: 35256a62fc8SJesse Brandeburg return ret_code; 35356a62fc8SJesse Brandeburg } 35456a62fc8SJesse Brandeburg 35556a62fc8SJesse Brandeburg /** 356cd552cb4SShannon Nelson * i40e_update_nvm_checksum - Updates the NVM checksum 357cd552cb4SShannon Nelson * @hw: pointer to hardware structure 358cd552cb4SShannon Nelson * 359cd552cb4SShannon Nelson * NVM ownership must be acquired before calling this function and released 360cd552cb4SShannon Nelson * on ARQ completion event reception by caller. 361cd552cb4SShannon Nelson * This function will commit SR to NVM. 362cd552cb4SShannon Nelson **/ 363cd552cb4SShannon Nelson i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw) 364cd552cb4SShannon Nelson { 365cd552cb4SShannon Nelson i40e_status ret_code = 0; 366cd552cb4SShannon Nelson u16 checksum; 367cd552cb4SShannon Nelson 368cd552cb4SShannon Nelson ret_code = i40e_calc_nvm_checksum(hw, &checksum); 369cd552cb4SShannon Nelson if (!ret_code) 370cd552cb4SShannon Nelson ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD, 371cd552cb4SShannon Nelson 1, &checksum, true); 372cd552cb4SShannon Nelson 373cd552cb4SShannon Nelson return ret_code; 374cd552cb4SShannon Nelson } 375cd552cb4SShannon Nelson 376cd552cb4SShannon Nelson /** 37756a62fc8SJesse Brandeburg * i40e_validate_nvm_checksum - Validate EEPROM checksum 37856a62fc8SJesse Brandeburg * @hw: pointer to hardware structure 37956a62fc8SJesse Brandeburg * @checksum: calculated checksum 38056a62fc8SJesse Brandeburg * 38156a62fc8SJesse Brandeburg * Performs checksum calculation and validates the NVM SW checksum. If the 38256a62fc8SJesse Brandeburg * caller does not need checksum, the value can be NULL. 38356a62fc8SJesse Brandeburg **/ 38456a62fc8SJesse Brandeburg i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, 38556a62fc8SJesse Brandeburg u16 *checksum) 38656a62fc8SJesse Brandeburg { 38756a62fc8SJesse Brandeburg i40e_status ret_code = 0; 38856a62fc8SJesse Brandeburg u16 checksum_sr = 0; 389e15c9fa0SJesse Brandeburg u16 checksum_local = 0; 39056a62fc8SJesse Brandeburg 39156a62fc8SJesse Brandeburg ret_code = i40e_calc_nvm_checksum(hw, &checksum_local); 39256a62fc8SJesse Brandeburg if (ret_code) 3937a208e83SKamil Krawczyk goto i40e_validate_nvm_checksum_exit; 39456a62fc8SJesse Brandeburg 39556a62fc8SJesse Brandeburg /* Do not use i40e_read_nvm_word() because we do not want to take 39656a62fc8SJesse Brandeburg * the synchronization semaphores twice here. 39756a62fc8SJesse Brandeburg */ 398a4bcfbb7SShannon Nelson i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr); 39956a62fc8SJesse Brandeburg 40056a62fc8SJesse Brandeburg /* Verify read checksum from EEPROM is the same as 40156a62fc8SJesse Brandeburg * calculated checksum 40256a62fc8SJesse Brandeburg */ 40356a62fc8SJesse Brandeburg if (checksum_local != checksum_sr) 40456a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 40556a62fc8SJesse Brandeburg 40656a62fc8SJesse Brandeburg /* If the user cares, return the calculated checksum */ 40756a62fc8SJesse Brandeburg if (checksum) 40856a62fc8SJesse Brandeburg *checksum = checksum_local; 40956a62fc8SJesse Brandeburg 41056a62fc8SJesse Brandeburg i40e_validate_nvm_checksum_exit: 41156a62fc8SJesse Brandeburg return ret_code; 41256a62fc8SJesse Brandeburg } 413cd552cb4SShannon Nelson 414cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw, 415cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 416cd552cb4SShannon Nelson u8 *bytes, int *errno); 417cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw, 418cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 419cd552cb4SShannon Nelson u8 *bytes, int *errno); 420cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw, 421cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 422cd552cb4SShannon Nelson u8 *bytes, int *errno); 423cd552cb4SShannon Nelson static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, 424cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 425cd552cb4SShannon Nelson int *errno); 426cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw, 427cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 428cd552cb4SShannon Nelson int *errno); 429cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw, 430cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 431cd552cb4SShannon Nelson u8 *bytes, int *errno); 432cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw, 433cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 434cd552cb4SShannon Nelson u8 *bytes, int *errno); 435cd552cb4SShannon Nelson static inline u8 i40e_nvmupd_get_module(u32 val) 436cd552cb4SShannon Nelson { 437cd552cb4SShannon Nelson return (u8)(val & I40E_NVM_MOD_PNT_MASK); 438cd552cb4SShannon Nelson } 439cd552cb4SShannon Nelson static inline u8 i40e_nvmupd_get_transaction(u32 val) 440cd552cb4SShannon Nelson { 441cd552cb4SShannon Nelson return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT); 442cd552cb4SShannon Nelson } 443cd552cb4SShannon Nelson 44474d0d0edSShannon Nelson static char *i40e_nvm_update_state_str[] = { 44574d0d0edSShannon Nelson "I40E_NVMUPD_INVALID", 44674d0d0edSShannon Nelson "I40E_NVMUPD_READ_CON", 44774d0d0edSShannon Nelson "I40E_NVMUPD_READ_SNT", 44874d0d0edSShannon Nelson "I40E_NVMUPD_READ_LCB", 44974d0d0edSShannon Nelson "I40E_NVMUPD_READ_SA", 45074d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_ERA", 45174d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_CON", 45274d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_SNT", 45374d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_LCB", 45474d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_SA", 45574d0d0edSShannon Nelson "I40E_NVMUPD_CSUM_CON", 45674d0d0edSShannon Nelson "I40E_NVMUPD_CSUM_SA", 45774d0d0edSShannon Nelson "I40E_NVMUPD_CSUM_LCB", 45874d0d0edSShannon Nelson }; 45974d0d0edSShannon Nelson 460cd552cb4SShannon Nelson /** 461cd552cb4SShannon Nelson * i40e_nvmupd_command - Process an NVM update command 462cd552cb4SShannon Nelson * @hw: pointer to hardware structure 463cd552cb4SShannon Nelson * @cmd: pointer to nvm update command 464cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 465cd552cb4SShannon Nelson * @errno: pointer to return error code 466cd552cb4SShannon Nelson * 467cd552cb4SShannon Nelson * Dispatches command depending on what update state is current 468cd552cb4SShannon Nelson **/ 469cd552cb4SShannon Nelson i40e_status i40e_nvmupd_command(struct i40e_hw *hw, 470cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 471cd552cb4SShannon Nelson u8 *bytes, int *errno) 472cd552cb4SShannon Nelson { 473cd552cb4SShannon Nelson i40e_status status; 474cd552cb4SShannon Nelson 475cd552cb4SShannon Nelson /* assume success */ 476cd552cb4SShannon Nelson *errno = 0; 477cd552cb4SShannon Nelson 478cd552cb4SShannon Nelson switch (hw->nvmupd_state) { 479cd552cb4SShannon Nelson case I40E_NVMUPD_STATE_INIT: 480cd552cb4SShannon Nelson status = i40e_nvmupd_state_init(hw, cmd, bytes, errno); 481cd552cb4SShannon Nelson break; 482cd552cb4SShannon Nelson 483cd552cb4SShannon Nelson case I40E_NVMUPD_STATE_READING: 484cd552cb4SShannon Nelson status = i40e_nvmupd_state_reading(hw, cmd, bytes, errno); 485cd552cb4SShannon Nelson break; 486cd552cb4SShannon Nelson 487cd552cb4SShannon Nelson case I40E_NVMUPD_STATE_WRITING: 488cd552cb4SShannon Nelson status = i40e_nvmupd_state_writing(hw, cmd, bytes, errno); 489cd552cb4SShannon Nelson break; 490cd552cb4SShannon Nelson 491cd552cb4SShannon Nelson default: 492cd552cb4SShannon Nelson /* invalid state, should never happen */ 49374d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 49474d0d0edSShannon Nelson "NVMUPD: no such state %d\n", hw->nvmupd_state); 495cd552cb4SShannon Nelson status = I40E_NOT_SUPPORTED; 496cd552cb4SShannon Nelson *errno = -ESRCH; 497cd552cb4SShannon Nelson break; 498cd552cb4SShannon Nelson } 499cd552cb4SShannon Nelson return status; 500cd552cb4SShannon Nelson } 501cd552cb4SShannon Nelson 502cd552cb4SShannon Nelson /** 503cd552cb4SShannon Nelson * i40e_nvmupd_state_init - Handle NVM update state Init 504cd552cb4SShannon Nelson * @hw: pointer to hardware structure 505cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 506cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 507cd552cb4SShannon Nelson * @errno: pointer to return error code 508cd552cb4SShannon Nelson * 509cd552cb4SShannon Nelson * Process legitimate commands of the Init state and conditionally set next 510cd552cb4SShannon Nelson * state. Reject all other commands. 511cd552cb4SShannon Nelson **/ 512cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw, 513cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 514cd552cb4SShannon Nelson u8 *bytes, int *errno) 515cd552cb4SShannon Nelson { 516cd552cb4SShannon Nelson i40e_status status = 0; 517cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 518cd552cb4SShannon Nelson 519cd552cb4SShannon Nelson upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); 520cd552cb4SShannon Nelson 521cd552cb4SShannon Nelson switch (upd_cmd) { 522cd552cb4SShannon Nelson case I40E_NVMUPD_READ_SA: 523cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 524cd552cb4SShannon Nelson if (status) { 525cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 526cd552cb4SShannon Nelson } else { 527cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); 528cd552cb4SShannon Nelson i40e_release_nvm(hw); 529cd552cb4SShannon Nelson } 530cd552cb4SShannon Nelson break; 531cd552cb4SShannon Nelson 532cd552cb4SShannon Nelson case I40E_NVMUPD_READ_SNT: 533cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 534cd552cb4SShannon Nelson if (status) { 535cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 536cd552cb4SShannon Nelson } else { 537cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); 538cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_READING; 539cd552cb4SShannon Nelson } 540cd552cb4SShannon Nelson break; 541cd552cb4SShannon Nelson 542cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_ERA: 543cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 544cd552cb4SShannon Nelson if (status) { 545cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 546cd552cb4SShannon Nelson } else { 547cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_erase(hw, cmd, errno); 548cd552cb4SShannon Nelson if (status) 549cd552cb4SShannon Nelson i40e_release_nvm(hw); 550cd552cb4SShannon Nelson else 551cd552cb4SShannon Nelson hw->aq.nvm_release_on_done = true; 552cd552cb4SShannon Nelson } 553cd552cb4SShannon Nelson break; 554cd552cb4SShannon Nelson 555cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_SA: 556cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 557cd552cb4SShannon Nelson if (status) { 558cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 559cd552cb4SShannon Nelson } else { 560cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); 561cd552cb4SShannon Nelson if (status) 562cd552cb4SShannon Nelson i40e_release_nvm(hw); 563cd552cb4SShannon Nelson else 564cd552cb4SShannon Nelson hw->aq.nvm_release_on_done = true; 565cd552cb4SShannon Nelson } 566cd552cb4SShannon Nelson break; 567cd552cb4SShannon Nelson 568cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_SNT: 569cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 570cd552cb4SShannon Nelson if (status) { 571cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 572cd552cb4SShannon Nelson } else { 573cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); 574cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING; 575cd552cb4SShannon Nelson } 576cd552cb4SShannon Nelson break; 577cd552cb4SShannon Nelson 578cd552cb4SShannon Nelson case I40E_NVMUPD_CSUM_SA: 579cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 580cd552cb4SShannon Nelson if (status) { 581cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 582cd552cb4SShannon Nelson } else { 583cd552cb4SShannon Nelson status = i40e_update_nvm_checksum(hw); 584cd552cb4SShannon Nelson if (status) { 585cd552cb4SShannon Nelson *errno = hw->aq.asq_last_status ? 586cd552cb4SShannon Nelson i40e_aq_rc_to_posix(hw->aq.asq_last_status) : 587cd552cb4SShannon Nelson -EIO; 588cd552cb4SShannon Nelson i40e_release_nvm(hw); 589cd552cb4SShannon Nelson } else { 590cd552cb4SShannon Nelson hw->aq.nvm_release_on_done = true; 591cd552cb4SShannon Nelson } 592cd552cb4SShannon Nelson } 593cd552cb4SShannon Nelson break; 594cd552cb4SShannon Nelson 595cd552cb4SShannon Nelson default: 59674d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 59774d0d0edSShannon Nelson "NVMUPD: bad cmd %s in init state\n", 59874d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 599cd552cb4SShannon Nelson status = I40E_ERR_NVM; 600cd552cb4SShannon Nelson *errno = -ESRCH; 601cd552cb4SShannon Nelson break; 602cd552cb4SShannon Nelson } 603cd552cb4SShannon Nelson return status; 604cd552cb4SShannon Nelson } 605cd552cb4SShannon Nelson 606cd552cb4SShannon Nelson /** 607cd552cb4SShannon Nelson * i40e_nvmupd_state_reading - Handle NVM update state Reading 608cd552cb4SShannon Nelson * @hw: pointer to hardware structure 609cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 610cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 611cd552cb4SShannon Nelson * @errno: pointer to return error code 612cd552cb4SShannon Nelson * 613cd552cb4SShannon Nelson * NVM ownership is already held. Process legitimate commands and set any 614cd552cb4SShannon Nelson * change in state; reject all other commands. 615cd552cb4SShannon Nelson **/ 616cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw, 617cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 618cd552cb4SShannon Nelson u8 *bytes, int *errno) 619cd552cb4SShannon Nelson { 620cd552cb4SShannon Nelson i40e_status status; 621cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 622cd552cb4SShannon Nelson 623cd552cb4SShannon Nelson upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); 624cd552cb4SShannon Nelson 625cd552cb4SShannon Nelson switch (upd_cmd) { 626cd552cb4SShannon Nelson case I40E_NVMUPD_READ_SA: 627cd552cb4SShannon Nelson case I40E_NVMUPD_READ_CON: 628cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); 629cd552cb4SShannon Nelson break; 630cd552cb4SShannon Nelson 631cd552cb4SShannon Nelson case I40E_NVMUPD_READ_LCB: 632cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); 633cd552cb4SShannon Nelson i40e_release_nvm(hw); 634cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 635cd552cb4SShannon Nelson break; 636cd552cb4SShannon Nelson 637cd552cb4SShannon Nelson default: 63874d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 63974d0d0edSShannon Nelson "NVMUPD: bad cmd %s in reading state.\n", 64074d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 641cd552cb4SShannon Nelson status = I40E_NOT_SUPPORTED; 642cd552cb4SShannon Nelson *errno = -ESRCH; 643cd552cb4SShannon Nelson break; 644cd552cb4SShannon Nelson } 645cd552cb4SShannon Nelson return status; 646cd552cb4SShannon Nelson } 647cd552cb4SShannon Nelson 648cd552cb4SShannon Nelson /** 649cd552cb4SShannon Nelson * i40e_nvmupd_state_writing - Handle NVM update state Writing 650cd552cb4SShannon Nelson * @hw: pointer to hardware structure 651cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 652cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 653cd552cb4SShannon Nelson * @errno: pointer to return error code 654cd552cb4SShannon Nelson * 655cd552cb4SShannon Nelson * NVM ownership is already held. Process legitimate commands and set any 656cd552cb4SShannon Nelson * change in state; reject all other commands 657cd552cb4SShannon Nelson **/ 658cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw, 659cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 660cd552cb4SShannon Nelson u8 *bytes, int *errno) 661cd552cb4SShannon Nelson { 662cd552cb4SShannon Nelson i40e_status status; 663cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 664cd552cb4SShannon Nelson 665cd552cb4SShannon Nelson upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); 666cd552cb4SShannon Nelson 667cd552cb4SShannon Nelson switch (upd_cmd) { 668cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_CON: 669cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); 670cd552cb4SShannon Nelson break; 671cd552cb4SShannon Nelson 672cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_LCB: 673cd552cb4SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); 674cd552cb4SShannon Nelson if (!status) { 675cd552cb4SShannon Nelson hw->aq.nvm_release_on_done = true; 676cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 677cd552cb4SShannon Nelson } 678cd552cb4SShannon Nelson break; 679cd552cb4SShannon Nelson 680cd552cb4SShannon Nelson case I40E_NVMUPD_CSUM_CON: 681cd552cb4SShannon Nelson status = i40e_update_nvm_checksum(hw); 682cd552cb4SShannon Nelson if (status) 683cd552cb4SShannon Nelson *errno = hw->aq.asq_last_status ? 684cd552cb4SShannon Nelson i40e_aq_rc_to_posix(hw->aq.asq_last_status) : 685cd552cb4SShannon Nelson -EIO; 686cd552cb4SShannon Nelson break; 687cd552cb4SShannon Nelson 688cd552cb4SShannon Nelson case I40E_NVMUPD_CSUM_LCB: 689cd552cb4SShannon Nelson status = i40e_update_nvm_checksum(hw); 690cd552cb4SShannon Nelson if (status) { 691cd552cb4SShannon Nelson *errno = hw->aq.asq_last_status ? 692cd552cb4SShannon Nelson i40e_aq_rc_to_posix(hw->aq.asq_last_status) : 693cd552cb4SShannon Nelson -EIO; 694cd552cb4SShannon Nelson } else { 695cd552cb4SShannon Nelson hw->aq.nvm_release_on_done = true; 696cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 697cd552cb4SShannon Nelson } 698cd552cb4SShannon Nelson break; 699cd552cb4SShannon Nelson 700cd552cb4SShannon Nelson default: 70174d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 70274d0d0edSShannon Nelson "NVMUPD: bad cmd %s in writing state.\n", 70374d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 704cd552cb4SShannon Nelson status = I40E_NOT_SUPPORTED; 705cd552cb4SShannon Nelson *errno = -ESRCH; 706cd552cb4SShannon Nelson break; 707cd552cb4SShannon Nelson } 708cd552cb4SShannon Nelson return status; 709cd552cb4SShannon Nelson } 710cd552cb4SShannon Nelson 711cd552cb4SShannon Nelson /** 712cd552cb4SShannon Nelson * i40e_nvmupd_validate_command - Validate given command 713cd552cb4SShannon Nelson * @hw: pointer to hardware structure 714cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 715cd552cb4SShannon Nelson * @errno: pointer to return error code 716cd552cb4SShannon Nelson * 717cd552cb4SShannon Nelson * Return one of the valid command types or I40E_NVMUPD_INVALID 718cd552cb4SShannon Nelson **/ 719cd552cb4SShannon Nelson static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, 720cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 721cd552cb4SShannon Nelson int *errno) 722cd552cb4SShannon Nelson { 723cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 724cd552cb4SShannon Nelson u8 transaction, module; 725cd552cb4SShannon Nelson 726cd552cb4SShannon Nelson /* anything that doesn't match a recognized case is an error */ 727cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_INVALID; 728cd552cb4SShannon Nelson 729cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 730cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 731cd552cb4SShannon Nelson 732cd552cb4SShannon Nelson /* limits on data size */ 733cd552cb4SShannon Nelson if ((cmd->data_size < 1) || 734cd552cb4SShannon Nelson (cmd->data_size > I40E_NVMUPD_MAX_DATA)) { 73574d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 73674d0d0edSShannon Nelson "i40e_nvmupd_validate_command data_size %d\n", 737cd552cb4SShannon Nelson cmd->data_size); 738cd552cb4SShannon Nelson *errno = -EFAULT; 739cd552cb4SShannon Nelson return I40E_NVMUPD_INVALID; 740cd552cb4SShannon Nelson } 741cd552cb4SShannon Nelson 742cd552cb4SShannon Nelson switch (cmd->command) { 743cd552cb4SShannon Nelson case I40E_NVM_READ: 744cd552cb4SShannon Nelson switch (transaction) { 745cd552cb4SShannon Nelson case I40E_NVM_CON: 746cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_CON; 747cd552cb4SShannon Nelson break; 748cd552cb4SShannon Nelson case I40E_NVM_SNT: 749cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_SNT; 750cd552cb4SShannon Nelson break; 751cd552cb4SShannon Nelson case I40E_NVM_LCB: 752cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_LCB; 753cd552cb4SShannon Nelson break; 754cd552cb4SShannon Nelson case I40E_NVM_SA: 755cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_SA; 756cd552cb4SShannon Nelson break; 757cd552cb4SShannon Nelson } 758cd552cb4SShannon Nelson break; 759cd552cb4SShannon Nelson 760cd552cb4SShannon Nelson case I40E_NVM_WRITE: 761cd552cb4SShannon Nelson switch (transaction) { 762cd552cb4SShannon Nelson case I40E_NVM_CON: 763cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_CON; 764cd552cb4SShannon Nelson break; 765cd552cb4SShannon Nelson case I40E_NVM_SNT: 766cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_SNT; 767cd552cb4SShannon Nelson break; 768cd552cb4SShannon Nelson case I40E_NVM_LCB: 769cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_LCB; 770cd552cb4SShannon Nelson break; 771cd552cb4SShannon Nelson case I40E_NVM_SA: 772cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_SA; 773cd552cb4SShannon Nelson break; 774cd552cb4SShannon Nelson case I40E_NVM_ERA: 775cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_ERA; 776cd552cb4SShannon Nelson break; 777cd552cb4SShannon Nelson case I40E_NVM_CSUM: 778cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_CSUM_CON; 779cd552cb4SShannon Nelson break; 780cd552cb4SShannon Nelson case (I40E_NVM_CSUM|I40E_NVM_SA): 781cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_CSUM_SA; 782cd552cb4SShannon Nelson break; 783cd552cb4SShannon Nelson case (I40E_NVM_CSUM|I40E_NVM_LCB): 784cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_CSUM_LCB; 785cd552cb4SShannon Nelson break; 786cd552cb4SShannon Nelson } 787cd552cb4SShannon Nelson break; 788cd552cb4SShannon Nelson } 78974d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "%s\n", 79074d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 791cd552cb4SShannon Nelson 792cd552cb4SShannon Nelson if (upd_cmd == I40E_NVMUPD_INVALID) { 793cd552cb4SShannon Nelson *errno = -EFAULT; 79474d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 79574d0d0edSShannon Nelson "i40e_nvmupd_validate_command returns %d errno %d\n", 796cd552cb4SShannon Nelson upd_cmd, *errno); 797cd552cb4SShannon Nelson } 798cd552cb4SShannon Nelson return upd_cmd; 799cd552cb4SShannon Nelson } 800cd552cb4SShannon Nelson 801cd552cb4SShannon Nelson /** 802cd552cb4SShannon Nelson * i40e_nvmupd_nvm_read - Read NVM 803cd552cb4SShannon Nelson * @hw: pointer to hardware structure 804cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 805cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 806cd552cb4SShannon Nelson * @errno: pointer to return error code 807cd552cb4SShannon Nelson * 808cd552cb4SShannon Nelson * cmd structure contains identifiers and data buffer 809cd552cb4SShannon Nelson **/ 810cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw, 811cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 812cd552cb4SShannon Nelson u8 *bytes, int *errno) 813cd552cb4SShannon Nelson { 814cd552cb4SShannon Nelson i40e_status status; 815cd552cb4SShannon Nelson u8 module, transaction; 816cd552cb4SShannon Nelson bool last; 817cd552cb4SShannon Nelson 818cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 819cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 820cd552cb4SShannon Nelson last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA); 821cd552cb4SShannon Nelson 822cd552cb4SShannon Nelson status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size, 823cd552cb4SShannon Nelson bytes, last, NULL); 82474d0d0edSShannon Nelson if (status) { 82574d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 82674d0d0edSShannon Nelson "i40e_nvmupd_nvm_read mod 0x%x off 0x%x len 0x%x\n", 82774d0d0edSShannon Nelson module, cmd->offset, cmd->data_size); 82874d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 82974d0d0edSShannon Nelson "i40e_nvmupd_nvm_read status %d aq %d\n", 83074d0d0edSShannon Nelson status, hw->aq.asq_last_status); 831cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 83274d0d0edSShannon Nelson } 833cd552cb4SShannon Nelson 834cd552cb4SShannon Nelson return status; 835cd552cb4SShannon Nelson } 836cd552cb4SShannon Nelson 837cd552cb4SShannon Nelson /** 838cd552cb4SShannon Nelson * i40e_nvmupd_nvm_erase - Erase an NVM module 839cd552cb4SShannon Nelson * @hw: pointer to hardware structure 840cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 841cd552cb4SShannon Nelson * @errno: pointer to return error code 842cd552cb4SShannon Nelson * 843cd552cb4SShannon Nelson * module, offset, data_size and data are in cmd structure 844cd552cb4SShannon Nelson **/ 845cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw, 846cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 847cd552cb4SShannon Nelson int *errno) 848cd552cb4SShannon Nelson { 849cd552cb4SShannon Nelson i40e_status status = 0; 850cd552cb4SShannon Nelson u8 module, transaction; 851cd552cb4SShannon Nelson bool last; 852cd552cb4SShannon Nelson 853cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 854cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 855cd552cb4SShannon Nelson last = (transaction & I40E_NVM_LCB); 856cd552cb4SShannon Nelson status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size, 857cd552cb4SShannon Nelson last, NULL); 85874d0d0edSShannon Nelson if (status) { 85974d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 86074d0d0edSShannon Nelson "i40e_nvmupd_nvm_erase mod 0x%x off 0x%x len 0x%x\n", 86174d0d0edSShannon Nelson module, cmd->offset, cmd->data_size); 86274d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 86374d0d0edSShannon Nelson "i40e_nvmupd_nvm_erase status %d aq %d\n", 86474d0d0edSShannon Nelson status, hw->aq.asq_last_status); 865cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 86674d0d0edSShannon Nelson } 867cd552cb4SShannon Nelson 868cd552cb4SShannon Nelson return status; 869cd552cb4SShannon Nelson } 870cd552cb4SShannon Nelson 871cd552cb4SShannon Nelson /** 872cd552cb4SShannon Nelson * i40e_nvmupd_nvm_write - Write NVM 873cd552cb4SShannon Nelson * @hw: pointer to hardware structure 874cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 875cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 876cd552cb4SShannon Nelson * @errno: pointer to return error code 877cd552cb4SShannon Nelson * 878cd552cb4SShannon Nelson * module, offset, data_size and data are in cmd structure 879cd552cb4SShannon Nelson **/ 880cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw, 881cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 882cd552cb4SShannon Nelson u8 *bytes, int *errno) 883cd552cb4SShannon Nelson { 884cd552cb4SShannon Nelson i40e_status status = 0; 885cd552cb4SShannon Nelson u8 module, transaction; 886cd552cb4SShannon Nelson bool last; 887cd552cb4SShannon Nelson 888cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 889cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 890cd552cb4SShannon Nelson last = (transaction & I40E_NVM_LCB); 89174d0d0edSShannon Nelson 892cd552cb4SShannon Nelson status = i40e_aq_update_nvm(hw, module, cmd->offset, 893cd552cb4SShannon Nelson (u16)cmd->data_size, bytes, last, NULL); 89474d0d0edSShannon Nelson if (status) { 89574d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 89674d0d0edSShannon Nelson "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n", 89774d0d0edSShannon Nelson module, cmd->offset, cmd->data_size); 89874d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 89974d0d0edSShannon Nelson "i40e_nvmupd_nvm_write status %d aq %d\n", 90074d0d0edSShannon Nelson status, hw->aq.asq_last_status); 901cd552cb4SShannon Nelson *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); 90274d0d0edSShannon Nelson } 903cd552cb4SShannon Nelson 904cd552cb4SShannon Nelson return status; 905cd552cb4SShannon Nelson } 906