xref: /freebsd/sys/dev/ixl/i40e_nvm.c (revision f247dc252337766d1a423ce46d43879a62a742fa)
161ae650dSJack F Vogel /******************************************************************************
261ae650dSJack F Vogel 
361ae650dSJack F Vogel   Copyright (c) 2013-2014, Intel Corporation
461ae650dSJack F Vogel   All rights reserved.
561ae650dSJack F Vogel 
661ae650dSJack F Vogel   Redistribution and use in source and binary forms, with or without
761ae650dSJack F Vogel   modification, are permitted provided that the following conditions are met:
861ae650dSJack F Vogel 
961ae650dSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
1061ae650dSJack F Vogel       this list of conditions and the following disclaimer.
1161ae650dSJack F Vogel 
1261ae650dSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
1361ae650dSJack F Vogel       notice, this list of conditions and the following disclaimer in the
1461ae650dSJack F Vogel       documentation and/or other materials provided with the distribution.
1561ae650dSJack F Vogel 
1661ae650dSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
1761ae650dSJack F Vogel       contributors may be used to endorse or promote products derived from
1861ae650dSJack F Vogel       this software without specific prior written permission.
1961ae650dSJack F Vogel 
2061ae650dSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2161ae650dSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2261ae650dSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2361ae650dSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2461ae650dSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2561ae650dSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2661ae650dSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2761ae650dSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2861ae650dSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2961ae650dSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3061ae650dSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
3161ae650dSJack F Vogel 
3261ae650dSJack F Vogel ******************************************************************************/
3361ae650dSJack F Vogel /*$FreeBSD$*/
3461ae650dSJack F Vogel 
3561ae650dSJack F Vogel #include "i40e_prototype.h"
3661ae650dSJack F Vogel 
37*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset,
38*f247dc25SJack F Vogel 					       u16 *data);
39*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
40*f247dc25SJack F Vogel 					    u16 *data);
41*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset,
42*f247dc25SJack F Vogel 						 u16 *words, u16 *data);
43*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset,
44*f247dc25SJack F Vogel 					      u16 *words, u16 *data);
45*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
46*f247dc25SJack F Vogel 				       u32 offset, u16 words, void *data,
47*f247dc25SJack F Vogel 				       bool last_command);
48*f247dc25SJack F Vogel 
4961ae650dSJack F Vogel /**
5061ae650dSJack F Vogel  * i40e_init_nvm_ops - Initialize NVM function pointers
5161ae650dSJack F Vogel  * @hw: pointer to the HW structure
5261ae650dSJack F Vogel  *
5361ae650dSJack F Vogel  * Setup the function pointers and the NVM info structure. Should be called
5461ae650dSJack F Vogel  * once per NVM initialization, e.g. inside the i40e_init_shared_code().
5561ae650dSJack F Vogel  * Please notice that the NVM term is used here (& in all methods covered
5661ae650dSJack F Vogel  * in this file) as an equivalent of the FLASH part mapped into the SR.
5761ae650dSJack F Vogel  * We are accessing FLASH always thru the Shadow RAM.
5861ae650dSJack F Vogel  **/
5961ae650dSJack F Vogel enum i40e_status_code i40e_init_nvm(struct i40e_hw *hw)
6061ae650dSJack F Vogel {
6161ae650dSJack F Vogel 	struct i40e_nvm_info *nvm = &hw->nvm;
6261ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
6361ae650dSJack F Vogel 	u32 fla, gens;
6461ae650dSJack F Vogel 	u8 sr_size;
6561ae650dSJack F Vogel 
6661ae650dSJack F Vogel 	DEBUGFUNC("i40e_init_nvm");
6761ae650dSJack F Vogel 
6861ae650dSJack F Vogel 	/* The SR size is stored regardless of the nvm programming mode
6961ae650dSJack F Vogel 	 * as the blank mode may be used in the factory line.
7061ae650dSJack F Vogel 	 */
7161ae650dSJack F Vogel 	gens = rd32(hw, I40E_GLNVM_GENS);
7261ae650dSJack F Vogel 	sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
7361ae650dSJack F Vogel 			   I40E_GLNVM_GENS_SR_SIZE_SHIFT);
7461ae650dSJack F Vogel 	/* Switching to words (sr_size contains power of 2KB) */
7561ae650dSJack F Vogel 	nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB;
7661ae650dSJack F Vogel 
7761ae650dSJack F Vogel 	/* Check if we are in the normal or blank NVM programming mode */
7861ae650dSJack F Vogel 	fla = rd32(hw, I40E_GLNVM_FLA);
7961ae650dSJack F Vogel 	if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
8061ae650dSJack F Vogel 		/* Max NVM timeout */
8161ae650dSJack F Vogel 		nvm->timeout = I40E_MAX_NVM_TIMEOUT;
8261ae650dSJack F Vogel 		nvm->blank_nvm_mode = FALSE;
8361ae650dSJack F Vogel 	} else { /* Blank programming mode */
8461ae650dSJack F Vogel 		nvm->blank_nvm_mode = TRUE;
8561ae650dSJack F Vogel 		ret_code = I40E_ERR_NVM_BLANK_MODE;
86*f247dc25SJack F Vogel 		i40e_debug(hw, I40E_DEBUG_NVM, "NVM init error: unsupported blank mode.\n");
8761ae650dSJack F Vogel 	}
8861ae650dSJack F Vogel 
8961ae650dSJack F Vogel 	return ret_code;
9061ae650dSJack F Vogel }
9161ae650dSJack F Vogel 
9261ae650dSJack F Vogel /**
9361ae650dSJack F Vogel  * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
9461ae650dSJack F Vogel  * @hw: pointer to the HW structure
9561ae650dSJack F Vogel  * @access: NVM access type (read or write)
9661ae650dSJack F Vogel  *
9761ae650dSJack F Vogel  * This function will request NVM ownership for reading
9861ae650dSJack F Vogel  * via the proper Admin Command.
9961ae650dSJack F Vogel  **/
10061ae650dSJack F Vogel enum i40e_status_code i40e_acquire_nvm(struct i40e_hw *hw,
10161ae650dSJack F Vogel 				       enum i40e_aq_resource_access_type access)
10261ae650dSJack F Vogel {
10361ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
10461ae650dSJack F Vogel 	u64 gtime, timeout;
105*f247dc25SJack F Vogel 	u64 time_left = 0;
10661ae650dSJack F Vogel 
10761ae650dSJack F Vogel 	DEBUGFUNC("i40e_acquire_nvm");
10861ae650dSJack F Vogel 
10961ae650dSJack F Vogel 	if (hw->nvm.blank_nvm_mode)
11061ae650dSJack F Vogel 		goto i40e_i40e_acquire_nvm_exit;
11161ae650dSJack F Vogel 
11261ae650dSJack F Vogel 	ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
113*f247dc25SJack F Vogel 					    0, &time_left, NULL);
11461ae650dSJack F Vogel 	/* Reading the Global Device Timer */
11561ae650dSJack F Vogel 	gtime = rd32(hw, I40E_GLVFGEN_TIMER);
11661ae650dSJack F Vogel 
11761ae650dSJack F Vogel 	/* Store the timeout */
118*f247dc25SJack F Vogel 	hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime;
11961ae650dSJack F Vogel 
120*f247dc25SJack F Vogel 	if (ret_code)
121*f247dc25SJack F Vogel 		i40e_debug(hw, I40E_DEBUG_NVM,
122*f247dc25SJack F Vogel 			   "NVM acquire type %d failed time_left=%llu ret=%d aq_err=%d\n",
123*f247dc25SJack F Vogel 			   access, time_left, ret_code, hw->aq.asq_last_status);
124*f247dc25SJack F Vogel 
125*f247dc25SJack F Vogel 	if (ret_code && time_left) {
12661ae650dSJack F Vogel 		/* Poll until the current NVM owner timeouts */
127*f247dc25SJack F Vogel 		timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime;
128*f247dc25SJack F Vogel 		while ((gtime < timeout) && time_left) {
12961ae650dSJack F Vogel 			i40e_msec_delay(10);
130*f247dc25SJack F Vogel 			gtime = rd32(hw, I40E_GLVFGEN_TIMER);
13161ae650dSJack F Vogel 			ret_code = i40e_aq_request_resource(hw,
13261ae650dSJack F Vogel 							I40E_NVM_RESOURCE_ID,
133*f247dc25SJack F Vogel 							access, 0, &time_left,
13461ae650dSJack F Vogel 							NULL);
13561ae650dSJack F Vogel 			if (ret_code == I40E_SUCCESS) {
13661ae650dSJack F Vogel 				hw->nvm.hw_semaphore_timeout =
137*f247dc25SJack F Vogel 					    I40E_MS_TO_GTIME(time_left) + gtime;
13861ae650dSJack F Vogel 				break;
13961ae650dSJack F Vogel 			}
14061ae650dSJack F Vogel 		}
14161ae650dSJack F Vogel 		if (ret_code != I40E_SUCCESS) {
14261ae650dSJack F Vogel 			hw->nvm.hw_semaphore_timeout = 0;
143*f247dc25SJack F Vogel 			i40e_debug(hw, I40E_DEBUG_NVM,
144*f247dc25SJack F Vogel 				   "NVM acquire timed out, wait %llu ms before trying again. status=%d aq_err=%d\n",
145*f247dc25SJack F Vogel 				   time_left, ret_code, hw->aq.asq_last_status);
14661ae650dSJack F Vogel 		}
14761ae650dSJack F Vogel 	}
14861ae650dSJack F Vogel 
14961ae650dSJack F Vogel i40e_i40e_acquire_nvm_exit:
15061ae650dSJack F Vogel 	return ret_code;
15161ae650dSJack F Vogel }
15261ae650dSJack F Vogel 
15361ae650dSJack F Vogel /**
15461ae650dSJack F Vogel  * i40e_release_nvm - Generic request for releasing the NVM ownership
15561ae650dSJack F Vogel  * @hw: pointer to the HW structure
15661ae650dSJack F Vogel  *
15761ae650dSJack F Vogel  * This function will release NVM resource via the proper Admin Command.
15861ae650dSJack F Vogel  **/
15961ae650dSJack F Vogel void i40e_release_nvm(struct i40e_hw *hw)
16061ae650dSJack F Vogel {
16161ae650dSJack F Vogel 	DEBUGFUNC("i40e_release_nvm");
16261ae650dSJack F Vogel 
16361ae650dSJack F Vogel 	if (!hw->nvm.blank_nvm_mode)
16461ae650dSJack F Vogel 		i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
16561ae650dSJack F Vogel }
16661ae650dSJack F Vogel 
16761ae650dSJack F Vogel /**
16861ae650dSJack F Vogel  * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
16961ae650dSJack F Vogel  * @hw: pointer to the HW structure
17061ae650dSJack F Vogel  *
17161ae650dSJack F Vogel  * Polls the SRCTL Shadow RAM register done bit.
17261ae650dSJack F Vogel  **/
17361ae650dSJack F Vogel static enum i40e_status_code i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
17461ae650dSJack F Vogel {
17561ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
17661ae650dSJack F Vogel 	u32 srctl, wait_cnt;
17761ae650dSJack F Vogel 
17861ae650dSJack F Vogel 	DEBUGFUNC("i40e_poll_sr_srctl_done_bit");
17961ae650dSJack F Vogel 
18061ae650dSJack F Vogel 	/* Poll the I40E_GLNVM_SRCTL until the done bit is set */
18161ae650dSJack F Vogel 	for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
18261ae650dSJack F Vogel 		srctl = rd32(hw, I40E_GLNVM_SRCTL);
18361ae650dSJack F Vogel 		if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
18461ae650dSJack F Vogel 			ret_code = I40E_SUCCESS;
18561ae650dSJack F Vogel 			break;
18661ae650dSJack F Vogel 		}
18761ae650dSJack F Vogel 		i40e_usec_delay(5);
18861ae650dSJack F Vogel 	}
18961ae650dSJack F Vogel 	if (ret_code == I40E_ERR_TIMEOUT)
190*f247dc25SJack F Vogel 		i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set");
19161ae650dSJack F Vogel 	return ret_code;
19261ae650dSJack F Vogel }
19361ae650dSJack F Vogel 
19461ae650dSJack F Vogel /**
19561ae650dSJack F Vogel  * i40e_read_nvm_word - Reads Shadow RAM
19661ae650dSJack F Vogel  * @hw: pointer to the HW structure
19761ae650dSJack F Vogel  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
19861ae650dSJack F Vogel  * @data: word read from the Shadow RAM
19961ae650dSJack F Vogel  *
20061ae650dSJack F Vogel  * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
20161ae650dSJack F Vogel  **/
20261ae650dSJack F Vogel enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
20361ae650dSJack F Vogel 					 u16 *data)
20461ae650dSJack F Vogel {
205*f247dc25SJack F Vogel 	return i40e_read_nvm_word_srctl(hw, offset, data);
206*f247dc25SJack F Vogel }
207*f247dc25SJack F Vogel 
208*f247dc25SJack F Vogel /**
209*f247dc25SJack F Vogel  * i40e_read_nvm_word_srctl - Reads Shadow RAM via SRCTL register
210*f247dc25SJack F Vogel  * @hw: pointer to the HW structure
211*f247dc25SJack F Vogel  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
212*f247dc25SJack F Vogel  * @data: word read from the Shadow RAM
213*f247dc25SJack F Vogel  *
214*f247dc25SJack F Vogel  * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
215*f247dc25SJack F Vogel  **/
216*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset,
217*f247dc25SJack F Vogel 					       u16 *data)
218*f247dc25SJack F Vogel {
21961ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
22061ae650dSJack F Vogel 	u32 sr_reg;
22161ae650dSJack F Vogel 
222*f247dc25SJack F Vogel 	DEBUGFUNC("i40e_read_nvm_word_srctl");
22361ae650dSJack F Vogel 
22461ae650dSJack F Vogel 	if (offset >= hw->nvm.sr_size) {
225*f247dc25SJack F Vogel 		i40e_debug(hw, I40E_DEBUG_NVM,
226*f247dc25SJack F Vogel 			   "NVM read error: Offset %d beyond Shadow RAM limit %d\n",
227*f247dc25SJack F Vogel 			   offset, hw->nvm.sr_size);
22861ae650dSJack F Vogel 		ret_code = I40E_ERR_PARAM;
22961ae650dSJack F Vogel 		goto read_nvm_exit;
23061ae650dSJack F Vogel 	}
23161ae650dSJack F Vogel 
23261ae650dSJack F Vogel 	/* Poll the done bit first */
23361ae650dSJack F Vogel 	ret_code = i40e_poll_sr_srctl_done_bit(hw);
23461ae650dSJack F Vogel 	if (ret_code == I40E_SUCCESS) {
23561ae650dSJack F Vogel 		/* Write the address and start reading */
23661ae650dSJack F Vogel 		sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
23761ae650dSJack F Vogel 			 (1 << I40E_GLNVM_SRCTL_START_SHIFT);
23861ae650dSJack F Vogel 		wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
23961ae650dSJack F Vogel 
24061ae650dSJack F Vogel 		/* Poll I40E_GLNVM_SRCTL until the done bit is set */
24161ae650dSJack F Vogel 		ret_code = i40e_poll_sr_srctl_done_bit(hw);
24261ae650dSJack F Vogel 		if (ret_code == I40E_SUCCESS) {
24361ae650dSJack F Vogel 			sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
24461ae650dSJack F Vogel 			*data = (u16)((sr_reg &
24561ae650dSJack F Vogel 				       I40E_GLNVM_SRDATA_RDDATA_MASK)
24661ae650dSJack F Vogel 				    >> I40E_GLNVM_SRDATA_RDDATA_SHIFT);
24761ae650dSJack F Vogel 		}
24861ae650dSJack F Vogel 	}
24961ae650dSJack F Vogel 	if (ret_code != I40E_SUCCESS)
250*f247dc25SJack F Vogel 		i40e_debug(hw, I40E_DEBUG_NVM,
251*f247dc25SJack F Vogel 			   "NVM read error: Couldn't access Shadow RAM address: 0x%x\n",
25261ae650dSJack F Vogel 			   offset);
25361ae650dSJack F Vogel 
25461ae650dSJack F Vogel read_nvm_exit:
25561ae650dSJack F Vogel 	return ret_code;
25661ae650dSJack F Vogel }
25761ae650dSJack F Vogel 
25861ae650dSJack F Vogel /**
259*f247dc25SJack F Vogel  * i40e_read_nvm_word_aq - Reads Shadow RAM via AQ
260*f247dc25SJack F Vogel  * @hw: pointer to the HW structure
261*f247dc25SJack F Vogel  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
262*f247dc25SJack F Vogel  * @data: word read from the Shadow RAM
263*f247dc25SJack F Vogel  *
264*f247dc25SJack F Vogel  * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
265*f247dc25SJack F Vogel  **/
266*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
267*f247dc25SJack F Vogel 					    u16 *data)
268*f247dc25SJack F Vogel {
269*f247dc25SJack F Vogel 	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
270*f247dc25SJack F Vogel 
271*f247dc25SJack F Vogel 	DEBUGFUNC("i40e_read_nvm_word_aq");
272*f247dc25SJack F Vogel 
273*f247dc25SJack F Vogel 	ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, TRUE);
274*f247dc25SJack F Vogel 	*data = LE16_TO_CPU(*(__le16 *)data);
275*f247dc25SJack F Vogel 
276*f247dc25SJack F Vogel 	return ret_code;
277*f247dc25SJack F Vogel }
278*f247dc25SJack F Vogel 
279*f247dc25SJack F Vogel /**
28061ae650dSJack F Vogel  * i40e_read_nvm_buffer - Reads Shadow RAM buffer
28161ae650dSJack F Vogel  * @hw: pointer to the HW structure
28261ae650dSJack F Vogel  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
28361ae650dSJack F Vogel  * @words: (in) number of words to read; (out) number of words actually read
28461ae650dSJack F Vogel  * @data: words read from the Shadow RAM
28561ae650dSJack F Vogel  *
28661ae650dSJack F Vogel  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
28761ae650dSJack F Vogel  * method. The buffer read is preceded by the NVM ownership take
28861ae650dSJack F Vogel  * and followed by the release.
28961ae650dSJack F Vogel  **/
29061ae650dSJack F Vogel enum i40e_status_code i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
29161ae650dSJack F Vogel 					   u16 *words, u16 *data)
29261ae650dSJack F Vogel {
293*f247dc25SJack F Vogel 	return i40e_read_nvm_buffer_srctl(hw, offset, words, data);
294*f247dc25SJack F Vogel }
295*f247dc25SJack F Vogel 
296*f247dc25SJack F Vogel /**
297*f247dc25SJack F Vogel  * i40e_read_nvm_buffer_srctl - Reads Shadow RAM buffer via SRCTL register
298*f247dc25SJack F Vogel  * @hw: pointer to the HW structure
299*f247dc25SJack F Vogel  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
300*f247dc25SJack F Vogel  * @words: (in) number of words to read; (out) number of words actually read
301*f247dc25SJack F Vogel  * @data: words read from the Shadow RAM
302*f247dc25SJack F Vogel  *
303*f247dc25SJack F Vogel  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
304*f247dc25SJack F Vogel  * method. The buffer read is preceded by the NVM ownership take
305*f247dc25SJack F Vogel  * and followed by the release.
306*f247dc25SJack F Vogel  **/
307*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset,
308*f247dc25SJack F Vogel 						 u16 *words, u16 *data)
309*f247dc25SJack F Vogel {
31061ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
31161ae650dSJack F Vogel 	u16 index, word;
31261ae650dSJack F Vogel 
313*f247dc25SJack F Vogel 	DEBUGFUNC("i40e_read_nvm_buffer_srctl");
31461ae650dSJack F Vogel 
31561ae650dSJack F Vogel 	/* Loop thru the selected region */
31661ae650dSJack F Vogel 	for (word = 0; word < *words; word++) {
31761ae650dSJack F Vogel 		index = offset + word;
318*f247dc25SJack F Vogel 		ret_code = i40e_read_nvm_word_srctl(hw, index, &data[word]);
31961ae650dSJack F Vogel 		if (ret_code != I40E_SUCCESS)
32061ae650dSJack F Vogel 			break;
32161ae650dSJack F Vogel 	}
32261ae650dSJack F Vogel 
32361ae650dSJack F Vogel 	/* Update the number of words read from the Shadow RAM */
32461ae650dSJack F Vogel 	*words = word;
32561ae650dSJack F Vogel 
32661ae650dSJack F Vogel 	return ret_code;
32761ae650dSJack F Vogel }
328*f247dc25SJack F Vogel 
329*f247dc25SJack F Vogel /**
330*f247dc25SJack F Vogel  * i40e_read_nvm_buffer_aq - Reads Shadow RAM buffer via AQ
331*f247dc25SJack F Vogel  * @hw: pointer to the HW structure
332*f247dc25SJack F Vogel  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
333*f247dc25SJack F Vogel  * @words: (in) number of words to read; (out) number of words actually read
334*f247dc25SJack F Vogel  * @data: words read from the Shadow RAM
335*f247dc25SJack F Vogel  *
336*f247dc25SJack F Vogel  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_aq()
337*f247dc25SJack F Vogel  * method. The buffer read is preceded by the NVM ownership take
338*f247dc25SJack F Vogel  * and followed by the release.
339*f247dc25SJack F Vogel  **/
340*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset,
341*f247dc25SJack F Vogel 					      u16 *words, u16 *data)
342*f247dc25SJack F Vogel {
343*f247dc25SJack F Vogel 	enum i40e_status_code ret_code;
344*f247dc25SJack F Vogel 	u16 read_size = *words;
345*f247dc25SJack F Vogel 	bool last_cmd = FALSE;
346*f247dc25SJack F Vogel 	u16 words_read = 0;
347*f247dc25SJack F Vogel 	u16 i = 0;
348*f247dc25SJack F Vogel 
349*f247dc25SJack F Vogel 	DEBUGFUNC("i40e_read_nvm_buffer_aq");
350*f247dc25SJack F Vogel 
351*f247dc25SJack F Vogel 	do {
352*f247dc25SJack F Vogel 		/* Calculate number of bytes we should read in this step.
353*f247dc25SJack F Vogel 		 * FVL AQ do not allow to read more than one page at a time or
354*f247dc25SJack F Vogel 		 * to cross page boundaries.
355*f247dc25SJack F Vogel 		 */
356*f247dc25SJack F Vogel 		if (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)
357*f247dc25SJack F Vogel 			read_size = min(*words,
358*f247dc25SJack F Vogel 					(u16)(I40E_SR_SECTOR_SIZE_IN_WORDS -
359*f247dc25SJack F Vogel 				      (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)));
360*f247dc25SJack F Vogel 		else
361*f247dc25SJack F Vogel 			read_size = min((*words - words_read),
362*f247dc25SJack F Vogel 					I40E_SR_SECTOR_SIZE_IN_WORDS);
363*f247dc25SJack F Vogel 
364*f247dc25SJack F Vogel 		/* Check if this is last command, if so set proper flag */
365*f247dc25SJack F Vogel 		if ((words_read + read_size) >= *words)
366*f247dc25SJack F Vogel 			last_cmd = TRUE;
367*f247dc25SJack F Vogel 
368*f247dc25SJack F Vogel 		ret_code = i40e_read_nvm_aq(hw, 0x0, offset, read_size,
369*f247dc25SJack F Vogel 					    data + words_read, last_cmd);
370*f247dc25SJack F Vogel 		if (ret_code != I40E_SUCCESS)
371*f247dc25SJack F Vogel 			goto read_nvm_buffer_aq_exit;
372*f247dc25SJack F Vogel 
373*f247dc25SJack F Vogel 		/* Increment counter for words already read and move offset to
374*f247dc25SJack F Vogel 		 * new read location
375*f247dc25SJack F Vogel 		 */
376*f247dc25SJack F Vogel 		words_read += read_size;
377*f247dc25SJack F Vogel 		offset += read_size;
378*f247dc25SJack F Vogel 	} while (words_read < *words);
379*f247dc25SJack F Vogel 
380*f247dc25SJack F Vogel 	for (i = 0; i < *words; i++)
381*f247dc25SJack F Vogel 		data[i] = LE16_TO_CPU(((__le16 *)data)[i]);
382*f247dc25SJack F Vogel 
383*f247dc25SJack F Vogel read_nvm_buffer_aq_exit:
384*f247dc25SJack F Vogel 	*words = words_read;
385*f247dc25SJack F Vogel 	return ret_code;
386*f247dc25SJack F Vogel }
387*f247dc25SJack F Vogel 
388*f247dc25SJack F Vogel /**
389*f247dc25SJack F Vogel  * i40e_read_nvm_aq - Read Shadow RAM.
390*f247dc25SJack F Vogel  * @hw: pointer to the HW structure.
391*f247dc25SJack F Vogel  * @module_pointer: module pointer location in words from the NVM beginning
392*f247dc25SJack F Vogel  * @offset: offset in words from module start
393*f247dc25SJack F Vogel  * @words: number of words to write
394*f247dc25SJack F Vogel  * @data: buffer with words to write to the Shadow RAM
395*f247dc25SJack F Vogel  * @last_command: tells the AdminQ that this is the last command
396*f247dc25SJack F Vogel  *
397*f247dc25SJack F Vogel  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
398*f247dc25SJack F Vogel  **/
399*f247dc25SJack F Vogel enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
400*f247dc25SJack F Vogel 				       u32 offset, u16 words, void *data,
401*f247dc25SJack F Vogel 				       bool last_command)
402*f247dc25SJack F Vogel {
403*f247dc25SJack F Vogel 	enum i40e_status_code ret_code = I40E_ERR_NVM;
404*f247dc25SJack F Vogel 
405*f247dc25SJack F Vogel 	DEBUGFUNC("i40e_read_nvm_aq");
406*f247dc25SJack F Vogel 
407*f247dc25SJack F Vogel 	/* Here we are checking the SR limit only for the flat memory model.
408*f247dc25SJack F Vogel 	 * We cannot do it for the module-based model, as we did not acquire
409*f247dc25SJack F Vogel 	 * the NVM resource yet (we cannot get the module pointer value).
410*f247dc25SJack F Vogel 	 * Firmware will check the module-based model.
411*f247dc25SJack F Vogel 	 */
412*f247dc25SJack F Vogel 	if ((offset + words) > hw->nvm.sr_size)
413*f247dc25SJack F Vogel 		i40e_debug(hw, I40E_DEBUG_NVM,
414*f247dc25SJack F Vogel 			   "NVM write error: offset %d beyond Shadow RAM limit %d\n",
415*f247dc25SJack F Vogel 			   (offset + words), hw->nvm.sr_size);
416*f247dc25SJack F Vogel 	else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
417*f247dc25SJack F Vogel 		/* We can write only up to 4KB (one sector), in one AQ write */
418*f247dc25SJack F Vogel 		i40e_debug(hw, I40E_DEBUG_NVM,
419*f247dc25SJack F Vogel 			   "NVM write fail error: tried to write %d words, limit is %d.\n",
420*f247dc25SJack F Vogel 			   words, I40E_SR_SECTOR_SIZE_IN_WORDS);
421*f247dc25SJack F Vogel 	else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
422*f247dc25SJack F Vogel 		 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
423*f247dc25SJack F Vogel 		/* A single write cannot spread over two sectors */
424*f247dc25SJack F Vogel 		i40e_debug(hw, I40E_DEBUG_NVM,
425*f247dc25SJack F Vogel 			   "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n",
426*f247dc25SJack F Vogel 			   offset, words);
427*f247dc25SJack F Vogel 	else
428*f247dc25SJack F Vogel 		ret_code = i40e_aq_read_nvm(hw, module_pointer,
429*f247dc25SJack F Vogel 					    2 * offset,  /*bytes*/
430*f247dc25SJack F Vogel 					    2 * words,   /*bytes*/
431*f247dc25SJack F Vogel 					    data, last_command, NULL);
432*f247dc25SJack F Vogel 
433*f247dc25SJack F Vogel 	return ret_code;
434*f247dc25SJack F Vogel }
435*f247dc25SJack F Vogel 
43661ae650dSJack F Vogel /**
43761ae650dSJack F Vogel  * i40e_write_nvm_aq - Writes Shadow RAM.
43861ae650dSJack F Vogel  * @hw: pointer to the HW structure.
43961ae650dSJack F Vogel  * @module_pointer: module pointer location in words from the NVM beginning
44061ae650dSJack F Vogel  * @offset: offset in words from module start
44161ae650dSJack F Vogel  * @words: number of words to write
44261ae650dSJack F Vogel  * @data: buffer with words to write to the Shadow RAM
44361ae650dSJack F Vogel  * @last_command: tells the AdminQ that this is the last command
44461ae650dSJack F Vogel  *
44561ae650dSJack F Vogel  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
44661ae650dSJack F Vogel  **/
44761ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
44861ae650dSJack F Vogel 					u32 offset, u16 words, void *data,
44961ae650dSJack F Vogel 					bool last_command)
45061ae650dSJack F Vogel {
45161ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_ERR_NVM;
45261ae650dSJack F Vogel 
45361ae650dSJack F Vogel 	DEBUGFUNC("i40e_write_nvm_aq");
45461ae650dSJack F Vogel 
45561ae650dSJack F Vogel 	/* Here we are checking the SR limit only for the flat memory model.
45661ae650dSJack F Vogel 	 * We cannot do it for the module-based model, as we did not acquire
45761ae650dSJack F Vogel 	 * the NVM resource yet (we cannot get the module pointer value).
45861ae650dSJack F Vogel 	 * Firmware will check the module-based model.
45961ae650dSJack F Vogel 	 */
46061ae650dSJack F Vogel 	if ((offset + words) > hw->nvm.sr_size)
46161ae650dSJack F Vogel 		DEBUGOUT("NVM write error: offset beyond Shadow RAM limit.\n");
46261ae650dSJack F Vogel 	else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
46361ae650dSJack F Vogel 		/* We can write only up to 4KB (one sector), in one AQ write */
46461ae650dSJack F Vogel 		DEBUGOUT("NVM write fail error: cannot write more than 4KB in a single write.\n");
46561ae650dSJack F Vogel 	else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
46661ae650dSJack F Vogel 		 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
46761ae650dSJack F Vogel 		/* A single write cannot spread over two sectors */
46861ae650dSJack F Vogel 		DEBUGOUT("NVM write error: cannot spread over two sectors in a single write.\n");
46961ae650dSJack F Vogel 	else
47061ae650dSJack F Vogel 		ret_code = i40e_aq_update_nvm(hw, module_pointer,
47161ae650dSJack F Vogel 					      2 * offset,  /*bytes*/
47261ae650dSJack F Vogel 					      2 * words,   /*bytes*/
47361ae650dSJack F Vogel 					      data, last_command, NULL);
47461ae650dSJack F Vogel 
47561ae650dSJack F Vogel 	return ret_code;
47661ae650dSJack F Vogel }
47761ae650dSJack F Vogel 
47861ae650dSJack F Vogel /**
47961ae650dSJack F Vogel  * i40e_write_nvm_word - Writes Shadow RAM word
48061ae650dSJack F Vogel  * @hw: pointer to the HW structure
48161ae650dSJack F Vogel  * @offset: offset of the Shadow RAM word to write
48261ae650dSJack F Vogel  * @data: word to write to the Shadow RAM
48361ae650dSJack F Vogel  *
48461ae650dSJack F Vogel  * Writes a 16 bit word to the SR using the i40e_write_nvm_aq() method.
48561ae650dSJack F Vogel  * NVM ownership have to be acquired and released (on ARQ completion event
48661ae650dSJack F Vogel  * reception) by caller. To commit SR to NVM update checksum function
48761ae650dSJack F Vogel  * should be called.
48861ae650dSJack F Vogel  **/
48961ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_word(struct i40e_hw *hw, u32 offset,
49061ae650dSJack F Vogel 					  void *data)
49161ae650dSJack F Vogel {
49261ae650dSJack F Vogel 	DEBUGFUNC("i40e_write_nvm_word");
49361ae650dSJack F Vogel 
494*f247dc25SJack F Vogel 	*((__le16 *)data) = CPU_TO_LE16(*((u16 *)data));
495*f247dc25SJack F Vogel 
49661ae650dSJack F Vogel 	/* Value 0x00 below means that we treat SR as a flat mem */
49761ae650dSJack F Vogel 	return i40e_write_nvm_aq(hw, 0x00, offset, 1, data, FALSE);
49861ae650dSJack F Vogel }
49961ae650dSJack F Vogel 
50061ae650dSJack F Vogel /**
50161ae650dSJack F Vogel  * i40e_write_nvm_buffer - Writes Shadow RAM buffer
50261ae650dSJack F Vogel  * @hw: pointer to the HW structure
50361ae650dSJack F Vogel  * @module_pointer: module pointer location in words from the NVM beginning
50461ae650dSJack F Vogel  * @offset: offset of the Shadow RAM buffer to write
50561ae650dSJack F Vogel  * @words: number of words to write
50661ae650dSJack F Vogel  * @data: words to write to the Shadow RAM
50761ae650dSJack F Vogel  *
50861ae650dSJack F Vogel  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
50961ae650dSJack F Vogel  * NVM ownership must be acquired before calling this function and released
51061ae650dSJack F Vogel  * on ARQ completion event reception by caller. To commit SR to NVM update
51161ae650dSJack F Vogel  * checksum function should be called.
51261ae650dSJack F Vogel  **/
51361ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_buffer(struct i40e_hw *hw,
51461ae650dSJack F Vogel 					    u8 module_pointer, u32 offset,
51561ae650dSJack F Vogel 					    u16 words, void *data)
51661ae650dSJack F Vogel {
517*f247dc25SJack F Vogel 	__le16 *le_word_ptr = (__le16 *)data;
518*f247dc25SJack F Vogel 	u16 *word_ptr = (u16 *)data;
519*f247dc25SJack F Vogel 	u32 i = 0;
520*f247dc25SJack F Vogel 
52161ae650dSJack F Vogel 	DEBUGFUNC("i40e_write_nvm_buffer");
52261ae650dSJack F Vogel 
523*f247dc25SJack F Vogel 	for (i = 0; i < words; i++)
524*f247dc25SJack F Vogel 		le_word_ptr[i] = CPU_TO_LE16(word_ptr[i]);
525*f247dc25SJack F Vogel 
52661ae650dSJack F Vogel 	/* Here we will only write one buffer as the size of the modules
52761ae650dSJack F Vogel 	 * mirrored in the Shadow RAM is always less than 4K.
52861ae650dSJack F Vogel 	 */
52961ae650dSJack F Vogel 	return i40e_write_nvm_aq(hw, module_pointer, offset, words,
53061ae650dSJack F Vogel 				 data, FALSE);
53161ae650dSJack F Vogel }
53261ae650dSJack F Vogel 
53361ae650dSJack F Vogel /**
53461ae650dSJack F Vogel  * i40e_calc_nvm_checksum - Calculates and returns the checksum
53561ae650dSJack F Vogel  * @hw: pointer to hardware structure
53661ae650dSJack F Vogel  * @checksum: pointer to the checksum
53761ae650dSJack F Vogel  *
53861ae650dSJack F Vogel  * This function calculates SW Checksum that covers the whole 64kB shadow RAM
53961ae650dSJack F Vogel  * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
54061ae650dSJack F Vogel  * is customer specific and unknown. Therefore, this function skips all maximum
54161ae650dSJack F Vogel  * possible size of VPD (1kB).
54261ae650dSJack F Vogel  **/
54361ae650dSJack F Vogel enum i40e_status_code i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum)
54461ae650dSJack F Vogel {
54561ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
546*f247dc25SJack F Vogel 	struct i40e_virt_mem vmem;
54761ae650dSJack F Vogel 	u16 pcie_alt_module = 0;
54861ae650dSJack F Vogel 	u16 checksum_local = 0;
54961ae650dSJack F Vogel 	u16 vpd_module = 0;
550*f247dc25SJack F Vogel 	u16 *data;
551*f247dc25SJack F Vogel 	u16 i = 0;
55261ae650dSJack F Vogel 
55361ae650dSJack F Vogel 	DEBUGFUNC("i40e_calc_nvm_checksum");
55461ae650dSJack F Vogel 
555*f247dc25SJack F Vogel 	ret_code = i40e_allocate_virt_mem(hw, &vmem,
556*f247dc25SJack F Vogel 				    I40E_SR_SECTOR_SIZE_IN_WORDS * sizeof(u16));
557*f247dc25SJack F Vogel 	if (ret_code)
558*f247dc25SJack F Vogel 		goto i40e_calc_nvm_checksum_exit;
559*f247dc25SJack F Vogel 	data = (u16 *)vmem.va;
560*f247dc25SJack F Vogel 
56161ae650dSJack F Vogel 	/* read pointer to VPD area */
56261ae650dSJack F Vogel 	ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
56361ae650dSJack F Vogel 	if (ret_code != I40E_SUCCESS) {
56461ae650dSJack F Vogel 		ret_code = I40E_ERR_NVM_CHECKSUM;
56561ae650dSJack F Vogel 		goto i40e_calc_nvm_checksum_exit;
56661ae650dSJack F Vogel 	}
56761ae650dSJack F Vogel 
56861ae650dSJack F Vogel 	/* read pointer to PCIe Alt Auto-load module */
56961ae650dSJack F Vogel 	ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
57061ae650dSJack F Vogel 				      &pcie_alt_module);
57161ae650dSJack F Vogel 	if (ret_code != I40E_SUCCESS) {
57261ae650dSJack F Vogel 		ret_code = I40E_ERR_NVM_CHECKSUM;
57361ae650dSJack F Vogel 		goto i40e_calc_nvm_checksum_exit;
57461ae650dSJack F Vogel 	}
57561ae650dSJack F Vogel 
57661ae650dSJack F Vogel 	/* Calculate SW checksum that covers the whole 64kB shadow RAM
57761ae650dSJack F Vogel 	 * except the VPD and PCIe ALT Auto-load modules
57861ae650dSJack F Vogel 	 */
57961ae650dSJack F Vogel 	for (i = 0; i < hw->nvm.sr_size; i++) {
580*f247dc25SJack F Vogel 		/* Read SR page */
581*f247dc25SJack F Vogel 		if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) {
582*f247dc25SJack F Vogel 			u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS;
583*f247dc25SJack F Vogel 			ret_code = i40e_read_nvm_buffer(hw, i, &words, data);
58461ae650dSJack F Vogel 			if (ret_code != I40E_SUCCESS) {
58561ae650dSJack F Vogel 				ret_code = I40E_ERR_NVM_CHECKSUM;
58661ae650dSJack F Vogel 				goto i40e_calc_nvm_checksum_exit;
58761ae650dSJack F Vogel 			}
588*f247dc25SJack F Vogel 		}
589*f247dc25SJack F Vogel 
590*f247dc25SJack F Vogel 		/* Skip Checksum word */
591*f247dc25SJack F Vogel 		if (i == I40E_SR_SW_CHECKSUM_WORD)
592*f247dc25SJack F Vogel 			continue;
593*f247dc25SJack F Vogel 		/* Skip VPD module (convert byte size to word count) */
594*f247dc25SJack F Vogel 		if ((i >= (u32)vpd_module) &&
595*f247dc25SJack F Vogel 		    (i < ((u32)vpd_module +
596*f247dc25SJack F Vogel 		     (I40E_SR_VPD_MODULE_MAX_SIZE / 2)))) {
597*f247dc25SJack F Vogel 			continue;
598*f247dc25SJack F Vogel 		}
599*f247dc25SJack F Vogel 		/* Skip PCIe ALT module (convert byte size to word count) */
600*f247dc25SJack F Vogel 		if ((i >= (u32)pcie_alt_module) &&
601*f247dc25SJack F Vogel 		    (i < ((u32)pcie_alt_module +
602*f247dc25SJack F Vogel 		     (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2)))) {
603*f247dc25SJack F Vogel 			continue;
604*f247dc25SJack F Vogel 		}
605*f247dc25SJack F Vogel 
606*f247dc25SJack F Vogel 		checksum_local += data[i % I40E_SR_SECTOR_SIZE_IN_WORDS];
60761ae650dSJack F Vogel 	}
60861ae650dSJack F Vogel 
60961ae650dSJack F Vogel 	*checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local;
61061ae650dSJack F Vogel 
61161ae650dSJack F Vogel i40e_calc_nvm_checksum_exit:
612*f247dc25SJack F Vogel 	i40e_free_virt_mem(hw, &vmem);
61361ae650dSJack F Vogel 	return ret_code;
61461ae650dSJack F Vogel }
61561ae650dSJack F Vogel 
61661ae650dSJack F Vogel /**
61761ae650dSJack F Vogel  * i40e_update_nvm_checksum - Updates the NVM checksum
61861ae650dSJack F Vogel  * @hw: pointer to hardware structure
61961ae650dSJack F Vogel  *
62061ae650dSJack F Vogel  * NVM ownership must be acquired before calling this function and released
62161ae650dSJack F Vogel  * on ARQ completion event reception by caller.
62261ae650dSJack F Vogel  * This function will commit SR to NVM.
62361ae650dSJack F Vogel  **/
62461ae650dSJack F Vogel enum i40e_status_code i40e_update_nvm_checksum(struct i40e_hw *hw)
62561ae650dSJack F Vogel {
62661ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
62761ae650dSJack F Vogel 	u16 checksum;
62861ae650dSJack F Vogel 
62961ae650dSJack F Vogel 	DEBUGFUNC("i40e_update_nvm_checksum");
63061ae650dSJack F Vogel 
63161ae650dSJack F Vogel 	ret_code = i40e_calc_nvm_checksum(hw, &checksum);
63261ae650dSJack F Vogel 	if (ret_code == I40E_SUCCESS)
63361ae650dSJack F Vogel 		ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD,
63461ae650dSJack F Vogel 					     1, &checksum, TRUE);
63561ae650dSJack F Vogel 
63661ae650dSJack F Vogel 	return ret_code;
63761ae650dSJack F Vogel }
63861ae650dSJack F Vogel 
63961ae650dSJack F Vogel /**
64061ae650dSJack F Vogel  * i40e_validate_nvm_checksum - Validate EEPROM checksum
64161ae650dSJack F Vogel  * @hw: pointer to hardware structure
64261ae650dSJack F Vogel  * @checksum: calculated checksum
64361ae650dSJack F Vogel  *
64461ae650dSJack F Vogel  * Performs checksum calculation and validates the NVM SW checksum. If the
64561ae650dSJack F Vogel  * caller does not need checksum, the value can be NULL.
64661ae650dSJack F Vogel  **/
64761ae650dSJack F Vogel enum i40e_status_code i40e_validate_nvm_checksum(struct i40e_hw *hw,
64861ae650dSJack F Vogel 						 u16 *checksum)
64961ae650dSJack F Vogel {
65061ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
65161ae650dSJack F Vogel 	u16 checksum_sr = 0;
65261ae650dSJack F Vogel 	u16 checksum_local = 0;
65361ae650dSJack F Vogel 
65461ae650dSJack F Vogel 	DEBUGFUNC("i40e_validate_nvm_checksum");
65561ae650dSJack F Vogel 
65661ae650dSJack F Vogel 	ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
65761ae650dSJack F Vogel 	if (ret_code != I40E_SUCCESS)
65861ae650dSJack F Vogel 		goto i40e_validate_nvm_checksum_exit;
65961ae650dSJack F Vogel 
66061ae650dSJack F Vogel 	/* Do not use i40e_read_nvm_word() because we do not want to take
66161ae650dSJack F Vogel 	 * the synchronization semaphores twice here.
66261ae650dSJack F Vogel 	 */
66361ae650dSJack F Vogel 	i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
66461ae650dSJack F Vogel 
66561ae650dSJack F Vogel 	/* Verify read checksum from EEPROM is the same as
66661ae650dSJack F Vogel 	 * calculated checksum
66761ae650dSJack F Vogel 	 */
66861ae650dSJack F Vogel 	if (checksum_local != checksum_sr)
66961ae650dSJack F Vogel 		ret_code = I40E_ERR_NVM_CHECKSUM;
67061ae650dSJack F Vogel 
67161ae650dSJack F Vogel 	/* If the user cares, return the calculated checksum */
67261ae650dSJack F Vogel 	if (checksum)
67361ae650dSJack F Vogel 		*checksum = checksum_local;
67461ae650dSJack F Vogel 
67561ae650dSJack F Vogel i40e_validate_nvm_checksum_exit:
67661ae650dSJack F Vogel 	return ret_code;
67761ae650dSJack F Vogel }
678