xref: /freebsd/sys/dev/ixl/i40e_nvm.c (revision 61ae650d55553d48c55fbe023706dfa4b97483bb)
1*61ae650dSJack F Vogel /******************************************************************************
2*61ae650dSJack F Vogel 
3*61ae650dSJack F Vogel   Copyright (c) 2013-2014, Intel Corporation
4*61ae650dSJack F Vogel   All rights reserved.
5*61ae650dSJack F Vogel 
6*61ae650dSJack F Vogel   Redistribution and use in source and binary forms, with or without
7*61ae650dSJack F Vogel   modification, are permitted provided that the following conditions are met:
8*61ae650dSJack F Vogel 
9*61ae650dSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
10*61ae650dSJack F Vogel       this list of conditions and the following disclaimer.
11*61ae650dSJack F Vogel 
12*61ae650dSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
13*61ae650dSJack F Vogel       notice, this list of conditions and the following disclaimer in the
14*61ae650dSJack F Vogel       documentation and/or other materials provided with the distribution.
15*61ae650dSJack F Vogel 
16*61ae650dSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
17*61ae650dSJack F Vogel       contributors may be used to endorse or promote products derived from
18*61ae650dSJack F Vogel       this software without specific prior written permission.
19*61ae650dSJack F Vogel 
20*61ae650dSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21*61ae650dSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*61ae650dSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*61ae650dSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24*61ae650dSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25*61ae650dSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26*61ae650dSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27*61ae650dSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28*61ae650dSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29*61ae650dSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30*61ae650dSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
31*61ae650dSJack F Vogel 
32*61ae650dSJack F Vogel ******************************************************************************/
33*61ae650dSJack F Vogel /*$FreeBSD$*/
34*61ae650dSJack F Vogel 
35*61ae650dSJack F Vogel #include "i40e_prototype.h"
36*61ae650dSJack F Vogel 
37*61ae650dSJack F Vogel /**
38*61ae650dSJack F Vogel  * i40e_init_nvm_ops - Initialize NVM function pointers
39*61ae650dSJack F Vogel  * @hw: pointer to the HW structure
40*61ae650dSJack F Vogel  *
41*61ae650dSJack F Vogel  * Setup the function pointers and the NVM info structure. Should be called
42*61ae650dSJack F Vogel  * once per NVM initialization, e.g. inside the i40e_init_shared_code().
43*61ae650dSJack F Vogel  * Please notice that the NVM term is used here (& in all methods covered
44*61ae650dSJack F Vogel  * in this file) as an equivalent of the FLASH part mapped into the SR.
45*61ae650dSJack F Vogel  * We are accessing FLASH always thru the Shadow RAM.
46*61ae650dSJack F Vogel  **/
47*61ae650dSJack F Vogel enum i40e_status_code i40e_init_nvm(struct i40e_hw *hw)
48*61ae650dSJack F Vogel {
49*61ae650dSJack F Vogel 	struct i40e_nvm_info *nvm = &hw->nvm;
50*61ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
51*61ae650dSJack F Vogel 	u32 fla, gens;
52*61ae650dSJack F Vogel 	u8 sr_size;
53*61ae650dSJack F Vogel 
54*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_init_nvm");
55*61ae650dSJack F Vogel 
56*61ae650dSJack F Vogel 	/* The SR size is stored regardless of the nvm programming mode
57*61ae650dSJack F Vogel 	 * as the blank mode may be used in the factory line.
58*61ae650dSJack F Vogel 	 */
59*61ae650dSJack F Vogel 	gens = rd32(hw, I40E_GLNVM_GENS);
60*61ae650dSJack F Vogel 	sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
61*61ae650dSJack F Vogel 			   I40E_GLNVM_GENS_SR_SIZE_SHIFT);
62*61ae650dSJack F Vogel 	/* Switching to words (sr_size contains power of 2KB) */
63*61ae650dSJack F Vogel 	nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB;
64*61ae650dSJack F Vogel 
65*61ae650dSJack F Vogel 	/* Check if we are in the normal or blank NVM programming mode */
66*61ae650dSJack F Vogel 	fla = rd32(hw, I40E_GLNVM_FLA);
67*61ae650dSJack F Vogel 	if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
68*61ae650dSJack F Vogel 		/* Max NVM timeout */
69*61ae650dSJack F Vogel 		nvm->timeout = I40E_MAX_NVM_TIMEOUT;
70*61ae650dSJack F Vogel 		nvm->blank_nvm_mode = FALSE;
71*61ae650dSJack F Vogel 	} else { /* Blank programming mode */
72*61ae650dSJack F Vogel 		nvm->blank_nvm_mode = TRUE;
73*61ae650dSJack F Vogel 		ret_code = I40E_ERR_NVM_BLANK_MODE;
74*61ae650dSJack F Vogel 		DEBUGOUT("NVM init error: unsupported blank mode.\n");
75*61ae650dSJack F Vogel 	}
76*61ae650dSJack F Vogel 
77*61ae650dSJack F Vogel 	return ret_code;
78*61ae650dSJack F Vogel }
79*61ae650dSJack F Vogel 
80*61ae650dSJack F Vogel /**
81*61ae650dSJack F Vogel  * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
82*61ae650dSJack F Vogel  * @hw: pointer to the HW structure
83*61ae650dSJack F Vogel  * @access: NVM access type (read or write)
84*61ae650dSJack F Vogel  *
85*61ae650dSJack F Vogel  * This function will request NVM ownership for reading
86*61ae650dSJack F Vogel  * via the proper Admin Command.
87*61ae650dSJack F Vogel  **/
88*61ae650dSJack F Vogel enum i40e_status_code i40e_acquire_nvm(struct i40e_hw *hw,
89*61ae650dSJack F Vogel 				       enum i40e_aq_resource_access_type access)
90*61ae650dSJack F Vogel {
91*61ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
92*61ae650dSJack F Vogel 	u64 gtime, timeout;
93*61ae650dSJack F Vogel 	u64 time = 0;
94*61ae650dSJack F Vogel 
95*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_acquire_nvm");
96*61ae650dSJack F Vogel 
97*61ae650dSJack F Vogel 	if (hw->nvm.blank_nvm_mode)
98*61ae650dSJack F Vogel 		goto i40e_i40e_acquire_nvm_exit;
99*61ae650dSJack F Vogel 
100*61ae650dSJack F Vogel 	ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
101*61ae650dSJack F Vogel 					    0, &time, NULL);
102*61ae650dSJack F Vogel 	/* Reading the Global Device Timer */
103*61ae650dSJack F Vogel 	gtime = rd32(hw, I40E_GLVFGEN_TIMER);
104*61ae650dSJack F Vogel 
105*61ae650dSJack F Vogel 	/* Store the timeout */
106*61ae650dSJack F Vogel 	hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time) + gtime;
107*61ae650dSJack F Vogel 
108*61ae650dSJack F Vogel 	if (ret_code != I40E_SUCCESS) {
109*61ae650dSJack F Vogel 		/* Set the polling timeout */
110*61ae650dSJack F Vogel 		if (time > I40E_MAX_NVM_TIMEOUT)
111*61ae650dSJack F Vogel 			timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT)
112*61ae650dSJack F Vogel 				  + gtime;
113*61ae650dSJack F Vogel 		else
114*61ae650dSJack F Vogel 			timeout = hw->nvm.hw_semaphore_timeout;
115*61ae650dSJack F Vogel 		/* Poll until the current NVM owner timeouts */
116*61ae650dSJack F Vogel 		while (gtime < timeout) {
117*61ae650dSJack F Vogel 			i40e_msec_delay(10);
118*61ae650dSJack F Vogel 			ret_code = i40e_aq_request_resource(hw,
119*61ae650dSJack F Vogel 							I40E_NVM_RESOURCE_ID,
120*61ae650dSJack F Vogel 							access, 0, &time,
121*61ae650dSJack F Vogel 							NULL);
122*61ae650dSJack F Vogel 			if (ret_code == I40E_SUCCESS) {
123*61ae650dSJack F Vogel 				hw->nvm.hw_semaphore_timeout =
124*61ae650dSJack F Vogel 						I40E_MS_TO_GTIME(time) + gtime;
125*61ae650dSJack F Vogel 				break;
126*61ae650dSJack F Vogel 			}
127*61ae650dSJack F Vogel 			gtime = rd32(hw, I40E_GLVFGEN_TIMER);
128*61ae650dSJack F Vogel 		}
129*61ae650dSJack F Vogel 		if (ret_code != I40E_SUCCESS) {
130*61ae650dSJack F Vogel 			hw->nvm.hw_semaphore_timeout = 0;
131*61ae650dSJack F Vogel 			hw->nvm.hw_semaphore_wait =
132*61ae650dSJack F Vogel 						I40E_MS_TO_GTIME(time) + gtime;
133*61ae650dSJack F Vogel 			DEBUGOUT1("NVM acquire timed out, wait %llu ms before trying again.\n",
134*61ae650dSJack F Vogel 				  time);
135*61ae650dSJack F Vogel 		}
136*61ae650dSJack F Vogel 	}
137*61ae650dSJack F Vogel 
138*61ae650dSJack F Vogel i40e_i40e_acquire_nvm_exit:
139*61ae650dSJack F Vogel 	return ret_code;
140*61ae650dSJack F Vogel }
141*61ae650dSJack F Vogel 
142*61ae650dSJack F Vogel /**
143*61ae650dSJack F Vogel  * i40e_release_nvm - Generic request for releasing the NVM ownership
144*61ae650dSJack F Vogel  * @hw: pointer to the HW structure
145*61ae650dSJack F Vogel  *
146*61ae650dSJack F Vogel  * This function will release NVM resource via the proper Admin Command.
147*61ae650dSJack F Vogel  **/
148*61ae650dSJack F Vogel void i40e_release_nvm(struct i40e_hw *hw)
149*61ae650dSJack F Vogel {
150*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_release_nvm");
151*61ae650dSJack F Vogel 
152*61ae650dSJack F Vogel 	if (!hw->nvm.blank_nvm_mode)
153*61ae650dSJack F Vogel 		i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
154*61ae650dSJack F Vogel }
155*61ae650dSJack F Vogel 
156*61ae650dSJack F Vogel /**
157*61ae650dSJack F Vogel  * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
158*61ae650dSJack F Vogel  * @hw: pointer to the HW structure
159*61ae650dSJack F Vogel  *
160*61ae650dSJack F Vogel  * Polls the SRCTL Shadow RAM register done bit.
161*61ae650dSJack F Vogel  **/
162*61ae650dSJack F Vogel static enum i40e_status_code i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
163*61ae650dSJack F Vogel {
164*61ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
165*61ae650dSJack F Vogel 	u32 srctl, wait_cnt;
166*61ae650dSJack F Vogel 
167*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_poll_sr_srctl_done_bit");
168*61ae650dSJack F Vogel 
169*61ae650dSJack F Vogel 	/* Poll the I40E_GLNVM_SRCTL until the done bit is set */
170*61ae650dSJack F Vogel 	for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
171*61ae650dSJack F Vogel 		srctl = rd32(hw, I40E_GLNVM_SRCTL);
172*61ae650dSJack F Vogel 		if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
173*61ae650dSJack F Vogel 			ret_code = I40E_SUCCESS;
174*61ae650dSJack F Vogel 			break;
175*61ae650dSJack F Vogel 		}
176*61ae650dSJack F Vogel 		i40e_usec_delay(5);
177*61ae650dSJack F Vogel 	}
178*61ae650dSJack F Vogel 	if (ret_code == I40E_ERR_TIMEOUT)
179*61ae650dSJack F Vogel 		DEBUGOUT("Done bit in GLNVM_SRCTL not set");
180*61ae650dSJack F Vogel 	return ret_code;
181*61ae650dSJack F Vogel }
182*61ae650dSJack F Vogel 
183*61ae650dSJack F Vogel /**
184*61ae650dSJack F Vogel  * i40e_read_nvm_word - Reads Shadow RAM
185*61ae650dSJack F Vogel  * @hw: pointer to the HW structure
186*61ae650dSJack F Vogel  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
187*61ae650dSJack F Vogel  * @data: word read from the Shadow RAM
188*61ae650dSJack F Vogel  *
189*61ae650dSJack F Vogel  * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
190*61ae650dSJack F Vogel  **/
191*61ae650dSJack F Vogel enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
192*61ae650dSJack F Vogel 					 u16 *data)
193*61ae650dSJack F Vogel {
194*61ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
195*61ae650dSJack F Vogel 	u32 sr_reg;
196*61ae650dSJack F Vogel 
197*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_read_nvm_srctl");
198*61ae650dSJack F Vogel 
199*61ae650dSJack F Vogel 	if (offset >= hw->nvm.sr_size) {
200*61ae650dSJack F Vogel 		DEBUGOUT("NVM read error: Offset beyond Shadow RAM limit.\n");
201*61ae650dSJack F Vogel 		ret_code = I40E_ERR_PARAM;
202*61ae650dSJack F Vogel 		goto read_nvm_exit;
203*61ae650dSJack F Vogel 	}
204*61ae650dSJack F Vogel 
205*61ae650dSJack F Vogel 	/* Poll the done bit first */
206*61ae650dSJack F Vogel 	ret_code = i40e_poll_sr_srctl_done_bit(hw);
207*61ae650dSJack F Vogel 	if (ret_code == I40E_SUCCESS) {
208*61ae650dSJack F Vogel 		/* Write the address and start reading */
209*61ae650dSJack F Vogel 		sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
210*61ae650dSJack F Vogel 			 (1 << I40E_GLNVM_SRCTL_START_SHIFT);
211*61ae650dSJack F Vogel 		wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
212*61ae650dSJack F Vogel 
213*61ae650dSJack F Vogel 		/* Poll I40E_GLNVM_SRCTL until the done bit is set */
214*61ae650dSJack F Vogel 		ret_code = i40e_poll_sr_srctl_done_bit(hw);
215*61ae650dSJack F Vogel 		if (ret_code == I40E_SUCCESS) {
216*61ae650dSJack F Vogel 			sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
217*61ae650dSJack F Vogel 			*data = (u16)((sr_reg &
218*61ae650dSJack F Vogel 				       I40E_GLNVM_SRDATA_RDDATA_MASK)
219*61ae650dSJack F Vogel 				    >> I40E_GLNVM_SRDATA_RDDATA_SHIFT);
220*61ae650dSJack F Vogel 		}
221*61ae650dSJack F Vogel 	}
222*61ae650dSJack F Vogel 	if (ret_code != I40E_SUCCESS)
223*61ae650dSJack F Vogel 		DEBUGOUT1("NVM read error: Couldn't access Shadow RAM address: 0x%x\n",
224*61ae650dSJack F Vogel 			  offset);
225*61ae650dSJack F Vogel 
226*61ae650dSJack F Vogel read_nvm_exit:
227*61ae650dSJack F Vogel 	return ret_code;
228*61ae650dSJack F Vogel }
229*61ae650dSJack F Vogel 
230*61ae650dSJack F Vogel /**
231*61ae650dSJack F Vogel  * i40e_read_nvm_buffer - Reads Shadow RAM buffer
232*61ae650dSJack F Vogel  * @hw: pointer to the HW structure
233*61ae650dSJack F Vogel  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
234*61ae650dSJack F Vogel  * @words: (in) number of words to read; (out) number of words actually read
235*61ae650dSJack F Vogel  * @data: words read from the Shadow RAM
236*61ae650dSJack F Vogel  *
237*61ae650dSJack F Vogel  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
238*61ae650dSJack F Vogel  * method. The buffer read is preceded by the NVM ownership take
239*61ae650dSJack F Vogel  * and followed by the release.
240*61ae650dSJack F Vogel  **/
241*61ae650dSJack F Vogel enum i40e_status_code i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
242*61ae650dSJack F Vogel 					   u16 *words, u16 *data)
243*61ae650dSJack F Vogel {
244*61ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
245*61ae650dSJack F Vogel 	u16 index, word;
246*61ae650dSJack F Vogel 
247*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_read_nvm_buffer");
248*61ae650dSJack F Vogel 
249*61ae650dSJack F Vogel 	/* Loop thru the selected region */
250*61ae650dSJack F Vogel 	for (word = 0; word < *words; word++) {
251*61ae650dSJack F Vogel 		index = offset + word;
252*61ae650dSJack F Vogel 		ret_code = i40e_read_nvm_word(hw, index, &data[word]);
253*61ae650dSJack F Vogel 		if (ret_code != I40E_SUCCESS)
254*61ae650dSJack F Vogel 			break;
255*61ae650dSJack F Vogel 	}
256*61ae650dSJack F Vogel 
257*61ae650dSJack F Vogel 	/* Update the number of words read from the Shadow RAM */
258*61ae650dSJack F Vogel 	*words = word;
259*61ae650dSJack F Vogel 
260*61ae650dSJack F Vogel 	return ret_code;
261*61ae650dSJack F Vogel }
262*61ae650dSJack F Vogel /**
263*61ae650dSJack F Vogel  * i40e_write_nvm_aq - Writes Shadow RAM.
264*61ae650dSJack F Vogel  * @hw: pointer to the HW structure.
265*61ae650dSJack F Vogel  * @module_pointer: module pointer location in words from the NVM beginning
266*61ae650dSJack F Vogel  * @offset: offset in words from module start
267*61ae650dSJack F Vogel  * @words: number of words to write
268*61ae650dSJack F Vogel  * @data: buffer with words to write to the Shadow RAM
269*61ae650dSJack F Vogel  * @last_command: tells the AdminQ that this is the last command
270*61ae650dSJack F Vogel  *
271*61ae650dSJack F Vogel  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
272*61ae650dSJack F Vogel  **/
273*61ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
274*61ae650dSJack F Vogel 					u32 offset, u16 words, void *data,
275*61ae650dSJack F Vogel 					bool last_command)
276*61ae650dSJack F Vogel {
277*61ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_ERR_NVM;
278*61ae650dSJack F Vogel 
279*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_write_nvm_aq");
280*61ae650dSJack F Vogel 
281*61ae650dSJack F Vogel 	/* Here we are checking the SR limit only for the flat memory model.
282*61ae650dSJack F Vogel 	 * We cannot do it for the module-based model, as we did not acquire
283*61ae650dSJack F Vogel 	 * the NVM resource yet (we cannot get the module pointer value).
284*61ae650dSJack F Vogel 	 * Firmware will check the module-based model.
285*61ae650dSJack F Vogel 	 */
286*61ae650dSJack F Vogel 	if ((offset + words) > hw->nvm.sr_size)
287*61ae650dSJack F Vogel 		DEBUGOUT("NVM write error: offset beyond Shadow RAM limit.\n");
288*61ae650dSJack F Vogel 	else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
289*61ae650dSJack F Vogel 		/* We can write only up to 4KB (one sector), in one AQ write */
290*61ae650dSJack F Vogel 		DEBUGOUT("NVM write fail error: cannot write more than 4KB in a single write.\n");
291*61ae650dSJack F Vogel 	else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
292*61ae650dSJack F Vogel 		 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
293*61ae650dSJack F Vogel 		/* A single write cannot spread over two sectors */
294*61ae650dSJack F Vogel 		DEBUGOUT("NVM write error: cannot spread over two sectors in a single write.\n");
295*61ae650dSJack F Vogel 	else
296*61ae650dSJack F Vogel 		ret_code = i40e_aq_update_nvm(hw, module_pointer,
297*61ae650dSJack F Vogel 					      2 * offset,  /*bytes*/
298*61ae650dSJack F Vogel 					      2 * words,   /*bytes*/
299*61ae650dSJack F Vogel 					      data, last_command, NULL);
300*61ae650dSJack F Vogel 
301*61ae650dSJack F Vogel 	return ret_code;
302*61ae650dSJack F Vogel }
303*61ae650dSJack F Vogel 
304*61ae650dSJack F Vogel /**
305*61ae650dSJack F Vogel  * i40e_write_nvm_word - Writes Shadow RAM word
306*61ae650dSJack F Vogel  * @hw: pointer to the HW structure
307*61ae650dSJack F Vogel  * @offset: offset of the Shadow RAM word to write
308*61ae650dSJack F Vogel  * @data: word to write to the Shadow RAM
309*61ae650dSJack F Vogel  *
310*61ae650dSJack F Vogel  * Writes a 16 bit word to the SR using the i40e_write_nvm_aq() method.
311*61ae650dSJack F Vogel  * NVM ownership have to be acquired and released (on ARQ completion event
312*61ae650dSJack F Vogel  * reception) by caller. To commit SR to NVM update checksum function
313*61ae650dSJack F Vogel  * should be called.
314*61ae650dSJack F Vogel  **/
315*61ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_word(struct i40e_hw *hw, u32 offset,
316*61ae650dSJack F Vogel 					  void *data)
317*61ae650dSJack F Vogel {
318*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_write_nvm_word");
319*61ae650dSJack F Vogel 
320*61ae650dSJack F Vogel 	/* Value 0x00 below means that we treat SR as a flat mem */
321*61ae650dSJack F Vogel 	return i40e_write_nvm_aq(hw, 0x00, offset, 1, data, FALSE);
322*61ae650dSJack F Vogel }
323*61ae650dSJack F Vogel 
324*61ae650dSJack F Vogel /**
325*61ae650dSJack F Vogel  * i40e_write_nvm_buffer - Writes Shadow RAM buffer
326*61ae650dSJack F Vogel  * @hw: pointer to the HW structure
327*61ae650dSJack F Vogel  * @module_pointer: module pointer location in words from the NVM beginning
328*61ae650dSJack F Vogel  * @offset: offset of the Shadow RAM buffer to write
329*61ae650dSJack F Vogel  * @words: number of words to write
330*61ae650dSJack F Vogel  * @data: words to write to the Shadow RAM
331*61ae650dSJack F Vogel  *
332*61ae650dSJack F Vogel  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
333*61ae650dSJack F Vogel  * NVM ownership must be acquired before calling this function and released
334*61ae650dSJack F Vogel  * on ARQ completion event reception by caller. To commit SR to NVM update
335*61ae650dSJack F Vogel  * checksum function should be called.
336*61ae650dSJack F Vogel  **/
337*61ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_buffer(struct i40e_hw *hw,
338*61ae650dSJack F Vogel 					    u8 module_pointer, u32 offset,
339*61ae650dSJack F Vogel 					    u16 words, void *data)
340*61ae650dSJack F Vogel {
341*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_write_nvm_buffer");
342*61ae650dSJack F Vogel 
343*61ae650dSJack F Vogel 	/* Here we will only write one buffer as the size of the modules
344*61ae650dSJack F Vogel 	 * mirrored in the Shadow RAM is always less than 4K.
345*61ae650dSJack F Vogel 	 */
346*61ae650dSJack F Vogel 	return i40e_write_nvm_aq(hw, module_pointer, offset, words,
347*61ae650dSJack F Vogel 				 data, FALSE);
348*61ae650dSJack F Vogel }
349*61ae650dSJack F Vogel 
350*61ae650dSJack F Vogel /**
351*61ae650dSJack F Vogel  * i40e_calc_nvm_checksum - Calculates and returns the checksum
352*61ae650dSJack F Vogel  * @hw: pointer to hardware structure
353*61ae650dSJack F Vogel  * @checksum: pointer to the checksum
354*61ae650dSJack F Vogel  *
355*61ae650dSJack F Vogel  * This function calculates SW Checksum that covers the whole 64kB shadow RAM
356*61ae650dSJack F Vogel  * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
357*61ae650dSJack F Vogel  * is customer specific and unknown. Therefore, this function skips all maximum
358*61ae650dSJack F Vogel  * possible size of VPD (1kB).
359*61ae650dSJack F Vogel  **/
360*61ae650dSJack F Vogel enum i40e_status_code i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum)
361*61ae650dSJack F Vogel {
362*61ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
363*61ae650dSJack F Vogel 	u16 pcie_alt_module = 0;
364*61ae650dSJack F Vogel 	u16 checksum_local = 0;
365*61ae650dSJack F Vogel 	u16 vpd_module = 0;
366*61ae650dSJack F Vogel 	u16 word = 0;
367*61ae650dSJack F Vogel 	u32 i = 0;
368*61ae650dSJack F Vogel 
369*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_calc_nvm_checksum");
370*61ae650dSJack F Vogel 
371*61ae650dSJack F Vogel 	/* read pointer to VPD area */
372*61ae650dSJack F Vogel 	ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
373*61ae650dSJack F Vogel 	if (ret_code != I40E_SUCCESS) {
374*61ae650dSJack F Vogel 		ret_code = I40E_ERR_NVM_CHECKSUM;
375*61ae650dSJack F Vogel 		goto i40e_calc_nvm_checksum_exit;
376*61ae650dSJack F Vogel 	}
377*61ae650dSJack F Vogel 
378*61ae650dSJack F Vogel 	/* read pointer to PCIe Alt Auto-load module */
379*61ae650dSJack F Vogel 	ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
380*61ae650dSJack F Vogel 				       &pcie_alt_module);
381*61ae650dSJack F Vogel 	if (ret_code != I40E_SUCCESS) {
382*61ae650dSJack F Vogel 		ret_code = I40E_ERR_NVM_CHECKSUM;
383*61ae650dSJack F Vogel 		goto i40e_calc_nvm_checksum_exit;
384*61ae650dSJack F Vogel 	}
385*61ae650dSJack F Vogel 
386*61ae650dSJack F Vogel 	/* Calculate SW checksum that covers the whole 64kB shadow RAM
387*61ae650dSJack F Vogel 	 * except the VPD and PCIe ALT Auto-load modules
388*61ae650dSJack F Vogel 	 */
389*61ae650dSJack F Vogel 	for (i = 0; i < hw->nvm.sr_size; i++) {
390*61ae650dSJack F Vogel 		/* Skip Checksum word */
391*61ae650dSJack F Vogel 		if (i == I40E_SR_SW_CHECKSUM_WORD)
392*61ae650dSJack F Vogel 			i++;
393*61ae650dSJack F Vogel 		/* Skip VPD module (convert byte size to word count) */
394*61ae650dSJack F Vogel 		if (i == (u32)vpd_module) {
395*61ae650dSJack F Vogel 			i += (I40E_SR_VPD_MODULE_MAX_SIZE / 2);
396*61ae650dSJack F Vogel 			if (i >= hw->nvm.sr_size)
397*61ae650dSJack F Vogel 				break;
398*61ae650dSJack F Vogel 		}
399*61ae650dSJack F Vogel 		/* Skip PCIe ALT module (convert byte size to word count) */
400*61ae650dSJack F Vogel 		if (i == (u32)pcie_alt_module) {
401*61ae650dSJack F Vogel 			i += (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2);
402*61ae650dSJack F Vogel 			if (i >= hw->nvm.sr_size)
403*61ae650dSJack F Vogel 				break;
404*61ae650dSJack F Vogel 		}
405*61ae650dSJack F Vogel 
406*61ae650dSJack F Vogel 		ret_code = i40e_read_nvm_word(hw, (u16)i, &word);
407*61ae650dSJack F Vogel 		if (ret_code != I40E_SUCCESS) {
408*61ae650dSJack F Vogel 			ret_code = I40E_ERR_NVM_CHECKSUM;
409*61ae650dSJack F Vogel 			goto i40e_calc_nvm_checksum_exit;
410*61ae650dSJack F Vogel 		}
411*61ae650dSJack F Vogel 		checksum_local += word;
412*61ae650dSJack F Vogel 	}
413*61ae650dSJack F Vogel 
414*61ae650dSJack F Vogel 	*checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local;
415*61ae650dSJack F Vogel 
416*61ae650dSJack F Vogel i40e_calc_nvm_checksum_exit:
417*61ae650dSJack F Vogel 	return ret_code;
418*61ae650dSJack F Vogel }
419*61ae650dSJack F Vogel 
420*61ae650dSJack F Vogel /**
421*61ae650dSJack F Vogel  * i40e_update_nvm_checksum - Updates the NVM checksum
422*61ae650dSJack F Vogel  * @hw: pointer to hardware structure
423*61ae650dSJack F Vogel  *
424*61ae650dSJack F Vogel  * NVM ownership must be acquired before calling this function and released
425*61ae650dSJack F Vogel  * on ARQ completion event reception by caller.
426*61ae650dSJack F Vogel  * This function will commit SR to NVM.
427*61ae650dSJack F Vogel  **/
428*61ae650dSJack F Vogel enum i40e_status_code i40e_update_nvm_checksum(struct i40e_hw *hw)
429*61ae650dSJack F Vogel {
430*61ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
431*61ae650dSJack F Vogel 	u16 checksum;
432*61ae650dSJack F Vogel 
433*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_update_nvm_checksum");
434*61ae650dSJack F Vogel 
435*61ae650dSJack F Vogel 	ret_code = i40e_calc_nvm_checksum(hw, &checksum);
436*61ae650dSJack F Vogel 	if (ret_code == I40E_SUCCESS)
437*61ae650dSJack F Vogel 		ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD,
438*61ae650dSJack F Vogel 					     1, &checksum, TRUE);
439*61ae650dSJack F Vogel 
440*61ae650dSJack F Vogel 	return ret_code;
441*61ae650dSJack F Vogel }
442*61ae650dSJack F Vogel 
443*61ae650dSJack F Vogel /**
444*61ae650dSJack F Vogel  * i40e_validate_nvm_checksum - Validate EEPROM checksum
445*61ae650dSJack F Vogel  * @hw: pointer to hardware structure
446*61ae650dSJack F Vogel  * @checksum: calculated checksum
447*61ae650dSJack F Vogel  *
448*61ae650dSJack F Vogel  * Performs checksum calculation and validates the NVM SW checksum. If the
449*61ae650dSJack F Vogel  * caller does not need checksum, the value can be NULL.
450*61ae650dSJack F Vogel  **/
451*61ae650dSJack F Vogel enum i40e_status_code i40e_validate_nvm_checksum(struct i40e_hw *hw,
452*61ae650dSJack F Vogel 						 u16 *checksum)
453*61ae650dSJack F Vogel {
454*61ae650dSJack F Vogel 	enum i40e_status_code ret_code = I40E_SUCCESS;
455*61ae650dSJack F Vogel 	u16 checksum_sr = 0;
456*61ae650dSJack F Vogel 	u16 checksum_local = 0;
457*61ae650dSJack F Vogel 
458*61ae650dSJack F Vogel 	DEBUGFUNC("i40e_validate_nvm_checksum");
459*61ae650dSJack F Vogel 
460*61ae650dSJack F Vogel 	ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
461*61ae650dSJack F Vogel 	if (ret_code != I40E_SUCCESS)
462*61ae650dSJack F Vogel 		goto i40e_validate_nvm_checksum_exit;
463*61ae650dSJack F Vogel 
464*61ae650dSJack F Vogel 	/* Do not use i40e_read_nvm_word() because we do not want to take
465*61ae650dSJack F Vogel 	 * the synchronization semaphores twice here.
466*61ae650dSJack F Vogel 	 */
467*61ae650dSJack F Vogel 	i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
468*61ae650dSJack F Vogel 
469*61ae650dSJack F Vogel 	/* Verify read checksum from EEPROM is the same as
470*61ae650dSJack F Vogel 	 * calculated checksum
471*61ae650dSJack F Vogel 	 */
472*61ae650dSJack F Vogel 	if (checksum_local != checksum_sr)
473*61ae650dSJack F Vogel 		ret_code = I40E_ERR_NVM_CHECKSUM;
474*61ae650dSJack F Vogel 
475*61ae650dSJack F Vogel 	/* If the user cares, return the calculated checksum */
476*61ae650dSJack F Vogel 	if (checksum)
477*61ae650dSJack F Vogel 		*checksum = checksum_local;
478*61ae650dSJack F Vogel 
479*61ae650dSJack F Vogel i40e_validate_nvm_checksum_exit:
480*61ae650dSJack F Vogel 	return ret_code;
481*61ae650dSJack F Vogel }
482