1ae06c70bSJeff Kirsher // SPDX-License-Identifier: GPL-2.0 251dce24bSJeff Kirsher /* Copyright(c) 2013 - 2018 Intel Corporation. */ 356a62fc8SJesse Brandeburg 456a62fc8SJesse Brandeburg #include "i40e_prototype.h" 556a62fc8SJesse Brandeburg 656a62fc8SJesse Brandeburg /** 73e26186dSShannon Nelson * i40e_init_nvm_ops - Initialize NVM function pointers 83e26186dSShannon Nelson * @hw: pointer to the HW structure 956a62fc8SJesse Brandeburg * 103e26186dSShannon Nelson * Setup the function pointers and the NVM info structure. Should be called 1156a62fc8SJesse Brandeburg * once per NVM initialization, e.g. inside the i40e_init_shared_code(). 1256a62fc8SJesse Brandeburg * Please notice that the NVM term is used here (& in all methods covered 1356a62fc8SJesse Brandeburg * in this file) as an equivalent of the FLASH part mapped into the SR. 1456a62fc8SJesse Brandeburg * We are accessing FLASH always thru the Shadow RAM. 1556a62fc8SJesse Brandeburg **/ 1656a62fc8SJesse Brandeburg i40e_status i40e_init_nvm(struct i40e_hw *hw) 1756a62fc8SJesse Brandeburg { 1856a62fc8SJesse Brandeburg struct i40e_nvm_info *nvm = &hw->nvm; 1956a62fc8SJesse Brandeburg i40e_status ret_code = 0; 2056a62fc8SJesse Brandeburg u32 fla, gens; 2156a62fc8SJesse Brandeburg u8 sr_size; 2256a62fc8SJesse Brandeburg 2356a62fc8SJesse Brandeburg /* The SR size is stored regardless of the nvm programming mode 2456a62fc8SJesse Brandeburg * as the blank mode may be used in the factory line. 2556a62fc8SJesse Brandeburg */ 2656a62fc8SJesse Brandeburg gens = rd32(hw, I40E_GLNVM_GENS); 2756a62fc8SJesse Brandeburg sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >> 2856a62fc8SJesse Brandeburg I40E_GLNVM_GENS_SR_SIZE_SHIFT); 293e26186dSShannon Nelson /* Switching to words (sr_size contains power of 2KB) */ 3041a1d04bSJesse Brandeburg nvm->sr_size = BIT(sr_size) * I40E_SR_WORDS_IN_1KB; 3156a62fc8SJesse Brandeburg 323e26186dSShannon Nelson /* Check if we are in the normal or blank NVM programming mode */ 3356a62fc8SJesse Brandeburg fla = rd32(hw, I40E_GLNVM_FLA); 343e26186dSShannon Nelson if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */ 353e26186dSShannon Nelson /* Max NVM timeout */ 3656a62fc8SJesse Brandeburg nvm->timeout = I40E_MAX_NVM_TIMEOUT; 3756a62fc8SJesse Brandeburg nvm->blank_nvm_mode = false; 383e26186dSShannon Nelson } else { /* Blank programming mode */ 3956a62fc8SJesse Brandeburg nvm->blank_nvm_mode = true; 4056a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_BLANK_MODE; 4174d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "NVM init error: unsupported blank mode.\n"); 4256a62fc8SJesse Brandeburg } 4356a62fc8SJesse Brandeburg 4456a62fc8SJesse Brandeburg return ret_code; 4556a62fc8SJesse Brandeburg } 4656a62fc8SJesse Brandeburg 4756a62fc8SJesse Brandeburg /** 483e26186dSShannon Nelson * i40e_acquire_nvm - Generic request for acquiring the NVM ownership 493e26186dSShannon Nelson * @hw: pointer to the HW structure 503e26186dSShannon Nelson * @access: NVM access type (read or write) 5156a62fc8SJesse Brandeburg * 5256a62fc8SJesse Brandeburg * This function will request NVM ownership for reading 5356a62fc8SJesse Brandeburg * via the proper Admin Command. 5456a62fc8SJesse Brandeburg **/ 5556a62fc8SJesse Brandeburg i40e_status i40e_acquire_nvm(struct i40e_hw *hw, 5656a62fc8SJesse Brandeburg enum i40e_aq_resource_access_type access) 5756a62fc8SJesse Brandeburg { 5856a62fc8SJesse Brandeburg i40e_status ret_code = 0; 5956a62fc8SJesse Brandeburg u64 gtime, timeout; 60c509c1deSShannon Nelson u64 time_left = 0; 6156a62fc8SJesse Brandeburg 6256a62fc8SJesse Brandeburg if (hw->nvm.blank_nvm_mode) 6356a62fc8SJesse Brandeburg goto i40e_i40e_acquire_nvm_exit; 6456a62fc8SJesse Brandeburg 6556a62fc8SJesse Brandeburg ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access, 66c509c1deSShannon Nelson 0, &time_left, NULL); 673e26186dSShannon Nelson /* Reading the Global Device Timer */ 6856a62fc8SJesse Brandeburg gtime = rd32(hw, I40E_GLVFGEN_TIMER); 6956a62fc8SJesse Brandeburg 703e26186dSShannon Nelson /* Store the timeout */ 71c509c1deSShannon Nelson hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime; 7256a62fc8SJesse Brandeburg 73a3f0b381SShannon Nelson if (ret_code) 74a3f0b381SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 75a3f0b381SShannon Nelson "NVM acquire type %d failed time_left=%llu ret=%d aq_err=%d\n", 76a3f0b381SShannon Nelson access, time_left, ret_code, hw->aq.asq_last_status); 77a3f0b381SShannon Nelson 78a3f0b381SShannon Nelson if (ret_code && time_left) { 793e26186dSShannon Nelson /* Poll until the current NVM owner timeouts */ 80c509c1deSShannon Nelson timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime; 81a3f0b381SShannon Nelson while ((gtime < timeout) && time_left) { 8256a62fc8SJesse Brandeburg usleep_range(10000, 20000); 83c509c1deSShannon Nelson gtime = rd32(hw, I40E_GLVFGEN_TIMER); 8456a62fc8SJesse Brandeburg ret_code = i40e_aq_request_resource(hw, 8556a62fc8SJesse Brandeburg I40E_NVM_RESOURCE_ID, 86c509c1deSShannon Nelson access, 0, &time_left, 8756a62fc8SJesse Brandeburg NULL); 8856a62fc8SJesse Brandeburg if (!ret_code) { 8956a62fc8SJesse Brandeburg hw->nvm.hw_semaphore_timeout = 90c509c1deSShannon Nelson I40E_MS_TO_GTIME(time_left) + gtime; 9156a62fc8SJesse Brandeburg break; 9256a62fc8SJesse Brandeburg } 9356a62fc8SJesse Brandeburg } 9456a62fc8SJesse Brandeburg if (ret_code) { 9556a62fc8SJesse Brandeburg hw->nvm.hw_semaphore_timeout = 0; 9674d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 97a3f0b381SShannon Nelson "NVM acquire timed out, wait %llu ms before trying again. status=%d aq_err=%d\n", 98a3f0b381SShannon Nelson time_left, ret_code, hw->aq.asq_last_status); 9956a62fc8SJesse Brandeburg } 10056a62fc8SJesse Brandeburg } 10156a62fc8SJesse Brandeburg 10256a62fc8SJesse Brandeburg i40e_i40e_acquire_nvm_exit: 10356a62fc8SJesse Brandeburg return ret_code; 10456a62fc8SJesse Brandeburg } 10556a62fc8SJesse Brandeburg 10656a62fc8SJesse Brandeburg /** 1073e26186dSShannon Nelson * i40e_release_nvm - Generic request for releasing the NVM ownership 1083e26186dSShannon Nelson * @hw: pointer to the HW structure 10956a62fc8SJesse Brandeburg * 11056a62fc8SJesse Brandeburg * This function will release NVM resource via the proper Admin Command. 11156a62fc8SJesse Brandeburg **/ 11256a62fc8SJesse Brandeburg void i40e_release_nvm(struct i40e_hw *hw) 11356a62fc8SJesse Brandeburg { 114981e25c3SPaul M Stillwell Jr i40e_status ret_code = I40E_SUCCESS; 115981e25c3SPaul M Stillwell Jr u32 total_delay = 0; 116981e25c3SPaul M Stillwell Jr 117981e25c3SPaul M Stillwell Jr if (hw->nvm.blank_nvm_mode) 118981e25c3SPaul M Stillwell Jr return; 119981e25c3SPaul M Stillwell Jr 120981e25c3SPaul M Stillwell Jr ret_code = i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL); 121981e25c3SPaul M Stillwell Jr 122981e25c3SPaul M Stillwell Jr /* there are some rare cases when trying to release the resource 123981e25c3SPaul M Stillwell Jr * results in an admin Q timeout, so handle them correctly 124981e25c3SPaul M Stillwell Jr */ 125981e25c3SPaul M Stillwell Jr while ((ret_code == I40E_ERR_ADMIN_QUEUE_TIMEOUT) && 126981e25c3SPaul M Stillwell Jr (total_delay < hw->aq.asq_cmd_timeout)) { 127981e25c3SPaul M Stillwell Jr usleep_range(1000, 2000); 128981e25c3SPaul M Stillwell Jr ret_code = i40e_aq_release_resource(hw, 129981e25c3SPaul M Stillwell Jr I40E_NVM_RESOURCE_ID, 130981e25c3SPaul M Stillwell Jr 0, NULL); 131981e25c3SPaul M Stillwell Jr total_delay++; 132981e25c3SPaul M Stillwell Jr } 13356a62fc8SJesse Brandeburg } 13456a62fc8SJesse Brandeburg 13556a62fc8SJesse Brandeburg /** 1363e26186dSShannon Nelson * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit 1373e26186dSShannon Nelson * @hw: pointer to the HW structure 13856a62fc8SJesse Brandeburg * 13956a62fc8SJesse Brandeburg * Polls the SRCTL Shadow RAM register done bit. 14056a62fc8SJesse Brandeburg **/ 14156a62fc8SJesse Brandeburg static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) 14256a62fc8SJesse Brandeburg { 14356a62fc8SJesse Brandeburg i40e_status ret_code = I40E_ERR_TIMEOUT; 14456a62fc8SJesse Brandeburg u32 srctl, wait_cnt; 14556a62fc8SJesse Brandeburg 1463e26186dSShannon Nelson /* Poll the I40E_GLNVM_SRCTL until the done bit is set */ 14756a62fc8SJesse Brandeburg for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) { 14856a62fc8SJesse Brandeburg srctl = rd32(hw, I40E_GLNVM_SRCTL); 14956a62fc8SJesse Brandeburg if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) { 15056a62fc8SJesse Brandeburg ret_code = 0; 15156a62fc8SJesse Brandeburg break; 15256a62fc8SJesse Brandeburg } 15356a62fc8SJesse Brandeburg udelay(5); 15456a62fc8SJesse Brandeburg } 15556a62fc8SJesse Brandeburg if (ret_code == I40E_ERR_TIMEOUT) 15674d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set"); 15756a62fc8SJesse Brandeburg return ret_code; 15856a62fc8SJesse Brandeburg } 15956a62fc8SJesse Brandeburg 16056a62fc8SJesse Brandeburg /** 161d1bbe0eaSKamil Krawczyk * i40e_read_nvm_word_srctl - Reads Shadow RAM via SRCTL register 1623e26186dSShannon Nelson * @hw: pointer to the HW structure 1633e26186dSShannon Nelson * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 1643e26186dSShannon Nelson * @data: word read from the Shadow RAM 16556a62fc8SJesse Brandeburg * 1663e26186dSShannon Nelson * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. 16756a62fc8SJesse Brandeburg **/ 16837a2973aSShannon Nelson static i40e_status i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset, 16956a62fc8SJesse Brandeburg u16 *data) 17056a62fc8SJesse Brandeburg { 17156a62fc8SJesse Brandeburg i40e_status ret_code = I40E_ERR_TIMEOUT; 17256a62fc8SJesse Brandeburg u32 sr_reg; 17356a62fc8SJesse Brandeburg 17456a62fc8SJesse Brandeburg if (offset >= hw->nvm.sr_size) { 17574d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 17674d0d0edSShannon Nelson "NVM read error: offset %d beyond Shadow RAM limit %d\n", 17774d0d0edSShannon Nelson offset, hw->nvm.sr_size); 17856a62fc8SJesse Brandeburg ret_code = I40E_ERR_PARAM; 17956a62fc8SJesse Brandeburg goto read_nvm_exit; 18056a62fc8SJesse Brandeburg } 18156a62fc8SJesse Brandeburg 1823e26186dSShannon Nelson /* Poll the done bit first */ 18356a62fc8SJesse Brandeburg ret_code = i40e_poll_sr_srctl_done_bit(hw); 18456a62fc8SJesse Brandeburg if (!ret_code) { 1853e26186dSShannon Nelson /* Write the address and start reading */ 18641a1d04bSJesse Brandeburg sr_reg = ((u32)offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | 18741a1d04bSJesse Brandeburg BIT(I40E_GLNVM_SRCTL_START_SHIFT); 18856a62fc8SJesse Brandeburg wr32(hw, I40E_GLNVM_SRCTL, sr_reg); 18956a62fc8SJesse Brandeburg 1903e26186dSShannon Nelson /* Poll I40E_GLNVM_SRCTL until the done bit is set */ 19156a62fc8SJesse Brandeburg ret_code = i40e_poll_sr_srctl_done_bit(hw); 19256a62fc8SJesse Brandeburg if (!ret_code) { 19356a62fc8SJesse Brandeburg sr_reg = rd32(hw, I40E_GLNVM_SRDATA); 19456a62fc8SJesse Brandeburg *data = (u16)((sr_reg & 19556a62fc8SJesse Brandeburg I40E_GLNVM_SRDATA_RDDATA_MASK) 19656a62fc8SJesse Brandeburg >> I40E_GLNVM_SRDATA_RDDATA_SHIFT); 19756a62fc8SJesse Brandeburg } 19856a62fc8SJesse Brandeburg } 19956a62fc8SJesse Brandeburg if (ret_code) 20074d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 20174d0d0edSShannon Nelson "NVM read error: Couldn't access Shadow RAM address: 0x%x\n", 20256a62fc8SJesse Brandeburg offset); 20356a62fc8SJesse Brandeburg 20456a62fc8SJesse Brandeburg read_nvm_exit: 20556a62fc8SJesse Brandeburg return ret_code; 20656a62fc8SJesse Brandeburg } 20756a62fc8SJesse Brandeburg 20856a62fc8SJesse Brandeburg /** 2097073f46eSShannon Nelson * i40e_read_nvm_aq - Read Shadow RAM. 2107073f46eSShannon Nelson * @hw: pointer to the HW structure. 2117073f46eSShannon Nelson * @module_pointer: module pointer location in words from the NVM beginning 2127073f46eSShannon Nelson * @offset: offset in words from module start 2137073f46eSShannon Nelson * @words: number of words to write 2147073f46eSShannon Nelson * @data: buffer with words to write to the Shadow RAM 2157073f46eSShannon Nelson * @last_command: tells the AdminQ that this is the last command 2167073f46eSShannon Nelson * 2177073f46eSShannon Nelson * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 2187073f46eSShannon Nelson **/ 219e3a5d6e6SPawel Jablonski static i40e_status i40e_read_nvm_aq(struct i40e_hw *hw, 220e3a5d6e6SPawel Jablonski u8 module_pointer, u32 offset, 221e3a5d6e6SPawel Jablonski u16 words, void *data, 2227073f46eSShannon Nelson bool last_command) 2237073f46eSShannon Nelson { 2247073f46eSShannon Nelson i40e_status ret_code = I40E_ERR_NVM; 2257073f46eSShannon Nelson struct i40e_asq_cmd_details cmd_details; 2267073f46eSShannon Nelson 2277073f46eSShannon Nelson memset(&cmd_details, 0, sizeof(cmd_details)); 2283c8f3e96SJacob Keller cmd_details.wb_desc = &hw->nvm_wb_desc; 2297073f46eSShannon Nelson 2307073f46eSShannon Nelson /* Here we are checking the SR limit only for the flat memory model. 2317073f46eSShannon Nelson * We cannot do it for the module-based model, as we did not acquire 2327073f46eSShannon Nelson * the NVM resource yet (we cannot get the module pointer value). 2337073f46eSShannon Nelson * Firmware will check the module-based model. 2347073f46eSShannon Nelson */ 2357073f46eSShannon Nelson if ((offset + words) > hw->nvm.sr_size) 2367073f46eSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 2377073f46eSShannon Nelson "NVM write error: offset %d beyond Shadow RAM limit %d\n", 2387073f46eSShannon Nelson (offset + words), hw->nvm.sr_size); 2397073f46eSShannon Nelson else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) 2407073f46eSShannon Nelson /* We can write only up to 4KB (one sector), in one AQ write */ 2417073f46eSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 2427073f46eSShannon Nelson "NVM write fail error: tried to write %d words, limit is %d.\n", 2437073f46eSShannon Nelson words, I40E_SR_SECTOR_SIZE_IN_WORDS); 2447073f46eSShannon Nelson else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) 2457073f46eSShannon Nelson != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) 2467073f46eSShannon Nelson /* A single write cannot spread over two sectors */ 2477073f46eSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 2487073f46eSShannon Nelson "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n", 2497073f46eSShannon Nelson offset, words); 2507073f46eSShannon Nelson else 2517073f46eSShannon Nelson ret_code = i40e_aq_read_nvm(hw, module_pointer, 2527073f46eSShannon Nelson 2 * offset, /*bytes*/ 2537073f46eSShannon Nelson 2 * words, /*bytes*/ 2547073f46eSShannon Nelson data, last_command, &cmd_details); 2557073f46eSShannon Nelson 2567073f46eSShannon Nelson return ret_code; 2577073f46eSShannon Nelson } 2587073f46eSShannon Nelson 2597073f46eSShannon Nelson /** 2607073f46eSShannon Nelson * i40e_read_nvm_word_aq - Reads Shadow RAM via AQ 2617073f46eSShannon Nelson * @hw: pointer to the HW structure 2627073f46eSShannon Nelson * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 2637073f46eSShannon Nelson * @data: word read from the Shadow RAM 2647073f46eSShannon Nelson * 26509f79fd4SAnjali Singhai Jain * Reads one 16 bit word from the Shadow RAM using the AdminQ 2667073f46eSShannon Nelson **/ 2677073f46eSShannon Nelson static i40e_status i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset, 2687073f46eSShannon Nelson u16 *data) 2697073f46eSShannon Nelson { 2707073f46eSShannon Nelson i40e_status ret_code = I40E_ERR_TIMEOUT; 2717073f46eSShannon Nelson 2727073f46eSShannon Nelson ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, true); 2737073f46eSShannon Nelson *data = le16_to_cpu(*(__le16 *)data); 2747073f46eSShannon Nelson 2757073f46eSShannon Nelson return ret_code; 2767073f46eSShannon Nelson } 2777073f46eSShannon Nelson 2787073f46eSShannon Nelson /** 279e836e321SStefano Brivio * __i40e_read_nvm_word - Reads nvm word, assumes caller does the locking 280d1bbe0eaSKamil Krawczyk * @hw: pointer to the HW structure 281d1bbe0eaSKamil Krawczyk * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 282d1bbe0eaSKamil Krawczyk * @data: word read from the Shadow RAM 283d1bbe0eaSKamil Krawczyk * 28409f79fd4SAnjali Singhai Jain * Reads one 16 bit word from the Shadow RAM. 28509f79fd4SAnjali Singhai Jain * 28609f79fd4SAnjali Singhai Jain * Do not use this function except in cases where the nvm lock is already 28709f79fd4SAnjali Singhai Jain * taken via i40e_acquire_nvm(). 28809f79fd4SAnjali Singhai Jain **/ 28909f79fd4SAnjali Singhai Jain static i40e_status __i40e_read_nvm_word(struct i40e_hw *hw, 29009f79fd4SAnjali Singhai Jain u16 offset, u16 *data) 29109f79fd4SAnjali Singhai Jain { 29209f79fd4SAnjali Singhai Jain if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) 2932c4d36b7SStefano Brivio return i40e_read_nvm_word_aq(hw, offset, data); 2942c4d36b7SStefano Brivio 2952c4d36b7SStefano Brivio return i40e_read_nvm_word_srctl(hw, offset, data); 29609f79fd4SAnjali Singhai Jain } 29709f79fd4SAnjali Singhai Jain 29809f79fd4SAnjali Singhai Jain /** 29909f79fd4SAnjali Singhai Jain * i40e_read_nvm_word - Reads nvm word and acquire lock if necessary 30009f79fd4SAnjali Singhai Jain * @hw: pointer to the HW structure 30109f79fd4SAnjali Singhai Jain * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 30209f79fd4SAnjali Singhai Jain * @data: word read from the Shadow RAM 30309f79fd4SAnjali Singhai Jain * 30409f79fd4SAnjali Singhai Jain * Reads one 16 bit word from the Shadow RAM. 305d1bbe0eaSKamil Krawczyk **/ 306d1bbe0eaSKamil Krawczyk i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, 307d1bbe0eaSKamil Krawczyk u16 *data) 308d1bbe0eaSKamil Krawczyk { 3093d72aebfSJacob Keller i40e_status ret_code = 0; 31007f89be8SAnjali Singhai 3113d72aebfSJacob Keller if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK) 31207f89be8SAnjali Singhai ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 31309f79fd4SAnjali Singhai Jain if (ret_code) 31409f79fd4SAnjali Singhai Jain return ret_code; 31509f79fd4SAnjali Singhai Jain 31609f79fd4SAnjali Singhai Jain ret_code = __i40e_read_nvm_word(hw, offset, data); 31709f79fd4SAnjali Singhai Jain 3183d72aebfSJacob Keller if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK) 31996a39aedSAaron Salter i40e_release_nvm(hw); 32009f79fd4SAnjali Singhai Jain 32107f89be8SAnjali Singhai return ret_code; 322d1bbe0eaSKamil Krawczyk } 323d1bbe0eaSKamil Krawczyk 324d1bbe0eaSKamil Krawczyk /** 325d1bbe0eaSKamil Krawczyk * i40e_read_nvm_buffer_srctl - Reads Shadow RAM buffer via SRCTL register 326d1bbe0eaSKamil Krawczyk * @hw: pointer to the HW structure 327d1bbe0eaSKamil Krawczyk * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 328d1bbe0eaSKamil Krawczyk * @words: (in) number of words to read; (out) number of words actually read 329d1bbe0eaSKamil Krawczyk * @data: words read from the Shadow RAM 330d1bbe0eaSKamil Krawczyk * 331d1bbe0eaSKamil Krawczyk * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() 332d1bbe0eaSKamil Krawczyk * method. The buffer read is preceded by the NVM ownership take 333d1bbe0eaSKamil Krawczyk * and followed by the release. 334d1bbe0eaSKamil Krawczyk **/ 33537a2973aSShannon Nelson static i40e_status i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset, 336d1bbe0eaSKamil Krawczyk u16 *words, u16 *data) 337d1bbe0eaSKamil Krawczyk { 338d1bbe0eaSKamil Krawczyk i40e_status ret_code = 0; 339d1bbe0eaSKamil Krawczyk u16 index, word; 340d1bbe0eaSKamil Krawczyk 341d1bbe0eaSKamil Krawczyk /* Loop thru the selected region */ 342d1bbe0eaSKamil Krawczyk for (word = 0; word < *words; word++) { 343d1bbe0eaSKamil Krawczyk index = offset + word; 344d1bbe0eaSKamil Krawczyk ret_code = i40e_read_nvm_word_srctl(hw, index, &data[word]); 345d1bbe0eaSKamil Krawczyk if (ret_code) 346d1bbe0eaSKamil Krawczyk break; 347d1bbe0eaSKamil Krawczyk } 348d1bbe0eaSKamil Krawczyk 349d1bbe0eaSKamil Krawczyk /* Update the number of words read from the Shadow RAM */ 350d1bbe0eaSKamil Krawczyk *words = word; 351d1bbe0eaSKamil Krawczyk 352d1bbe0eaSKamil Krawczyk return ret_code; 353d1bbe0eaSKamil Krawczyk } 354d1bbe0eaSKamil Krawczyk 355d1bbe0eaSKamil Krawczyk /** 3567073f46eSShannon Nelson * i40e_read_nvm_buffer_aq - Reads Shadow RAM buffer via AQ 3577073f46eSShannon Nelson * @hw: pointer to the HW structure 3587073f46eSShannon Nelson * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 3597073f46eSShannon Nelson * @words: (in) number of words to read; (out) number of words actually read 3607073f46eSShannon Nelson * @data: words read from the Shadow RAM 3617073f46eSShannon Nelson * 3627073f46eSShannon Nelson * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_aq() 3637073f46eSShannon Nelson * method. The buffer read is preceded by the NVM ownership take 3647073f46eSShannon Nelson * and followed by the release. 3657073f46eSShannon Nelson **/ 3667073f46eSShannon Nelson static i40e_status i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset, 3677073f46eSShannon Nelson u16 *words, u16 *data) 3687073f46eSShannon Nelson { 3697073f46eSShannon Nelson i40e_status ret_code; 370793c6f8cSColin Ian King u16 read_size; 3717073f46eSShannon Nelson bool last_cmd = false; 3727073f46eSShannon Nelson u16 words_read = 0; 3737073f46eSShannon Nelson u16 i = 0; 3747073f46eSShannon Nelson 3757073f46eSShannon Nelson do { 3767073f46eSShannon Nelson /* Calculate number of bytes we should read in this step. 3777073f46eSShannon Nelson * FVL AQ do not allow to read more than one page at a time or 3787073f46eSShannon Nelson * to cross page boundaries. 3797073f46eSShannon Nelson */ 3807073f46eSShannon Nelson if (offset % I40E_SR_SECTOR_SIZE_IN_WORDS) 3817073f46eSShannon Nelson read_size = min(*words, 3827073f46eSShannon Nelson (u16)(I40E_SR_SECTOR_SIZE_IN_WORDS - 3837073f46eSShannon Nelson (offset % I40E_SR_SECTOR_SIZE_IN_WORDS))); 3847073f46eSShannon Nelson else 3857073f46eSShannon Nelson read_size = min((*words - words_read), 3867073f46eSShannon Nelson I40E_SR_SECTOR_SIZE_IN_WORDS); 3877073f46eSShannon Nelson 3887073f46eSShannon Nelson /* Check if this is last command, if so set proper flag */ 3897073f46eSShannon Nelson if ((words_read + read_size) >= *words) 3907073f46eSShannon Nelson last_cmd = true; 3917073f46eSShannon Nelson 3927073f46eSShannon Nelson ret_code = i40e_read_nvm_aq(hw, 0x0, offset, read_size, 3937073f46eSShannon Nelson data + words_read, last_cmd); 3947073f46eSShannon Nelson if (ret_code) 3957073f46eSShannon Nelson goto read_nvm_buffer_aq_exit; 3967073f46eSShannon Nelson 3977073f46eSShannon Nelson /* Increment counter for words already read and move offset to 3987073f46eSShannon Nelson * new read location 3997073f46eSShannon Nelson */ 4007073f46eSShannon Nelson words_read += read_size; 4017073f46eSShannon Nelson offset += read_size; 4027073f46eSShannon Nelson } while (words_read < *words); 4037073f46eSShannon Nelson 4047073f46eSShannon Nelson for (i = 0; i < *words; i++) 4057073f46eSShannon Nelson data[i] = le16_to_cpu(((__le16 *)data)[i]); 4067073f46eSShannon Nelson 4077073f46eSShannon Nelson read_nvm_buffer_aq_exit: 4087073f46eSShannon Nelson *words = words_read; 4097073f46eSShannon Nelson return ret_code; 4107073f46eSShannon Nelson } 4117073f46eSShannon Nelson 4127073f46eSShannon Nelson /** 41309f79fd4SAnjali Singhai Jain * __i40e_read_nvm_buffer - Reads nvm buffer, caller must acquire lock 4143e26186dSShannon Nelson * @hw: pointer to the HW structure 41556a62fc8SJesse Brandeburg * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 4163e26186dSShannon Nelson * @words: (in) number of words to read; (out) number of words actually read 4173e26186dSShannon Nelson * @data: words read from the Shadow RAM 41856a62fc8SJesse Brandeburg * 41956a62fc8SJesse Brandeburg * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() 42009f79fd4SAnjali Singhai Jain * method. 42156a62fc8SJesse Brandeburg **/ 42209f79fd4SAnjali Singhai Jain static i40e_status __i40e_read_nvm_buffer(struct i40e_hw *hw, 42309f79fd4SAnjali Singhai Jain u16 offset, u16 *words, 42409f79fd4SAnjali Singhai Jain u16 *data) 42556a62fc8SJesse Brandeburg { 42609f79fd4SAnjali Singhai Jain if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) 4272c4d36b7SStefano Brivio return i40e_read_nvm_buffer_aq(hw, offset, words, data); 4282c4d36b7SStefano Brivio 4292c4d36b7SStefano Brivio return i40e_read_nvm_buffer_srctl(hw, offset, words, data); 43056a62fc8SJesse Brandeburg } 43156a62fc8SJesse Brandeburg 43256a62fc8SJesse Brandeburg /** 433cd552cb4SShannon Nelson * i40e_write_nvm_aq - Writes Shadow RAM. 434cd552cb4SShannon Nelson * @hw: pointer to the HW structure. 435cd552cb4SShannon Nelson * @module_pointer: module pointer location in words from the NVM beginning 436cd552cb4SShannon Nelson * @offset: offset in words from module start 437cd552cb4SShannon Nelson * @words: number of words to write 438cd552cb4SShannon Nelson * @data: buffer with words to write to the Shadow RAM 439cd552cb4SShannon Nelson * @last_command: tells the AdminQ that this is the last command 440cd552cb4SShannon Nelson * 441cd552cb4SShannon Nelson * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 442cd552cb4SShannon Nelson **/ 443952d9639SWei Yongjun static i40e_status i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer, 444cd552cb4SShannon Nelson u32 offset, u16 words, void *data, 445cd552cb4SShannon Nelson bool last_command) 446cd552cb4SShannon Nelson { 447cd552cb4SShannon Nelson i40e_status ret_code = I40E_ERR_NVM; 4486b5c1b89SShannon Nelson struct i40e_asq_cmd_details cmd_details; 4496b5c1b89SShannon Nelson 4506b5c1b89SShannon Nelson memset(&cmd_details, 0, sizeof(cmd_details)); 4516b5c1b89SShannon Nelson cmd_details.wb_desc = &hw->nvm_wb_desc; 452cd552cb4SShannon Nelson 453cd552cb4SShannon Nelson /* Here we are checking the SR limit only for the flat memory model. 454cd552cb4SShannon Nelson * We cannot do it for the module-based model, as we did not acquire 455cd552cb4SShannon Nelson * the NVM resource yet (we cannot get the module pointer value). 456cd552cb4SShannon Nelson * Firmware will check the module-based model. 457cd552cb4SShannon Nelson */ 458cd552cb4SShannon Nelson if ((offset + words) > hw->nvm.sr_size) 45974d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 46074d0d0edSShannon Nelson "NVM write error: offset %d beyond Shadow RAM limit %d\n", 46174d0d0edSShannon Nelson (offset + words), hw->nvm.sr_size); 462cd552cb4SShannon Nelson else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) 463cd552cb4SShannon Nelson /* We can write only up to 4KB (one sector), in one AQ write */ 46474d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 46574d0d0edSShannon Nelson "NVM write fail error: tried to write %d words, limit is %d.\n", 46674d0d0edSShannon Nelson words, I40E_SR_SECTOR_SIZE_IN_WORDS); 467cd552cb4SShannon Nelson else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) 468cd552cb4SShannon Nelson != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) 469cd552cb4SShannon Nelson /* A single write cannot spread over two sectors */ 47074d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 47174d0d0edSShannon Nelson "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n", 47274d0d0edSShannon Nelson offset, words); 473cd552cb4SShannon Nelson else 474cd552cb4SShannon Nelson ret_code = i40e_aq_update_nvm(hw, module_pointer, 475cd552cb4SShannon Nelson 2 * offset, /*bytes*/ 476cd552cb4SShannon Nelson 2 * words, /*bytes*/ 477e3a5d6e6SPawel Jablonski data, last_command, 0, 478e3a5d6e6SPawel Jablonski &cmd_details); 479cd552cb4SShannon Nelson 480cd552cb4SShannon Nelson return ret_code; 481cd552cb4SShannon Nelson } 482cd552cb4SShannon Nelson 483cd552cb4SShannon Nelson /** 48456a62fc8SJesse Brandeburg * i40e_calc_nvm_checksum - Calculates and returns the checksum 48556a62fc8SJesse Brandeburg * @hw: pointer to hardware structure 48698d44381SJeff Kirsher * @checksum: pointer to the checksum 48756a62fc8SJesse Brandeburg * 4883e26186dSShannon Nelson * This function calculates SW Checksum that covers the whole 64kB shadow RAM 48956a62fc8SJesse Brandeburg * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD 49056a62fc8SJesse Brandeburg * is customer specific and unknown. Therefore, this function skips all maximum 49156a62fc8SJesse Brandeburg * possible size of VPD (1kB). 49256a62fc8SJesse Brandeburg **/ 49356a62fc8SJesse Brandeburg static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw, 49456a62fc8SJesse Brandeburg u16 *checksum) 49556a62fc8SJesse Brandeburg { 4960e5229c6SJean Sacren i40e_status ret_code; 497d1bbe0eaSKamil Krawczyk struct i40e_virt_mem vmem; 49856a62fc8SJesse Brandeburg u16 pcie_alt_module = 0; 49956a62fc8SJesse Brandeburg u16 checksum_local = 0; 50056a62fc8SJesse Brandeburg u16 vpd_module = 0; 501d1bbe0eaSKamil Krawczyk u16 *data; 502d1bbe0eaSKamil Krawczyk u16 i = 0; 503d1bbe0eaSKamil Krawczyk 504d1bbe0eaSKamil Krawczyk ret_code = i40e_allocate_virt_mem(hw, &vmem, 505d1bbe0eaSKamil Krawczyk I40E_SR_SECTOR_SIZE_IN_WORDS * sizeof(u16)); 506d1bbe0eaSKamil Krawczyk if (ret_code) 507d1bbe0eaSKamil Krawczyk goto i40e_calc_nvm_checksum_exit; 508d1bbe0eaSKamil Krawczyk data = (u16 *)vmem.va; 50956a62fc8SJesse Brandeburg 51056a62fc8SJesse Brandeburg /* read pointer to VPD area */ 51109f79fd4SAnjali Singhai Jain ret_code = __i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module); 51256a62fc8SJesse Brandeburg if (ret_code) { 51356a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 51456a62fc8SJesse Brandeburg goto i40e_calc_nvm_checksum_exit; 51556a62fc8SJesse Brandeburg } 51656a62fc8SJesse Brandeburg 51756a62fc8SJesse Brandeburg /* read pointer to PCIe Alt Auto-load module */ 51809f79fd4SAnjali Singhai Jain ret_code = __i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR, 51956a62fc8SJesse Brandeburg &pcie_alt_module); 52056a62fc8SJesse Brandeburg if (ret_code) { 52156a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 52256a62fc8SJesse Brandeburg goto i40e_calc_nvm_checksum_exit; 52356a62fc8SJesse Brandeburg } 52456a62fc8SJesse Brandeburg 52556a62fc8SJesse Brandeburg /* Calculate SW checksum that covers the whole 64kB shadow RAM 52656a62fc8SJesse Brandeburg * except the VPD and PCIe ALT Auto-load modules 52756a62fc8SJesse Brandeburg */ 52856a62fc8SJesse Brandeburg for (i = 0; i < hw->nvm.sr_size; i++) { 529d1bbe0eaSKamil Krawczyk /* Read SR page */ 530d1bbe0eaSKamil Krawczyk if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) { 531d1bbe0eaSKamil Krawczyk u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS; 53256a62fc8SJesse Brandeburg 53309f79fd4SAnjali Singhai Jain ret_code = __i40e_read_nvm_buffer(hw, i, &words, data); 53456a62fc8SJesse Brandeburg if (ret_code) { 53556a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 53656a62fc8SJesse Brandeburg goto i40e_calc_nvm_checksum_exit; 53756a62fc8SJesse Brandeburg } 538d1bbe0eaSKamil Krawczyk } 539d1bbe0eaSKamil Krawczyk 540d1bbe0eaSKamil Krawczyk /* Skip Checksum word */ 541d1bbe0eaSKamil Krawczyk if (i == I40E_SR_SW_CHECKSUM_WORD) 542d1bbe0eaSKamil Krawczyk continue; 543d1bbe0eaSKamil Krawczyk /* Skip VPD module (convert byte size to word count) */ 544d1bbe0eaSKamil Krawczyk if ((i >= (u32)vpd_module) && 545d1bbe0eaSKamil Krawczyk (i < ((u32)vpd_module + 546d1bbe0eaSKamil Krawczyk (I40E_SR_VPD_MODULE_MAX_SIZE / 2)))) { 547d1bbe0eaSKamil Krawczyk continue; 548d1bbe0eaSKamil Krawczyk } 549d1bbe0eaSKamil Krawczyk /* Skip PCIe ALT module (convert byte size to word count) */ 550d1bbe0eaSKamil Krawczyk if ((i >= (u32)pcie_alt_module) && 551d1bbe0eaSKamil Krawczyk (i < ((u32)pcie_alt_module + 552d1bbe0eaSKamil Krawczyk (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2)))) { 553d1bbe0eaSKamil Krawczyk continue; 554d1bbe0eaSKamil Krawczyk } 555d1bbe0eaSKamil Krawczyk 556d1bbe0eaSKamil Krawczyk checksum_local += data[i % I40E_SR_SECTOR_SIZE_IN_WORDS]; 55756a62fc8SJesse Brandeburg } 55856a62fc8SJesse Brandeburg 55956a62fc8SJesse Brandeburg *checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local; 56056a62fc8SJesse Brandeburg 56156a62fc8SJesse Brandeburg i40e_calc_nvm_checksum_exit: 562d1bbe0eaSKamil Krawczyk i40e_free_virt_mem(hw, &vmem); 56356a62fc8SJesse Brandeburg return ret_code; 56456a62fc8SJesse Brandeburg } 56556a62fc8SJesse Brandeburg 56656a62fc8SJesse Brandeburg /** 567cd552cb4SShannon Nelson * i40e_update_nvm_checksum - Updates the NVM checksum 568cd552cb4SShannon Nelson * @hw: pointer to hardware structure 569cd552cb4SShannon Nelson * 570cd552cb4SShannon Nelson * NVM ownership must be acquired before calling this function and released 571cd552cb4SShannon Nelson * on ARQ completion event reception by caller. 572cd552cb4SShannon Nelson * This function will commit SR to NVM. 573cd552cb4SShannon Nelson **/ 574cd552cb4SShannon Nelson i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw) 575cd552cb4SShannon Nelson { 5760e5229c6SJean Sacren i40e_status ret_code; 577cd552cb4SShannon Nelson u16 checksum; 578dd38c583SJesse Brandeburg __le16 le_sum; 579cd552cb4SShannon Nelson 580cd552cb4SShannon Nelson ret_code = i40e_calc_nvm_checksum(hw, &checksum); 5812fc4cd52SJean Sacren if (!ret_code) { 582dd38c583SJesse Brandeburg le_sum = cpu_to_le16(checksum); 583cd552cb4SShannon Nelson ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD, 584dd38c583SJesse Brandeburg 1, &le_sum, true); 5852fc4cd52SJean Sacren } 586cd552cb4SShannon Nelson 587cd552cb4SShannon Nelson return ret_code; 588cd552cb4SShannon Nelson } 589cd552cb4SShannon Nelson 590cd552cb4SShannon Nelson /** 59156a62fc8SJesse Brandeburg * i40e_validate_nvm_checksum - Validate EEPROM checksum 59256a62fc8SJesse Brandeburg * @hw: pointer to hardware structure 59356a62fc8SJesse Brandeburg * @checksum: calculated checksum 59456a62fc8SJesse Brandeburg * 59556a62fc8SJesse Brandeburg * Performs checksum calculation and validates the NVM SW checksum. If the 59656a62fc8SJesse Brandeburg * caller does not need checksum, the value can be NULL. 59756a62fc8SJesse Brandeburg **/ 59856a62fc8SJesse Brandeburg i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, 59956a62fc8SJesse Brandeburg u16 *checksum) 60056a62fc8SJesse Brandeburg { 60156a62fc8SJesse Brandeburg i40e_status ret_code = 0; 60256a62fc8SJesse Brandeburg u16 checksum_sr = 0; 603e15c9fa0SJesse Brandeburg u16 checksum_local = 0; 60456a62fc8SJesse Brandeburg 60509f79fd4SAnjali Singhai Jain /* We must acquire the NVM lock in order to correctly synchronize the 60609f79fd4SAnjali Singhai Jain * NVM accesses across multiple PFs. Without doing so it is possible 60709f79fd4SAnjali Singhai Jain * for one of the PFs to read invalid data potentially indicating that 60809f79fd4SAnjali Singhai Jain * the checksum is invalid. 60956a62fc8SJesse Brandeburg */ 61009f79fd4SAnjali Singhai Jain ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 61109f79fd4SAnjali Singhai Jain if (ret_code) 61209f79fd4SAnjali Singhai Jain return ret_code; 61309f79fd4SAnjali Singhai Jain ret_code = i40e_calc_nvm_checksum(hw, &checksum_local); 61409f79fd4SAnjali Singhai Jain __i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr); 61509f79fd4SAnjali Singhai Jain i40e_release_nvm(hw); 61609f79fd4SAnjali Singhai Jain if (ret_code) 61709f79fd4SAnjali Singhai Jain return ret_code; 61856a62fc8SJesse Brandeburg 61956a62fc8SJesse Brandeburg /* Verify read checksum from EEPROM is the same as 62056a62fc8SJesse Brandeburg * calculated checksum 62156a62fc8SJesse Brandeburg */ 62256a62fc8SJesse Brandeburg if (checksum_local != checksum_sr) 62356a62fc8SJesse Brandeburg ret_code = I40E_ERR_NVM_CHECKSUM; 62456a62fc8SJesse Brandeburg 62556a62fc8SJesse Brandeburg /* If the user cares, return the calculated checksum */ 62656a62fc8SJesse Brandeburg if (checksum) 62756a62fc8SJesse Brandeburg *checksum = checksum_local; 62856a62fc8SJesse Brandeburg 62956a62fc8SJesse Brandeburg return ret_code; 63056a62fc8SJesse Brandeburg } 631cd552cb4SShannon Nelson 632cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw, 633cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 63479afe839SShannon Nelson u8 *bytes, int *perrno); 635cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw, 636cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 63779afe839SShannon Nelson u8 *bytes, int *perrno); 638cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw, 639cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 640cd552cb4SShannon Nelson u8 *bytes, int *errno); 641cd552cb4SShannon Nelson static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, 642cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 64379afe839SShannon Nelson int *perrno); 644cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw, 645cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 64679afe839SShannon Nelson int *perrno); 647cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw, 648cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 64979afe839SShannon Nelson u8 *bytes, int *perrno); 650cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw, 651cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 65279afe839SShannon Nelson u8 *bytes, int *perrno); 653e4c83c20SShannon Nelson static i40e_status i40e_nvmupd_exec_aq(struct i40e_hw *hw, 654e4c83c20SShannon Nelson struct i40e_nvm_access *cmd, 655e4c83c20SShannon Nelson u8 *bytes, int *perrno); 656b72dc7b1SShannon Nelson static i40e_status i40e_nvmupd_get_aq_result(struct i40e_hw *hw, 657b72dc7b1SShannon Nelson struct i40e_nvm_access *cmd, 658b72dc7b1SShannon Nelson u8 *bytes, int *perrno); 659e3a5d6e6SPawel Jablonski static i40e_status i40e_nvmupd_get_aq_event(struct i40e_hw *hw, 660e3a5d6e6SPawel Jablonski struct i40e_nvm_access *cmd, 661e3a5d6e6SPawel Jablonski u8 *bytes, int *perrno); 662cd552cb4SShannon Nelson static inline u8 i40e_nvmupd_get_module(u32 val) 663cd552cb4SShannon Nelson { 664cd552cb4SShannon Nelson return (u8)(val & I40E_NVM_MOD_PNT_MASK); 665cd552cb4SShannon Nelson } 666cd552cb4SShannon Nelson static inline u8 i40e_nvmupd_get_transaction(u32 val) 667cd552cb4SShannon Nelson { 668cd552cb4SShannon Nelson return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT); 669cd552cb4SShannon Nelson } 670cd552cb4SShannon Nelson 671e3a5d6e6SPawel Jablonski static inline u8 i40e_nvmupd_get_preservation_flags(u32 val) 672e3a5d6e6SPawel Jablonski { 673e3a5d6e6SPawel Jablonski return (u8)((val & I40E_NVM_PRESERVATION_FLAGS_MASK) >> 674e3a5d6e6SPawel Jablonski I40E_NVM_PRESERVATION_FLAGS_SHIFT); 675e3a5d6e6SPawel Jablonski } 676e3a5d6e6SPawel Jablonski 6774e68adfeSJingjing Wu static const char * const i40e_nvm_update_state_str[] = { 67874d0d0edSShannon Nelson "I40E_NVMUPD_INVALID", 67974d0d0edSShannon Nelson "I40E_NVMUPD_READ_CON", 68074d0d0edSShannon Nelson "I40E_NVMUPD_READ_SNT", 68174d0d0edSShannon Nelson "I40E_NVMUPD_READ_LCB", 68274d0d0edSShannon Nelson "I40E_NVMUPD_READ_SA", 68374d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_ERA", 68474d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_CON", 68574d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_SNT", 68674d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_LCB", 68774d0d0edSShannon Nelson "I40E_NVMUPD_WRITE_SA", 68874d0d0edSShannon Nelson "I40E_NVMUPD_CSUM_CON", 68974d0d0edSShannon Nelson "I40E_NVMUPD_CSUM_SA", 69074d0d0edSShannon Nelson "I40E_NVMUPD_CSUM_LCB", 6910af8e9dbSShannon Nelson "I40E_NVMUPD_STATUS", 692e4c83c20SShannon Nelson "I40E_NVMUPD_EXEC_AQ", 693b72dc7b1SShannon Nelson "I40E_NVMUPD_GET_AQ_RESULT", 694e3a5d6e6SPawel Jablonski "I40E_NVMUPD_GET_AQ_EVENT", 69574d0d0edSShannon Nelson }; 69674d0d0edSShannon Nelson 697cd552cb4SShannon Nelson /** 698cd552cb4SShannon Nelson * i40e_nvmupd_command - Process an NVM update command 699cd552cb4SShannon Nelson * @hw: pointer to hardware structure 700cd552cb4SShannon Nelson * @cmd: pointer to nvm update command 701cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 70279afe839SShannon Nelson * @perrno: pointer to return error code 703cd552cb4SShannon Nelson * 704cd552cb4SShannon Nelson * Dispatches command depending on what update state is current 705cd552cb4SShannon Nelson **/ 706cd552cb4SShannon Nelson i40e_status i40e_nvmupd_command(struct i40e_hw *hw, 707cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 70879afe839SShannon Nelson u8 *bytes, int *perrno) 709cd552cb4SShannon Nelson { 710cd552cb4SShannon Nelson i40e_status status; 7110af8e9dbSShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 712cd552cb4SShannon Nelson 713cd552cb4SShannon Nelson /* assume success */ 71479afe839SShannon Nelson *perrno = 0; 715cd552cb4SShannon Nelson 7160af8e9dbSShannon Nelson /* early check for status command and debug msgs */ 7170af8e9dbSShannon Nelson upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno); 7180af8e9dbSShannon Nelson 719fed2db99SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "%s state %d nvm_release_on_hold %d opc 0x%04x cmd 0x%08x config 0x%08x offset 0x%08x data_size 0x%08x\n", 7200af8e9dbSShannon Nelson i40e_nvm_update_state_str[upd_cmd], 7210af8e9dbSShannon Nelson hw->nvmupd_state, 722fed2db99SShannon Nelson hw->nvm_release_on_done, hw->nvm_wait_opcode, 7231d73b2dbSShannon Nelson cmd->command, cmd->config, cmd->offset, cmd->data_size); 7240af8e9dbSShannon Nelson 7250af8e9dbSShannon Nelson if (upd_cmd == I40E_NVMUPD_INVALID) { 7260af8e9dbSShannon Nelson *perrno = -EFAULT; 7270af8e9dbSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 7280af8e9dbSShannon Nelson "i40e_nvmupd_validate_command returns %d errno %d\n", 7290af8e9dbSShannon Nelson upd_cmd, *perrno); 7300af8e9dbSShannon Nelson } 7310af8e9dbSShannon Nelson 7320af8e9dbSShannon Nelson /* a status request returns immediately rather than 7330af8e9dbSShannon Nelson * going into the state machine 7340af8e9dbSShannon Nelson */ 7350af8e9dbSShannon Nelson if (upd_cmd == I40E_NVMUPD_STATUS) { 736fed2db99SShannon Nelson if (!cmd->data_size) { 737fed2db99SShannon Nelson *perrno = -EFAULT; 738fed2db99SShannon Nelson return I40E_ERR_BUF_TOO_SHORT; 739fed2db99SShannon Nelson } 740fed2db99SShannon Nelson 7410af8e9dbSShannon Nelson bytes[0] = hw->nvmupd_state; 742fed2db99SShannon Nelson 743fed2db99SShannon Nelson if (cmd->data_size >= 4) { 744fed2db99SShannon Nelson bytes[1] = 0; 745fed2db99SShannon Nelson *((u16 *)&bytes[2]) = hw->nvm_wait_opcode; 746fed2db99SShannon Nelson } 747fed2db99SShannon Nelson 74881fa7c97SMaciej Sosin /* Clear error status on read */ 74981fa7c97SMaciej Sosin if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR) 75081fa7c97SMaciej Sosin hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 75181fa7c97SMaciej Sosin 7520af8e9dbSShannon Nelson return 0; 7530af8e9dbSShannon Nelson } 7540af8e9dbSShannon Nelson 75581fa7c97SMaciej Sosin /* Clear status even it is not read and log */ 75681fa7c97SMaciej Sosin if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR) { 75781fa7c97SMaciej Sosin i40e_debug(hw, I40E_DEBUG_NVM, 75881fa7c97SMaciej Sosin "Clearing I40E_NVMUPD_STATE_ERROR state without reading\n"); 75981fa7c97SMaciej Sosin hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 76081fa7c97SMaciej Sosin } 76181fa7c97SMaciej Sosin 7622bf01935SSudheer Mogilappagari /* Acquire lock to prevent race condition where adminq_task 7632bf01935SSudheer Mogilappagari * can execute after i40e_nvmupd_nvm_read/write but before state 764167d52edSSudheer Mogilappagari * variables (nvm_wait_opcode, nvm_release_on_done) are updated. 765167d52edSSudheer Mogilappagari * 766167d52edSSudheer Mogilappagari * During NVMUpdate, it is observed that lock could be held for 767167d52edSSudheer Mogilappagari * ~5ms for most commands. However lock is held for ~60ms for 768167d52edSSudheer Mogilappagari * NVMUPD_CSUM_LCB command. 7692bf01935SSudheer Mogilappagari */ 7702bf01935SSudheer Mogilappagari mutex_lock(&hw->aq.arq_mutex); 771cd552cb4SShannon Nelson switch (hw->nvmupd_state) { 772cd552cb4SShannon Nelson case I40E_NVMUPD_STATE_INIT: 77379afe839SShannon Nelson status = i40e_nvmupd_state_init(hw, cmd, bytes, perrno); 774cd552cb4SShannon Nelson break; 775cd552cb4SShannon Nelson 776cd552cb4SShannon Nelson case I40E_NVMUPD_STATE_READING: 77779afe839SShannon Nelson status = i40e_nvmupd_state_reading(hw, cmd, bytes, perrno); 778cd552cb4SShannon Nelson break; 779cd552cb4SShannon Nelson 780cd552cb4SShannon Nelson case I40E_NVMUPD_STATE_WRITING: 78179afe839SShannon Nelson status = i40e_nvmupd_state_writing(hw, cmd, bytes, perrno); 782cd552cb4SShannon Nelson break; 783cd552cb4SShannon Nelson 7842f1b5bc8SShannon Nelson case I40E_NVMUPD_STATE_INIT_WAIT: 7852f1b5bc8SShannon Nelson case I40E_NVMUPD_STATE_WRITE_WAIT: 786fed2db99SShannon Nelson /* if we need to stop waiting for an event, clear 787fed2db99SShannon Nelson * the wait info and return before doing anything else 788fed2db99SShannon Nelson */ 789fed2db99SShannon Nelson if (cmd->offset == 0xffff) { 790e3a5d6e6SPawel Jablonski i40e_nvmupd_clear_wait_state(hw); 791167d52edSSudheer Mogilappagari status = 0; 792e3a5d6e6SPawel Jablonski break; 793fed2db99SShannon Nelson } 794fed2db99SShannon Nelson 7952f1b5bc8SShannon Nelson status = I40E_ERR_NOT_READY; 7962f1b5bc8SShannon Nelson *perrno = -EBUSY; 7972f1b5bc8SShannon Nelson break; 7982f1b5bc8SShannon Nelson 799cd552cb4SShannon Nelson default: 800cd552cb4SShannon Nelson /* invalid state, should never happen */ 80174d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 80274d0d0edSShannon Nelson "NVMUPD: no such state %d\n", hw->nvmupd_state); 803cd552cb4SShannon Nelson status = I40E_NOT_SUPPORTED; 80479afe839SShannon Nelson *perrno = -ESRCH; 805cd552cb4SShannon Nelson break; 806cd552cb4SShannon Nelson } 807e3a5d6e6SPawel Jablonski 8082bf01935SSudheer Mogilappagari mutex_unlock(&hw->aq.arq_mutex); 809cd552cb4SShannon Nelson return status; 810cd552cb4SShannon Nelson } 811cd552cb4SShannon Nelson 812cd552cb4SShannon Nelson /** 813cd552cb4SShannon Nelson * i40e_nvmupd_state_init - Handle NVM update state Init 814cd552cb4SShannon Nelson * @hw: pointer to hardware structure 815cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 816cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 81779afe839SShannon Nelson * @perrno: pointer to return error code 818cd552cb4SShannon Nelson * 819cd552cb4SShannon Nelson * Process legitimate commands of the Init state and conditionally set next 820cd552cb4SShannon Nelson * state. Reject all other commands. 821cd552cb4SShannon Nelson **/ 822cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw, 823cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 82479afe839SShannon Nelson u8 *bytes, int *perrno) 825cd552cb4SShannon Nelson { 826cd552cb4SShannon Nelson i40e_status status = 0; 827cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 828cd552cb4SShannon Nelson 82979afe839SShannon Nelson upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno); 830cd552cb4SShannon Nelson 831cd552cb4SShannon Nelson switch (upd_cmd) { 832cd552cb4SShannon Nelson case I40E_NVMUPD_READ_SA: 833cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 834cd552cb4SShannon Nelson if (status) { 83579afe839SShannon Nelson *perrno = i40e_aq_rc_to_posix(status, 836bf848f32SShannon Nelson hw->aq.asq_last_status); 837cd552cb4SShannon Nelson } else { 83879afe839SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno); 839cd552cb4SShannon Nelson i40e_release_nvm(hw); 840cd552cb4SShannon Nelson } 841cd552cb4SShannon Nelson break; 842cd552cb4SShannon Nelson 843cd552cb4SShannon Nelson case I40E_NVMUPD_READ_SNT: 844cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); 845cd552cb4SShannon Nelson if (status) { 84679afe839SShannon Nelson *perrno = i40e_aq_rc_to_posix(status, 847bf848f32SShannon Nelson hw->aq.asq_last_status); 848cd552cb4SShannon Nelson } else { 84979afe839SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno); 8500fdd052cSShannon Nelson if (status) 8510fdd052cSShannon Nelson i40e_release_nvm(hw); 8520fdd052cSShannon Nelson else 853cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_READING; 854cd552cb4SShannon Nelson } 855cd552cb4SShannon Nelson break; 856cd552cb4SShannon Nelson 857cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_ERA: 858cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 859cd552cb4SShannon Nelson if (status) { 86079afe839SShannon Nelson *perrno = i40e_aq_rc_to_posix(status, 861bf848f32SShannon Nelson hw->aq.asq_last_status); 862cd552cb4SShannon Nelson } else { 86379afe839SShannon Nelson status = i40e_nvmupd_nvm_erase(hw, cmd, perrno); 8642f1b5bc8SShannon Nelson if (status) { 865cd552cb4SShannon Nelson i40e_release_nvm(hw); 8662f1b5bc8SShannon Nelson } else { 867437f82a2SShannon Nelson hw->nvm_release_on_done = true; 868fed2db99SShannon Nelson hw->nvm_wait_opcode = i40e_aqc_opc_nvm_erase; 8692f1b5bc8SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 8702f1b5bc8SShannon Nelson } 871cd552cb4SShannon Nelson } 872cd552cb4SShannon Nelson break; 873cd552cb4SShannon Nelson 874cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_SA: 875cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 876cd552cb4SShannon Nelson if (status) { 87779afe839SShannon Nelson *perrno = i40e_aq_rc_to_posix(status, 878bf848f32SShannon Nelson hw->aq.asq_last_status); 879cd552cb4SShannon Nelson } else { 88079afe839SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno); 8812f1b5bc8SShannon Nelson if (status) { 882cd552cb4SShannon Nelson i40e_release_nvm(hw); 8832f1b5bc8SShannon Nelson } else { 884437f82a2SShannon Nelson hw->nvm_release_on_done = true; 885fed2db99SShannon Nelson hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update; 8862f1b5bc8SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 8872f1b5bc8SShannon Nelson } 888cd552cb4SShannon Nelson } 889cd552cb4SShannon Nelson break; 890cd552cb4SShannon Nelson 891cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_SNT: 892cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 893cd552cb4SShannon Nelson if (status) { 89479afe839SShannon Nelson *perrno = i40e_aq_rc_to_posix(status, 895bf848f32SShannon Nelson hw->aq.asq_last_status); 896cd552cb4SShannon Nelson } else { 89779afe839SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno); 898fed2db99SShannon Nelson if (status) { 8990fdd052cSShannon Nelson i40e_release_nvm(hw); 900fed2db99SShannon Nelson } else { 901fed2db99SShannon Nelson hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update; 9022f1b5bc8SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT; 903cd552cb4SShannon Nelson } 904fed2db99SShannon Nelson } 905cd552cb4SShannon Nelson break; 906cd552cb4SShannon Nelson 907cd552cb4SShannon Nelson case I40E_NVMUPD_CSUM_SA: 908cd552cb4SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 909cd552cb4SShannon Nelson if (status) { 91079afe839SShannon Nelson *perrno = i40e_aq_rc_to_posix(status, 911bf848f32SShannon Nelson hw->aq.asq_last_status); 912cd552cb4SShannon Nelson } else { 913cd552cb4SShannon Nelson status = i40e_update_nvm_checksum(hw); 914cd552cb4SShannon Nelson if (status) { 91579afe839SShannon Nelson *perrno = hw->aq.asq_last_status ? 916bf848f32SShannon Nelson i40e_aq_rc_to_posix(status, 917bf848f32SShannon Nelson hw->aq.asq_last_status) : 918cd552cb4SShannon Nelson -EIO; 919cd552cb4SShannon Nelson i40e_release_nvm(hw); 920cd552cb4SShannon Nelson } else { 921437f82a2SShannon Nelson hw->nvm_release_on_done = true; 922fed2db99SShannon Nelson hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update; 9232f1b5bc8SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 924cd552cb4SShannon Nelson } 925cd552cb4SShannon Nelson } 926cd552cb4SShannon Nelson break; 927cd552cb4SShannon Nelson 928e4c83c20SShannon Nelson case I40E_NVMUPD_EXEC_AQ: 929e4c83c20SShannon Nelson status = i40e_nvmupd_exec_aq(hw, cmd, bytes, perrno); 930e4c83c20SShannon Nelson break; 931e4c83c20SShannon Nelson 932b72dc7b1SShannon Nelson case I40E_NVMUPD_GET_AQ_RESULT: 933b72dc7b1SShannon Nelson status = i40e_nvmupd_get_aq_result(hw, cmd, bytes, perrno); 934b72dc7b1SShannon Nelson break; 935b72dc7b1SShannon Nelson 936e3a5d6e6SPawel Jablonski case I40E_NVMUPD_GET_AQ_EVENT: 937e3a5d6e6SPawel Jablonski status = i40e_nvmupd_get_aq_event(hw, cmd, bytes, perrno); 938e3a5d6e6SPawel Jablonski break; 939e3a5d6e6SPawel Jablonski 940cd552cb4SShannon Nelson default: 94174d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 94274d0d0edSShannon Nelson "NVMUPD: bad cmd %s in init state\n", 94374d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 944cd552cb4SShannon Nelson status = I40E_ERR_NVM; 94579afe839SShannon Nelson *perrno = -ESRCH; 946cd552cb4SShannon Nelson break; 947cd552cb4SShannon Nelson } 948cd552cb4SShannon Nelson return status; 949cd552cb4SShannon Nelson } 950cd552cb4SShannon Nelson 951cd552cb4SShannon Nelson /** 952cd552cb4SShannon Nelson * i40e_nvmupd_state_reading - Handle NVM update state Reading 953cd552cb4SShannon Nelson * @hw: pointer to hardware structure 954cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 955cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 95679afe839SShannon Nelson * @perrno: pointer to return error code 957cd552cb4SShannon Nelson * 958cd552cb4SShannon Nelson * NVM ownership is already held. Process legitimate commands and set any 959cd552cb4SShannon Nelson * change in state; reject all other commands. 960cd552cb4SShannon Nelson **/ 961cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw, 962cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 96379afe839SShannon Nelson u8 *bytes, int *perrno) 964cd552cb4SShannon Nelson { 9652f1b5bc8SShannon Nelson i40e_status status = 0; 966cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 967cd552cb4SShannon Nelson 96879afe839SShannon Nelson upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno); 969cd552cb4SShannon Nelson 970cd552cb4SShannon Nelson switch (upd_cmd) { 971cd552cb4SShannon Nelson case I40E_NVMUPD_READ_SA: 972cd552cb4SShannon Nelson case I40E_NVMUPD_READ_CON: 97379afe839SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno); 974cd552cb4SShannon Nelson break; 975cd552cb4SShannon Nelson 976cd552cb4SShannon Nelson case I40E_NVMUPD_READ_LCB: 97779afe839SShannon Nelson status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno); 978cd552cb4SShannon Nelson i40e_release_nvm(hw); 979cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 980cd552cb4SShannon Nelson break; 981cd552cb4SShannon Nelson 982cd552cb4SShannon Nelson default: 98374d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 98474d0d0edSShannon Nelson "NVMUPD: bad cmd %s in reading state.\n", 98574d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 986cd552cb4SShannon Nelson status = I40E_NOT_SUPPORTED; 98779afe839SShannon Nelson *perrno = -ESRCH; 988cd552cb4SShannon Nelson break; 989cd552cb4SShannon Nelson } 990cd552cb4SShannon Nelson return status; 991cd552cb4SShannon Nelson } 992cd552cb4SShannon Nelson 993cd552cb4SShannon Nelson /** 994cd552cb4SShannon Nelson * i40e_nvmupd_state_writing - Handle NVM update state Writing 995cd552cb4SShannon Nelson * @hw: pointer to hardware structure 996cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 997cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 99879afe839SShannon Nelson * @perrno: pointer to return error code 999cd552cb4SShannon Nelson * 1000cd552cb4SShannon Nelson * NVM ownership is already held. Process legitimate commands and set any 1001cd552cb4SShannon Nelson * change in state; reject all other commands 1002cd552cb4SShannon Nelson **/ 1003cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw, 1004cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 100579afe839SShannon Nelson u8 *bytes, int *perrno) 1006cd552cb4SShannon Nelson { 10072f1b5bc8SShannon Nelson i40e_status status = 0; 1008cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 10092c47e351SShannon Nelson bool retry_attempt = false; 1010cd552cb4SShannon Nelson 101179afe839SShannon Nelson upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno); 1012cd552cb4SShannon Nelson 10132c47e351SShannon Nelson retry: 1014cd552cb4SShannon Nelson switch (upd_cmd) { 1015cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_CON: 101679afe839SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno); 1017fed2db99SShannon Nelson if (!status) { 1018fed2db99SShannon Nelson hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update; 10192f1b5bc8SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT; 1020fed2db99SShannon Nelson } 1021cd552cb4SShannon Nelson break; 1022cd552cb4SShannon Nelson 1023cd552cb4SShannon Nelson case I40E_NVMUPD_WRITE_LCB: 102479afe839SShannon Nelson status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno); 10252f1b5bc8SShannon Nelson if (status) { 10262f1b5bc8SShannon Nelson *perrno = hw->aq.asq_last_status ? 10272f1b5bc8SShannon Nelson i40e_aq_rc_to_posix(status, 10282f1b5bc8SShannon Nelson hw->aq.asq_last_status) : 10292f1b5bc8SShannon Nelson -EIO; 1030cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 10312f1b5bc8SShannon Nelson } else { 1032437f82a2SShannon Nelson hw->nvm_release_on_done = true; 1033fed2db99SShannon Nelson hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update; 10342f1b5bc8SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 10352f1b5bc8SShannon Nelson } 1036cd552cb4SShannon Nelson break; 1037cd552cb4SShannon Nelson 1038cd552cb4SShannon Nelson case I40E_NVMUPD_CSUM_CON: 103909f79fd4SAnjali Singhai Jain /* Assumes the caller has acquired the nvm */ 1040cd552cb4SShannon Nelson status = i40e_update_nvm_checksum(hw); 1041cd552cb4SShannon Nelson if (status) { 104279afe839SShannon Nelson *perrno = hw->aq.asq_last_status ? 1043bf848f32SShannon Nelson i40e_aq_rc_to_posix(status, 1044bf848f32SShannon Nelson hw->aq.asq_last_status) : 1045cd552cb4SShannon Nelson -EIO; 1046cd552cb4SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 10472f1b5bc8SShannon Nelson } else { 1048fed2db99SShannon Nelson hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update; 10492f1b5bc8SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT; 1050cd552cb4SShannon Nelson } 1051cd552cb4SShannon Nelson break; 1052cd552cb4SShannon Nelson 10530fdd052cSShannon Nelson case I40E_NVMUPD_CSUM_LCB: 105409f79fd4SAnjali Singhai Jain /* Assumes the caller has acquired the nvm */ 10550fdd052cSShannon Nelson status = i40e_update_nvm_checksum(hw); 10562f1b5bc8SShannon Nelson if (status) { 105779afe839SShannon Nelson *perrno = hw->aq.asq_last_status ? 1058bf848f32SShannon Nelson i40e_aq_rc_to_posix(status, 1059bf848f32SShannon Nelson hw->aq.asq_last_status) : 10600fdd052cSShannon Nelson -EIO; 10610fdd052cSShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 10622f1b5bc8SShannon Nelson } else { 1063437f82a2SShannon Nelson hw->nvm_release_on_done = true; 1064fed2db99SShannon Nelson hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update; 10652f1b5bc8SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 10662f1b5bc8SShannon Nelson } 10670fdd052cSShannon Nelson break; 10680fdd052cSShannon Nelson 1069cd552cb4SShannon Nelson default: 107074d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 107174d0d0edSShannon Nelson "NVMUPD: bad cmd %s in writing state.\n", 107274d0d0edSShannon Nelson i40e_nvm_update_state_str[upd_cmd]); 1073cd552cb4SShannon Nelson status = I40E_NOT_SUPPORTED; 107479afe839SShannon Nelson *perrno = -ESRCH; 1075cd552cb4SShannon Nelson break; 1076cd552cb4SShannon Nelson } 10772c47e351SShannon Nelson 10782c47e351SShannon Nelson /* In some circumstances, a multi-write transaction takes longer 10792c47e351SShannon Nelson * than the default 3 minute timeout on the write semaphore. If 10802c47e351SShannon Nelson * the write failed with an EBUSY status, this is likely the problem, 10812c47e351SShannon Nelson * so here we try to reacquire the semaphore then retry the write. 10822c47e351SShannon Nelson * We only do one retry, then give up. 10832c47e351SShannon Nelson */ 10842c47e351SShannon Nelson if (status && (hw->aq.asq_last_status == I40E_AQ_RC_EBUSY) && 10852c47e351SShannon Nelson !retry_attempt) { 10862c47e351SShannon Nelson i40e_status old_status = status; 10872c47e351SShannon Nelson u32 old_asq_status = hw->aq.asq_last_status; 10882c47e351SShannon Nelson u32 gtime; 10892c47e351SShannon Nelson 10902c47e351SShannon Nelson gtime = rd32(hw, I40E_GLVFGEN_TIMER); 10912c47e351SShannon Nelson if (gtime >= hw->nvm.hw_semaphore_timeout) { 10922c47e351SShannon Nelson i40e_debug(hw, I40E_DEBUG_ALL, 10932c47e351SShannon Nelson "NVMUPD: write semaphore expired (%d >= %lld), retrying\n", 10942c47e351SShannon Nelson gtime, hw->nvm.hw_semaphore_timeout); 10952c47e351SShannon Nelson i40e_release_nvm(hw); 10962c47e351SShannon Nelson status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); 10972c47e351SShannon Nelson if (status) { 10982c47e351SShannon Nelson i40e_debug(hw, I40E_DEBUG_ALL, 10992c47e351SShannon Nelson "NVMUPD: write semaphore reacquire failed aq_err = %d\n", 11002c47e351SShannon Nelson hw->aq.asq_last_status); 11012c47e351SShannon Nelson status = old_status; 11022c47e351SShannon Nelson hw->aq.asq_last_status = old_asq_status; 11032c47e351SShannon Nelson } else { 11042c47e351SShannon Nelson retry_attempt = true; 11052c47e351SShannon Nelson goto retry; 11062c47e351SShannon Nelson } 11072c47e351SShannon Nelson } 11082c47e351SShannon Nelson } 11092c47e351SShannon Nelson 1110cd552cb4SShannon Nelson return status; 1111cd552cb4SShannon Nelson } 1112cd552cb4SShannon Nelson 1113cd552cb4SShannon Nelson /** 1114e3a5d6e6SPawel Jablonski * i40e_nvmupd_clear_wait_state - clear wait state on hw 1115bab2fb60SShannon Nelson * @hw: pointer to the hardware structure 1116bab2fb60SShannon Nelson **/ 1117e3a5d6e6SPawel Jablonski void i40e_nvmupd_clear_wait_state(struct i40e_hw *hw) 1118bab2fb60SShannon Nelson { 1119bab2fb60SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 1120e3a5d6e6SPawel Jablonski "NVMUPD: clearing wait on opcode 0x%04x\n", 1121e3a5d6e6SPawel Jablonski hw->nvm_wait_opcode); 1122e3a5d6e6SPawel Jablonski 1123bab2fb60SShannon Nelson if (hw->nvm_release_on_done) { 1124bab2fb60SShannon Nelson i40e_release_nvm(hw); 1125bab2fb60SShannon Nelson hw->nvm_release_on_done = false; 1126bab2fb60SShannon Nelson } 1127fed2db99SShannon Nelson hw->nvm_wait_opcode = 0; 1128bab2fb60SShannon Nelson 112981fa7c97SMaciej Sosin if (hw->aq.arq_last_status) { 113081fa7c97SMaciej Sosin hw->nvmupd_state = I40E_NVMUPD_STATE_ERROR; 113181fa7c97SMaciej Sosin return; 113281fa7c97SMaciej Sosin } 113381fa7c97SMaciej Sosin 1134bab2fb60SShannon Nelson switch (hw->nvmupd_state) { 1135bab2fb60SShannon Nelson case I40E_NVMUPD_STATE_INIT_WAIT: 1136bab2fb60SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; 1137bab2fb60SShannon Nelson break; 1138bab2fb60SShannon Nelson 1139bab2fb60SShannon Nelson case I40E_NVMUPD_STATE_WRITE_WAIT: 1140bab2fb60SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING; 1141bab2fb60SShannon Nelson break; 1142bab2fb60SShannon Nelson 1143bab2fb60SShannon Nelson default: 1144bab2fb60SShannon Nelson break; 1145bab2fb60SShannon Nelson } 1146bab2fb60SShannon Nelson } 1147e3a5d6e6SPawel Jablonski 1148e3a5d6e6SPawel Jablonski /** 1149e3a5d6e6SPawel Jablonski * i40e_nvmupd_check_wait_event - handle NVM update operation events 1150e3a5d6e6SPawel Jablonski * @hw: pointer to the hardware structure 1151e3a5d6e6SPawel Jablonski * @opcode: the event that just happened 1152f5254429SJacob Keller * @desc: AdminQ descriptor 1153e3a5d6e6SPawel Jablonski **/ 1154e3a5d6e6SPawel Jablonski void i40e_nvmupd_check_wait_event(struct i40e_hw *hw, u16 opcode, 1155e3a5d6e6SPawel Jablonski struct i40e_aq_desc *desc) 1156e3a5d6e6SPawel Jablonski { 1157e3a5d6e6SPawel Jablonski u32 aq_desc_len = sizeof(struct i40e_aq_desc); 1158e3a5d6e6SPawel Jablonski 1159e3a5d6e6SPawel Jablonski if (opcode == hw->nvm_wait_opcode) { 1160e3a5d6e6SPawel Jablonski memcpy(&hw->nvm_aq_event_desc, desc, aq_desc_len); 1161e3a5d6e6SPawel Jablonski i40e_nvmupd_clear_wait_state(hw); 1162e3a5d6e6SPawel Jablonski } 1163bab2fb60SShannon Nelson } 1164bab2fb60SShannon Nelson 1165bab2fb60SShannon Nelson /** 1166cd552cb4SShannon Nelson * i40e_nvmupd_validate_command - Validate given command 1167cd552cb4SShannon Nelson * @hw: pointer to hardware structure 1168cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 116979afe839SShannon Nelson * @perrno: pointer to return error code 1170cd552cb4SShannon Nelson * 1171cd552cb4SShannon Nelson * Return one of the valid command types or I40E_NVMUPD_INVALID 1172cd552cb4SShannon Nelson **/ 1173cd552cb4SShannon Nelson static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, 1174cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 117579afe839SShannon Nelson int *perrno) 1176cd552cb4SShannon Nelson { 1177cd552cb4SShannon Nelson enum i40e_nvmupd_cmd upd_cmd; 11780af8e9dbSShannon Nelson u8 module, transaction; 1179cd552cb4SShannon Nelson 1180cd552cb4SShannon Nelson /* anything that doesn't match a recognized case is an error */ 1181cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_INVALID; 1182cd552cb4SShannon Nelson 1183cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 11840af8e9dbSShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 1185cd552cb4SShannon Nelson 1186cd552cb4SShannon Nelson /* limits on data size */ 1187cd552cb4SShannon Nelson if ((cmd->data_size < 1) || 1188cd552cb4SShannon Nelson (cmd->data_size > I40E_NVMUPD_MAX_DATA)) { 118974d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 119074d0d0edSShannon Nelson "i40e_nvmupd_validate_command data_size %d\n", 1191cd552cb4SShannon Nelson cmd->data_size); 119279afe839SShannon Nelson *perrno = -EFAULT; 1193cd552cb4SShannon Nelson return I40E_NVMUPD_INVALID; 1194cd552cb4SShannon Nelson } 1195cd552cb4SShannon Nelson 1196cd552cb4SShannon Nelson switch (cmd->command) { 1197cd552cb4SShannon Nelson case I40E_NVM_READ: 1198cd552cb4SShannon Nelson switch (transaction) { 1199cd552cb4SShannon Nelson case I40E_NVM_CON: 1200cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_CON; 1201cd552cb4SShannon Nelson break; 1202cd552cb4SShannon Nelson case I40E_NVM_SNT: 1203cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_SNT; 1204cd552cb4SShannon Nelson break; 1205cd552cb4SShannon Nelson case I40E_NVM_LCB: 1206cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_LCB; 1207cd552cb4SShannon Nelson break; 1208cd552cb4SShannon Nelson case I40E_NVM_SA: 1209cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_READ_SA; 1210cd552cb4SShannon Nelson break; 12110af8e9dbSShannon Nelson case I40E_NVM_EXEC: 12120af8e9dbSShannon Nelson if (module == 0xf) 12130af8e9dbSShannon Nelson upd_cmd = I40E_NVMUPD_STATUS; 1214b72dc7b1SShannon Nelson else if (module == 0) 1215b72dc7b1SShannon Nelson upd_cmd = I40E_NVMUPD_GET_AQ_RESULT; 12160af8e9dbSShannon Nelson break; 1217e3a5d6e6SPawel Jablonski case I40E_NVM_AQE: 1218e3a5d6e6SPawel Jablonski upd_cmd = I40E_NVMUPD_GET_AQ_EVENT; 1219e3a5d6e6SPawel Jablonski break; 1220cd552cb4SShannon Nelson } 1221cd552cb4SShannon Nelson break; 1222cd552cb4SShannon Nelson 1223cd552cb4SShannon Nelson case I40E_NVM_WRITE: 1224cd552cb4SShannon Nelson switch (transaction) { 1225cd552cb4SShannon Nelson case I40E_NVM_CON: 1226cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_CON; 1227cd552cb4SShannon Nelson break; 1228cd552cb4SShannon Nelson case I40E_NVM_SNT: 1229cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_SNT; 1230cd552cb4SShannon Nelson break; 1231cd552cb4SShannon Nelson case I40E_NVM_LCB: 1232cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_LCB; 1233cd552cb4SShannon Nelson break; 1234cd552cb4SShannon Nelson case I40E_NVM_SA: 1235cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_SA; 1236cd552cb4SShannon Nelson break; 1237cd552cb4SShannon Nelson case I40E_NVM_ERA: 1238cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_WRITE_ERA; 1239cd552cb4SShannon Nelson break; 1240cd552cb4SShannon Nelson case I40E_NVM_CSUM: 1241cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_CSUM_CON; 1242cd552cb4SShannon Nelson break; 1243cd552cb4SShannon Nelson case (I40E_NVM_CSUM|I40E_NVM_SA): 1244cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_CSUM_SA; 1245cd552cb4SShannon Nelson break; 1246cd552cb4SShannon Nelson case (I40E_NVM_CSUM|I40E_NVM_LCB): 1247cd552cb4SShannon Nelson upd_cmd = I40E_NVMUPD_CSUM_LCB; 1248cd552cb4SShannon Nelson break; 1249e4c83c20SShannon Nelson case I40E_NVM_EXEC: 1250e4c83c20SShannon Nelson if (module == 0) 1251e4c83c20SShannon Nelson upd_cmd = I40E_NVMUPD_EXEC_AQ; 1252e4c83c20SShannon Nelson break; 1253cd552cb4SShannon Nelson } 1254cd552cb4SShannon Nelson break; 1255cd552cb4SShannon Nelson } 1256cd552cb4SShannon Nelson 1257cd552cb4SShannon Nelson return upd_cmd; 1258cd552cb4SShannon Nelson } 1259cd552cb4SShannon Nelson 1260cd552cb4SShannon Nelson /** 1261e4c83c20SShannon Nelson * i40e_nvmupd_exec_aq - Run an AQ command 1262e4c83c20SShannon Nelson * @hw: pointer to hardware structure 1263e4c83c20SShannon Nelson * @cmd: pointer to nvm update command buffer 1264e4c83c20SShannon Nelson * @bytes: pointer to the data buffer 1265e4c83c20SShannon Nelson * @perrno: pointer to return error code 1266e4c83c20SShannon Nelson * 1267e4c83c20SShannon Nelson * cmd structure contains identifiers and data buffer 1268e4c83c20SShannon Nelson **/ 1269e4c83c20SShannon Nelson static i40e_status i40e_nvmupd_exec_aq(struct i40e_hw *hw, 1270e4c83c20SShannon Nelson struct i40e_nvm_access *cmd, 1271e4c83c20SShannon Nelson u8 *bytes, int *perrno) 1272e4c83c20SShannon Nelson { 1273e4c83c20SShannon Nelson struct i40e_asq_cmd_details cmd_details; 1274e4c83c20SShannon Nelson i40e_status status; 1275e4c83c20SShannon Nelson struct i40e_aq_desc *aq_desc; 1276e4c83c20SShannon Nelson u32 buff_size = 0; 1277e4c83c20SShannon Nelson u8 *buff = NULL; 1278e4c83c20SShannon Nelson u32 aq_desc_len; 1279e4c83c20SShannon Nelson u32 aq_data_len; 1280e4c83c20SShannon Nelson 1281e4c83c20SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__); 1282e3a5d6e6SPawel Jablonski if (cmd->offset == 0xffff) 1283e3a5d6e6SPawel Jablonski return 0; 1284e3a5d6e6SPawel Jablonski 1285e4c83c20SShannon Nelson memset(&cmd_details, 0, sizeof(cmd_details)); 1286e4c83c20SShannon Nelson cmd_details.wb_desc = &hw->nvm_wb_desc; 1287e4c83c20SShannon Nelson 1288e4c83c20SShannon Nelson aq_desc_len = sizeof(struct i40e_aq_desc); 1289e4c83c20SShannon Nelson memset(&hw->nvm_wb_desc, 0, aq_desc_len); 1290e4c83c20SShannon Nelson 1291e4c83c20SShannon Nelson /* get the aq descriptor */ 1292e4c83c20SShannon Nelson if (cmd->data_size < aq_desc_len) { 1293e4c83c20SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 1294e4c83c20SShannon Nelson "NVMUPD: not enough aq desc bytes for exec, size %d < %d\n", 1295e4c83c20SShannon Nelson cmd->data_size, aq_desc_len); 1296e4c83c20SShannon Nelson *perrno = -EINVAL; 1297e4c83c20SShannon Nelson return I40E_ERR_PARAM; 1298e4c83c20SShannon Nelson } 1299e4c83c20SShannon Nelson aq_desc = (struct i40e_aq_desc *)bytes; 1300e4c83c20SShannon Nelson 1301e4c83c20SShannon Nelson /* if data buffer needed, make sure it's ready */ 1302e4c83c20SShannon Nelson aq_data_len = cmd->data_size - aq_desc_len; 1303e4c83c20SShannon Nelson buff_size = max_t(u32, aq_data_len, le16_to_cpu(aq_desc->datalen)); 1304e4c83c20SShannon Nelson if (buff_size) { 1305e4c83c20SShannon Nelson if (!hw->nvm_buff.va) { 1306e4c83c20SShannon Nelson status = i40e_allocate_virt_mem(hw, &hw->nvm_buff, 1307e4c83c20SShannon Nelson hw->aq.asq_buf_size); 1308e4c83c20SShannon Nelson if (status) 1309e4c83c20SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 1310e4c83c20SShannon Nelson "NVMUPD: i40e_allocate_virt_mem for exec buff failed, %d\n", 1311e4c83c20SShannon Nelson status); 1312e4c83c20SShannon Nelson } 1313e4c83c20SShannon Nelson 1314e4c83c20SShannon Nelson if (hw->nvm_buff.va) { 1315e4c83c20SShannon Nelson buff = hw->nvm_buff.va; 1316e4c83c20SShannon Nelson memcpy(buff, &bytes[aq_desc_len], aq_data_len); 1317e4c83c20SShannon Nelson } 1318e4c83c20SShannon Nelson } 1319e4c83c20SShannon Nelson 1320e3a5d6e6SPawel Jablonski if (cmd->offset) 1321e3a5d6e6SPawel Jablonski memset(&hw->nvm_aq_event_desc, 0, aq_desc_len); 1322e3a5d6e6SPawel Jablonski 1323e4c83c20SShannon Nelson /* and away we go! */ 1324e4c83c20SShannon Nelson status = i40e_asq_send_command(hw, aq_desc, buff, 1325e4c83c20SShannon Nelson buff_size, &cmd_details); 1326e4c83c20SShannon Nelson if (status) { 1327e4c83c20SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 1328e4c83c20SShannon Nelson "i40e_nvmupd_exec_aq err %s aq_err %s\n", 1329e4c83c20SShannon Nelson i40e_stat_str(hw, status), 1330e4c83c20SShannon Nelson i40e_aq_str(hw, hw->aq.asq_last_status)); 1331e4c83c20SShannon Nelson *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status); 1332e3a5d6e6SPawel Jablonski return status; 1333e4c83c20SShannon Nelson } 1334e4c83c20SShannon Nelson 1335fed2db99SShannon Nelson /* should we wait for a followup event? */ 1336fed2db99SShannon Nelson if (cmd->offset) { 1337fed2db99SShannon Nelson hw->nvm_wait_opcode = cmd->offset; 1338fed2db99SShannon Nelson hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT; 1339fed2db99SShannon Nelson } 1340fed2db99SShannon Nelson 1341e4c83c20SShannon Nelson return status; 1342e4c83c20SShannon Nelson } 1343e4c83c20SShannon Nelson 1344e4c83c20SShannon Nelson /** 1345b72dc7b1SShannon Nelson * i40e_nvmupd_get_aq_result - Get the results from the previous exec_aq 1346b72dc7b1SShannon Nelson * @hw: pointer to hardware structure 1347b72dc7b1SShannon Nelson * @cmd: pointer to nvm update command buffer 1348b72dc7b1SShannon Nelson * @bytes: pointer to the data buffer 1349b72dc7b1SShannon Nelson * @perrno: pointer to return error code 1350b72dc7b1SShannon Nelson * 1351b72dc7b1SShannon Nelson * cmd structure contains identifiers and data buffer 1352b72dc7b1SShannon Nelson **/ 1353b72dc7b1SShannon Nelson static i40e_status i40e_nvmupd_get_aq_result(struct i40e_hw *hw, 1354b72dc7b1SShannon Nelson struct i40e_nvm_access *cmd, 1355b72dc7b1SShannon Nelson u8 *bytes, int *perrno) 1356b72dc7b1SShannon Nelson { 1357b72dc7b1SShannon Nelson u32 aq_total_len; 1358b72dc7b1SShannon Nelson u32 aq_desc_len; 1359b72dc7b1SShannon Nelson int remainder; 1360b72dc7b1SShannon Nelson u8 *buff; 1361b72dc7b1SShannon Nelson 1362b72dc7b1SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__); 1363b72dc7b1SShannon Nelson 1364b72dc7b1SShannon Nelson aq_desc_len = sizeof(struct i40e_aq_desc); 1365b72dc7b1SShannon Nelson aq_total_len = aq_desc_len + le16_to_cpu(hw->nvm_wb_desc.datalen); 1366b72dc7b1SShannon Nelson 1367b72dc7b1SShannon Nelson /* check offset range */ 1368b72dc7b1SShannon Nelson if (cmd->offset > aq_total_len) { 1369b72dc7b1SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "%s: offset too big %d > %d\n", 1370b72dc7b1SShannon Nelson __func__, cmd->offset, aq_total_len); 1371b72dc7b1SShannon Nelson *perrno = -EINVAL; 1372b72dc7b1SShannon Nelson return I40E_ERR_PARAM; 1373b72dc7b1SShannon Nelson } 1374b72dc7b1SShannon Nelson 1375b72dc7b1SShannon Nelson /* check copylength range */ 1376b72dc7b1SShannon Nelson if (cmd->data_size > (aq_total_len - cmd->offset)) { 1377b72dc7b1SShannon Nelson int new_len = aq_total_len - cmd->offset; 1378b72dc7b1SShannon Nelson 1379b72dc7b1SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "%s: copy length %d too big, trimming to %d\n", 1380b72dc7b1SShannon Nelson __func__, cmd->data_size, new_len); 1381b72dc7b1SShannon Nelson cmd->data_size = new_len; 1382b72dc7b1SShannon Nelson } 1383b72dc7b1SShannon Nelson 1384b72dc7b1SShannon Nelson remainder = cmd->data_size; 1385b72dc7b1SShannon Nelson if (cmd->offset < aq_desc_len) { 1386b72dc7b1SShannon Nelson u32 len = aq_desc_len - cmd->offset; 1387b72dc7b1SShannon Nelson 1388b72dc7b1SShannon Nelson len = min(len, cmd->data_size); 1389b72dc7b1SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "%s: aq_desc bytes %d to %d\n", 1390b72dc7b1SShannon Nelson __func__, cmd->offset, cmd->offset + len); 1391b72dc7b1SShannon Nelson 1392b72dc7b1SShannon Nelson buff = ((u8 *)&hw->nvm_wb_desc) + cmd->offset; 1393b72dc7b1SShannon Nelson memcpy(bytes, buff, len); 1394b72dc7b1SShannon Nelson 1395b72dc7b1SShannon Nelson bytes += len; 1396b72dc7b1SShannon Nelson remainder -= len; 1397b72dc7b1SShannon Nelson buff = hw->nvm_buff.va; 1398b72dc7b1SShannon Nelson } else { 1399b72dc7b1SShannon Nelson buff = hw->nvm_buff.va + (cmd->offset - aq_desc_len); 1400b72dc7b1SShannon Nelson } 1401b72dc7b1SShannon Nelson 1402b72dc7b1SShannon Nelson if (remainder > 0) { 1403b72dc7b1SShannon Nelson int start_byte = buff - (u8 *)hw->nvm_buff.va; 1404b72dc7b1SShannon Nelson 1405b72dc7b1SShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, "%s: databuf bytes %d to %d\n", 1406b72dc7b1SShannon Nelson __func__, start_byte, start_byte + remainder); 1407b72dc7b1SShannon Nelson memcpy(bytes, buff, remainder); 1408b72dc7b1SShannon Nelson } 1409b72dc7b1SShannon Nelson 1410b72dc7b1SShannon Nelson return 0; 1411b72dc7b1SShannon Nelson } 1412b72dc7b1SShannon Nelson 1413b72dc7b1SShannon Nelson /** 1414e3a5d6e6SPawel Jablonski * i40e_nvmupd_get_aq_event - Get the Admin Queue event from previous exec_aq 1415e3a5d6e6SPawel Jablonski * @hw: pointer to hardware structure 1416e3a5d6e6SPawel Jablonski * @cmd: pointer to nvm update command buffer 1417e3a5d6e6SPawel Jablonski * @bytes: pointer to the data buffer 1418e3a5d6e6SPawel Jablonski * @perrno: pointer to return error code 1419e3a5d6e6SPawel Jablonski * 1420e3a5d6e6SPawel Jablonski * cmd structure contains identifiers and data buffer 1421e3a5d6e6SPawel Jablonski **/ 1422e3a5d6e6SPawel Jablonski static i40e_status i40e_nvmupd_get_aq_event(struct i40e_hw *hw, 1423e3a5d6e6SPawel Jablonski struct i40e_nvm_access *cmd, 1424e3a5d6e6SPawel Jablonski u8 *bytes, int *perrno) 1425e3a5d6e6SPawel Jablonski { 1426e3a5d6e6SPawel Jablonski u32 aq_total_len; 1427e3a5d6e6SPawel Jablonski u32 aq_desc_len; 1428e3a5d6e6SPawel Jablonski 1429e3a5d6e6SPawel Jablonski i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__); 1430e3a5d6e6SPawel Jablonski 1431e3a5d6e6SPawel Jablonski aq_desc_len = sizeof(struct i40e_aq_desc); 1432e3a5d6e6SPawel Jablonski aq_total_len = aq_desc_len + le16_to_cpu(hw->nvm_aq_event_desc.datalen); 1433e3a5d6e6SPawel Jablonski 1434e3a5d6e6SPawel Jablonski /* check copylength range */ 1435e3a5d6e6SPawel Jablonski if (cmd->data_size > aq_total_len) { 1436e3a5d6e6SPawel Jablonski i40e_debug(hw, I40E_DEBUG_NVM, 1437e3a5d6e6SPawel Jablonski "%s: copy length %d too big, trimming to %d\n", 1438e3a5d6e6SPawel Jablonski __func__, cmd->data_size, aq_total_len); 1439e3a5d6e6SPawel Jablonski cmd->data_size = aq_total_len; 1440e3a5d6e6SPawel Jablonski } 1441e3a5d6e6SPawel Jablonski 1442e3a5d6e6SPawel Jablonski memcpy(bytes, &hw->nvm_aq_event_desc, cmd->data_size); 1443e3a5d6e6SPawel Jablonski 1444e3a5d6e6SPawel Jablonski return 0; 1445e3a5d6e6SPawel Jablonski } 1446e3a5d6e6SPawel Jablonski 1447e3a5d6e6SPawel Jablonski /** 1448cd552cb4SShannon Nelson * i40e_nvmupd_nvm_read - Read NVM 1449cd552cb4SShannon Nelson * @hw: pointer to hardware structure 1450cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 1451cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 145279afe839SShannon Nelson * @perrno: pointer to return error code 1453cd552cb4SShannon Nelson * 1454cd552cb4SShannon Nelson * cmd structure contains identifiers and data buffer 1455cd552cb4SShannon Nelson **/ 1456cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw, 1457cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 145879afe839SShannon Nelson u8 *bytes, int *perrno) 1459cd552cb4SShannon Nelson { 14606b5c1b89SShannon Nelson struct i40e_asq_cmd_details cmd_details; 1461cd552cb4SShannon Nelson i40e_status status; 1462cd552cb4SShannon Nelson u8 module, transaction; 1463cd552cb4SShannon Nelson bool last; 1464cd552cb4SShannon Nelson 1465cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 1466cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 1467cd552cb4SShannon Nelson last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA); 1468cd552cb4SShannon Nelson 14696b5c1b89SShannon Nelson memset(&cmd_details, 0, sizeof(cmd_details)); 14706b5c1b89SShannon Nelson cmd_details.wb_desc = &hw->nvm_wb_desc; 14716b5c1b89SShannon Nelson 1472cd552cb4SShannon Nelson status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size, 14736b5c1b89SShannon Nelson bytes, last, &cmd_details); 147474d0d0edSShannon Nelson if (status) { 147574d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 147674d0d0edSShannon Nelson "i40e_nvmupd_nvm_read mod 0x%x off 0x%x len 0x%x\n", 147774d0d0edSShannon Nelson module, cmd->offset, cmd->data_size); 147874d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 147974d0d0edSShannon Nelson "i40e_nvmupd_nvm_read status %d aq %d\n", 148074d0d0edSShannon Nelson status, hw->aq.asq_last_status); 148179afe839SShannon Nelson *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status); 148274d0d0edSShannon Nelson } 1483cd552cb4SShannon Nelson 1484cd552cb4SShannon Nelson return status; 1485cd552cb4SShannon Nelson } 1486cd552cb4SShannon Nelson 1487cd552cb4SShannon Nelson /** 1488cd552cb4SShannon Nelson * i40e_nvmupd_nvm_erase - Erase an NVM module 1489cd552cb4SShannon Nelson * @hw: pointer to hardware structure 1490cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 149179afe839SShannon Nelson * @perrno: pointer to return error code 1492cd552cb4SShannon Nelson * 1493cd552cb4SShannon Nelson * module, offset, data_size and data are in cmd structure 1494cd552cb4SShannon Nelson **/ 1495cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw, 1496cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 149779afe839SShannon Nelson int *perrno) 1498cd552cb4SShannon Nelson { 1499cd552cb4SShannon Nelson i40e_status status = 0; 15006b5c1b89SShannon Nelson struct i40e_asq_cmd_details cmd_details; 1501cd552cb4SShannon Nelson u8 module, transaction; 1502cd552cb4SShannon Nelson bool last; 1503cd552cb4SShannon Nelson 1504cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 1505cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 1506cd552cb4SShannon Nelson last = (transaction & I40E_NVM_LCB); 15076b5c1b89SShannon Nelson 15086b5c1b89SShannon Nelson memset(&cmd_details, 0, sizeof(cmd_details)); 15096b5c1b89SShannon Nelson cmd_details.wb_desc = &hw->nvm_wb_desc; 15106b5c1b89SShannon Nelson 1511cd552cb4SShannon Nelson status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size, 15126b5c1b89SShannon Nelson last, &cmd_details); 151374d0d0edSShannon Nelson if (status) { 151474d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 151574d0d0edSShannon Nelson "i40e_nvmupd_nvm_erase mod 0x%x off 0x%x len 0x%x\n", 151674d0d0edSShannon Nelson module, cmd->offset, cmd->data_size); 151774d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 151874d0d0edSShannon Nelson "i40e_nvmupd_nvm_erase status %d aq %d\n", 151974d0d0edSShannon Nelson status, hw->aq.asq_last_status); 152079afe839SShannon Nelson *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status); 152174d0d0edSShannon Nelson } 1522cd552cb4SShannon Nelson 1523cd552cb4SShannon Nelson return status; 1524cd552cb4SShannon Nelson } 1525cd552cb4SShannon Nelson 1526cd552cb4SShannon Nelson /** 1527cd552cb4SShannon Nelson * i40e_nvmupd_nvm_write - Write NVM 1528cd552cb4SShannon Nelson * @hw: pointer to hardware structure 1529cd552cb4SShannon Nelson * @cmd: pointer to nvm update command buffer 1530cd552cb4SShannon Nelson * @bytes: pointer to the data buffer 153179afe839SShannon Nelson * @perrno: pointer to return error code 1532cd552cb4SShannon Nelson * 1533cd552cb4SShannon Nelson * module, offset, data_size and data are in cmd structure 1534cd552cb4SShannon Nelson **/ 1535cd552cb4SShannon Nelson static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw, 1536cd552cb4SShannon Nelson struct i40e_nvm_access *cmd, 153779afe839SShannon Nelson u8 *bytes, int *perrno) 1538cd552cb4SShannon Nelson { 1539cd552cb4SShannon Nelson i40e_status status = 0; 15406b5c1b89SShannon Nelson struct i40e_asq_cmd_details cmd_details; 1541cd552cb4SShannon Nelson u8 module, transaction; 1542e3a5d6e6SPawel Jablonski u8 preservation_flags; 1543cd552cb4SShannon Nelson bool last; 1544cd552cb4SShannon Nelson 1545cd552cb4SShannon Nelson transaction = i40e_nvmupd_get_transaction(cmd->config); 1546cd552cb4SShannon Nelson module = i40e_nvmupd_get_module(cmd->config); 1547cd552cb4SShannon Nelson last = (transaction & I40E_NVM_LCB); 1548e3a5d6e6SPawel Jablonski preservation_flags = i40e_nvmupd_get_preservation_flags(cmd->config); 154974d0d0edSShannon Nelson 15506b5c1b89SShannon Nelson memset(&cmd_details, 0, sizeof(cmd_details)); 15516b5c1b89SShannon Nelson cmd_details.wb_desc = &hw->nvm_wb_desc; 15526b5c1b89SShannon Nelson 1553cd552cb4SShannon Nelson status = i40e_aq_update_nvm(hw, module, cmd->offset, 15546b5c1b89SShannon Nelson (u16)cmd->data_size, bytes, last, 1555e3a5d6e6SPawel Jablonski preservation_flags, &cmd_details); 155674d0d0edSShannon Nelson if (status) { 155774d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 155874d0d0edSShannon Nelson "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n", 155974d0d0edSShannon Nelson module, cmd->offset, cmd->data_size); 156074d0d0edSShannon Nelson i40e_debug(hw, I40E_DEBUG_NVM, 156174d0d0edSShannon Nelson "i40e_nvmupd_nvm_write status %d aq %d\n", 156274d0d0edSShannon Nelson status, hw->aq.asq_last_status); 156379afe839SShannon Nelson *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status); 156474d0d0edSShannon Nelson } 1565cd552cb4SShannon Nelson 1566cd552cb4SShannon Nelson return status; 1567cd552cb4SShannon Nelson } 1568