1270631Sjfv/******************************************************************************
2270631Sjfv
3292100Ssmh  Copyright (c) 2013-2015, Intel Corporation
4270631Sjfv  All rights reserved.
5270631Sjfv
6270631Sjfv  Redistribution and use in source and binary forms, with or without
7270631Sjfv  modification, are permitted provided that the following conditions are met:
8270631Sjfv
9270631Sjfv   1. Redistributions of source code must retain the above copyright notice,
10270631Sjfv      this list of conditions and the following disclaimer.
11270631Sjfv
12270631Sjfv   2. Redistributions in binary form must reproduce the above copyright
13270631Sjfv      notice, this list of conditions and the following disclaimer in the
14270631Sjfv      documentation and/or other materials provided with the distribution.
15270631Sjfv
16270631Sjfv   3. Neither the name of the Intel Corporation nor the names of its
17270631Sjfv      contributors may be used to endorse or promote products derived from
18270631Sjfv      this software without specific prior written permission.
19270631Sjfv
20270631Sjfv  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21270631Sjfv  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22270631Sjfv  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23270631Sjfv  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24270631Sjfv  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25270631Sjfv  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26270631Sjfv  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27270631Sjfv  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28270631Sjfv  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29270631Sjfv  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30270631Sjfv  POSSIBILITY OF SUCH DAMAGE.
31270631Sjfv
32270631Sjfv******************************************************************************/
33270631Sjfv/*$FreeBSD$*/
34270631Sjfv
35270631Sjfv#include "i40e_prototype.h"
36270631Sjfv
37291248Ssmhenum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset,
38291248Ssmh					       u16 *data);
39291248Ssmhenum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
40291248Ssmh					    u16 *data);
41291248Ssmhenum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset,
42291248Ssmh						 u16 *words, u16 *data);
43291248Ssmhenum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset,
44291248Ssmh					      u16 *words, u16 *data);
45291248Ssmhenum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
46291248Ssmh				       u32 offset, u16 words, void *data,
47291248Ssmh				       bool last_command);
48291248Ssmh
49270631Sjfv/**
50270631Sjfv * i40e_init_nvm_ops - Initialize NVM function pointers
51270631Sjfv * @hw: pointer to the HW structure
52270631Sjfv *
53270631Sjfv * Setup the function pointers and the NVM info structure. Should be called
54270631Sjfv * once per NVM initialization, e.g. inside the i40e_init_shared_code().
55270631Sjfv * Please notice that the NVM term is used here (& in all methods covered
56270631Sjfv * in this file) as an equivalent of the FLASH part mapped into the SR.
57270631Sjfv * We are accessing FLASH always thru the Shadow RAM.
58270631Sjfv **/
59270631Sjfvenum i40e_status_code i40e_init_nvm(struct i40e_hw *hw)
60270631Sjfv{
61270631Sjfv	struct i40e_nvm_info *nvm = &hw->nvm;
62270631Sjfv	enum i40e_status_code ret_code = I40E_SUCCESS;
63270631Sjfv	u32 fla, gens;
64270631Sjfv	u8 sr_size;
65270631Sjfv
66270631Sjfv	DEBUGFUNC("i40e_init_nvm");
67270631Sjfv
68270631Sjfv	/* The SR size is stored regardless of the nvm programming mode
69270631Sjfv	 * as the blank mode may be used in the factory line.
70270631Sjfv	 */
71270631Sjfv	gens = rd32(hw, I40E_GLNVM_GENS);
72270631Sjfv	sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
73270631Sjfv			   I40E_GLNVM_GENS_SR_SIZE_SHIFT);
74270631Sjfv	/* Switching to words (sr_size contains power of 2KB) */
75292100Ssmh	nvm->sr_size = BIT(sr_size) * I40E_SR_WORDS_IN_1KB;
76270631Sjfv
77270631Sjfv	/* Check if we are in the normal or blank NVM programming mode */
78270631Sjfv	fla = rd32(hw, I40E_GLNVM_FLA);
79270631Sjfv	if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
80270631Sjfv		/* Max NVM timeout */
81270631Sjfv		nvm->timeout = I40E_MAX_NVM_TIMEOUT;
82270631Sjfv		nvm->blank_nvm_mode = FALSE;
83270631Sjfv	} else { /* Blank programming mode */
84270631Sjfv		nvm->blank_nvm_mode = TRUE;
85270631Sjfv		ret_code = I40E_ERR_NVM_BLANK_MODE;
86291248Ssmh		i40e_debug(hw, I40E_DEBUG_NVM, "NVM init error: unsupported blank mode.\n");
87270631Sjfv	}
88270631Sjfv
89270631Sjfv	return ret_code;
90270631Sjfv}
91270631Sjfv
92270631Sjfv/**
93270631Sjfv * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
94270631Sjfv * @hw: pointer to the HW structure
95270631Sjfv * @access: NVM access type (read or write)
96270631Sjfv *
97270631Sjfv * This function will request NVM ownership for reading
98270631Sjfv * via the proper Admin Command.
99270631Sjfv **/
100270631Sjfvenum i40e_status_code i40e_acquire_nvm(struct i40e_hw *hw,
101270631Sjfv				       enum i40e_aq_resource_access_type access)
102270631Sjfv{
103270631Sjfv	enum i40e_status_code ret_code = I40E_SUCCESS;
104270631Sjfv	u64 gtime, timeout;
105291248Ssmh	u64 time_left = 0;
106270631Sjfv
107270631Sjfv	DEBUGFUNC("i40e_acquire_nvm");
108270631Sjfv
109270631Sjfv	if (hw->nvm.blank_nvm_mode)
110270631Sjfv		goto i40e_i40e_acquire_nvm_exit;
111270631Sjfv
112270631Sjfv	ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
113291248Ssmh					    0, &time_left, NULL);
114270631Sjfv	/* Reading the Global Device Timer */
115270631Sjfv	gtime = rd32(hw, I40E_GLVFGEN_TIMER);
116270631Sjfv
117270631Sjfv	/* Store the timeout */
118291248Ssmh	hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime;
119270631Sjfv
120291248Ssmh	if (ret_code)
121291248Ssmh		i40e_debug(hw, I40E_DEBUG_NVM,
122291248Ssmh			   "NVM acquire type %d failed time_left=%llu ret=%d aq_err=%d\n",
123291248Ssmh			   access, time_left, ret_code, hw->aq.asq_last_status);
124291248Ssmh
125291248Ssmh	if (ret_code && time_left) {
126270631Sjfv		/* Poll until the current NVM owner timeouts */
127291248Ssmh		timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime;
128291248Ssmh		while ((gtime < timeout) && time_left) {
129270631Sjfv			i40e_msec_delay(10);
130291248Ssmh			gtime = rd32(hw, I40E_GLVFGEN_TIMER);
131270631Sjfv			ret_code = i40e_aq_request_resource(hw,
132270631Sjfv							I40E_NVM_RESOURCE_ID,
133291248Ssmh							access, 0, &time_left,
134270631Sjfv							NULL);
135270631Sjfv			if (ret_code == I40E_SUCCESS) {
136270631Sjfv				hw->nvm.hw_semaphore_timeout =
137291248Ssmh					    I40E_MS_TO_GTIME(time_left) + gtime;
138270631Sjfv				break;
139270631Sjfv			}
140270631Sjfv		}
141270631Sjfv		if (ret_code != I40E_SUCCESS) {
142270631Sjfv			hw->nvm.hw_semaphore_timeout = 0;
143291248Ssmh			i40e_debug(hw, I40E_DEBUG_NVM,
144291248Ssmh				   "NVM acquire timed out, wait %llu ms before trying again. status=%d aq_err=%d\n",
145291248Ssmh				   time_left, ret_code, hw->aq.asq_last_status);
146270631Sjfv		}
147270631Sjfv	}
148270631Sjfv
149270631Sjfvi40e_i40e_acquire_nvm_exit:
150270631Sjfv	return ret_code;
151270631Sjfv}
152270631Sjfv
153270631Sjfv/**
154270631Sjfv * i40e_release_nvm - Generic request for releasing the NVM ownership
155270631Sjfv * @hw: pointer to the HW structure
156270631Sjfv *
157270631Sjfv * This function will release NVM resource via the proper Admin Command.
158270631Sjfv **/
159270631Sjfvvoid i40e_release_nvm(struct i40e_hw *hw)
160270631Sjfv{
161292100Ssmh	enum i40e_status_code ret_code = I40E_SUCCESS;
162292100Ssmh	u32 total_delay = 0;
163292100Ssmh
164270631Sjfv	DEBUGFUNC("i40e_release_nvm");
165270631Sjfv
166292100Ssmh	if (hw->nvm.blank_nvm_mode)
167292100Ssmh		return;
168292100Ssmh
169292100Ssmh	ret_code = i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
170292100Ssmh
171292100Ssmh	/* there are some rare cases when trying to release the resource
172292100Ssmh	 * results in an admin Q timeout, so handle them correctly
173292100Ssmh	 */
174292100Ssmh	while ((ret_code == I40E_ERR_ADMIN_QUEUE_TIMEOUT) &&
175292100Ssmh	       (total_delay < hw->aq.asq_cmd_timeout)) {
176292100Ssmh			i40e_msec_delay(1);
177292100Ssmh			ret_code = i40e_aq_release_resource(hw,
178292100Ssmh						I40E_NVM_RESOURCE_ID, 0, NULL);
179292100Ssmh			total_delay++;
180292100Ssmh	}
181270631Sjfv}
182270631Sjfv
183270631Sjfv/**
184270631Sjfv * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
185270631Sjfv * @hw: pointer to the HW structure
186270631Sjfv *
187270631Sjfv * Polls the SRCTL Shadow RAM register done bit.
188270631Sjfv **/
189270631Sjfvstatic enum i40e_status_code i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
190270631Sjfv{
191270631Sjfv	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
192270631Sjfv	u32 srctl, wait_cnt;
193270631Sjfv
194270631Sjfv	DEBUGFUNC("i40e_poll_sr_srctl_done_bit");
195270631Sjfv
196270631Sjfv	/* Poll the I40E_GLNVM_SRCTL until the done bit is set */
197270631Sjfv	for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
198270631Sjfv		srctl = rd32(hw, I40E_GLNVM_SRCTL);
199270631Sjfv		if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
200270631Sjfv			ret_code = I40E_SUCCESS;
201270631Sjfv			break;
202270631Sjfv		}
203270631Sjfv		i40e_usec_delay(5);
204270631Sjfv	}
205270631Sjfv	if (ret_code == I40E_ERR_TIMEOUT)
206291248Ssmh		i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set");
207270631Sjfv	return ret_code;
208270631Sjfv}
209270631Sjfv
210270631Sjfv/**
211270631Sjfv * i40e_read_nvm_word - Reads Shadow RAM
212270631Sjfv * @hw: pointer to the HW structure
213270631Sjfv * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
214270631Sjfv * @data: word read from the Shadow RAM
215270631Sjfv *
216270631Sjfv * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
217270631Sjfv **/
218270631Sjfvenum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
219270631Sjfv					 u16 *data)
220270631Sjfv{
221292100Ssmh#ifdef X722_SUPPORT
222292100Ssmh	if (hw->mac.type == I40E_MAC_X722)
223292100Ssmh		return i40e_read_nvm_word_aq(hw, offset, data);
224292100Ssmh#endif
225291248Ssmh	return i40e_read_nvm_word_srctl(hw, offset, data);
226291248Ssmh}
227291248Ssmh
228291248Ssmh/**
229291248Ssmh * i40e_read_nvm_word_srctl - Reads Shadow RAM via SRCTL register
230291248Ssmh * @hw: pointer to the HW structure
231291248Ssmh * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
232291248Ssmh * @data: word read from the Shadow RAM
233291248Ssmh *
234291248Ssmh * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
235291248Ssmh **/
236291248Ssmhenum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset,
237291248Ssmh					       u16 *data)
238291248Ssmh{
239270631Sjfv	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
240270631Sjfv	u32 sr_reg;
241270631Sjfv
242291248Ssmh	DEBUGFUNC("i40e_read_nvm_word_srctl");
243270631Sjfv
244270631Sjfv	if (offset >= hw->nvm.sr_size) {
245291248Ssmh		i40e_debug(hw, I40E_DEBUG_NVM,
246291248Ssmh			   "NVM read error: Offset %d beyond Shadow RAM limit %d\n",
247291248Ssmh			   offset, hw->nvm.sr_size);
248270631Sjfv		ret_code = I40E_ERR_PARAM;
249270631Sjfv		goto read_nvm_exit;
250270631Sjfv	}
251270631Sjfv
252270631Sjfv	/* Poll the done bit first */
253270631Sjfv	ret_code = i40e_poll_sr_srctl_done_bit(hw);
254270631Sjfv	if (ret_code == I40E_SUCCESS) {
255270631Sjfv		/* Write the address and start reading */
256292100Ssmh		sr_reg = ((u32)offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
257292100Ssmh			 BIT(I40E_GLNVM_SRCTL_START_SHIFT);
258270631Sjfv		wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
259270631Sjfv
260270631Sjfv		/* Poll I40E_GLNVM_SRCTL until the done bit is set */
261270631Sjfv		ret_code = i40e_poll_sr_srctl_done_bit(hw);
262270631Sjfv		if (ret_code == I40E_SUCCESS) {
263270631Sjfv			sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
264270631Sjfv			*data = (u16)((sr_reg &
265270631Sjfv				       I40E_GLNVM_SRDATA_RDDATA_MASK)
266270631Sjfv				    >> I40E_GLNVM_SRDATA_RDDATA_SHIFT);
267270631Sjfv		}
268270631Sjfv	}
269270631Sjfv	if (ret_code != I40E_SUCCESS)
270291248Ssmh		i40e_debug(hw, I40E_DEBUG_NVM,
271291248Ssmh			   "NVM read error: Couldn't access Shadow RAM address: 0x%x\n",
272291248Ssmh			   offset);
273270631Sjfv
274270631Sjfvread_nvm_exit:
275270631Sjfv	return ret_code;
276270631Sjfv}
277270631Sjfv
278270631Sjfv/**
279291248Ssmh * i40e_read_nvm_word_aq - Reads Shadow RAM via AQ
280291248Ssmh * @hw: pointer to the HW structure
281291248Ssmh * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
282291248Ssmh * @data: word read from the Shadow RAM
283291248Ssmh *
284291248Ssmh * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
285291248Ssmh **/
286291248Ssmhenum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
287291248Ssmh					    u16 *data)
288291248Ssmh{
289291248Ssmh	enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
290291248Ssmh
291291248Ssmh	DEBUGFUNC("i40e_read_nvm_word_aq");
292291248Ssmh
293291248Ssmh	ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, TRUE);
294291248Ssmh	*data = LE16_TO_CPU(*(__le16 *)data);
295291248Ssmh
296291248Ssmh	return ret_code;
297291248Ssmh}
298291248Ssmh
299291248Ssmh/**
300270631Sjfv * i40e_read_nvm_buffer - Reads Shadow RAM buffer
301270631Sjfv * @hw: pointer to the HW structure
302270631Sjfv * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
303270631Sjfv * @words: (in) number of words to read; (out) number of words actually read
304270631Sjfv * @data: words read from the Shadow RAM
305270631Sjfv *
306270631Sjfv * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
307270631Sjfv * method. The buffer read is preceded by the NVM ownership take
308270631Sjfv * and followed by the release.
309270631Sjfv **/
310270631Sjfvenum i40e_status_code i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
311270631Sjfv					   u16 *words, u16 *data)
312270631Sjfv{
313292100Ssmh#ifdef X722_SUPPORT
314292100Ssmh	if (hw->mac.type == I40E_MAC_X722)
315292100Ssmh		return i40e_read_nvm_buffer_aq(hw, offset, words, data);
316292100Ssmh#endif
317291248Ssmh	return i40e_read_nvm_buffer_srctl(hw, offset, words, data);
318291248Ssmh}
319291248Ssmh
320291248Ssmh/**
321291248Ssmh * i40e_read_nvm_buffer_srctl - Reads Shadow RAM buffer via SRCTL register
322291248Ssmh * @hw: pointer to the HW structure
323291248Ssmh * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
324291248Ssmh * @words: (in) number of words to read; (out) number of words actually read
325291248Ssmh * @data: words read from the Shadow RAM
326291248Ssmh *
327291248Ssmh * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
328291248Ssmh * method. The buffer read is preceded by the NVM ownership take
329291248Ssmh * and followed by the release.
330291248Ssmh **/
331291248Ssmhenum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset,
332291248Ssmh						 u16 *words, u16 *data)
333291248Ssmh{
334270631Sjfv	enum i40e_status_code ret_code = I40E_SUCCESS;
335270631Sjfv	u16 index, word;
336270631Sjfv
337291248Ssmh	DEBUGFUNC("i40e_read_nvm_buffer_srctl");
338270631Sjfv
339270631Sjfv	/* Loop thru the selected region */
340270631Sjfv	for (word = 0; word < *words; word++) {
341270631Sjfv		index = offset + word;
342291248Ssmh		ret_code = i40e_read_nvm_word_srctl(hw, index, &data[word]);
343270631Sjfv		if (ret_code != I40E_SUCCESS)
344270631Sjfv			break;
345270631Sjfv	}
346270631Sjfv
347270631Sjfv	/* Update the number of words read from the Shadow RAM */
348270631Sjfv	*words = word;
349270631Sjfv
350270631Sjfv	return ret_code;
351270631Sjfv}
352291248Ssmh
353270631Sjfv/**
354291248Ssmh * i40e_read_nvm_buffer_aq - Reads Shadow RAM buffer via AQ
355291248Ssmh * @hw: pointer to the HW structure
356291248Ssmh * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
357291248Ssmh * @words: (in) number of words to read; (out) number of words actually read
358291248Ssmh * @data: words read from the Shadow RAM
359291248Ssmh *
360291248Ssmh * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_aq()
361291248Ssmh * method. The buffer read is preceded by the NVM ownership take
362291248Ssmh * and followed by the release.
363291248Ssmh **/
364291248Ssmhenum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset,
365291248Ssmh					      u16 *words, u16 *data)
366291248Ssmh{
367291248Ssmh	enum i40e_status_code ret_code;
368291248Ssmh	u16 read_size = *words;
369291248Ssmh	bool last_cmd = FALSE;
370291248Ssmh	u16 words_read = 0;
371291248Ssmh	u16 i = 0;
372291248Ssmh
373291248Ssmh	DEBUGFUNC("i40e_read_nvm_buffer_aq");
374291248Ssmh
375291248Ssmh	do {
376291248Ssmh		/* Calculate number of bytes we should read in this step.
377291248Ssmh		 * FVL AQ do not allow to read more than one page at a time or
378291248Ssmh		 * to cross page boundaries.
379291248Ssmh		 */
380291248Ssmh		if (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)
381291248Ssmh			read_size = min(*words,
382291248Ssmh					(u16)(I40E_SR_SECTOR_SIZE_IN_WORDS -
383291248Ssmh				      (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)));
384291248Ssmh		else
385291248Ssmh			read_size = min((*words - words_read),
386291248Ssmh					I40E_SR_SECTOR_SIZE_IN_WORDS);
387291248Ssmh
388291248Ssmh		/* Check if this is last command, if so set proper flag */
389291248Ssmh		if ((words_read + read_size) >= *words)
390291248Ssmh			last_cmd = TRUE;
391291248Ssmh
392291248Ssmh		ret_code = i40e_read_nvm_aq(hw, 0x0, offset, read_size,
393291248Ssmh					    data + words_read, last_cmd);
394291248Ssmh		if (ret_code != I40E_SUCCESS)
395291248Ssmh			goto read_nvm_buffer_aq_exit;
396291248Ssmh
397291248Ssmh		/* Increment counter for words already read and move offset to
398291248Ssmh		 * new read location
399291248Ssmh		 */
400291248Ssmh		words_read += read_size;
401291248Ssmh		offset += read_size;
402291248Ssmh	} while (words_read < *words);
403291248Ssmh
404291248Ssmh	for (i = 0; i < *words; i++)
405291248Ssmh		data[i] = LE16_TO_CPU(((__le16 *)data)[i]);
406291248Ssmh
407291248Ssmhread_nvm_buffer_aq_exit:
408291248Ssmh	*words = words_read;
409291248Ssmh	return ret_code;
410291248Ssmh}
411291248Ssmh
412291248Ssmh/**
413291248Ssmh * i40e_read_nvm_aq - Read Shadow RAM.
414291248Ssmh * @hw: pointer to the HW structure.
415291248Ssmh * @module_pointer: module pointer location in words from the NVM beginning
416291248Ssmh * @offset: offset in words from module start
417291248Ssmh * @words: number of words to write
418291248Ssmh * @data: buffer with words to write to the Shadow RAM
419291248Ssmh * @last_command: tells the AdminQ that this is the last command
420291248Ssmh *
421291248Ssmh * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
422291248Ssmh **/
423291248Ssmhenum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
424291248Ssmh				       u32 offset, u16 words, void *data,
425291248Ssmh				       bool last_command)
426291248Ssmh{
427291248Ssmh	enum i40e_status_code ret_code = I40E_ERR_NVM;
428292100Ssmh	struct i40e_asq_cmd_details cmd_details;
429291248Ssmh
430291248Ssmh	DEBUGFUNC("i40e_read_nvm_aq");
431291248Ssmh
432292100Ssmh	memset(&cmd_details, 0, sizeof(cmd_details));
433292100Ssmh	cmd_details.wb_desc = &hw->nvm_wb_desc;
434292100Ssmh
435291248Ssmh	/* Here we are checking the SR limit only for the flat memory model.
436291248Ssmh	 * We cannot do it for the module-based model, as we did not acquire
437291248Ssmh	 * the NVM resource yet (we cannot get the module pointer value).
438291248Ssmh	 * Firmware will check the module-based model.
439291248Ssmh	 */
440291248Ssmh	if ((offset + words) > hw->nvm.sr_size)
441291248Ssmh		i40e_debug(hw, I40E_DEBUG_NVM,
442291248Ssmh			   "NVM write error: offset %d beyond Shadow RAM limit %d\n",
443291248Ssmh			   (offset + words), hw->nvm.sr_size);
444291248Ssmh	else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
445291248Ssmh		/* We can write only up to 4KB (one sector), in one AQ write */
446291248Ssmh		i40e_debug(hw, I40E_DEBUG_NVM,
447291248Ssmh			   "NVM write fail error: tried to write %d words, limit is %d.\n",
448291248Ssmh			   words, I40E_SR_SECTOR_SIZE_IN_WORDS);
449291248Ssmh	else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
450291248Ssmh		 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
451291248Ssmh		/* A single write cannot spread over two sectors */
452291248Ssmh		i40e_debug(hw, I40E_DEBUG_NVM,
453291248Ssmh			   "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n",
454291248Ssmh			   offset, words);
455291248Ssmh	else
456291248Ssmh		ret_code = i40e_aq_read_nvm(hw, module_pointer,
457291248Ssmh					    2 * offset,  /*bytes*/
458291248Ssmh					    2 * words,   /*bytes*/
459292100Ssmh					    data, last_command, &cmd_details);
460291248Ssmh
461291248Ssmh	return ret_code;
462291248Ssmh}
463291248Ssmh
464291248Ssmh/**
465270631Sjfv * i40e_write_nvm_aq - Writes Shadow RAM.
466270631Sjfv * @hw: pointer to the HW structure.
467270631Sjfv * @module_pointer: module pointer location in words from the NVM beginning
468270631Sjfv * @offset: offset in words from module start
469270631Sjfv * @words: number of words to write
470270631Sjfv * @data: buffer with words to write to the Shadow RAM
471270631Sjfv * @last_command: tells the AdminQ that this is the last command
472270631Sjfv *
473270631Sjfv * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
474270631Sjfv **/
475270631Sjfvenum i40e_status_code i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
476270631Sjfv					u32 offset, u16 words, void *data,
477270631Sjfv					bool last_command)
478270631Sjfv{
479270631Sjfv	enum i40e_status_code ret_code = I40E_ERR_NVM;
480292100Ssmh	struct i40e_asq_cmd_details cmd_details;
481270631Sjfv
482270631Sjfv	DEBUGFUNC("i40e_write_nvm_aq");
483270631Sjfv
484292100Ssmh	memset(&cmd_details, 0, sizeof(cmd_details));
485292100Ssmh	cmd_details.wb_desc = &hw->nvm_wb_desc;
486292100Ssmh
487270631Sjfv	/* Here we are checking the SR limit only for the flat memory model.
488270631Sjfv	 * We cannot do it for the module-based model, as we did not acquire
489270631Sjfv	 * the NVM resource yet (we cannot get the module pointer value).
490270631Sjfv	 * Firmware will check the module-based model.
491270631Sjfv	 */
492270631Sjfv	if ((offset + words) > hw->nvm.sr_size)
493270631Sjfv		DEBUGOUT("NVM write error: offset beyond Shadow RAM limit.\n");
494270631Sjfv	else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
495270631Sjfv		/* We can write only up to 4KB (one sector), in one AQ write */
496270631Sjfv		DEBUGOUT("NVM write fail error: cannot write more than 4KB in a single write.\n");
497270631Sjfv	else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
498270631Sjfv		 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
499270631Sjfv		/* A single write cannot spread over two sectors */
500270631Sjfv		DEBUGOUT("NVM write error: cannot spread over two sectors in a single write.\n");
501270631Sjfv	else
502270631Sjfv		ret_code = i40e_aq_update_nvm(hw, module_pointer,
503270631Sjfv					      2 * offset,  /*bytes*/
504270631Sjfv					      2 * words,   /*bytes*/
505292100Ssmh					      data, last_command, &cmd_details);
506270631Sjfv
507270631Sjfv	return ret_code;
508270631Sjfv}
509270631Sjfv
510270631Sjfv/**
511270631Sjfv * i40e_write_nvm_word - Writes Shadow RAM word
512270631Sjfv * @hw: pointer to the HW structure
513270631Sjfv * @offset: offset of the Shadow RAM word to write
514270631Sjfv * @data: word to write to the Shadow RAM
515270631Sjfv *
516270631Sjfv * Writes a 16 bit word to the SR using the i40e_write_nvm_aq() method.
517270631Sjfv * NVM ownership have to be acquired and released (on ARQ completion event
518270631Sjfv * reception) by caller. To commit SR to NVM update checksum function
519270631Sjfv * should be called.
520270631Sjfv **/
521270631Sjfvenum i40e_status_code i40e_write_nvm_word(struct i40e_hw *hw, u32 offset,
522270631Sjfv					  void *data)
523270631Sjfv{
524270631Sjfv	DEBUGFUNC("i40e_write_nvm_word");
525270631Sjfv
526291248Ssmh	*((__le16 *)data) = CPU_TO_LE16(*((u16 *)data));
527291248Ssmh
528270631Sjfv	/* Value 0x00 below means that we treat SR as a flat mem */
529270631Sjfv	return i40e_write_nvm_aq(hw, 0x00, offset, 1, data, FALSE);
530270631Sjfv}
531270631Sjfv
532270631Sjfv/**
533270631Sjfv * i40e_write_nvm_buffer - Writes Shadow RAM buffer
534270631Sjfv * @hw: pointer to the HW structure
535270631Sjfv * @module_pointer: module pointer location in words from the NVM beginning
536270631Sjfv * @offset: offset of the Shadow RAM buffer to write
537270631Sjfv * @words: number of words to write
538270631Sjfv * @data: words to write to the Shadow RAM
539270631Sjfv *
540270631Sjfv * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
541270631Sjfv * NVM ownership must be acquired before calling this function and released
542270631Sjfv * on ARQ completion event reception by caller. To commit SR to NVM update
543270631Sjfv * checksum function should be called.
544270631Sjfv **/
545270631Sjfvenum i40e_status_code i40e_write_nvm_buffer(struct i40e_hw *hw,
546270631Sjfv					    u8 module_pointer, u32 offset,
547270631Sjfv					    u16 words, void *data)
548270631Sjfv{
549291248Ssmh	__le16 *le_word_ptr = (__le16 *)data;
550291248Ssmh	u16 *word_ptr = (u16 *)data;
551291248Ssmh	u32 i = 0;
552291248Ssmh
553270631Sjfv	DEBUGFUNC("i40e_write_nvm_buffer");
554270631Sjfv
555291248Ssmh	for (i = 0; i < words; i++)
556291248Ssmh		le_word_ptr[i] = CPU_TO_LE16(word_ptr[i]);
557291248Ssmh
558270631Sjfv	/* Here we will only write one buffer as the size of the modules
559270631Sjfv	 * mirrored in the Shadow RAM is always less than 4K.
560270631Sjfv	 */
561270631Sjfv	return i40e_write_nvm_aq(hw, module_pointer, offset, words,
562270631Sjfv				 data, FALSE);
563270631Sjfv}
564270631Sjfv
565270631Sjfv/**
566270631Sjfv * i40e_calc_nvm_checksum - Calculates and returns the checksum
567270631Sjfv * @hw: pointer to hardware structure
568270631Sjfv * @checksum: pointer to the checksum
569270631Sjfv *
570270631Sjfv * This function calculates SW Checksum that covers the whole 64kB shadow RAM
571270631Sjfv * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
572270631Sjfv * is customer specific and unknown. Therefore, this function skips all maximum
573270631Sjfv * possible size of VPD (1kB).
574270631Sjfv **/
575270631Sjfvenum i40e_status_code i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum)
576270631Sjfv{
577270631Sjfv	enum i40e_status_code ret_code = I40E_SUCCESS;
578291248Ssmh	struct i40e_virt_mem vmem;
579270631Sjfv	u16 pcie_alt_module = 0;
580270631Sjfv	u16 checksum_local = 0;
581270631Sjfv	u16 vpd_module = 0;
582291248Ssmh	u16 *data;
583291248Ssmh	u16 i = 0;
584270631Sjfv
585270631Sjfv	DEBUGFUNC("i40e_calc_nvm_checksum");
586270631Sjfv
587291248Ssmh	ret_code = i40e_allocate_virt_mem(hw, &vmem,
588291248Ssmh				    I40E_SR_SECTOR_SIZE_IN_WORDS * sizeof(u16));
589291248Ssmh	if (ret_code)
590291248Ssmh		goto i40e_calc_nvm_checksum_exit;
591291248Ssmh	data = (u16 *)vmem.va;
592291248Ssmh
593270631Sjfv	/* read pointer to VPD area */
594270631Sjfv	ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
595270631Sjfv	if (ret_code != I40E_SUCCESS) {
596270631Sjfv		ret_code = I40E_ERR_NVM_CHECKSUM;
597270631Sjfv		goto i40e_calc_nvm_checksum_exit;
598270631Sjfv	}
599270631Sjfv
600270631Sjfv	/* read pointer to PCIe Alt Auto-load module */
601270631Sjfv	ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
602291248Ssmh				      &pcie_alt_module);
603270631Sjfv	if (ret_code != I40E_SUCCESS) {
604270631Sjfv		ret_code = I40E_ERR_NVM_CHECKSUM;
605270631Sjfv		goto i40e_calc_nvm_checksum_exit;
606270631Sjfv	}
607270631Sjfv
608270631Sjfv	/* Calculate SW checksum that covers the whole 64kB shadow RAM
609270631Sjfv	 * except the VPD and PCIe ALT Auto-load modules
610270631Sjfv	 */
611270631Sjfv	for (i = 0; i < hw->nvm.sr_size; i++) {
612291248Ssmh		/* Read SR page */
613291248Ssmh		if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) {
614291248Ssmh			u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS;
615292100Ssmh
616291248Ssmh			ret_code = i40e_read_nvm_buffer(hw, i, &words, data);
617291248Ssmh			if (ret_code != I40E_SUCCESS) {
618291248Ssmh				ret_code = I40E_ERR_NVM_CHECKSUM;
619291248Ssmh				goto i40e_calc_nvm_checksum_exit;
620291248Ssmh			}
621291248Ssmh		}
622291248Ssmh
623270631Sjfv		/* Skip Checksum word */
624270631Sjfv		if (i == I40E_SR_SW_CHECKSUM_WORD)
625291248Ssmh			continue;
626270631Sjfv		/* Skip VPD module (convert byte size to word count) */
627291248Ssmh		if ((i >= (u32)vpd_module) &&
628291248Ssmh		    (i < ((u32)vpd_module +
629291248Ssmh		     (I40E_SR_VPD_MODULE_MAX_SIZE / 2)))) {
630291248Ssmh			continue;
631270631Sjfv		}
632270631Sjfv		/* Skip PCIe ALT module (convert byte size to word count) */
633291248Ssmh		if ((i >= (u32)pcie_alt_module) &&
634291248Ssmh		    (i < ((u32)pcie_alt_module +
635291248Ssmh		     (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2)))) {
636291248Ssmh			continue;
637270631Sjfv		}
638270631Sjfv
639291248Ssmh		checksum_local += data[i % I40E_SR_SECTOR_SIZE_IN_WORDS];
640270631Sjfv	}
641270631Sjfv
642270631Sjfv	*checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local;
643270631Sjfv
644270631Sjfvi40e_calc_nvm_checksum_exit:
645291248Ssmh	i40e_free_virt_mem(hw, &vmem);
646270631Sjfv	return ret_code;
647270631Sjfv}
648270631Sjfv
649270631Sjfv/**
650270631Sjfv * i40e_update_nvm_checksum - Updates the NVM checksum
651270631Sjfv * @hw: pointer to hardware structure
652270631Sjfv *
653270631Sjfv * NVM ownership must be acquired before calling this function and released
654270631Sjfv * on ARQ completion event reception by caller.
655270631Sjfv * This function will commit SR to NVM.
656270631Sjfv **/
657270631Sjfvenum i40e_status_code i40e_update_nvm_checksum(struct i40e_hw *hw)
658270631Sjfv{
659270631Sjfv	enum i40e_status_code ret_code = I40E_SUCCESS;
660270631Sjfv	u16 checksum;
661292100Ssmh	__le16 le_sum;
662270631Sjfv
663270631Sjfv	DEBUGFUNC("i40e_update_nvm_checksum");
664270631Sjfv
665270631Sjfv	ret_code = i40e_calc_nvm_checksum(hw, &checksum);
666292100Ssmh	le_sum = CPU_TO_LE16(checksum);
667270631Sjfv	if (ret_code == I40E_SUCCESS)
668270631Sjfv		ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD,
669292100Ssmh					     1, &le_sum, TRUE);
670270631Sjfv
671270631Sjfv	return ret_code;
672270631Sjfv}
673270631Sjfv
674270631Sjfv/**
675270631Sjfv * i40e_validate_nvm_checksum - Validate EEPROM checksum
676270631Sjfv * @hw: pointer to hardware structure
677270631Sjfv * @checksum: calculated checksum
678270631Sjfv *
679270631Sjfv * Performs checksum calculation and validates the NVM SW checksum. If the
680270631Sjfv * caller does not need checksum, the value can be NULL.
681270631Sjfv **/
682270631Sjfvenum i40e_status_code i40e_validate_nvm_checksum(struct i40e_hw *hw,
683270631Sjfv						 u16 *checksum)
684270631Sjfv{
685270631Sjfv	enum i40e_status_code ret_code = I40E_SUCCESS;
686270631Sjfv	u16 checksum_sr = 0;
687270631Sjfv	u16 checksum_local = 0;
688270631Sjfv
689270631Sjfv	DEBUGFUNC("i40e_validate_nvm_checksum");
690270631Sjfv
691270631Sjfv	ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
692270631Sjfv	if (ret_code != I40E_SUCCESS)
693270631Sjfv		goto i40e_validate_nvm_checksum_exit;
694270631Sjfv
695270631Sjfv	/* Do not use i40e_read_nvm_word() because we do not want to take
696270631Sjfv	 * the synchronization semaphores twice here.
697270631Sjfv	 */
698270631Sjfv	i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
699270631Sjfv
700270631Sjfv	/* Verify read checksum from EEPROM is the same as
701270631Sjfv	 * calculated checksum
702270631Sjfv	 */
703270631Sjfv	if (checksum_local != checksum_sr)
704270631Sjfv		ret_code = I40E_ERR_NVM_CHECKSUM;
705270631Sjfv
706270631Sjfv	/* If the user cares, return the calculated checksum */
707270631Sjfv	if (checksum)
708270631Sjfv		*checksum = checksum_local;
709270631Sjfv
710270631Sjfvi40e_validate_nvm_checksum_exit:
711270631Sjfv	return ret_code;
712270631Sjfv}
713