19d26e4fcSRobert Mustacchi /******************************************************************************
29d26e4fcSRobert Mustacchi 
3*df36e06dSRobert Mustacchi   Copyright (c) 2013-2018, Intel Corporation
49d26e4fcSRobert Mustacchi   All rights reserved.
59d26e4fcSRobert Mustacchi 
69d26e4fcSRobert Mustacchi   Redistribution and use in source and binary forms, with or without
79d26e4fcSRobert Mustacchi   modification, are permitted provided that the following conditions are met:
89d26e4fcSRobert Mustacchi 
99d26e4fcSRobert Mustacchi    1. Redistributions of source code must retain the above copyright notice,
109d26e4fcSRobert Mustacchi       this list of conditions and the following disclaimer.
119d26e4fcSRobert Mustacchi 
129d26e4fcSRobert Mustacchi    2. Redistributions in binary form must reproduce the above copyright
139d26e4fcSRobert Mustacchi       notice, this list of conditions and the following disclaimer in the
149d26e4fcSRobert Mustacchi       documentation and/or other materials provided with the distribution.
159d26e4fcSRobert Mustacchi 
169d26e4fcSRobert Mustacchi    3. Neither the name of the Intel Corporation nor the names of its
179d26e4fcSRobert Mustacchi       contributors may be used to endorse or promote products derived from
189d26e4fcSRobert Mustacchi       this software without specific prior written permission.
199d26e4fcSRobert Mustacchi 
209d26e4fcSRobert Mustacchi   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
219d26e4fcSRobert Mustacchi   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229d26e4fcSRobert Mustacchi   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239d26e4fcSRobert Mustacchi   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
249d26e4fcSRobert Mustacchi   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
259d26e4fcSRobert Mustacchi   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
269d26e4fcSRobert Mustacchi   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
279d26e4fcSRobert Mustacchi   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
289d26e4fcSRobert Mustacchi   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
299d26e4fcSRobert Mustacchi   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
309d26e4fcSRobert Mustacchi   POSSIBILITY OF SUCH DAMAGE.
319d26e4fcSRobert Mustacchi 
329d26e4fcSRobert Mustacchi ******************************************************************************/
333d75a287SRobert Mustacchi /*$FreeBSD$*/
349d26e4fcSRobert Mustacchi 
359d26e4fcSRobert Mustacchi #include "i40e_prototype.h"
369d26e4fcSRobert Mustacchi 
379d26e4fcSRobert Mustacchi /**
389d26e4fcSRobert Mustacchi  * i40e_init_nvm_ops - Initialize NVM function pointers
399d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
409d26e4fcSRobert Mustacchi  *
419d26e4fcSRobert Mustacchi  * Setup the function pointers and the NVM info structure. Should be called
429d26e4fcSRobert Mustacchi  * once per NVM initialization, e.g. inside the i40e_init_shared_code().
439d26e4fcSRobert Mustacchi  * Please notice that the NVM term is used here (& in all methods covered
449d26e4fcSRobert Mustacchi  * in this file) as an equivalent of the FLASH part mapped into the SR.
453d75a287SRobert Mustacchi  * We are accessing FLASH always through the Shadow RAM.
469d26e4fcSRobert Mustacchi  **/
i40e_init_nvm(struct i40e_hw * hw)479d26e4fcSRobert Mustacchi enum i40e_status_code i40e_init_nvm(struct i40e_hw *hw)
489d26e4fcSRobert Mustacchi {
499d26e4fcSRobert Mustacchi 	struct i40e_nvm_info *nvm = &hw->nvm;
509d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_SUCCESS;
519d26e4fcSRobert Mustacchi 	u32 fla, gens;
529d26e4fcSRobert Mustacchi 	u8 sr_size;
539d26e4fcSRobert Mustacchi 
549d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_init_nvm");
559d26e4fcSRobert Mustacchi 
569d26e4fcSRobert Mustacchi 	/* The SR size is stored regardless of the nvm programming mode
579d26e4fcSRobert Mustacchi 	 * as the blank mode may be used in the factory line.
589d26e4fcSRobert Mustacchi 	 */
599d26e4fcSRobert Mustacchi 	gens = rd32(hw, I40E_GLNVM_GENS);
609d26e4fcSRobert Mustacchi 	sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
619d26e4fcSRobert Mustacchi 			   I40E_GLNVM_GENS_SR_SIZE_SHIFT);
629d26e4fcSRobert Mustacchi 	/* Switching to words (sr_size contains power of 2KB) */
639d26e4fcSRobert Mustacchi 	nvm->sr_size = BIT(sr_size) * I40E_SR_WORDS_IN_1KB;
649d26e4fcSRobert Mustacchi 
659d26e4fcSRobert Mustacchi 	/* Check if we are in the normal or blank NVM programming mode */
669d26e4fcSRobert Mustacchi 	fla = rd32(hw, I40E_GLNVM_FLA);
679d26e4fcSRobert Mustacchi 	if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
689d26e4fcSRobert Mustacchi 		/* Max NVM timeout */
699d26e4fcSRobert Mustacchi 		nvm->timeout = I40E_MAX_NVM_TIMEOUT;
709d26e4fcSRobert Mustacchi 		nvm->blank_nvm_mode = FALSE;
719d26e4fcSRobert Mustacchi 	} else { /* Blank programming mode */
729d26e4fcSRobert Mustacchi 		nvm->blank_nvm_mode = TRUE;
739d26e4fcSRobert Mustacchi 		ret_code = I40E_ERR_NVM_BLANK_MODE;
749d26e4fcSRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM, "NVM init error: unsupported blank mode.\n");
759d26e4fcSRobert Mustacchi 	}
769d26e4fcSRobert Mustacchi 
779d26e4fcSRobert Mustacchi 	return ret_code;
789d26e4fcSRobert Mustacchi }
799d26e4fcSRobert Mustacchi 
809d26e4fcSRobert Mustacchi /**
819d26e4fcSRobert Mustacchi  * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
829d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
839d26e4fcSRobert Mustacchi  * @access: NVM access type (read or write)
849d26e4fcSRobert Mustacchi  *
859d26e4fcSRobert Mustacchi  * This function will request NVM ownership for reading
869d26e4fcSRobert Mustacchi  * via the proper Admin Command.
879d26e4fcSRobert Mustacchi  **/
i40e_acquire_nvm(struct i40e_hw * hw,enum i40e_aq_resource_access_type access)889d26e4fcSRobert Mustacchi enum i40e_status_code i40e_acquire_nvm(struct i40e_hw *hw,
899d26e4fcSRobert Mustacchi 				       enum i40e_aq_resource_access_type access)
909d26e4fcSRobert Mustacchi {
919d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_SUCCESS;
929d26e4fcSRobert Mustacchi 	u64 gtime, timeout;
939d26e4fcSRobert Mustacchi 	u64 time_left = 0;
949d26e4fcSRobert Mustacchi 
959d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_acquire_nvm");
969d26e4fcSRobert Mustacchi 
979d26e4fcSRobert Mustacchi 	if (hw->nvm.blank_nvm_mode)
989d26e4fcSRobert Mustacchi 		goto i40e_i40e_acquire_nvm_exit;
999d26e4fcSRobert Mustacchi 
1009d26e4fcSRobert Mustacchi 	ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
1019d26e4fcSRobert Mustacchi 					    0, &time_left, NULL);
1029d26e4fcSRobert Mustacchi 	/* Reading the Global Device Timer */
1039d26e4fcSRobert Mustacchi 	gtime = rd32(hw, I40E_GLVFGEN_TIMER);
1049d26e4fcSRobert Mustacchi 
1059d26e4fcSRobert Mustacchi 	/* Store the timeout */
1069d26e4fcSRobert Mustacchi 	hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime;
1079d26e4fcSRobert Mustacchi 
1089d26e4fcSRobert Mustacchi 	if (ret_code)
1099d26e4fcSRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
1109d26e4fcSRobert Mustacchi 			   "NVM acquire type %d failed time_left=%llu ret=%d aq_err=%d\n",
1119d26e4fcSRobert Mustacchi 			   access, time_left, ret_code, hw->aq.asq_last_status);
1129d26e4fcSRobert Mustacchi 
1139d26e4fcSRobert Mustacchi 	if (ret_code && time_left) {
1149d26e4fcSRobert Mustacchi 		/* Poll until the current NVM owner timeouts */
1159d26e4fcSRobert Mustacchi 		timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime;
1169d26e4fcSRobert Mustacchi 		while ((gtime < timeout) && time_left) {
1179d26e4fcSRobert Mustacchi 			i40e_msec_delay(10);
1189d26e4fcSRobert Mustacchi 			gtime = rd32(hw, I40E_GLVFGEN_TIMER);
1199d26e4fcSRobert Mustacchi 			ret_code = i40e_aq_request_resource(hw,
1209d26e4fcSRobert Mustacchi 							I40E_NVM_RESOURCE_ID,
1219d26e4fcSRobert Mustacchi 							access, 0, &time_left,
1229d26e4fcSRobert Mustacchi 							NULL);
1239d26e4fcSRobert Mustacchi 			if (ret_code == I40E_SUCCESS) {
1249d26e4fcSRobert Mustacchi 				hw->nvm.hw_semaphore_timeout =
1259d26e4fcSRobert Mustacchi 					    I40E_MS_TO_GTIME(time_left) + gtime;
1269d26e4fcSRobert Mustacchi 				break;
1279d26e4fcSRobert Mustacchi 			}
1289d26e4fcSRobert Mustacchi 		}
1299d26e4fcSRobert Mustacchi 		if (ret_code != I40E_SUCCESS) {
1309d26e4fcSRobert Mustacchi 			hw->nvm.hw_semaphore_timeout = 0;
1319d26e4fcSRobert Mustacchi 			i40e_debug(hw, I40E_DEBUG_NVM,
1329d26e4fcSRobert Mustacchi 				   "NVM acquire timed out, wait %llu ms before trying again. status=%d aq_err=%d\n",
1339d26e4fcSRobert Mustacchi 				   time_left, ret_code, hw->aq.asq_last_status);
1349d26e4fcSRobert Mustacchi 		}
1359d26e4fcSRobert Mustacchi 	}
1369d26e4fcSRobert Mustacchi 
1379d26e4fcSRobert Mustacchi i40e_i40e_acquire_nvm_exit:
1389d26e4fcSRobert Mustacchi 	return ret_code;
1399d26e4fcSRobert Mustacchi }
1409d26e4fcSRobert Mustacchi 
1419d26e4fcSRobert Mustacchi /**
1429d26e4fcSRobert Mustacchi  * i40e_release_nvm - Generic request for releasing the NVM ownership
1439d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
1449d26e4fcSRobert Mustacchi  *
1459d26e4fcSRobert Mustacchi  * This function will release NVM resource via the proper Admin Command.
1469d26e4fcSRobert Mustacchi  **/
i40e_release_nvm(struct i40e_hw * hw)1479d26e4fcSRobert Mustacchi void i40e_release_nvm(struct i40e_hw *hw)
1489d26e4fcSRobert Mustacchi {
1499d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_SUCCESS;
1509d26e4fcSRobert Mustacchi 	u32 total_delay = 0;
1519d26e4fcSRobert Mustacchi 
1529d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_release_nvm");
1539d26e4fcSRobert Mustacchi 
1549d26e4fcSRobert Mustacchi 	if (hw->nvm.blank_nvm_mode)
1559d26e4fcSRobert Mustacchi 		return;
1569d26e4fcSRobert Mustacchi 
1579d26e4fcSRobert Mustacchi 	ret_code = i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
1589d26e4fcSRobert Mustacchi 
1599d26e4fcSRobert Mustacchi 	/* there are some rare cases when trying to release the resource
1609d26e4fcSRobert Mustacchi 	 * results in an admin Q timeout, so handle them correctly
1619d26e4fcSRobert Mustacchi 	 */
1629d26e4fcSRobert Mustacchi 	while ((ret_code == I40E_ERR_ADMIN_QUEUE_TIMEOUT) &&
1639d26e4fcSRobert Mustacchi 	       (total_delay < hw->aq.asq_cmd_timeout)) {
1649d26e4fcSRobert Mustacchi 			i40e_msec_delay(1);
1659d26e4fcSRobert Mustacchi 			ret_code = i40e_aq_release_resource(hw,
1669d26e4fcSRobert Mustacchi 						I40E_NVM_RESOURCE_ID, 0, NULL);
1679d26e4fcSRobert Mustacchi 			total_delay++;
1689d26e4fcSRobert Mustacchi 	}
1699d26e4fcSRobert Mustacchi }
1709d26e4fcSRobert Mustacchi 
1719d26e4fcSRobert Mustacchi /**
1729d26e4fcSRobert Mustacchi  * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
1739d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
1749d26e4fcSRobert Mustacchi  *
1759d26e4fcSRobert Mustacchi  * Polls the SRCTL Shadow RAM register done bit.
1769d26e4fcSRobert Mustacchi  **/
i40e_poll_sr_srctl_done_bit(struct i40e_hw * hw)1779d26e4fcSRobert Mustacchi static enum i40e_status_code i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
1789d26e4fcSRobert Mustacchi {
1799d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
1809d26e4fcSRobert Mustacchi 	u32 srctl, wait_cnt;
1819d26e4fcSRobert Mustacchi 
1829d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_poll_sr_srctl_done_bit");
1839d26e4fcSRobert Mustacchi 
1849d26e4fcSRobert Mustacchi 	/* Poll the I40E_GLNVM_SRCTL until the done bit is set */
1859d26e4fcSRobert Mustacchi 	for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
1869d26e4fcSRobert Mustacchi 		srctl = rd32(hw, I40E_GLNVM_SRCTL);
1879d26e4fcSRobert Mustacchi 		if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
1889d26e4fcSRobert Mustacchi 			ret_code = I40E_SUCCESS;
1899d26e4fcSRobert Mustacchi 			break;
1909d26e4fcSRobert Mustacchi 		}
1919d26e4fcSRobert Mustacchi 		i40e_usec_delay(5);
1929d26e4fcSRobert Mustacchi 	}
1939d26e4fcSRobert Mustacchi 	if (ret_code == I40E_ERR_TIMEOUT)
1949d26e4fcSRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set");
1959d26e4fcSRobert Mustacchi 	return ret_code;
1969d26e4fcSRobert Mustacchi }
1979d26e4fcSRobert Mustacchi 
1989d26e4fcSRobert Mustacchi /**
1999d26e4fcSRobert Mustacchi  * i40e_read_nvm_word_srctl - Reads Shadow RAM via SRCTL register
2009d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
2019d26e4fcSRobert Mustacchi  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
2029d26e4fcSRobert Mustacchi  * @data: word read from the Shadow RAM
2039d26e4fcSRobert Mustacchi  *
2049d26e4fcSRobert Mustacchi  * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
2059d26e4fcSRobert Mustacchi  **/
i40e_read_nvm_word_srctl(struct i40e_hw * hw,u16 offset,u16 * data)2069d26e4fcSRobert Mustacchi enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset,
2079d26e4fcSRobert Mustacchi 					       u16 *data)
2089d26e4fcSRobert Mustacchi {
2099d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
2109d26e4fcSRobert Mustacchi 	u32 sr_reg;
2119d26e4fcSRobert Mustacchi 
2129d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_read_nvm_word_srctl");
2139d26e4fcSRobert Mustacchi 
2149d26e4fcSRobert Mustacchi 	if (offset >= hw->nvm.sr_size) {
2159d26e4fcSRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
2169d26e4fcSRobert Mustacchi 			   "NVM read error: Offset %d beyond Shadow RAM limit %d\n",
2179d26e4fcSRobert Mustacchi 			   offset, hw->nvm.sr_size);
2189d26e4fcSRobert Mustacchi 		ret_code = I40E_ERR_PARAM;
2199d26e4fcSRobert Mustacchi 		goto read_nvm_exit;
2209d26e4fcSRobert Mustacchi 	}
2219d26e4fcSRobert Mustacchi 
2229d26e4fcSRobert Mustacchi 	/* Poll the done bit first */
2239d26e4fcSRobert Mustacchi 	ret_code = i40e_poll_sr_srctl_done_bit(hw);
2249d26e4fcSRobert Mustacchi 	if (ret_code == I40E_SUCCESS) {
2259d26e4fcSRobert Mustacchi 		/* Write the address and start reading */
2269d26e4fcSRobert Mustacchi 		sr_reg = ((u32)offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
2279d26e4fcSRobert Mustacchi 			 BIT(I40E_GLNVM_SRCTL_START_SHIFT);
2289d26e4fcSRobert Mustacchi 		wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
2299d26e4fcSRobert Mustacchi 
2309d26e4fcSRobert Mustacchi 		/* Poll I40E_GLNVM_SRCTL until the done bit is set */
2319d26e4fcSRobert Mustacchi 		ret_code = i40e_poll_sr_srctl_done_bit(hw);
2329d26e4fcSRobert Mustacchi 		if (ret_code == I40E_SUCCESS) {
2339d26e4fcSRobert Mustacchi 			sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
2349d26e4fcSRobert Mustacchi 			*data = (u16)((sr_reg &
2359d26e4fcSRobert Mustacchi 				       I40E_GLNVM_SRDATA_RDDATA_MASK)
2369d26e4fcSRobert Mustacchi 				    >> I40E_GLNVM_SRDATA_RDDATA_SHIFT);
2379d26e4fcSRobert Mustacchi 		}
2389d26e4fcSRobert Mustacchi 	}
2399d26e4fcSRobert Mustacchi 	if (ret_code != I40E_SUCCESS)
2409d26e4fcSRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
2419d26e4fcSRobert Mustacchi 			   "NVM read error: Couldn't access Shadow RAM address: 0x%x\n",
2429d26e4fcSRobert Mustacchi 			   offset);
2439d26e4fcSRobert Mustacchi 
2449d26e4fcSRobert Mustacchi read_nvm_exit:
2459d26e4fcSRobert Mustacchi 	return ret_code;
2469d26e4fcSRobert Mustacchi }
2479d26e4fcSRobert Mustacchi 
24893f1cac5SPaul Winder /**
24993f1cac5SPaul Winder  * i40e_read_nvm_aq - Read Shadow RAM.
25093f1cac5SPaul Winder  * @hw: pointer to the HW structure.
25193f1cac5SPaul Winder  * @module_pointer: module pointer location in words from the NVM beginning
25293f1cac5SPaul Winder  * @offset: offset in words from module start
25393f1cac5SPaul Winder  * @words: number of words to write
25493f1cac5SPaul Winder  * @data: buffer with words to write to the Shadow RAM
25593f1cac5SPaul Winder  * @last_command: tells the AdminQ that this is the last command
25693f1cac5SPaul Winder  *
25793f1cac5SPaul Winder  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
25893f1cac5SPaul Winder  **/
i40e_read_nvm_aq(struct i40e_hw * hw,u8 module_pointer,u32 offset,u16 words,void * data,bool last_command)25993f1cac5SPaul Winder static enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw,
26093f1cac5SPaul Winder 					      u8 module_pointer, u32 offset,
26193f1cac5SPaul Winder 					      u16 words, void *data,
26293f1cac5SPaul Winder 					      bool last_command)
26393f1cac5SPaul Winder {
26493f1cac5SPaul Winder 	enum i40e_status_code ret_code = I40E_ERR_NVM;
26593f1cac5SPaul Winder 	struct i40e_asq_cmd_details cmd_details;
26693f1cac5SPaul Winder 
26793f1cac5SPaul Winder 	DEBUGFUNC("i40e_read_nvm_aq");
26893f1cac5SPaul Winder 
26993f1cac5SPaul Winder 	memset(&cmd_details, 0, sizeof(cmd_details));
27093f1cac5SPaul Winder 	cmd_details.wb_desc = &hw->nvm_wb_desc;
27193f1cac5SPaul Winder 
27293f1cac5SPaul Winder 	/* Here we are checking the SR limit only for the flat memory model.
27393f1cac5SPaul Winder 	 * We cannot do it for the module-based model, as we did not acquire
27493f1cac5SPaul Winder 	 * the NVM resource yet (we cannot get the module pointer value).
27593f1cac5SPaul Winder 	 * Firmware will check the module-based model.
27693f1cac5SPaul Winder 	 */
27793f1cac5SPaul Winder 	if ((offset + words) > hw->nvm.sr_size)
27893f1cac5SPaul Winder 		i40e_debug(hw, I40E_DEBUG_NVM,
27993f1cac5SPaul Winder 			   "NVM write error: offset %d beyond Shadow RAM limit %d\n",
28093f1cac5SPaul Winder 			   (offset + words), hw->nvm.sr_size);
28193f1cac5SPaul Winder 	else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
28293f1cac5SPaul Winder 		/* We can write only up to 4KB (one sector), in one AQ write */
28393f1cac5SPaul Winder 		i40e_debug(hw, I40E_DEBUG_NVM,
28493f1cac5SPaul Winder 			   "NVM write fail error: tried to write %d words, limit is %d.\n",
28593f1cac5SPaul Winder 			   words, I40E_SR_SECTOR_SIZE_IN_WORDS);
28693f1cac5SPaul Winder 	else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
28793f1cac5SPaul Winder 		 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
28893f1cac5SPaul Winder 		/* A single write cannot spread over two sectors */
28993f1cac5SPaul Winder 		i40e_debug(hw, I40E_DEBUG_NVM,
29093f1cac5SPaul Winder 			   "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n",
29193f1cac5SPaul Winder 			   offset, words);
29293f1cac5SPaul Winder 	else
29393f1cac5SPaul Winder 		ret_code = i40e_aq_read_nvm(hw, module_pointer,
29493f1cac5SPaul Winder 					    2 * offset,  /*bytes*/
29593f1cac5SPaul Winder 					    2 * words,   /*bytes*/
29693f1cac5SPaul Winder 					    data, last_command, &cmd_details);
29793f1cac5SPaul Winder 
29893f1cac5SPaul Winder 	return ret_code;
29993f1cac5SPaul Winder }
30093f1cac5SPaul Winder 
3019d26e4fcSRobert Mustacchi /**
3029d26e4fcSRobert Mustacchi  * i40e_read_nvm_word_aq - Reads Shadow RAM via AQ
3039d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
3049d26e4fcSRobert Mustacchi  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
3059d26e4fcSRobert Mustacchi  * @data: word read from the Shadow RAM
3069d26e4fcSRobert Mustacchi  *
30793f1cac5SPaul Winder  * Reads one 16 bit word from the Shadow RAM using the AdminQ
3089d26e4fcSRobert Mustacchi  **/
i40e_read_nvm_word_aq(struct i40e_hw * hw,u16 offset,u16 * data)30993f1cac5SPaul Winder static enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
31093f1cac5SPaul Winder 						   u16 *data)
3119d26e4fcSRobert Mustacchi {
3129d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
3139d26e4fcSRobert Mustacchi 
3149d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_read_nvm_word_aq");
3159d26e4fcSRobert Mustacchi 
3169d26e4fcSRobert Mustacchi 	ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, TRUE);
3179d26e4fcSRobert Mustacchi 	*data = LE16_TO_CPU(*(__le16 *)data);
3189d26e4fcSRobert Mustacchi 
3199d26e4fcSRobert Mustacchi 	return ret_code;
3209d26e4fcSRobert Mustacchi }
3219d26e4fcSRobert Mustacchi 
3229d26e4fcSRobert Mustacchi /**
32393f1cac5SPaul Winder  * __i40e_read_nvm_word - Reads NVM word, assumes caller does the locking
3243d75a287SRobert Mustacchi  * @hw: pointer to the HW structure
32593f1cac5SPaul Winder  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
32693f1cac5SPaul Winder  * @data: word read from the Shadow RAM
3273d75a287SRobert Mustacchi  *
32893f1cac5SPaul Winder  * Reads one 16 bit word from the Shadow RAM.
32993f1cac5SPaul Winder  *
33093f1cac5SPaul Winder  * Do not use this function except in cases where the nvm lock is already
33193f1cac5SPaul Winder  * taken via i40e_acquire_nvm().
3323d75a287SRobert Mustacchi  **/
__i40e_read_nvm_word(struct i40e_hw * hw,u16 offset,u16 * data)33393f1cac5SPaul Winder enum i40e_status_code __i40e_read_nvm_word(struct i40e_hw *hw,
33493f1cac5SPaul Winder 					   u16 offset,
33593f1cac5SPaul Winder 					   u16 *data)
3363d75a287SRobert Mustacchi {
3373d75a287SRobert Mustacchi 
3383d75a287SRobert Mustacchi 	if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
33993f1cac5SPaul Winder 		return i40e_read_nvm_word_aq(hw, offset, data);
34093f1cac5SPaul Winder 
34193f1cac5SPaul Winder 	return i40e_read_nvm_word_srctl(hw, offset, data);
3423d75a287SRobert Mustacchi }
3433d75a287SRobert Mustacchi 
3443d75a287SRobert Mustacchi /**
34593f1cac5SPaul Winder  * i40e_read_nvm_word - Reads NVM word, acquires lock if necessary
3469d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
34793f1cac5SPaul Winder  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
34893f1cac5SPaul Winder  * @data: word read from the Shadow RAM
3499d26e4fcSRobert Mustacchi  *
35093f1cac5SPaul Winder  * Reads one 16 bit word from the Shadow RAM.
3519d26e4fcSRobert Mustacchi  **/
i40e_read_nvm_word(struct i40e_hw * hw,u16 offset,u16 * data)35293f1cac5SPaul Winder enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
35393f1cac5SPaul Winder 					 u16 *data)
3549d26e4fcSRobert Mustacchi {
3553d75a287SRobert Mustacchi 	enum i40e_status_code ret_code = I40E_SUCCESS;
3563d75a287SRobert Mustacchi 
35793f1cac5SPaul Winder 	if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
3583d75a287SRobert Mustacchi 		ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
35993f1cac5SPaul Winder 
36093f1cac5SPaul Winder 	if (ret_code)
36193f1cac5SPaul Winder 		return ret_code;
36293f1cac5SPaul Winder 	ret_code = __i40e_read_nvm_word(hw, offset, data);
36393f1cac5SPaul Winder 
36493f1cac5SPaul Winder 	if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
36593f1cac5SPaul Winder 		i40e_release_nvm(hw);
3663d75a287SRobert Mustacchi 	return ret_code;
3679d26e4fcSRobert Mustacchi }
3689d26e4fcSRobert Mustacchi 
369*df36e06dSRobert Mustacchi /**
370*df36e06dSRobert Mustacchi  * i40e_read_nvm_module_data - Reads NVM Buffer to specified memory location
371*df36e06dSRobert Mustacchi  * @hw: Pointer to the HW structure
372*df36e06dSRobert Mustacchi  * @module_ptr: Pointer to module in words with respect to NVM beginning
373*df36e06dSRobert Mustacchi  * @module_offset: Offset in words from module start
374*df36e06dSRobert Mustacchi  * @data_offset: Offset in words from reading data area start
375*df36e06dSRobert Mustacchi  * @words_data_size: Words to read from NVM
376*df36e06dSRobert Mustacchi  * @data_ptr: Pointer to memory location where resulting buffer will be stored
377*df36e06dSRobert Mustacchi  **/
378*df36e06dSRobert Mustacchi enum i40e_status_code
i40e_read_nvm_module_data(struct i40e_hw * hw,u8 module_ptr,u16 module_offset,u16 data_offset,u16 words_data_size,u16 * data_ptr)379*df36e06dSRobert Mustacchi i40e_read_nvm_module_data(struct i40e_hw *hw, u8 module_ptr, u16 module_offset,
380*df36e06dSRobert Mustacchi 			  u16 data_offset, u16 words_data_size, u16 *data_ptr)
381*df36e06dSRobert Mustacchi {
382*df36e06dSRobert Mustacchi 	enum i40e_status_code status;
383*df36e06dSRobert Mustacchi 	u16 specific_ptr = 0;
384*df36e06dSRobert Mustacchi 	u16 ptr_value = 0;
385*df36e06dSRobert Mustacchi 	u16 offset = 0;
386*df36e06dSRobert Mustacchi 
387*df36e06dSRobert Mustacchi 	if (module_ptr != 0) {
388*df36e06dSRobert Mustacchi 		status = i40e_read_nvm_word(hw, module_ptr, &ptr_value);
389*df36e06dSRobert Mustacchi 		if (status != I40E_SUCCESS) {
390*df36e06dSRobert Mustacchi 			i40e_debug(hw, I40E_DEBUG_ALL,
391*df36e06dSRobert Mustacchi 				   "Reading nvm word failed.Error code: %d.\n",
392*df36e06dSRobert Mustacchi 				   status);
393*df36e06dSRobert Mustacchi 			return I40E_ERR_NVM;
394*df36e06dSRobert Mustacchi 		}
395*df36e06dSRobert Mustacchi 	}
396*df36e06dSRobert Mustacchi #define I40E_NVM_INVALID_PTR_VAL 0x7FFF
397*df36e06dSRobert Mustacchi #define I40E_NVM_INVALID_VAL 0xFFFF
398*df36e06dSRobert Mustacchi 
399*df36e06dSRobert Mustacchi 	/* Pointer not initialized */
400*df36e06dSRobert Mustacchi 	if (ptr_value == I40E_NVM_INVALID_PTR_VAL ||
401*df36e06dSRobert Mustacchi 	    ptr_value == I40E_NVM_INVALID_VAL) {
402*df36e06dSRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_ALL, "Pointer not initialized.\n");
403*df36e06dSRobert Mustacchi 		return I40E_ERR_BAD_PTR;
404*df36e06dSRobert Mustacchi 	}
405*df36e06dSRobert Mustacchi 
406*df36e06dSRobert Mustacchi 	/* Check whether the module is in SR mapped area or outside */
407*df36e06dSRobert Mustacchi 	if (ptr_value & I40E_PTR_TYPE) {
408*df36e06dSRobert Mustacchi 		/* Pointer points outside of the Shared RAM mapped area */
409*df36e06dSRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_ALL,
410*df36e06dSRobert Mustacchi 			   "Reading nvm data failed. Pointer points outside of the Shared RAM mapped area.\n");
411*df36e06dSRobert Mustacchi 
412*df36e06dSRobert Mustacchi 		return I40E_ERR_PARAM;
413*df36e06dSRobert Mustacchi 	} else {
414*df36e06dSRobert Mustacchi 		/* Read from the Shadow RAM */
415*df36e06dSRobert Mustacchi 
416*df36e06dSRobert Mustacchi 		status = i40e_read_nvm_word(hw, ptr_value + module_offset,
417*df36e06dSRobert Mustacchi 					    &specific_ptr);
418*df36e06dSRobert Mustacchi 		if (status != I40E_SUCCESS) {
419*df36e06dSRobert Mustacchi 			i40e_debug(hw, I40E_DEBUG_ALL,
420*df36e06dSRobert Mustacchi 				   "Reading nvm word failed.Error code: %d.\n",
421*df36e06dSRobert Mustacchi 				   status);
422*df36e06dSRobert Mustacchi 			return I40E_ERR_NVM;
423*df36e06dSRobert Mustacchi 		}
424*df36e06dSRobert Mustacchi 
425*df36e06dSRobert Mustacchi 		offset = ptr_value + module_offset + specific_ptr +
426*df36e06dSRobert Mustacchi 			data_offset;
427*df36e06dSRobert Mustacchi 
428*df36e06dSRobert Mustacchi 		status = i40e_read_nvm_buffer(hw, offset, &words_data_size,
429*df36e06dSRobert Mustacchi 					      data_ptr);
430*df36e06dSRobert Mustacchi 		if (status != I40E_SUCCESS) {
431*df36e06dSRobert Mustacchi 			i40e_debug(hw, I40E_DEBUG_ALL,
432*df36e06dSRobert Mustacchi 				   "Reading nvm buffer failed.Error code: %d.\n",
433*df36e06dSRobert Mustacchi 				   status);
434*df36e06dSRobert Mustacchi 		}
435*df36e06dSRobert Mustacchi 	}
436*df36e06dSRobert Mustacchi 
437*df36e06dSRobert Mustacchi 	return status;
438*df36e06dSRobert Mustacchi }
439*df36e06dSRobert Mustacchi 
4409d26e4fcSRobert Mustacchi /**
4419d26e4fcSRobert Mustacchi  * i40e_read_nvm_buffer_srctl - Reads Shadow RAM buffer via SRCTL register
4429d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
4439d26e4fcSRobert Mustacchi  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
4449d26e4fcSRobert Mustacchi  * @words: (in) number of words to read; (out) number of words actually read
4459d26e4fcSRobert Mustacchi  * @data: words read from the Shadow RAM
4469d26e4fcSRobert Mustacchi  *
4479d26e4fcSRobert Mustacchi  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
4489d26e4fcSRobert Mustacchi  * method. The buffer read is preceded by the NVM ownership take
4499d26e4fcSRobert Mustacchi  * and followed by the release.
4509d26e4fcSRobert Mustacchi  **/
i40e_read_nvm_buffer_srctl(struct i40e_hw * hw,u16 offset,u16 * words,u16 * data)45193f1cac5SPaul Winder static enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset,
45293f1cac5SPaul Winder 							u16 *words, u16 *data)
4539d26e4fcSRobert Mustacchi {
4549d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_SUCCESS;
4559d26e4fcSRobert Mustacchi 	u16 index, word;
4569d26e4fcSRobert Mustacchi 
4579d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_read_nvm_buffer_srctl");
4589d26e4fcSRobert Mustacchi 
4593d75a287SRobert Mustacchi 	/* Loop through the selected region */
4609d26e4fcSRobert Mustacchi 	for (word = 0; word < *words; word++) {
4619d26e4fcSRobert Mustacchi 		index = offset + word;
4629d26e4fcSRobert Mustacchi 		ret_code = i40e_read_nvm_word_srctl(hw, index, &data[word]);
4639d26e4fcSRobert Mustacchi 		if (ret_code != I40E_SUCCESS)
4649d26e4fcSRobert Mustacchi 			break;
4659d26e4fcSRobert Mustacchi 	}
4669d26e4fcSRobert Mustacchi 
4679d26e4fcSRobert Mustacchi 	/* Update the number of words read from the Shadow RAM */
4689d26e4fcSRobert Mustacchi 	*words = word;
4699d26e4fcSRobert Mustacchi 
4709d26e4fcSRobert Mustacchi 	return ret_code;
4719d26e4fcSRobert Mustacchi }
4729d26e4fcSRobert Mustacchi 
4739d26e4fcSRobert Mustacchi /**
4749d26e4fcSRobert Mustacchi  * i40e_read_nvm_buffer_aq - Reads Shadow RAM buffer via AQ
4759d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
4769d26e4fcSRobert Mustacchi  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
4779d26e4fcSRobert Mustacchi  * @words: (in) number of words to read; (out) number of words actually read
4789d26e4fcSRobert Mustacchi  * @data: words read from the Shadow RAM
4799d26e4fcSRobert Mustacchi  *
4809d26e4fcSRobert Mustacchi  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_aq()
4819d26e4fcSRobert Mustacchi  * method. The buffer read is preceded by the NVM ownership take
4829d26e4fcSRobert Mustacchi  * and followed by the release.
4839d26e4fcSRobert Mustacchi  **/
i40e_read_nvm_buffer_aq(struct i40e_hw * hw,u16 offset,u16 * words,u16 * data)48493f1cac5SPaul Winder static enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset,
48593f1cac5SPaul Winder 						     u16 *words, u16 *data)
4869d26e4fcSRobert Mustacchi {
4879d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code;
4889d26e4fcSRobert Mustacchi 	u16 read_size = *words;
4899d26e4fcSRobert Mustacchi 	bool last_cmd = FALSE;
4909d26e4fcSRobert Mustacchi 	u16 words_read = 0;
4919d26e4fcSRobert Mustacchi 	u16 i = 0;
4929d26e4fcSRobert Mustacchi 
4939d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_read_nvm_buffer_aq");
4949d26e4fcSRobert Mustacchi 
4959d26e4fcSRobert Mustacchi 	do {
4969d26e4fcSRobert Mustacchi 		/* Calculate number of bytes we should read in this step.
4979d26e4fcSRobert Mustacchi 		 * FVL AQ do not allow to read more than one page at a time or
4989d26e4fcSRobert Mustacchi 		 * to cross page boundaries.
4999d26e4fcSRobert Mustacchi 		 */
5009d26e4fcSRobert Mustacchi 		if (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)
5019d26e4fcSRobert Mustacchi 			read_size = min(*words,
5029d26e4fcSRobert Mustacchi 					(u16)(I40E_SR_SECTOR_SIZE_IN_WORDS -
5039d26e4fcSRobert Mustacchi 				      (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)));
5049d26e4fcSRobert Mustacchi 		else
5059d26e4fcSRobert Mustacchi 			read_size = min((*words - words_read),
5069d26e4fcSRobert Mustacchi 					I40E_SR_SECTOR_SIZE_IN_WORDS);
5079d26e4fcSRobert Mustacchi 
5089d26e4fcSRobert Mustacchi 		/* Check if this is last command, if so set proper flag */
5099d26e4fcSRobert Mustacchi 		if ((words_read + read_size) >= *words)
5109d26e4fcSRobert Mustacchi 			last_cmd = TRUE;
5119d26e4fcSRobert Mustacchi 
5129d26e4fcSRobert Mustacchi 		ret_code = i40e_read_nvm_aq(hw, 0x0, offset, read_size,
5139d26e4fcSRobert Mustacchi 					    data + words_read, last_cmd);
5149d26e4fcSRobert Mustacchi 		if (ret_code != I40E_SUCCESS)
5159d26e4fcSRobert Mustacchi 			goto read_nvm_buffer_aq_exit;
5169d26e4fcSRobert Mustacchi 
5179d26e4fcSRobert Mustacchi 		/* Increment counter for words already read and move offset to
5189d26e4fcSRobert Mustacchi 		 * new read location
5199d26e4fcSRobert Mustacchi 		 */
5209d26e4fcSRobert Mustacchi 		words_read += read_size;
5219d26e4fcSRobert Mustacchi 		offset += read_size;
5229d26e4fcSRobert Mustacchi 	} while (words_read < *words);
5239d26e4fcSRobert Mustacchi 
5249d26e4fcSRobert Mustacchi 	for (i = 0; i < *words; i++)
5259d26e4fcSRobert Mustacchi 		data[i] = LE16_TO_CPU(((__le16 *)data)[i]);
5269d26e4fcSRobert Mustacchi 
5279d26e4fcSRobert Mustacchi read_nvm_buffer_aq_exit:
5289d26e4fcSRobert Mustacchi 	*words = words_read;
5299d26e4fcSRobert Mustacchi 	return ret_code;
5309d26e4fcSRobert Mustacchi }
5319d26e4fcSRobert Mustacchi 
5329d26e4fcSRobert Mustacchi /**
53393f1cac5SPaul Winder  * __i40e_read_nvm_buffer - Reads NVM buffer, caller must acquire lock
53493f1cac5SPaul Winder  * @hw: pointer to the HW structure
53593f1cac5SPaul Winder  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
53693f1cac5SPaul Winder  * @words: (in) number of words to read; (out) number of words actually read
53793f1cac5SPaul Winder  * @data: words read from the Shadow RAM
5389d26e4fcSRobert Mustacchi  *
53993f1cac5SPaul Winder  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
54093f1cac5SPaul Winder  * method.
5419d26e4fcSRobert Mustacchi  **/
__i40e_read_nvm_buffer(struct i40e_hw * hw,u16 offset,u16 * words,u16 * data)54293f1cac5SPaul Winder enum i40e_status_code __i40e_read_nvm_buffer(struct i40e_hw *hw,
54393f1cac5SPaul Winder 					     u16 offset,
54493f1cac5SPaul Winder 					     u16 *words, u16 *data)
5459d26e4fcSRobert Mustacchi {
54693f1cac5SPaul Winder 	if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
54793f1cac5SPaul Winder 		return i40e_read_nvm_buffer_aq(hw, offset, words, data);
5489d26e4fcSRobert Mustacchi 
54993f1cac5SPaul Winder 	return i40e_read_nvm_buffer_srctl(hw, offset, words, data);
55093f1cac5SPaul Winder }
5519d26e4fcSRobert Mustacchi 
55293f1cac5SPaul Winder /**
55393f1cac5SPaul Winder  * i40e_read_nvm_buffer - Reads Shadow RAM buffer and acquire lock if necessary
55493f1cac5SPaul Winder  * @hw: pointer to the HW structure
55593f1cac5SPaul Winder  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
55693f1cac5SPaul Winder  * @words: (in) number of words to read; (out) number of words actually read
55793f1cac5SPaul Winder  * @data: words read from the Shadow RAM
55893f1cac5SPaul Winder  *
55993f1cac5SPaul Winder  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
56093f1cac5SPaul Winder  * method. The buffer read is preceded by the NVM ownership take
56193f1cac5SPaul Winder  * and followed by the release.
56293f1cac5SPaul Winder  **/
i40e_read_nvm_buffer(struct i40e_hw * hw,u16 offset,u16 * words,u16 * data)56393f1cac5SPaul Winder enum i40e_status_code i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
56493f1cac5SPaul Winder 					   u16 *words, u16 *data)
56593f1cac5SPaul Winder {
56693f1cac5SPaul Winder 	enum i40e_status_code ret_code = I40E_SUCCESS;
5679d26e4fcSRobert Mustacchi 
56893f1cac5SPaul Winder 	if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
56993f1cac5SPaul Winder 		ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
57093f1cac5SPaul Winder 		if (!ret_code) {
57193f1cac5SPaul Winder 			ret_code = i40e_read_nvm_buffer_aq(hw, offset, words,
57293f1cac5SPaul Winder 							 data);
57393f1cac5SPaul Winder 			i40e_release_nvm(hw);
57493f1cac5SPaul Winder 		}
57593f1cac5SPaul Winder 	} else {
57693f1cac5SPaul Winder 		ret_code = i40e_read_nvm_buffer_srctl(hw, offset, words, data);
57793f1cac5SPaul Winder 	}
578*df36e06dSRobert Mustacchi 
5799d26e4fcSRobert Mustacchi 	return ret_code;
5809d26e4fcSRobert Mustacchi }
5819d26e4fcSRobert Mustacchi 
5829d26e4fcSRobert Mustacchi /**
5839d26e4fcSRobert Mustacchi  * i40e_write_nvm_aq - Writes Shadow RAM.
5849d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure.
5859d26e4fcSRobert Mustacchi  * @module_pointer: module pointer location in words from the NVM beginning
5869d26e4fcSRobert Mustacchi  * @offset: offset in words from module start
5879d26e4fcSRobert Mustacchi  * @words: number of words to write
5889d26e4fcSRobert Mustacchi  * @data: buffer with words to write to the Shadow RAM
5899d26e4fcSRobert Mustacchi  * @last_command: tells the AdminQ that this is the last command
5909d26e4fcSRobert Mustacchi  *
5919d26e4fcSRobert Mustacchi  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
5929d26e4fcSRobert Mustacchi  **/
i40e_write_nvm_aq(struct i40e_hw * hw,u8 module_pointer,u32 offset,u16 words,void * data,bool last_command)5939d26e4fcSRobert Mustacchi enum i40e_status_code i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
5949d26e4fcSRobert Mustacchi 					u32 offset, u16 words, void *data,
5959d26e4fcSRobert Mustacchi 					bool last_command)
5969d26e4fcSRobert Mustacchi {
5979d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_ERR_NVM;
5989d26e4fcSRobert Mustacchi 	struct i40e_asq_cmd_details cmd_details;
5999d26e4fcSRobert Mustacchi 
6009d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_write_nvm_aq");
6019d26e4fcSRobert Mustacchi 
6029d26e4fcSRobert Mustacchi 	memset(&cmd_details, 0, sizeof(cmd_details));
6039d26e4fcSRobert Mustacchi 	cmd_details.wb_desc = &hw->nvm_wb_desc;
6049d26e4fcSRobert Mustacchi 
6059d26e4fcSRobert Mustacchi 	/* Here we are checking the SR limit only for the flat memory model.
6069d26e4fcSRobert Mustacchi 	 * We cannot do it for the module-based model, as we did not acquire
6079d26e4fcSRobert Mustacchi 	 * the NVM resource yet (we cannot get the module pointer value).
6089d26e4fcSRobert Mustacchi 	 * Firmware will check the module-based model.
6099d26e4fcSRobert Mustacchi 	 */
6109d26e4fcSRobert Mustacchi 	if ((offset + words) > hw->nvm.sr_size)
6119d26e4fcSRobert Mustacchi 		DEBUGOUT("NVM write error: offset beyond Shadow RAM limit.\n");
6129d26e4fcSRobert Mustacchi 	else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
6139d26e4fcSRobert Mustacchi 		/* We can write only up to 4KB (one sector), in one AQ write */
6149d26e4fcSRobert Mustacchi 		DEBUGOUT("NVM write fail error: cannot write more than 4KB in a single write.\n");
6159d26e4fcSRobert Mustacchi 	else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
6169d26e4fcSRobert Mustacchi 		 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
6179d26e4fcSRobert Mustacchi 		/* A single write cannot spread over two sectors */
6189d26e4fcSRobert Mustacchi 		DEBUGOUT("NVM write error: cannot spread over two sectors in a single write.\n");
6199d26e4fcSRobert Mustacchi 	else
6209d26e4fcSRobert Mustacchi 		ret_code = i40e_aq_update_nvm(hw, module_pointer,
6219d26e4fcSRobert Mustacchi 					      2 * offset,  /*bytes*/
6229d26e4fcSRobert Mustacchi 					      2 * words,   /*bytes*/
62393f1cac5SPaul Winder 					      data, last_command, 0,
62493f1cac5SPaul Winder 					      &cmd_details);
6259d26e4fcSRobert Mustacchi 
6269d26e4fcSRobert Mustacchi 	return ret_code;
6279d26e4fcSRobert Mustacchi }
6289d26e4fcSRobert Mustacchi 
6299d26e4fcSRobert Mustacchi /**
6303d75a287SRobert Mustacchi  * __i40e_write_nvm_word - Writes Shadow RAM word
6319d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
6329d26e4fcSRobert Mustacchi  * @offset: offset of the Shadow RAM word to write
6339d26e4fcSRobert Mustacchi  * @data: word to write to the Shadow RAM
6349d26e4fcSRobert Mustacchi  *
6359d26e4fcSRobert Mustacchi  * Writes a 16 bit word to the SR using the i40e_write_nvm_aq() method.
6369d26e4fcSRobert Mustacchi  * NVM ownership have to be acquired and released (on ARQ completion event
6379d26e4fcSRobert Mustacchi  * reception) by caller. To commit SR to NVM update checksum function
6389d26e4fcSRobert Mustacchi  * should be called.
6399d26e4fcSRobert Mustacchi  **/
__i40e_write_nvm_word(struct i40e_hw * hw,u32 offset,void * data)6403d75a287SRobert Mustacchi enum i40e_status_code __i40e_write_nvm_word(struct i40e_hw *hw, u32 offset,
6413d75a287SRobert Mustacchi 					    void *data)
6429d26e4fcSRobert Mustacchi {
6439d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_write_nvm_word");
6449d26e4fcSRobert Mustacchi 
6459d26e4fcSRobert Mustacchi 	*((__le16 *)data) = CPU_TO_LE16(*((u16 *)data));
6469d26e4fcSRobert Mustacchi 
6479d26e4fcSRobert Mustacchi 	/* Value 0x00 below means that we treat SR as a flat mem */
6489d26e4fcSRobert Mustacchi 	return i40e_write_nvm_aq(hw, 0x00, offset, 1, data, FALSE);
6499d26e4fcSRobert Mustacchi }
6509d26e4fcSRobert Mustacchi 
6519d26e4fcSRobert Mustacchi /**
6523d75a287SRobert Mustacchi  * __i40e_write_nvm_buffer - Writes Shadow RAM buffer
6539d26e4fcSRobert Mustacchi  * @hw: pointer to the HW structure
6549d26e4fcSRobert Mustacchi  * @module_pointer: module pointer location in words from the NVM beginning
6559d26e4fcSRobert Mustacchi  * @offset: offset of the Shadow RAM buffer to write
6569d26e4fcSRobert Mustacchi  * @words: number of words to write
6579d26e4fcSRobert Mustacchi  * @data: words to write to the Shadow RAM
6589d26e4fcSRobert Mustacchi  *
6599d26e4fcSRobert Mustacchi  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
6609d26e4fcSRobert Mustacchi  * NVM ownership must be acquired before calling this function and released
6619d26e4fcSRobert Mustacchi  * on ARQ completion event reception by caller. To commit SR to NVM update
6629d26e4fcSRobert Mustacchi  * checksum function should be called.
6639d26e4fcSRobert Mustacchi  **/
__i40e_write_nvm_buffer(struct i40e_hw * hw,u8 module_pointer,u32 offset,u16 words,void * data)6643d75a287SRobert Mustacchi enum i40e_status_code __i40e_write_nvm_buffer(struct i40e_hw *hw,
6653d75a287SRobert Mustacchi 					      u8 module_pointer, u32 offset,
6663d75a287SRobert Mustacchi 					      u16 words, void *data)
6679d26e4fcSRobert Mustacchi {
6689d26e4fcSRobert Mustacchi 	__le16 *le_word_ptr = (__le16 *)data;
6699d26e4fcSRobert Mustacchi 	u16 *word_ptr = (u16 *)data;
6709d26e4fcSRobert Mustacchi 	u32 i = 0;
6719d26e4fcSRobert Mustacchi 
6729d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_write_nvm_buffer");
6739d26e4fcSRobert Mustacchi 
6749d26e4fcSRobert Mustacchi 	for (i = 0; i < words; i++)
6759d26e4fcSRobert Mustacchi 		le_word_ptr[i] = CPU_TO_LE16(word_ptr[i]);
6769d26e4fcSRobert Mustacchi 
6779d26e4fcSRobert Mustacchi 	/* Here we will only write one buffer as the size of the modules
6789d26e4fcSRobert Mustacchi 	 * mirrored in the Shadow RAM is always less than 4K.
6799d26e4fcSRobert Mustacchi 	 */
6809d26e4fcSRobert Mustacchi 	return i40e_write_nvm_aq(hw, module_pointer, offset, words,
6819d26e4fcSRobert Mustacchi 				 data, FALSE);
6829d26e4fcSRobert Mustacchi }
6839d26e4fcSRobert Mustacchi 
6849d26e4fcSRobert Mustacchi /**
6859d26e4fcSRobert Mustacchi  * i40e_calc_nvm_checksum - Calculates and returns the checksum
6869d26e4fcSRobert Mustacchi  * @hw: pointer to hardware structure
6879d26e4fcSRobert Mustacchi  * @checksum: pointer to the checksum
6889d26e4fcSRobert Mustacchi  *
6899d26e4fcSRobert Mustacchi  * This function calculates SW Checksum that covers the whole 64kB shadow RAM
6909d26e4fcSRobert Mustacchi  * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
6919d26e4fcSRobert Mustacchi  * is customer specific and unknown. Therefore, this function skips all maximum
6929d26e4fcSRobert Mustacchi  * possible size of VPD (1kB).
6939d26e4fcSRobert Mustacchi  **/
i40e_calc_nvm_checksum(struct i40e_hw * hw,u16 * checksum)6949d26e4fcSRobert Mustacchi enum i40e_status_code i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum)
6959d26e4fcSRobert Mustacchi {
6969d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_SUCCESS;
6979d26e4fcSRobert Mustacchi 	struct i40e_virt_mem vmem;
6989d26e4fcSRobert Mustacchi 	u16 pcie_alt_module = 0;
6999d26e4fcSRobert Mustacchi 	u16 checksum_local = 0;
7009d26e4fcSRobert Mustacchi 	u16 vpd_module = 0;
7019d26e4fcSRobert Mustacchi 	u16 *data;
7029d26e4fcSRobert Mustacchi 	u16 i = 0;
7039d26e4fcSRobert Mustacchi 
7049d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_calc_nvm_checksum");
7059d26e4fcSRobert Mustacchi 
7069d26e4fcSRobert Mustacchi 	ret_code = i40e_allocate_virt_mem(hw, &vmem,
7079d26e4fcSRobert Mustacchi 				    I40E_SR_SECTOR_SIZE_IN_WORDS * sizeof(u16));
7089d26e4fcSRobert Mustacchi 	if (ret_code)
7099d26e4fcSRobert Mustacchi 		goto i40e_calc_nvm_checksum_exit;
7109d26e4fcSRobert Mustacchi 	data = (u16 *)vmem.va;
7119d26e4fcSRobert Mustacchi 
7129d26e4fcSRobert Mustacchi 	/* read pointer to VPD area */
71393f1cac5SPaul Winder 	ret_code = __i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
7149d26e4fcSRobert Mustacchi 	if (ret_code != I40E_SUCCESS) {
7159d26e4fcSRobert Mustacchi 		ret_code = I40E_ERR_NVM_CHECKSUM;
7169d26e4fcSRobert Mustacchi 		goto i40e_calc_nvm_checksum_exit;
7179d26e4fcSRobert Mustacchi 	}
7189d26e4fcSRobert Mustacchi 
7199d26e4fcSRobert Mustacchi 	/* read pointer to PCIe Alt Auto-load module */
72093f1cac5SPaul Winder 	ret_code = __i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
7213d75a287SRobert Mustacchi 					&pcie_alt_module);
7229d26e4fcSRobert Mustacchi 	if (ret_code != I40E_SUCCESS) {
7239d26e4fcSRobert Mustacchi 		ret_code = I40E_ERR_NVM_CHECKSUM;
7249d26e4fcSRobert Mustacchi 		goto i40e_calc_nvm_checksum_exit;
7259d26e4fcSRobert Mustacchi 	}
7269d26e4fcSRobert Mustacchi 
7279d26e4fcSRobert Mustacchi 	/* Calculate SW checksum that covers the whole 64kB shadow RAM
7289d26e4fcSRobert Mustacchi 	 * except the VPD and PCIe ALT Auto-load modules
7299d26e4fcSRobert Mustacchi 	 */
7309d26e4fcSRobert Mustacchi 	for (i = 0; i < hw->nvm.sr_size; i++) {
7319d26e4fcSRobert Mustacchi 		/* Read SR page */
7329d26e4fcSRobert Mustacchi 		if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) {
7339d26e4fcSRobert Mustacchi 			u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS;
7349d26e4fcSRobert Mustacchi 
7353d75a287SRobert Mustacchi 			ret_code = __i40e_read_nvm_buffer(hw, i, &words, data);
7369d26e4fcSRobert Mustacchi 			if (ret_code != I40E_SUCCESS) {
7379d26e4fcSRobert Mustacchi 				ret_code = I40E_ERR_NVM_CHECKSUM;
7389d26e4fcSRobert Mustacchi 				goto i40e_calc_nvm_checksum_exit;
7399d26e4fcSRobert Mustacchi 			}
7409d26e4fcSRobert Mustacchi 		}
7419d26e4fcSRobert Mustacchi 
7429d26e4fcSRobert Mustacchi 		/* Skip Checksum word */
7439d26e4fcSRobert Mustacchi 		if (i == I40E_SR_SW_CHECKSUM_WORD)
7449d26e4fcSRobert Mustacchi 			continue;
7459d26e4fcSRobert Mustacchi 		/* Skip VPD module (convert byte size to word count) */
7469d26e4fcSRobert Mustacchi 		if ((i >= (u32)vpd_module) &&
7479d26e4fcSRobert Mustacchi 		    (i < ((u32)vpd_module +
7489d26e4fcSRobert Mustacchi 		     (I40E_SR_VPD_MODULE_MAX_SIZE / 2)))) {
7499d26e4fcSRobert Mustacchi 			continue;
7509d26e4fcSRobert Mustacchi 		}
7519d26e4fcSRobert Mustacchi 		/* Skip PCIe ALT module (convert byte size to word count) */
7529d26e4fcSRobert Mustacchi 		if ((i >= (u32)pcie_alt_module) &&
7539d26e4fcSRobert Mustacchi 		    (i < ((u32)pcie_alt_module +
7549d26e4fcSRobert Mustacchi 		     (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2)))) {
7559d26e4fcSRobert Mustacchi 			continue;
7569d26e4fcSRobert Mustacchi 		}
7579d26e4fcSRobert Mustacchi 
7589d26e4fcSRobert Mustacchi 		checksum_local += data[i % I40E_SR_SECTOR_SIZE_IN_WORDS];
7599d26e4fcSRobert Mustacchi 	}
7609d26e4fcSRobert Mustacchi 
7619d26e4fcSRobert Mustacchi 	*checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local;
7629d26e4fcSRobert Mustacchi 
7639d26e4fcSRobert Mustacchi i40e_calc_nvm_checksum_exit:
7649d26e4fcSRobert Mustacchi 	i40e_free_virt_mem(hw, &vmem);
7659d26e4fcSRobert Mustacchi 	return ret_code;
7669d26e4fcSRobert Mustacchi }
7679d26e4fcSRobert Mustacchi 
7689d26e4fcSRobert Mustacchi /**
7699d26e4fcSRobert Mustacchi  * i40e_update_nvm_checksum - Updates the NVM checksum
7709d26e4fcSRobert Mustacchi  * @hw: pointer to hardware structure
7719d26e4fcSRobert Mustacchi  *
7729d26e4fcSRobert Mustacchi  * NVM ownership must be acquired before calling this function and released
7739d26e4fcSRobert Mustacchi  * on ARQ completion event reception by caller.
7749d26e4fcSRobert Mustacchi  * This function will commit SR to NVM.
7759d26e4fcSRobert Mustacchi  **/
i40e_update_nvm_checksum(struct i40e_hw * hw)7769d26e4fcSRobert Mustacchi enum i40e_status_code i40e_update_nvm_checksum(struct i40e_hw *hw)
7779d26e4fcSRobert Mustacchi {
7789d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_SUCCESS;
7799d26e4fcSRobert Mustacchi 	u16 checksum;
7809d26e4fcSRobert Mustacchi 	__le16 le_sum;
7819d26e4fcSRobert Mustacchi 
7829d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_update_nvm_checksum");
7839d26e4fcSRobert Mustacchi 
7849d26e4fcSRobert Mustacchi 	ret_code = i40e_calc_nvm_checksum(hw, &checksum);
7859d26e4fcSRobert Mustacchi 	le_sum = CPU_TO_LE16(checksum);
7869d26e4fcSRobert Mustacchi 	if (ret_code == I40E_SUCCESS)
7879d26e4fcSRobert Mustacchi 		ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD,
7889d26e4fcSRobert Mustacchi 					     1, &le_sum, TRUE);
7899d26e4fcSRobert Mustacchi 
7909d26e4fcSRobert Mustacchi 	return ret_code;
7919d26e4fcSRobert Mustacchi }
7929d26e4fcSRobert Mustacchi 
7939d26e4fcSRobert Mustacchi /**
7949d26e4fcSRobert Mustacchi  * i40e_validate_nvm_checksum - Validate EEPROM checksum
7959d26e4fcSRobert Mustacchi  * @hw: pointer to hardware structure
7969d26e4fcSRobert Mustacchi  * @checksum: calculated checksum
7979d26e4fcSRobert Mustacchi  *
7989d26e4fcSRobert Mustacchi  * Performs checksum calculation and validates the NVM SW checksum. If the
7999d26e4fcSRobert Mustacchi  * caller does not need checksum, the value can be NULL.
8009d26e4fcSRobert Mustacchi  **/
i40e_validate_nvm_checksum(struct i40e_hw * hw,u16 * checksum)8019d26e4fcSRobert Mustacchi enum i40e_status_code i40e_validate_nvm_checksum(struct i40e_hw *hw,
8029d26e4fcSRobert Mustacchi 						 u16 *checksum)
8039d26e4fcSRobert Mustacchi {
8049d26e4fcSRobert Mustacchi 	enum i40e_status_code ret_code = I40E_SUCCESS;
8059d26e4fcSRobert Mustacchi 	u16 checksum_sr = 0;
8069d26e4fcSRobert Mustacchi 	u16 checksum_local = 0;
8079d26e4fcSRobert Mustacchi 
8089d26e4fcSRobert Mustacchi 	DEBUGFUNC("i40e_validate_nvm_checksum");
8099d26e4fcSRobert Mustacchi 
81093f1cac5SPaul Winder 	/* We must acquire the NVM lock in order to correctly synchronize the
81193f1cac5SPaul Winder 	 * NVM accesses across multiple PFs. Without doing so it is possible
81293f1cac5SPaul Winder 	 * for one of the PFs to read invalid data potentially indicating that
81393f1cac5SPaul Winder 	 * the checksum is invalid.
81493f1cac5SPaul Winder 	 */
81593f1cac5SPaul Winder 	ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
81693f1cac5SPaul Winder 	if (ret_code)
81793f1cac5SPaul Winder 		return ret_code;
81893f1cac5SPaul Winder 	ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
81993f1cac5SPaul Winder 	__i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
82093f1cac5SPaul Winder 	i40e_release_nvm(hw);
82193f1cac5SPaul Winder 	if (ret_code)
82293f1cac5SPaul Winder 		return ret_code;
8239d26e4fcSRobert Mustacchi 
8249d26e4fcSRobert Mustacchi 	/* Verify read checksum from EEPROM is the same as
8259d26e4fcSRobert Mustacchi 	 * calculated checksum
8269d26e4fcSRobert Mustacchi 	 */
8279d26e4fcSRobert Mustacchi 	if (checksum_local != checksum_sr)
8289d26e4fcSRobert Mustacchi 		ret_code = I40E_ERR_NVM_CHECKSUM;
8299d26e4fcSRobert Mustacchi 
8309d26e4fcSRobert Mustacchi 	/* If the user cares, return the calculated checksum */
8319d26e4fcSRobert Mustacchi 	if (checksum)
8329d26e4fcSRobert Mustacchi 		*checksum = checksum_local;
8339d26e4fcSRobert Mustacchi 
8349d26e4fcSRobert Mustacchi 	return ret_code;
8359d26e4fcSRobert Mustacchi }
8363d75a287SRobert Mustacchi 
8373d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw,
8383d75a287SRobert Mustacchi 						    struct i40e_nvm_access *cmd,
8393d75a287SRobert Mustacchi 						    u8 *bytes, int *perrno);
8403d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_state_reading(struct i40e_hw *hw,
8413d75a287SRobert Mustacchi 						    struct i40e_nvm_access *cmd,
8423d75a287SRobert Mustacchi 						    u8 *bytes, int *perrno);
8433d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_state_writing(struct i40e_hw *hw,
8443d75a287SRobert Mustacchi 						    struct i40e_nvm_access *cmd,
8453d75a287SRobert Mustacchi 						    u8 *bytes, int *perrno);
8463d75a287SRobert Mustacchi static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
8473d75a287SRobert Mustacchi 						    struct i40e_nvm_access *cmd,
8483d75a287SRobert Mustacchi 						    int *perrno);
8493d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
8503d75a287SRobert Mustacchi 						   struct i40e_nvm_access *cmd,
8513d75a287SRobert Mustacchi 						   int *perrno);
8523d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_nvm_write(struct i40e_hw *hw,
8533d75a287SRobert Mustacchi 						   struct i40e_nvm_access *cmd,
8543d75a287SRobert Mustacchi 						   u8 *bytes, int *perrno);
8553d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_nvm_read(struct i40e_hw *hw,
8563d75a287SRobert Mustacchi 						  struct i40e_nvm_access *cmd,
8573d75a287SRobert Mustacchi 						  u8 *bytes, int *perrno);
8583d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw,
8593d75a287SRobert Mustacchi 						 struct i40e_nvm_access *cmd,
8603d75a287SRobert Mustacchi 						 u8 *bytes, int *perrno);
8613d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_get_aq_result(struct i40e_hw *hw,
8623d75a287SRobert Mustacchi 						    struct i40e_nvm_access *cmd,
8633d75a287SRobert Mustacchi 						    u8 *bytes, int *perrno);
86493f1cac5SPaul Winder static enum i40e_status_code i40e_nvmupd_get_aq_event(struct i40e_hw *hw,
86593f1cac5SPaul Winder 						    struct i40e_nvm_access *cmd,
86693f1cac5SPaul Winder 						    u8 *bytes, int *perrno);
i40e_nvmupd_get_module(u32 val)8673d75a287SRobert Mustacchi static INLINE u8 i40e_nvmupd_get_module(u32 val)
8683d75a287SRobert Mustacchi {
8693d75a287SRobert Mustacchi 	return (u8)(val & I40E_NVM_MOD_PNT_MASK);
8703d75a287SRobert Mustacchi }
i40e_nvmupd_get_transaction(u32 val)8713d75a287SRobert Mustacchi static INLINE u8 i40e_nvmupd_get_transaction(u32 val)
8723d75a287SRobert Mustacchi {
8733d75a287SRobert Mustacchi 	return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT);
8743d75a287SRobert Mustacchi }
8753d75a287SRobert Mustacchi 
i40e_nvmupd_get_preservation_flags(u32 val)87693f1cac5SPaul Winder static INLINE u8 i40e_nvmupd_get_preservation_flags(u32 val)
87793f1cac5SPaul Winder {
87893f1cac5SPaul Winder 	return (u8)((val & I40E_NVM_PRESERVATION_FLAGS_MASK) >>
87993f1cac5SPaul Winder 		    I40E_NVM_PRESERVATION_FLAGS_SHIFT);
88093f1cac5SPaul Winder }
88193f1cac5SPaul Winder 
8823d75a287SRobert Mustacchi static const char *i40e_nvm_update_state_str[] = {
8833d75a287SRobert Mustacchi 	"I40E_NVMUPD_INVALID",
8843d75a287SRobert Mustacchi 	"I40E_NVMUPD_READ_CON",
8853d75a287SRobert Mustacchi 	"I40E_NVMUPD_READ_SNT",
8863d75a287SRobert Mustacchi 	"I40E_NVMUPD_READ_LCB",
8873d75a287SRobert Mustacchi 	"I40E_NVMUPD_READ_SA",
8883d75a287SRobert Mustacchi 	"I40E_NVMUPD_WRITE_ERA",
8893d75a287SRobert Mustacchi 	"I40E_NVMUPD_WRITE_CON",
8903d75a287SRobert Mustacchi 	"I40E_NVMUPD_WRITE_SNT",
8913d75a287SRobert Mustacchi 	"I40E_NVMUPD_WRITE_LCB",
8923d75a287SRobert Mustacchi 	"I40E_NVMUPD_WRITE_SA",
8933d75a287SRobert Mustacchi 	"I40E_NVMUPD_CSUM_CON",
8943d75a287SRobert Mustacchi 	"I40E_NVMUPD_CSUM_SA",
8953d75a287SRobert Mustacchi 	"I40E_NVMUPD_CSUM_LCB",
8963d75a287SRobert Mustacchi 	"I40E_NVMUPD_STATUS",
8973d75a287SRobert Mustacchi 	"I40E_NVMUPD_EXEC_AQ",
8983d75a287SRobert Mustacchi 	"I40E_NVMUPD_GET_AQ_RESULT",
89993f1cac5SPaul Winder 	"I40E_NVMUPD_GET_AQ_EVENT",
900*df36e06dSRobert Mustacchi 	"I40E_NVMUPD_GET_FEATURES",
9013d75a287SRobert Mustacchi };
9023d75a287SRobert Mustacchi 
9033d75a287SRobert Mustacchi /**
9043d75a287SRobert Mustacchi  * i40e_nvmupd_command - Process an NVM update command
9053d75a287SRobert Mustacchi  * @hw: pointer to hardware structure
9063d75a287SRobert Mustacchi  * @cmd: pointer to nvm update command
9073d75a287SRobert Mustacchi  * @bytes: pointer to the data buffer
9083d75a287SRobert Mustacchi  * @perrno: pointer to return error code
9093d75a287SRobert Mustacchi  *
9103d75a287SRobert Mustacchi  * Dispatches command depending on what update state is current
9113d75a287SRobert Mustacchi  **/
i40e_nvmupd_command(struct i40e_hw * hw,struct i40e_nvm_access * cmd,u8 * bytes,int * perrno)9123d75a287SRobert Mustacchi enum i40e_status_code i40e_nvmupd_command(struct i40e_hw *hw,
9133d75a287SRobert Mustacchi 					  struct i40e_nvm_access *cmd,
9143d75a287SRobert Mustacchi 					  u8 *bytes, int *perrno)
9153d75a287SRobert Mustacchi {
9163d75a287SRobert Mustacchi 	enum i40e_status_code status;
9173d75a287SRobert Mustacchi 	enum i40e_nvmupd_cmd upd_cmd;
9183d75a287SRobert Mustacchi 
9193d75a287SRobert Mustacchi 	DEBUGFUNC("i40e_nvmupd_command");
9203d75a287SRobert Mustacchi 
9213d75a287SRobert Mustacchi 	/* assume success */
9223d75a287SRobert Mustacchi 	*perrno = 0;
9233d75a287SRobert Mustacchi 
9243d75a287SRobert Mustacchi 	/* early check for status command and debug msgs */
9253d75a287SRobert Mustacchi 	upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
9263d75a287SRobert Mustacchi 
9273d75a287SRobert Mustacchi 	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",
9283d75a287SRobert Mustacchi 		   i40e_nvm_update_state_str[upd_cmd],
9293d75a287SRobert Mustacchi 		   hw->nvmupd_state,
9303d75a287SRobert Mustacchi 		   hw->nvm_release_on_done, hw->nvm_wait_opcode,
9313d75a287SRobert Mustacchi 		   cmd->command, cmd->config, cmd->offset, cmd->data_size);
9323d75a287SRobert Mustacchi 
9333d75a287SRobert Mustacchi 	if (upd_cmd == I40E_NVMUPD_INVALID) {
9343d75a287SRobert Mustacchi 		*perrno = -EFAULT;
9353d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
9363d75a287SRobert Mustacchi 			   "i40e_nvmupd_validate_command returns %d errno %d\n",
9373d75a287SRobert Mustacchi 			   upd_cmd, *perrno);
9383d75a287SRobert Mustacchi 	}
9393d75a287SRobert Mustacchi 
9403d75a287SRobert Mustacchi 	/* a status request returns immediately rather than
9413d75a287SRobert Mustacchi 	 * going into the state machine
9423d75a287SRobert Mustacchi 	 */
9433d75a287SRobert Mustacchi 	if (upd_cmd == I40E_NVMUPD_STATUS) {
9443d75a287SRobert Mustacchi 		if (!cmd->data_size) {
9453d75a287SRobert Mustacchi 			*perrno = -EFAULT;
9463d75a287SRobert Mustacchi 			return I40E_ERR_BUF_TOO_SHORT;
9473d75a287SRobert Mustacchi 		}
9483d75a287SRobert Mustacchi 
9493d75a287SRobert Mustacchi 		bytes[0] = hw->nvmupd_state;
9503d75a287SRobert Mustacchi 
9513d75a287SRobert Mustacchi 		if (cmd->data_size >= 4) {
9523d75a287SRobert Mustacchi 			bytes[1] = 0;
9533d75a287SRobert Mustacchi 			*((u16 *)&bytes[2]) = hw->nvm_wait_opcode;
9543d75a287SRobert Mustacchi 		}
9553d75a287SRobert Mustacchi 
9563d75a287SRobert Mustacchi 		/* Clear error status on read */
9573d75a287SRobert Mustacchi 		if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR)
9583d75a287SRobert Mustacchi 			hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
9593d75a287SRobert Mustacchi 
9603d75a287SRobert Mustacchi 		return I40E_SUCCESS;
9613d75a287SRobert Mustacchi 	}
9623d75a287SRobert Mustacchi 
963*df36e06dSRobert Mustacchi 	/*
964*df36e06dSRobert Mustacchi 	 * A supported features request returns immediately
965*df36e06dSRobert Mustacchi 	 * rather than going into state machine
966*df36e06dSRobert Mustacchi 	 */
967*df36e06dSRobert Mustacchi 	if (upd_cmd == I40E_NVMUPD_FEATURES) {
968*df36e06dSRobert Mustacchi 		if (cmd->data_size < hw->nvmupd_features.size) {
969*df36e06dSRobert Mustacchi 			*perrno = -EFAULT;
970*df36e06dSRobert Mustacchi 			return I40E_ERR_BUF_TOO_SHORT;
971*df36e06dSRobert Mustacchi 		}
972*df36e06dSRobert Mustacchi 
973*df36e06dSRobert Mustacchi 		/*
974*df36e06dSRobert Mustacchi 		 * If buffer is bigger than i40e_nvmupd_features structure,
975*df36e06dSRobert Mustacchi 		 * make sure the trailing bytes are set to 0x0.
976*df36e06dSRobert Mustacchi 		 */
977*df36e06dSRobert Mustacchi 		if (cmd->data_size > hw->nvmupd_features.size)
978*df36e06dSRobert Mustacchi 			i40e_memset(bytes + hw->nvmupd_features.size, 0x0,
979*df36e06dSRobert Mustacchi 				    cmd->data_size - hw->nvmupd_features.size,
980*df36e06dSRobert Mustacchi 				    I40E_NONDMA_MEM);
981*df36e06dSRobert Mustacchi 
982*df36e06dSRobert Mustacchi 		i40e_memcpy(bytes, &hw->nvmupd_features,
983*df36e06dSRobert Mustacchi 			    hw->nvmupd_features.size, I40E_NONDMA_MEM);
984*df36e06dSRobert Mustacchi 
985*df36e06dSRobert Mustacchi 		return I40E_SUCCESS;
986*df36e06dSRobert Mustacchi 	}
987*df36e06dSRobert Mustacchi 
9883d75a287SRobert Mustacchi 	/* Clear status even it is not read and log */
9893d75a287SRobert Mustacchi 	if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR) {
9903d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
9913d75a287SRobert Mustacchi 			   "Clearing I40E_NVMUPD_STATE_ERROR state without reading\n");
9923d75a287SRobert Mustacchi 		hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
9933d75a287SRobert Mustacchi 	}
9943d75a287SRobert Mustacchi 
99593f1cac5SPaul Winder 	/* Acquire lock to prevent race condition where adminq_task
99693f1cac5SPaul Winder 	 * can execute after i40e_nvmupd_nvm_read/write but before state
99793f1cac5SPaul Winder 	 * variables (nvm_wait_opcode, nvm_release_on_done) are updated.
99893f1cac5SPaul Winder 	 *
99993f1cac5SPaul Winder 	 * During NVMUpdate, it is observed that lock could be held for
100093f1cac5SPaul Winder 	 * ~5ms for most commands. However lock is held for ~60ms for
100193f1cac5SPaul Winder 	 * NVMUPD_CSUM_LCB command.
100293f1cac5SPaul Winder 	 */
100393f1cac5SPaul Winder 	i40e_acquire_spinlock(&hw->aq.arq_spinlock);
10043d75a287SRobert Mustacchi 	switch (hw->nvmupd_state) {
10053d75a287SRobert Mustacchi 	case I40E_NVMUPD_STATE_INIT:
10063d75a287SRobert Mustacchi 		status = i40e_nvmupd_state_init(hw, cmd, bytes, perrno);
10073d75a287SRobert Mustacchi 		break;
10083d75a287SRobert Mustacchi 
10093d75a287SRobert Mustacchi 	case I40E_NVMUPD_STATE_READING:
10103d75a287SRobert Mustacchi 		status = i40e_nvmupd_state_reading(hw, cmd, bytes, perrno);
10113d75a287SRobert Mustacchi 		break;
10123d75a287SRobert Mustacchi 
10133d75a287SRobert Mustacchi 	case I40E_NVMUPD_STATE_WRITING:
10143d75a287SRobert Mustacchi 		status = i40e_nvmupd_state_writing(hw, cmd, bytes, perrno);
10153d75a287SRobert Mustacchi 		break;
10163d75a287SRobert Mustacchi 
10173d75a287SRobert Mustacchi 	case I40E_NVMUPD_STATE_INIT_WAIT:
10183d75a287SRobert Mustacchi 	case I40E_NVMUPD_STATE_WRITE_WAIT:
10193d75a287SRobert Mustacchi 		/* if we need to stop waiting for an event, clear
10203d75a287SRobert Mustacchi 		 * the wait info and return before doing anything else
10213d75a287SRobert Mustacchi 		 */
10223d75a287SRobert Mustacchi 		if (cmd->offset == 0xffff) {
102393f1cac5SPaul Winder 			i40e_nvmupd_clear_wait_state(hw);
102493f1cac5SPaul Winder 			status = I40E_SUCCESS;
102593f1cac5SPaul Winder 			break;
10263d75a287SRobert Mustacchi 		}
10273d75a287SRobert Mustacchi 
10283d75a287SRobert Mustacchi 		status = I40E_ERR_NOT_READY;
10293d75a287SRobert Mustacchi 		*perrno = -EBUSY;
10303d75a287SRobert Mustacchi 		break;
10313d75a287SRobert Mustacchi 
10323d75a287SRobert Mustacchi 	default:
10333d75a287SRobert Mustacchi 		/* invalid state, should never happen */
10343d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
10353d75a287SRobert Mustacchi 			   "NVMUPD: no such state %d\n", hw->nvmupd_state);
10363d75a287SRobert Mustacchi 		status = I40E_NOT_SUPPORTED;
10373d75a287SRobert Mustacchi 		*perrno = -ESRCH;
10383d75a287SRobert Mustacchi 		break;
10393d75a287SRobert Mustacchi 	}
104093f1cac5SPaul Winder 
104193f1cac5SPaul Winder 	i40e_release_spinlock(&hw->aq.arq_spinlock);
10423d75a287SRobert Mustacchi 	return status;
10433d75a287SRobert Mustacchi }
10443d75a287SRobert Mustacchi 
10453d75a287SRobert Mustacchi /**
10463d75a287SRobert Mustacchi  * i40e_nvmupd_state_init - Handle NVM update state Init
10473d75a287SRobert Mustacchi  * @hw: pointer to hardware structure
10483d75a287SRobert Mustacchi  * @cmd: pointer to nvm update command buffer
10493d75a287SRobert Mustacchi  * @bytes: pointer to the data buffer
10503d75a287SRobert Mustacchi  * @perrno: pointer to return error code
10513d75a287SRobert Mustacchi  *
10523d75a287SRobert Mustacchi  * Process legitimate commands of the Init state and conditionally set next
10533d75a287SRobert Mustacchi  * state. Reject all other commands.
10543d75a287SRobert Mustacchi  **/
i40e_nvmupd_state_init(struct i40e_hw * hw,struct i40e_nvm_access * cmd,u8 * bytes,int * perrno)10553d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw,
10563d75a287SRobert Mustacchi 						    struct i40e_nvm_access *cmd,
10573d75a287SRobert Mustacchi 						    u8 *bytes, int *perrno)
10583d75a287SRobert Mustacchi {
10593d75a287SRobert Mustacchi 	enum i40e_status_code status = I40E_SUCCESS;
10603d75a287SRobert Mustacchi 	enum i40e_nvmupd_cmd upd_cmd;
10613d75a287SRobert Mustacchi 
10623d75a287SRobert Mustacchi 	DEBUGFUNC("i40e_nvmupd_state_init");
10633d75a287SRobert Mustacchi 
10643d75a287SRobert Mustacchi 	upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
10653d75a287SRobert Mustacchi 
10663d75a287SRobert Mustacchi 	switch (upd_cmd) {
10673d75a287SRobert Mustacchi 	case I40E_NVMUPD_READ_SA:
10683d75a287SRobert Mustacchi 		status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
10693d75a287SRobert Mustacchi 		if (status) {
10703d75a287SRobert Mustacchi 			*perrno = i40e_aq_rc_to_posix(status,
10713d75a287SRobert Mustacchi 						     hw->aq.asq_last_status);
10723d75a287SRobert Mustacchi 		} else {
10733d75a287SRobert Mustacchi 			status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
10743d75a287SRobert Mustacchi 			i40e_release_nvm(hw);
10753d75a287SRobert Mustacchi 		}
10763d75a287SRobert Mustacchi 		break;
10773d75a287SRobert Mustacchi 
10783d75a287SRobert Mustacchi 	case I40E_NVMUPD_READ_SNT:
10793d75a287SRobert Mustacchi 		status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
10803d75a287SRobert Mustacchi 		if (status) {
10813d75a287SRobert Mustacchi 			*perrno = i40e_aq_rc_to_posix(status,
10823d75a287SRobert Mustacchi 						     hw->aq.asq_last_status);
10833d75a287SRobert Mustacchi 		} else {
10843d75a287SRobert Mustacchi 			status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
10853d75a287SRobert Mustacchi 			if (status)
10863d75a287SRobert Mustacchi 				i40e_release_nvm(hw);
10873d75a287SRobert Mustacchi 			else
10883d75a287SRobert Mustacchi 				hw->nvmupd_state = I40E_NVMUPD_STATE_READING;
10893d75a287SRobert Mustacchi 		}
10903d75a287SRobert Mustacchi 		break;
10913d75a287SRobert Mustacchi 
10923d75a287SRobert Mustacchi 	case I40E_NVMUPD_WRITE_ERA:
10933d75a287SRobert Mustacchi 		status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
10943d75a287SRobert Mustacchi 		if (status) {
10953d75a287SRobert Mustacchi 			*perrno = i40e_aq_rc_to_posix(status,
10963d75a287SRobert Mustacchi 						     hw->aq.asq_last_status);
10973d75a287SRobert Mustacchi 		} else {
10983d75a287SRobert Mustacchi 			status = i40e_nvmupd_nvm_erase(hw, cmd, perrno);
10993d75a287SRobert Mustacchi 			if (status) {
11003d75a287SRobert Mustacchi 				i40e_release_nvm(hw);
11013d75a287SRobert Mustacchi 			} else {
11023d75a287SRobert Mustacchi 				hw->nvm_release_on_done = TRUE;
11033d75a287SRobert Mustacchi 				hw->nvm_wait_opcode = i40e_aqc_opc_nvm_erase;
11043d75a287SRobert Mustacchi 				hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
11053d75a287SRobert Mustacchi 			}
11063d75a287SRobert Mustacchi 		}
11073d75a287SRobert Mustacchi 		break;
11083d75a287SRobert Mustacchi 
11093d75a287SRobert Mustacchi 	case I40E_NVMUPD_WRITE_SA:
11103d75a287SRobert Mustacchi 		status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
11113d75a287SRobert Mustacchi 		if (status) {
11123d75a287SRobert Mustacchi 			*perrno = i40e_aq_rc_to_posix(status,
11133d75a287SRobert Mustacchi 						     hw->aq.asq_last_status);
11143d75a287SRobert Mustacchi 		} else {
11153d75a287SRobert Mustacchi 			status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
11163d75a287SRobert Mustacchi 			if (status) {
11173d75a287SRobert Mustacchi 				i40e_release_nvm(hw);
11183d75a287SRobert Mustacchi 			} else {
11193d75a287SRobert Mustacchi 				hw->nvm_release_on_done = TRUE;
11203d75a287SRobert Mustacchi 				hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
11213d75a287SRobert Mustacchi 				hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
11223d75a287SRobert Mustacchi 			}
11233d75a287SRobert Mustacchi 		}
11243d75a287SRobert Mustacchi 		break;
11253d75a287SRobert Mustacchi 
11263d75a287SRobert Mustacchi 	case I40E_NVMUPD_WRITE_SNT:
11273d75a287SRobert Mustacchi 		status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
11283d75a287SRobert Mustacchi 		if (status) {
11293d75a287SRobert Mustacchi 			*perrno = i40e_aq_rc_to_posix(status,
11303d75a287SRobert Mustacchi 						     hw->aq.asq_last_status);
11313d75a287SRobert Mustacchi 		} else {
11323d75a287SRobert Mustacchi 			status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
11333d75a287SRobert Mustacchi 			if (status) {
11343d75a287SRobert Mustacchi 				i40e_release_nvm(hw);
11353d75a287SRobert Mustacchi 			} else {
11363d75a287SRobert Mustacchi 				hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
11373d75a287SRobert Mustacchi 				hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT;
11383d75a287SRobert Mustacchi 			}
11393d75a287SRobert Mustacchi 		}
11403d75a287SRobert Mustacchi 		break;
11413d75a287SRobert Mustacchi 
11423d75a287SRobert Mustacchi 	case I40E_NVMUPD_CSUM_SA:
11433d75a287SRobert Mustacchi 		status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
11443d75a287SRobert Mustacchi 		if (status) {
11453d75a287SRobert Mustacchi 			*perrno = i40e_aq_rc_to_posix(status,
11463d75a287SRobert Mustacchi 						     hw->aq.asq_last_status);
11473d75a287SRobert Mustacchi 		} else {
11483d75a287SRobert Mustacchi 			status = i40e_update_nvm_checksum(hw);
11493d75a287SRobert Mustacchi 			if (status) {
11503d75a287SRobert Mustacchi 				*perrno = hw->aq.asq_last_status ?
11513d75a287SRobert Mustacchi 				   i40e_aq_rc_to_posix(status,
11523d75a287SRobert Mustacchi 						       hw->aq.asq_last_status) :
11533d75a287SRobert Mustacchi 				   -EIO;
11543d75a287SRobert Mustacchi 				i40e_release_nvm(hw);
11553d75a287SRobert Mustacchi 			} else {
11563d75a287SRobert Mustacchi 				hw->nvm_release_on_done = TRUE;
11573d75a287SRobert Mustacchi 				hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
11583d75a287SRobert Mustacchi 				hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
11593d75a287SRobert Mustacchi 			}
11603d75a287SRobert Mustacchi 		}
11613d75a287SRobert Mustacchi 		break;
11623d75a287SRobert Mustacchi 
11633d75a287SRobert Mustacchi 	case I40E_NVMUPD_EXEC_AQ:
11643d75a287SRobert Mustacchi 		status = i40e_nvmupd_exec_aq(hw, cmd, bytes, perrno);
11653d75a287SRobert Mustacchi 		break;
11663d75a287SRobert Mustacchi 
11673d75a287SRobert Mustacchi 	case I40E_NVMUPD_GET_AQ_RESULT:
11683d75a287SRobert Mustacchi 		status = i40e_nvmupd_get_aq_result(hw, cmd, bytes, perrno);
11693d75a287SRobert Mustacchi 		break;
11703d75a287SRobert Mustacchi 
117193f1cac5SPaul Winder 	case I40E_NVMUPD_GET_AQ_EVENT:
117293f1cac5SPaul Winder 		status = i40e_nvmupd_get_aq_event(hw, cmd, bytes, perrno);
117393f1cac5SPaul Winder 		break;
117493f1cac5SPaul Winder 
11753d75a287SRobert Mustacchi 	default:
11763d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
11773d75a287SRobert Mustacchi 			   "NVMUPD: bad cmd %s in init state\n",
11783d75a287SRobert Mustacchi 			   i40e_nvm_update_state_str[upd_cmd]);
11793d75a287SRobert Mustacchi 		status = I40E_ERR_NVM;
11803d75a287SRobert Mustacchi 		*perrno = -ESRCH;
11813d75a287SRobert Mustacchi 		break;
11823d75a287SRobert Mustacchi 	}
11833d75a287SRobert Mustacchi 	return status;
11843d75a287SRobert Mustacchi }
11853d75a287SRobert Mustacchi 
11863d75a287SRobert Mustacchi /**
11873d75a287SRobert Mustacchi  * i40e_nvmupd_state_reading - Handle NVM update state Reading
11883d75a287SRobert Mustacchi  * @hw: pointer to hardware structure
11893d75a287SRobert Mustacchi  * @cmd: pointer to nvm update command buffer
11903d75a287SRobert Mustacchi  * @bytes: pointer to the data buffer
11913d75a287SRobert Mustacchi  * @perrno: pointer to return error code
11923d75a287SRobert Mustacchi  *
11933d75a287SRobert Mustacchi  * NVM ownership is already held.  Process legitimate commands and set any
11943d75a287SRobert Mustacchi  * change in state; reject all other commands.
11953d75a287SRobert Mustacchi  **/
i40e_nvmupd_state_reading(struct i40e_hw * hw,struct i40e_nvm_access * cmd,u8 * bytes,int * perrno)11963d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_state_reading(struct i40e_hw *hw,
11973d75a287SRobert Mustacchi 						    struct i40e_nvm_access *cmd,
11983d75a287SRobert Mustacchi 						    u8 *bytes, int *perrno)
11993d75a287SRobert Mustacchi {
12003d75a287SRobert Mustacchi 	enum i40e_status_code status = I40E_SUCCESS;
12013d75a287SRobert Mustacchi 	enum i40e_nvmupd_cmd upd_cmd;
12023d75a287SRobert Mustacchi 
12033d75a287SRobert Mustacchi 	DEBUGFUNC("i40e_nvmupd_state_reading");
12043d75a287SRobert Mustacchi 
12053d75a287SRobert Mustacchi 	upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
12063d75a287SRobert Mustacchi 
12073d75a287SRobert Mustacchi 	switch (upd_cmd) {
12083d75a287SRobert Mustacchi 	case I40E_NVMUPD_READ_SA:
12093d75a287SRobert Mustacchi 	case I40E_NVMUPD_READ_CON:
12103d75a287SRobert Mustacchi 		status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
12113d75a287SRobert Mustacchi 		break;
12123d75a287SRobert Mustacchi 
12133d75a287SRobert Mustacchi 	case I40E_NVMUPD_READ_LCB:
12143d75a287SRobert Mustacchi 		status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
12153d75a287SRobert Mustacchi 		i40e_release_nvm(hw);
12163d75a287SRobert Mustacchi 		hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
12173d75a287SRobert Mustacchi 		break;
12183d75a287SRobert Mustacchi 
12193d75a287SRobert Mustacchi 	default:
12203d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
12213d75a287SRobert Mustacchi 			   "NVMUPD: bad cmd %s in reading state.\n",
12223d75a287SRobert Mustacchi 			   i40e_nvm_update_state_str[upd_cmd]);
12233d75a287SRobert Mustacchi 		status = I40E_NOT_SUPPORTED;
12243d75a287SRobert Mustacchi 		*perrno = -ESRCH;
12253d75a287SRobert Mustacchi 		break;
12263d75a287SRobert Mustacchi 	}
12273d75a287SRobert Mustacchi 	return status;
12283d75a287SRobert Mustacchi }
12293d75a287SRobert Mustacchi 
12303d75a287SRobert Mustacchi /**
12313d75a287SRobert Mustacchi  * i40e_nvmupd_state_writing - Handle NVM update state Writing
12323d75a287SRobert Mustacchi  * @hw: pointer to hardware structure
12333d75a287SRobert Mustacchi  * @cmd: pointer to nvm update command buffer
12343d75a287SRobert Mustacchi  * @bytes: pointer to the data buffer
12353d75a287SRobert Mustacchi  * @perrno: pointer to return error code
12363d75a287SRobert Mustacchi  *
12373d75a287SRobert Mustacchi  * NVM ownership is already held.  Process legitimate commands and set any
12383d75a287SRobert Mustacchi  * change in state; reject all other commands
12393d75a287SRobert Mustacchi  **/
i40e_nvmupd_state_writing(struct i40e_hw * hw,struct i40e_nvm_access * cmd,u8 * bytes,int * perrno)12403d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_state_writing(struct i40e_hw *hw,
12413d75a287SRobert Mustacchi 						    struct i40e_nvm_access *cmd,
12423d75a287SRobert Mustacchi 						    u8 *bytes, int *perrno)
12433d75a287SRobert Mustacchi {
12443d75a287SRobert Mustacchi 	enum i40e_status_code status = I40E_SUCCESS;
12453d75a287SRobert Mustacchi 	enum i40e_nvmupd_cmd upd_cmd;
12463d75a287SRobert Mustacchi 	bool retry_attempt = FALSE;
12473d75a287SRobert Mustacchi 
12483d75a287SRobert Mustacchi 	DEBUGFUNC("i40e_nvmupd_state_writing");
12493d75a287SRobert Mustacchi 
12503d75a287SRobert Mustacchi 	upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
12513d75a287SRobert Mustacchi 
12523d75a287SRobert Mustacchi retry:
12533d75a287SRobert Mustacchi 	switch (upd_cmd) {
12543d75a287SRobert Mustacchi 	case I40E_NVMUPD_WRITE_CON:
12553d75a287SRobert Mustacchi 		status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
12563d75a287SRobert Mustacchi 		if (!status) {
12573d75a287SRobert Mustacchi 			hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
12583d75a287SRobert Mustacchi 			hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT;
12593d75a287SRobert Mustacchi 		}
12603d75a287SRobert Mustacchi 		break;
12613d75a287SRobert Mustacchi 
12623d75a287SRobert Mustacchi 	case I40E_NVMUPD_WRITE_LCB:
12633d75a287SRobert Mustacchi 		status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
12643d75a287SRobert Mustacchi 		if (status) {
12653d75a287SRobert Mustacchi 			*perrno = hw->aq.asq_last_status ?
12663d75a287SRobert Mustacchi 				   i40e_aq_rc_to_posix(status,
12673d75a287SRobert Mustacchi 						       hw->aq.asq_last_status) :
12683d75a287SRobert Mustacchi 				   -EIO;
12693d75a287SRobert Mustacchi 			hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
12703d75a287SRobert Mustacchi 		} else {
12713d75a287SRobert Mustacchi 			hw->nvm_release_on_done = TRUE;
12723d75a287SRobert Mustacchi 			hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
12733d75a287SRobert Mustacchi 			hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
12743d75a287SRobert Mustacchi 		}
12753d75a287SRobert Mustacchi 		break;
12763d75a287SRobert Mustacchi 
12773d75a287SRobert Mustacchi 	case I40E_NVMUPD_CSUM_CON:
12783d75a287SRobert Mustacchi 		/* Assumes the caller has acquired the nvm */
12793d75a287SRobert Mustacchi 		status = i40e_update_nvm_checksum(hw);
12803d75a287SRobert Mustacchi 		if (status) {
12813d75a287SRobert Mustacchi 			*perrno = hw->aq.asq_last_status ?
12823d75a287SRobert Mustacchi 				   i40e_aq_rc_to_posix(status,
12833d75a287SRobert Mustacchi 						       hw->aq.asq_last_status) :
12843d75a287SRobert Mustacchi 				   -EIO;
12853d75a287SRobert Mustacchi 			hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
12863d75a287SRobert Mustacchi 		} else {
12873d75a287SRobert Mustacchi 			hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
12883d75a287SRobert Mustacchi 			hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT;
12893d75a287SRobert Mustacchi 		}
12903d75a287SRobert Mustacchi 		break;
12913d75a287SRobert Mustacchi 
12923d75a287SRobert Mustacchi 	case I40E_NVMUPD_CSUM_LCB:
12933d75a287SRobert Mustacchi 		/* Assumes the caller has acquired the nvm */
12943d75a287SRobert Mustacchi 		status = i40e_update_nvm_checksum(hw);
12953d75a287SRobert Mustacchi 		if (status) {
12963d75a287SRobert Mustacchi 			*perrno = hw->aq.asq_last_status ?
12973d75a287SRobert Mustacchi 				   i40e_aq_rc_to_posix(status,
12983d75a287SRobert Mustacchi 						       hw->aq.asq_last_status) :
12993d75a287SRobert Mustacchi 				   -EIO;
13003d75a287SRobert Mustacchi 			hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
13013d75a287SRobert Mustacchi 		} else {
13023d75a287SRobert Mustacchi 			hw->nvm_release_on_done = TRUE;
13033d75a287SRobert Mustacchi 			hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
13043d75a287SRobert Mustacchi 			hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
13053d75a287SRobert Mustacchi 		}
13063d75a287SRobert Mustacchi 		break;
13073d75a287SRobert Mustacchi 
13083d75a287SRobert Mustacchi 	default:
13093d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
13103d75a287SRobert Mustacchi 			   "NVMUPD: bad cmd %s in writing state.\n",
13113d75a287SRobert Mustacchi 			   i40e_nvm_update_state_str[upd_cmd]);
13123d75a287SRobert Mustacchi 		status = I40E_NOT_SUPPORTED;
13133d75a287SRobert Mustacchi 		*perrno = -ESRCH;
13143d75a287SRobert Mustacchi 		break;
13153d75a287SRobert Mustacchi 	}
13163d75a287SRobert Mustacchi 
13173d75a287SRobert Mustacchi 	/* In some circumstances, a multi-write transaction takes longer
13183d75a287SRobert Mustacchi 	 * than the default 3 minute timeout on the write semaphore.  If
13193d75a287SRobert Mustacchi 	 * the write failed with an EBUSY status, this is likely the problem,
13203d75a287SRobert Mustacchi 	 * so here we try to reacquire the semaphore then retry the write.
13213d75a287SRobert Mustacchi 	 * We only do one retry, then give up.
13223d75a287SRobert Mustacchi 	 */
13233d75a287SRobert Mustacchi 	if (status && (hw->aq.asq_last_status == I40E_AQ_RC_EBUSY) &&
13243d75a287SRobert Mustacchi 	    !retry_attempt) {
13253d75a287SRobert Mustacchi 		enum i40e_status_code old_status = status;
13263d75a287SRobert Mustacchi 		u32 old_asq_status = hw->aq.asq_last_status;
13273d75a287SRobert Mustacchi 		u32 gtime;
13283d75a287SRobert Mustacchi 
13293d75a287SRobert Mustacchi 		gtime = rd32(hw, I40E_GLVFGEN_TIMER);
13303d75a287SRobert Mustacchi 		if (gtime >= hw->nvm.hw_semaphore_timeout) {
13313d75a287SRobert Mustacchi 			i40e_debug(hw, I40E_DEBUG_ALL,
13323d75a287SRobert Mustacchi 				   "NVMUPD: write semaphore expired (%d >= %lld), retrying\n",
13333d75a287SRobert Mustacchi 				   gtime, hw->nvm.hw_semaphore_timeout);
13343d75a287SRobert Mustacchi 			i40e_release_nvm(hw);
13353d75a287SRobert Mustacchi 			status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
13363d75a287SRobert Mustacchi 			if (status) {
13373d75a287SRobert Mustacchi 				i40e_debug(hw, I40E_DEBUG_ALL,
13383d75a287SRobert Mustacchi 					   "NVMUPD: write semaphore reacquire failed aq_err = %d\n",
13393d75a287SRobert Mustacchi 					   hw->aq.asq_last_status);
13403d75a287SRobert Mustacchi 				status = old_status;
13413d75a287SRobert Mustacchi 				hw->aq.asq_last_status = old_asq_status;
13423d75a287SRobert Mustacchi 			} else {
13433d75a287SRobert Mustacchi 				retry_attempt = TRUE;
13443d75a287SRobert Mustacchi 				goto retry;
13453d75a287SRobert Mustacchi 			}
13463d75a287SRobert Mustacchi 		}
13473d75a287SRobert Mustacchi 	}
13483d75a287SRobert Mustacchi 
13493d75a287SRobert Mustacchi 	return status;
13503d75a287SRobert Mustacchi }
13513d75a287SRobert Mustacchi 
13523d75a287SRobert Mustacchi /**
135393f1cac5SPaul Winder  * i40e_nvmupd_clear_wait_state - clear wait state on hw
13543d75a287SRobert Mustacchi  * @hw: pointer to the hardware structure
13553d75a287SRobert Mustacchi  **/
i40e_nvmupd_clear_wait_state(struct i40e_hw * hw)135693f1cac5SPaul Winder void i40e_nvmupd_clear_wait_state(struct i40e_hw *hw)
13573d75a287SRobert Mustacchi {
135893f1cac5SPaul Winder 	i40e_debug(hw, I40E_DEBUG_NVM,
135993f1cac5SPaul Winder 		   "NVMUPD: clearing wait on opcode 0x%04x\n",
136093f1cac5SPaul Winder 		   hw->nvm_wait_opcode);
13613d75a287SRobert Mustacchi 
136293f1cac5SPaul Winder 	if (hw->nvm_release_on_done) {
136393f1cac5SPaul Winder 		i40e_release_nvm(hw);
136493f1cac5SPaul Winder 		hw->nvm_release_on_done = FALSE;
136593f1cac5SPaul Winder 	}
136693f1cac5SPaul Winder 	hw->nvm_wait_opcode = 0;
13673d75a287SRobert Mustacchi 
136893f1cac5SPaul Winder 	if (hw->aq.arq_last_status) {
136993f1cac5SPaul Winder 		hw->nvmupd_state = I40E_NVMUPD_STATE_ERROR;
137093f1cac5SPaul Winder 		return;
137193f1cac5SPaul Winder 	}
13723d75a287SRobert Mustacchi 
137393f1cac5SPaul Winder 	switch (hw->nvmupd_state) {
137493f1cac5SPaul Winder 	case I40E_NVMUPD_STATE_INIT_WAIT:
137593f1cac5SPaul Winder 		hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
137693f1cac5SPaul Winder 		break;
13773d75a287SRobert Mustacchi 
137893f1cac5SPaul Winder 	case I40E_NVMUPD_STATE_WRITE_WAIT:
137993f1cac5SPaul Winder 		hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING;
138093f1cac5SPaul Winder 		break;
13813d75a287SRobert Mustacchi 
138293f1cac5SPaul Winder 	default:
138393f1cac5SPaul Winder 		break;
138493f1cac5SPaul Winder 	}
138593f1cac5SPaul Winder }
138693f1cac5SPaul Winder 
138793f1cac5SPaul Winder /**
138893f1cac5SPaul Winder  * i40e_nvmupd_check_wait_event - handle NVM update operation events
138993f1cac5SPaul Winder  * @hw: pointer to the hardware structure
139093f1cac5SPaul Winder  * @opcode: the event that just happened
139193f1cac5SPaul Winder  * @desc: AdminQ descriptor
139293f1cac5SPaul Winder  **/
i40e_nvmupd_check_wait_event(struct i40e_hw * hw,u16 opcode,struct i40e_aq_desc * desc)139393f1cac5SPaul Winder void i40e_nvmupd_check_wait_event(struct i40e_hw *hw, u16 opcode,
139493f1cac5SPaul Winder 				  struct i40e_aq_desc *desc)
139593f1cac5SPaul Winder {
139693f1cac5SPaul Winder 	u32 aq_desc_len = sizeof(struct i40e_aq_desc);
139793f1cac5SPaul Winder 
139893f1cac5SPaul Winder 	if (opcode == hw->nvm_wait_opcode) {
139993f1cac5SPaul Winder 		i40e_memcpy(&hw->nvm_aq_event_desc, desc,
140093f1cac5SPaul Winder 			    aq_desc_len, I40E_NONDMA_TO_NONDMA);
140193f1cac5SPaul Winder 		i40e_nvmupd_clear_wait_state(hw);
14023d75a287SRobert Mustacchi 	}
14033d75a287SRobert Mustacchi }
14043d75a287SRobert Mustacchi 
14053d75a287SRobert Mustacchi /**
14063d75a287SRobert Mustacchi  * i40e_nvmupd_validate_command - Validate given command
14073d75a287SRobert Mustacchi  * @hw: pointer to hardware structure
14083d75a287SRobert Mustacchi  * @cmd: pointer to nvm update command buffer
14093d75a287SRobert Mustacchi  * @perrno: pointer to return error code
14103d75a287SRobert Mustacchi  *
14113d75a287SRobert Mustacchi  * Return one of the valid command types or I40E_NVMUPD_INVALID
14123d75a287SRobert Mustacchi  **/
i40e_nvmupd_validate_command(struct i40e_hw * hw,struct i40e_nvm_access * cmd,int * perrno)14133d75a287SRobert Mustacchi static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
14143d75a287SRobert Mustacchi 						    struct i40e_nvm_access *cmd,
14153d75a287SRobert Mustacchi 						    int *perrno)
14163d75a287SRobert Mustacchi {
14173d75a287SRobert Mustacchi 	enum i40e_nvmupd_cmd upd_cmd;
14183d75a287SRobert Mustacchi 	u8 module, transaction;
14193d75a287SRobert Mustacchi 
14203d75a287SRobert Mustacchi 	DEBUGFUNC("i40e_nvmupd_validate_command\n");
14213d75a287SRobert Mustacchi 
14223d75a287SRobert Mustacchi 	/* anything that doesn't match a recognized case is an error */
14233d75a287SRobert Mustacchi 	upd_cmd = I40E_NVMUPD_INVALID;
14243d75a287SRobert Mustacchi 
14253d75a287SRobert Mustacchi 	transaction = i40e_nvmupd_get_transaction(cmd->config);
14263d75a287SRobert Mustacchi 	module = i40e_nvmupd_get_module(cmd->config);
14273d75a287SRobert Mustacchi 
14283d75a287SRobert Mustacchi 	/* limits on data size */
14293d75a287SRobert Mustacchi 	if ((cmd->data_size < 1) ||
14303d75a287SRobert Mustacchi 	    (cmd->data_size > I40E_NVMUPD_MAX_DATA)) {
14313d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
14323d75a287SRobert Mustacchi 			   "i40e_nvmupd_validate_command data_size %d\n",
14333d75a287SRobert Mustacchi 			   cmd->data_size);
14343d75a287SRobert Mustacchi 		*perrno = -EFAULT;
14353d75a287SRobert Mustacchi 		return I40E_NVMUPD_INVALID;
14363d75a287SRobert Mustacchi 	}
14373d75a287SRobert Mustacchi 
14383d75a287SRobert Mustacchi 	switch (cmd->command) {
14393d75a287SRobert Mustacchi 	case I40E_NVM_READ:
14403d75a287SRobert Mustacchi 		switch (transaction) {
14413d75a287SRobert Mustacchi 		case I40E_NVM_CON:
14423d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_READ_CON;
14433d75a287SRobert Mustacchi 			break;
14443d75a287SRobert Mustacchi 		case I40E_NVM_SNT:
14453d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_READ_SNT;
14463d75a287SRobert Mustacchi 			break;
14473d75a287SRobert Mustacchi 		case I40E_NVM_LCB:
14483d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_READ_LCB;
14493d75a287SRobert Mustacchi 			break;
14503d75a287SRobert Mustacchi 		case I40E_NVM_SA:
14513d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_READ_SA;
14523d75a287SRobert Mustacchi 			break;
14533d75a287SRobert Mustacchi 		case I40E_NVM_EXEC:
1454*df36e06dSRobert Mustacchi 			switch (module) {
1455*df36e06dSRobert Mustacchi 			case I40E_NVM_EXEC_GET_AQ_RESULT:
14563d75a287SRobert Mustacchi 				upd_cmd = I40E_NVMUPD_GET_AQ_RESULT;
1457*df36e06dSRobert Mustacchi 				break;
1458*df36e06dSRobert Mustacchi 			case I40E_NVM_EXEC_FEATURES:
1459*df36e06dSRobert Mustacchi 				upd_cmd = I40E_NVMUPD_FEATURES;
1460*df36e06dSRobert Mustacchi 				break;
1461*df36e06dSRobert Mustacchi 			case I40E_NVM_EXEC_STATUS:
1462*df36e06dSRobert Mustacchi 				upd_cmd = I40E_NVMUPD_STATUS;
1463*df36e06dSRobert Mustacchi 				break;
1464*df36e06dSRobert Mustacchi 			default:
1465*df36e06dSRobert Mustacchi 				*perrno = -EFAULT;
1466*df36e06dSRobert Mustacchi 				return I40E_NVMUPD_INVALID;
1467*df36e06dSRobert Mustacchi 			}
14683d75a287SRobert Mustacchi 			break;
146993f1cac5SPaul Winder 		case I40E_NVM_AQE:
147093f1cac5SPaul Winder 			upd_cmd = I40E_NVMUPD_GET_AQ_EVENT;
147193f1cac5SPaul Winder 			break;
14723d75a287SRobert Mustacchi 		}
14733d75a287SRobert Mustacchi 		break;
14743d75a287SRobert Mustacchi 
14753d75a287SRobert Mustacchi 	case I40E_NVM_WRITE:
14763d75a287SRobert Mustacchi 		switch (transaction) {
14773d75a287SRobert Mustacchi 		case I40E_NVM_CON:
14783d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_WRITE_CON;
14793d75a287SRobert Mustacchi 			break;
14803d75a287SRobert Mustacchi 		case I40E_NVM_SNT:
14813d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_WRITE_SNT;
14823d75a287SRobert Mustacchi 			break;
14833d75a287SRobert Mustacchi 		case I40E_NVM_LCB:
14843d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_WRITE_LCB;
14853d75a287SRobert Mustacchi 			break;
14863d75a287SRobert Mustacchi 		case I40E_NVM_SA:
14873d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_WRITE_SA;
14883d75a287SRobert Mustacchi 			break;
14893d75a287SRobert Mustacchi 		case I40E_NVM_ERA:
14903d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_WRITE_ERA;
14913d75a287SRobert Mustacchi 			break;
14923d75a287SRobert Mustacchi 		case I40E_NVM_CSUM:
14933d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_CSUM_CON;
14943d75a287SRobert Mustacchi 			break;
14953d75a287SRobert Mustacchi 		case (I40E_NVM_CSUM|I40E_NVM_SA):
14963d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_CSUM_SA;
14973d75a287SRobert Mustacchi 			break;
14983d75a287SRobert Mustacchi 		case (I40E_NVM_CSUM|I40E_NVM_LCB):
14993d75a287SRobert Mustacchi 			upd_cmd = I40E_NVMUPD_CSUM_LCB;
15003d75a287SRobert Mustacchi 			break;
15013d75a287SRobert Mustacchi 		case I40E_NVM_EXEC:
15023d75a287SRobert Mustacchi 			if (module == 0)
15033d75a287SRobert Mustacchi 				upd_cmd = I40E_NVMUPD_EXEC_AQ;
15043d75a287SRobert Mustacchi 			break;
15053d75a287SRobert Mustacchi 		}
15063d75a287SRobert Mustacchi 		break;
15073d75a287SRobert Mustacchi 	}
15083d75a287SRobert Mustacchi 
15093d75a287SRobert Mustacchi 	return upd_cmd;
15103d75a287SRobert Mustacchi }
15113d75a287SRobert Mustacchi 
15123d75a287SRobert Mustacchi /**
15133d75a287SRobert Mustacchi  * i40e_nvmupd_exec_aq - Run an AQ command
15143d75a287SRobert Mustacchi  * @hw: pointer to hardware structure
15153d75a287SRobert Mustacchi  * @cmd: pointer to nvm update command buffer
15163d75a287SRobert Mustacchi  * @bytes: pointer to the data buffer
15173d75a287SRobert Mustacchi  * @perrno: pointer to return error code
15183d75a287SRobert Mustacchi  *
15193d75a287SRobert Mustacchi  * cmd structure contains identifiers and data buffer
15203d75a287SRobert Mustacchi  **/
i40e_nvmupd_exec_aq(struct i40e_hw * hw,struct i40e_nvm_access * cmd,u8 * bytes,int * perrno)15213d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw,
15223d75a287SRobert Mustacchi 						 struct i40e_nvm_access *cmd,
15233d75a287SRobert Mustacchi 						 u8 *bytes, int *perrno)
15243d75a287SRobert Mustacchi {
15253d75a287SRobert Mustacchi 	struct i40e_asq_cmd_details cmd_details;
15263d75a287SRobert Mustacchi 	enum i40e_status_code status;
15273d75a287SRobert Mustacchi 	struct i40e_aq_desc *aq_desc;
15283d75a287SRobert Mustacchi 	u32 buff_size = 0;
15293d75a287SRobert Mustacchi 	u8 *buff = NULL;
15303d75a287SRobert Mustacchi 	u32 aq_desc_len;
15313d75a287SRobert Mustacchi 	u32 aq_data_len;
15323d75a287SRobert Mustacchi 
15333d75a287SRobert Mustacchi 	i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
153493f1cac5SPaul Winder 	if (cmd->offset == 0xffff)
153593f1cac5SPaul Winder 		return I40E_SUCCESS;
153693f1cac5SPaul Winder 
15373d75a287SRobert Mustacchi 	memset(&cmd_details, 0, sizeof(cmd_details));
15383d75a287SRobert Mustacchi 	cmd_details.wb_desc = &hw->nvm_wb_desc;
15393d75a287SRobert Mustacchi 
15403d75a287SRobert Mustacchi 	aq_desc_len = sizeof(struct i40e_aq_desc);
15413d75a287SRobert Mustacchi 	memset(&hw->nvm_wb_desc, 0, aq_desc_len);
15423d75a287SRobert Mustacchi 
15433d75a287SRobert Mustacchi 	/* get the aq descriptor */
15443d75a287SRobert Mustacchi 	if (cmd->data_size < aq_desc_len) {
15453d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
15463d75a287SRobert Mustacchi 			   "NVMUPD: not enough aq desc bytes for exec, size %d < %d\n",
15473d75a287SRobert Mustacchi 			   cmd->data_size, aq_desc_len);
15483d75a287SRobert Mustacchi 		*perrno = -EINVAL;
15493d75a287SRobert Mustacchi 		return I40E_ERR_PARAM;
15503d75a287SRobert Mustacchi 	}
15513d75a287SRobert Mustacchi 	aq_desc = (struct i40e_aq_desc *)bytes;
15523d75a287SRobert Mustacchi 
15533d75a287SRobert Mustacchi 	/* if data buffer needed, make sure it's ready */
15543d75a287SRobert Mustacchi 	aq_data_len = cmd->data_size - aq_desc_len;
15553d75a287SRobert Mustacchi 	buff_size = max(aq_data_len, (u32)LE16_TO_CPU(aq_desc->datalen));
15563d75a287SRobert Mustacchi 	if (buff_size) {
15573d75a287SRobert Mustacchi 		if (!hw->nvm_buff.va) {
15583d75a287SRobert Mustacchi 			status = i40e_allocate_virt_mem(hw, &hw->nvm_buff,
15593d75a287SRobert Mustacchi 							hw->aq.asq_buf_size);
15603d75a287SRobert Mustacchi 			if (status)
15613d75a287SRobert Mustacchi 				i40e_debug(hw, I40E_DEBUG_NVM,
15623d75a287SRobert Mustacchi 					   "NVMUPD: i40e_allocate_virt_mem for exec buff failed, %d\n",
15633d75a287SRobert Mustacchi 					   status);
15643d75a287SRobert Mustacchi 		}
15653d75a287SRobert Mustacchi 
15663d75a287SRobert Mustacchi 		if (hw->nvm_buff.va) {
15673d75a287SRobert Mustacchi 			buff = hw->nvm_buff.va;
15683d75a287SRobert Mustacchi 			i40e_memcpy(buff, &bytes[aq_desc_len], aq_data_len,
15693d75a287SRobert Mustacchi 				I40E_NONDMA_TO_NONDMA);
15703d75a287SRobert Mustacchi 		}
15713d75a287SRobert Mustacchi 	}
15723d75a287SRobert Mustacchi 
157393f1cac5SPaul Winder 	if (cmd->offset)
157493f1cac5SPaul Winder 		memset(&hw->nvm_aq_event_desc, 0, aq_desc_len);
157593f1cac5SPaul Winder 
15763d75a287SRobert Mustacchi 	/* and away we go! */
15773d75a287SRobert Mustacchi 	status = i40e_asq_send_command(hw, aq_desc, buff,
15783d75a287SRobert Mustacchi 				       buff_size, &cmd_details);
15793d75a287SRobert Mustacchi 	if (status) {
15803d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
15813d75a287SRobert Mustacchi 			   "i40e_nvmupd_exec_aq err %s aq_err %s\n",
15823d75a287SRobert Mustacchi 			   i40e_stat_str(hw, status),
15833d75a287SRobert Mustacchi 			   i40e_aq_str(hw, hw->aq.asq_last_status));
15843d75a287SRobert Mustacchi 		*perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
158593f1cac5SPaul Winder 		return status;
15863d75a287SRobert Mustacchi 	}
15873d75a287SRobert Mustacchi 
15883d75a287SRobert Mustacchi 	/* should we wait for a followup event? */
15893d75a287SRobert Mustacchi 	if (cmd->offset) {
15903d75a287SRobert Mustacchi 		hw->nvm_wait_opcode = cmd->offset;
15913d75a287SRobert Mustacchi 		hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
15923d75a287SRobert Mustacchi 	}
15933d75a287SRobert Mustacchi 
15943d75a287SRobert Mustacchi 	return status;
15953d75a287SRobert Mustacchi }
15963d75a287SRobert Mustacchi 
15973d75a287SRobert Mustacchi /**
15983d75a287SRobert Mustacchi  * i40e_nvmupd_get_aq_result - Get the results from the previous exec_aq
15993d75a287SRobert Mustacchi  * @hw: pointer to hardware structure
16003d75a287SRobert Mustacchi  * @cmd: pointer to nvm update command buffer
16013d75a287SRobert Mustacchi  * @bytes: pointer to the data buffer
16023d75a287SRobert Mustacchi  * @perrno: pointer to return error code
16033d75a287SRobert Mustacchi  *
16043d75a287SRobert Mustacchi  * cmd structure contains identifiers and data buffer
16053d75a287SRobert Mustacchi  **/
i40e_nvmupd_get_aq_result(struct i40e_hw * hw,struct i40e_nvm_access * cmd,u8 * bytes,int * perrno)16063d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_get_aq_result(struct i40e_hw *hw,
16073d75a287SRobert Mustacchi 						    struct i40e_nvm_access *cmd,
16083d75a287SRobert Mustacchi 						    u8 *bytes, int *perrno)
16093d75a287SRobert Mustacchi {
16103d75a287SRobert Mustacchi 	u32 aq_total_len;
16113d75a287SRobert Mustacchi 	u32 aq_desc_len;
16123d75a287SRobert Mustacchi 	int remainder;
16133d75a287SRobert Mustacchi 	u8 *buff;
16143d75a287SRobert Mustacchi 
16153d75a287SRobert Mustacchi 	i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
16163d75a287SRobert Mustacchi 
16173d75a287SRobert Mustacchi 	aq_desc_len = sizeof(struct i40e_aq_desc);
16183d75a287SRobert Mustacchi 	aq_total_len = aq_desc_len + LE16_TO_CPU(hw->nvm_wb_desc.datalen);
16193d75a287SRobert Mustacchi 
16203d75a287SRobert Mustacchi 	/* check offset range */
16213d75a287SRobert Mustacchi 	if (cmd->offset > aq_total_len) {
16223d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM, "%s: offset too big %d > %d\n",
16233d75a287SRobert Mustacchi 			   __func__, cmd->offset, aq_total_len);
16243d75a287SRobert Mustacchi 		*perrno = -EINVAL;
16253d75a287SRobert Mustacchi 		return I40E_ERR_PARAM;
16263d75a287SRobert Mustacchi 	}
16273d75a287SRobert Mustacchi 
16283d75a287SRobert Mustacchi 	/* check copylength range */
16293d75a287SRobert Mustacchi 	if (cmd->data_size > (aq_total_len - cmd->offset)) {
16303d75a287SRobert Mustacchi 		int new_len = aq_total_len - cmd->offset;
16313d75a287SRobert Mustacchi 
16323d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM, "%s: copy length %d too big, trimming to %d\n",
16333d75a287SRobert Mustacchi 			   __func__, cmd->data_size, new_len);
16343d75a287SRobert Mustacchi 		cmd->data_size = new_len;
16353d75a287SRobert Mustacchi 	}
16363d75a287SRobert Mustacchi 
16373d75a287SRobert Mustacchi 	remainder = cmd->data_size;
16383d75a287SRobert Mustacchi 	if (cmd->offset < aq_desc_len) {
16393d75a287SRobert Mustacchi 		u32 len = aq_desc_len - cmd->offset;
16403d75a287SRobert Mustacchi 
16413d75a287SRobert Mustacchi 		len = min(len, cmd->data_size);
16423d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM, "%s: aq_desc bytes %d to %d\n",
16433d75a287SRobert Mustacchi 			   __func__, cmd->offset, cmd->offset + len);
16443d75a287SRobert Mustacchi 
16453d75a287SRobert Mustacchi 		buff = ((u8 *)&hw->nvm_wb_desc) + cmd->offset;
16463d75a287SRobert Mustacchi 		i40e_memcpy(bytes, buff, len, I40E_NONDMA_TO_NONDMA);
16473d75a287SRobert Mustacchi 
16483d75a287SRobert Mustacchi 		bytes += len;
16493d75a287SRobert Mustacchi 		remainder -= len;
16503d75a287SRobert Mustacchi 		buff = hw->nvm_buff.va;
16513d75a287SRobert Mustacchi 	} else {
16523d75a287SRobert Mustacchi 		buff = (u8 *)hw->nvm_buff.va + (cmd->offset - aq_desc_len);
16533d75a287SRobert Mustacchi 	}
16543d75a287SRobert Mustacchi 
16553d75a287SRobert Mustacchi 	if (remainder > 0) {
16563d75a287SRobert Mustacchi 		int start_byte = buff - (u8 *)hw->nvm_buff.va;
16573d75a287SRobert Mustacchi 
16583d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM, "%s: databuf bytes %d to %d\n",
16593d75a287SRobert Mustacchi 			   __func__, start_byte, start_byte + remainder);
16603d75a287SRobert Mustacchi 		i40e_memcpy(bytes, buff, remainder, I40E_NONDMA_TO_NONDMA);
16613d75a287SRobert Mustacchi 	}
16623d75a287SRobert Mustacchi 
16633d75a287SRobert Mustacchi 	return I40E_SUCCESS;
16643d75a287SRobert Mustacchi }
16653d75a287SRobert Mustacchi 
166693f1cac5SPaul Winder /**
166793f1cac5SPaul Winder  * i40e_nvmupd_get_aq_event - Get the Admin Queue event from previous exec_aq
166893f1cac5SPaul Winder  * @hw: pointer to hardware structure
166993f1cac5SPaul Winder  * @cmd: pointer to nvm update command buffer
167093f1cac5SPaul Winder  * @bytes: pointer to the data buffer
167193f1cac5SPaul Winder  * @perrno: pointer to return error code
167293f1cac5SPaul Winder  *
167393f1cac5SPaul Winder  * cmd structure contains identifiers and data buffer
167493f1cac5SPaul Winder  **/
i40e_nvmupd_get_aq_event(struct i40e_hw * hw,struct i40e_nvm_access * cmd,u8 * bytes,int * perrno)167593f1cac5SPaul Winder static enum i40e_status_code i40e_nvmupd_get_aq_event(struct i40e_hw *hw,
167693f1cac5SPaul Winder 						    struct i40e_nvm_access *cmd,
167793f1cac5SPaul Winder 						    u8 *bytes, int *perrno)
167893f1cac5SPaul Winder {
167993f1cac5SPaul Winder 	u32 aq_total_len;
168093f1cac5SPaul Winder 	u32 aq_desc_len;
168193f1cac5SPaul Winder 
168293f1cac5SPaul Winder 	i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
168393f1cac5SPaul Winder 
168493f1cac5SPaul Winder 	aq_desc_len = sizeof(struct i40e_aq_desc);
168593f1cac5SPaul Winder 	aq_total_len = aq_desc_len + LE16_TO_CPU(hw->nvm_aq_event_desc.datalen);
168693f1cac5SPaul Winder 
168793f1cac5SPaul Winder 	/* check copylength range */
168893f1cac5SPaul Winder 	if (cmd->data_size > aq_total_len) {
168993f1cac5SPaul Winder 		i40e_debug(hw, I40E_DEBUG_NVM,
169093f1cac5SPaul Winder 			   "%s: copy length %d too big, trimming to %d\n",
169193f1cac5SPaul Winder 			   __func__, cmd->data_size, aq_total_len);
169293f1cac5SPaul Winder 		cmd->data_size = aq_total_len;
169393f1cac5SPaul Winder 	}
169493f1cac5SPaul Winder 
169593f1cac5SPaul Winder 	i40e_memcpy(bytes, &hw->nvm_aq_event_desc, cmd->data_size,
169693f1cac5SPaul Winder 		    I40E_NONDMA_TO_NONDMA);
169793f1cac5SPaul Winder 
169893f1cac5SPaul Winder 	return I40E_SUCCESS;
169993f1cac5SPaul Winder }
170093f1cac5SPaul Winder 
17013d75a287SRobert Mustacchi /**
17023d75a287SRobert Mustacchi  * i40e_nvmupd_nvm_read - Read NVM
17033d75a287SRobert Mustacchi  * @hw: pointer to hardware structure
17043d75a287SRobert Mustacchi  * @cmd: pointer to nvm update command buffer
17053d75a287SRobert Mustacchi  * @bytes: pointer to the data buffer
17063d75a287SRobert Mustacchi  * @perrno: pointer to return error code
17073d75a287SRobert Mustacchi  *
17083d75a287SRobert Mustacchi  * cmd structure contains identifiers and data buffer
17093d75a287SRobert Mustacchi  **/
i40e_nvmupd_nvm_read(struct i40e_hw * hw,struct i40e_nvm_access * cmd,u8 * bytes,int * perrno)17103d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_nvm_read(struct i40e_hw *hw,
17113d75a287SRobert Mustacchi 						  struct i40e_nvm_access *cmd,
17123d75a287SRobert Mustacchi 						  u8 *bytes, int *perrno)
17133d75a287SRobert Mustacchi {
17143d75a287SRobert Mustacchi 	struct i40e_asq_cmd_details cmd_details;
17153d75a287SRobert Mustacchi 	enum i40e_status_code status;
17163d75a287SRobert Mustacchi 	u8 module, transaction;
17173d75a287SRobert Mustacchi 	bool last;
17183d75a287SRobert Mustacchi 
17193d75a287SRobert Mustacchi 	transaction = i40e_nvmupd_get_transaction(cmd->config);
17203d75a287SRobert Mustacchi 	module = i40e_nvmupd_get_module(cmd->config);
17213d75a287SRobert Mustacchi 	last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA);
17223d75a287SRobert Mustacchi 
17233d75a287SRobert Mustacchi 	memset(&cmd_details, 0, sizeof(cmd_details));
17243d75a287SRobert Mustacchi 	cmd_details.wb_desc = &hw->nvm_wb_desc;
17253d75a287SRobert Mustacchi 
17263d75a287SRobert Mustacchi 	status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
17273d75a287SRobert Mustacchi 				  bytes, last, &cmd_details);
17283d75a287SRobert Mustacchi 	if (status) {
17293d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
17303d75a287SRobert Mustacchi 			   "i40e_nvmupd_nvm_read mod 0x%x  off 0x%x  len 0x%x\n",
17313d75a287SRobert Mustacchi 			   module, cmd->offset, cmd->data_size);
17323d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
17333d75a287SRobert Mustacchi 			   "i40e_nvmupd_nvm_read status %d aq %d\n",
17343d75a287SRobert Mustacchi 			   status, hw->aq.asq_last_status);
17353d75a287SRobert Mustacchi 		*perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
17363d75a287SRobert Mustacchi 	}
17373d75a287SRobert Mustacchi 
17383d75a287SRobert Mustacchi 	return status;
17393d75a287SRobert Mustacchi }
17403d75a287SRobert Mustacchi 
17413d75a287SRobert Mustacchi /**
17423d75a287SRobert Mustacchi  * i40e_nvmupd_nvm_erase - Erase an NVM module
17433d75a287SRobert Mustacchi  * @hw: pointer to hardware structure
17443d75a287SRobert Mustacchi  * @cmd: pointer to nvm update command buffer
17453d75a287SRobert Mustacchi  * @perrno: pointer to return error code
17463d75a287SRobert Mustacchi  *
17473d75a287SRobert Mustacchi  * module, offset, data_size and data are in cmd structure
17483d75a287SRobert Mustacchi  **/
i40e_nvmupd_nvm_erase(struct i40e_hw * hw,struct i40e_nvm_access * cmd,int * perrno)17493d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
17503d75a287SRobert Mustacchi 						   struct i40e_nvm_access *cmd,
17513d75a287SRobert Mustacchi 						   int *perrno)
17523d75a287SRobert Mustacchi {
17533d75a287SRobert Mustacchi 	enum i40e_status_code status = I40E_SUCCESS;
17543d75a287SRobert Mustacchi 	struct i40e_asq_cmd_details cmd_details;
17553d75a287SRobert Mustacchi 	u8 module, transaction;
17563d75a287SRobert Mustacchi 	bool last;
17573d75a287SRobert Mustacchi 
17583d75a287SRobert Mustacchi 	transaction = i40e_nvmupd_get_transaction(cmd->config);
17593d75a287SRobert Mustacchi 	module = i40e_nvmupd_get_module(cmd->config);
17603d75a287SRobert Mustacchi 	last = (transaction & I40E_NVM_LCB);
17613d75a287SRobert Mustacchi 
17623d75a287SRobert Mustacchi 	memset(&cmd_details, 0, sizeof(cmd_details));
17633d75a287SRobert Mustacchi 	cmd_details.wb_desc = &hw->nvm_wb_desc;
17643d75a287SRobert Mustacchi 
17653d75a287SRobert Mustacchi 	status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
17663d75a287SRobert Mustacchi 				   last, &cmd_details);
17673d75a287SRobert Mustacchi 	if (status) {
17683d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
17693d75a287SRobert Mustacchi 			   "i40e_nvmupd_nvm_erase mod 0x%x  off 0x%x len 0x%x\n",
17703d75a287SRobert Mustacchi 			   module, cmd->offset, cmd->data_size);
17713d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
17723d75a287SRobert Mustacchi 			   "i40e_nvmupd_nvm_erase status %d aq %d\n",
17733d75a287SRobert Mustacchi 			   status, hw->aq.asq_last_status);
17743d75a287SRobert Mustacchi 		*perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
17753d75a287SRobert Mustacchi 	}
17763d75a287SRobert Mustacchi 
17773d75a287SRobert Mustacchi 	return status;
17783d75a287SRobert Mustacchi }
17793d75a287SRobert Mustacchi 
17803d75a287SRobert Mustacchi /**
17813d75a287SRobert Mustacchi  * i40e_nvmupd_nvm_write - Write NVM
17823d75a287SRobert Mustacchi  * @hw: pointer to hardware structure
17833d75a287SRobert Mustacchi  * @cmd: pointer to nvm update command buffer
17843d75a287SRobert Mustacchi  * @bytes: pointer to the data buffer
17853d75a287SRobert Mustacchi  * @perrno: pointer to return error code
17863d75a287SRobert Mustacchi  *
17873d75a287SRobert Mustacchi  * module, offset, data_size and data are in cmd structure
17883d75a287SRobert Mustacchi  **/
i40e_nvmupd_nvm_write(struct i40e_hw * hw,struct i40e_nvm_access * cmd,u8 * bytes,int * perrno)17893d75a287SRobert Mustacchi static enum i40e_status_code i40e_nvmupd_nvm_write(struct i40e_hw *hw,
17903d75a287SRobert Mustacchi 						   struct i40e_nvm_access *cmd,
17913d75a287SRobert Mustacchi 						   u8 *bytes, int *perrno)
17923d75a287SRobert Mustacchi {
17933d75a287SRobert Mustacchi 	enum i40e_status_code status = I40E_SUCCESS;
17943d75a287SRobert Mustacchi 	struct i40e_asq_cmd_details cmd_details;
17953d75a287SRobert Mustacchi 	u8 module, transaction;
179693f1cac5SPaul Winder 	u8 preservation_flags;
17973d75a287SRobert Mustacchi 	bool last;
17983d75a287SRobert Mustacchi 
17993d75a287SRobert Mustacchi 	transaction = i40e_nvmupd_get_transaction(cmd->config);
18003d75a287SRobert Mustacchi 	module = i40e_nvmupd_get_module(cmd->config);
18013d75a287SRobert Mustacchi 	last = (transaction & I40E_NVM_LCB);
180293f1cac5SPaul Winder 	preservation_flags = i40e_nvmupd_get_preservation_flags(cmd->config);
18033d75a287SRobert Mustacchi 
18043d75a287SRobert Mustacchi 	memset(&cmd_details, 0, sizeof(cmd_details));
18053d75a287SRobert Mustacchi 	cmd_details.wb_desc = &hw->nvm_wb_desc;
18063d75a287SRobert Mustacchi 
18073d75a287SRobert Mustacchi 	status = i40e_aq_update_nvm(hw, module, cmd->offset,
18083d75a287SRobert Mustacchi 				    (u16)cmd->data_size, bytes, last,
180993f1cac5SPaul Winder 				    preservation_flags, &cmd_details);
18103d75a287SRobert Mustacchi 	if (status) {
18113d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
18123d75a287SRobert Mustacchi 			   "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n",
18133d75a287SRobert Mustacchi 			   module, cmd->offset, cmd->data_size);
18143d75a287SRobert Mustacchi 		i40e_debug(hw, I40E_DEBUG_NVM,
18153d75a287SRobert Mustacchi 			   "i40e_nvmupd_nvm_write status %d aq %d\n",
18163d75a287SRobert Mustacchi 			   status, hw->aq.asq_last_status);
18173d75a287SRobert Mustacchi 		*perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
18183d75a287SRobert Mustacchi 	}
18193d75a287SRobert Mustacchi 
18203d75a287SRobert Mustacchi 	return status;
18213d75a287SRobert Mustacchi }
1822