[go: nahoru, domu]

1/*******************************************************************************
2 *
3 * Intel Ethernet Controller XL710 Family Linux Driver
4 * Copyright(c) 2013 - 2014 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
20 *
21 * Contact Information:
22 * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24 *
25 ******************************************************************************/
26
27#include "i40e_prototype.h"
28
29/**
30 * i40e_init_nvm_ops - Initialize NVM function pointers
31 * @hw: pointer to the HW structure
32 *
33 * Setup the function pointers and the NVM info structure. Should be called
34 * once per NVM initialization, e.g. inside the i40e_init_shared_code().
35 * Please notice that the NVM term is used here (& in all methods covered
36 * in this file) as an equivalent of the FLASH part mapped into the SR.
37 * We are accessing FLASH always thru the Shadow RAM.
38 **/
39i40e_status i40e_init_nvm(struct i40e_hw *hw)
40{
41	struct i40e_nvm_info *nvm = &hw->nvm;
42	i40e_status ret_code = 0;
43	u32 fla, gens;
44	u8 sr_size;
45
46	/* The SR size is stored regardless of the nvm programming mode
47	 * as the blank mode may be used in the factory line.
48	 */
49	gens = rd32(hw, I40E_GLNVM_GENS);
50	sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
51			   I40E_GLNVM_GENS_SR_SIZE_SHIFT);
52	/* Switching to words (sr_size contains power of 2KB) */
53	nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB;
54
55	/* Check if we are in the normal or blank NVM programming mode */
56	fla = rd32(hw, I40E_GLNVM_FLA);
57	if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
58		/* Max NVM timeout */
59		nvm->timeout = I40E_MAX_NVM_TIMEOUT;
60		nvm->blank_nvm_mode = false;
61	} else { /* Blank programming mode */
62		nvm->blank_nvm_mode = true;
63		ret_code = I40E_ERR_NVM_BLANK_MODE;
64		hw_dbg(hw, "NVM init error: unsupported blank mode.\n");
65	}
66
67	return ret_code;
68}
69
70/**
71 * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
72 * @hw: pointer to the HW structure
73 * @access: NVM access type (read or write)
74 *
75 * This function will request NVM ownership for reading
76 * via the proper Admin Command.
77 **/
78i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
79				       enum i40e_aq_resource_access_type access)
80{
81	i40e_status ret_code = 0;
82	u64 gtime, timeout;
83	u64 time = 0;
84
85	if (hw->nvm.blank_nvm_mode)
86		goto i40e_i40e_acquire_nvm_exit;
87
88	ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
89					    0, &time, NULL);
90	/* Reading the Global Device Timer */
91	gtime = rd32(hw, I40E_GLVFGEN_TIMER);
92
93	/* Store the timeout */
94	hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time) + gtime;
95
96	if (ret_code) {
97		/* Set the polling timeout */
98		if (time > I40E_MAX_NVM_TIMEOUT)
99			timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT)
100				  + gtime;
101		else
102			timeout = hw->nvm.hw_semaphore_timeout;
103		/* Poll until the current NVM owner timeouts */
104		while (gtime < timeout) {
105			usleep_range(10000, 20000);
106			ret_code = i40e_aq_request_resource(hw,
107							I40E_NVM_RESOURCE_ID,
108							access, 0, &time,
109							NULL);
110			if (!ret_code) {
111				hw->nvm.hw_semaphore_timeout =
112						I40E_MS_TO_GTIME(time) + gtime;
113				break;
114			}
115			gtime = rd32(hw, I40E_GLVFGEN_TIMER);
116		}
117		if (ret_code) {
118			hw->nvm.hw_semaphore_timeout = 0;
119			hw->nvm.hw_semaphore_wait =
120						I40E_MS_TO_GTIME(time) + gtime;
121			hw_dbg(hw, "NVM acquire timed out, wait %llu ms before trying again.\n",
122				  time);
123		}
124	}
125
126i40e_i40e_acquire_nvm_exit:
127	return ret_code;
128}
129
130/**
131 * i40e_release_nvm - Generic request for releasing the NVM ownership
132 * @hw: pointer to the HW structure
133 *
134 * This function will release NVM resource via the proper Admin Command.
135 **/
136void i40e_release_nvm(struct i40e_hw *hw)
137{
138	if (!hw->nvm.blank_nvm_mode)
139		i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
140}
141
142/**
143 * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
144 * @hw: pointer to the HW structure
145 *
146 * Polls the SRCTL Shadow RAM register done bit.
147 **/
148static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
149{
150	i40e_status ret_code = I40E_ERR_TIMEOUT;
151	u32 srctl, wait_cnt;
152
153	/* Poll the I40E_GLNVM_SRCTL until the done bit is set */
154	for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
155		srctl = rd32(hw, I40E_GLNVM_SRCTL);
156		if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
157			ret_code = 0;
158			break;
159		}
160		udelay(5);
161	}
162	if (ret_code == I40E_ERR_TIMEOUT)
163		hw_dbg(hw, "Done bit in GLNVM_SRCTL not set\n");
164	return ret_code;
165}
166
167/**
168 * i40e_read_nvm_word - Reads Shadow RAM
169 * @hw: pointer to the HW structure
170 * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
171 * @data: word read from the Shadow RAM
172 *
173 * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
174 **/
175i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
176					 u16 *data)
177{
178	i40e_status ret_code = I40E_ERR_TIMEOUT;
179	u32 sr_reg;
180
181	if (offset >= hw->nvm.sr_size) {
182		hw_dbg(hw, "NVM read error: Offset beyond Shadow RAM limit.\n");
183		ret_code = I40E_ERR_PARAM;
184		goto read_nvm_exit;
185	}
186
187	/* Poll the done bit first */
188	ret_code = i40e_poll_sr_srctl_done_bit(hw);
189	if (!ret_code) {
190		/* Write the address and start reading */
191		sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
192			 (1 << I40E_GLNVM_SRCTL_START_SHIFT);
193		wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
194
195		/* Poll I40E_GLNVM_SRCTL until the done bit is set */
196		ret_code = i40e_poll_sr_srctl_done_bit(hw);
197		if (!ret_code) {
198			sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
199			*data = (u16)((sr_reg &
200				       I40E_GLNVM_SRDATA_RDDATA_MASK)
201				    >> I40E_GLNVM_SRDATA_RDDATA_SHIFT);
202		}
203	}
204	if (ret_code)
205		hw_dbg(hw, "NVM read error: Couldn't access Shadow RAM address: 0x%x\n",
206			  offset);
207
208read_nvm_exit:
209	return ret_code;
210}
211
212/**
213 * i40e_read_nvm_buffer - Reads Shadow RAM buffer
214 * @hw: pointer to the HW structure
215 * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
216 * @words: (in) number of words to read; (out) number of words actually read
217 * @data: words read from the Shadow RAM
218 *
219 * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
220 * method. The buffer read is preceded by the NVM ownership take
221 * and followed by the release.
222 **/
223i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
224					   u16 *words, u16 *data)
225{
226	i40e_status ret_code = 0;
227	u16 index, word;
228
229	/* Loop thru the selected region */
230	for (word = 0; word < *words; word++) {
231		index = offset + word;
232		ret_code = i40e_read_nvm_word(hw, index, &data[word]);
233		if (ret_code)
234			break;
235	}
236
237	/* Update the number of words read from the Shadow RAM */
238	*words = word;
239
240	return ret_code;
241}
242
243/**
244 * i40e_write_nvm_aq - Writes Shadow RAM.
245 * @hw: pointer to the HW structure.
246 * @module_pointer: module pointer location in words from the NVM beginning
247 * @offset: offset in words from module start
248 * @words: number of words to write
249 * @data: buffer with words to write to the Shadow RAM
250 * @last_command: tells the AdminQ that this is the last command
251 *
252 * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
253 **/
254static i40e_status i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
255				     u32 offset, u16 words, void *data,
256				     bool last_command)
257{
258	i40e_status ret_code = I40E_ERR_NVM;
259
260	/* Here we are checking the SR limit only for the flat memory model.
261	 * We cannot do it for the module-based model, as we did not acquire
262	 * the NVM resource yet (we cannot get the module pointer value).
263	 * Firmware will check the module-based model.
264	 */
265	if ((offset + words) > hw->nvm.sr_size)
266		hw_dbg(hw, "NVM write error: offset beyond Shadow RAM limit.\n");
267	else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
268		/* We can write only up to 4KB (one sector), in one AQ write */
269		hw_dbg(hw, "NVM write fail error: cannot write more than 4KB in a single write.\n");
270	else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
271		 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
272		/* A single write cannot spread over two sectors */
273		hw_dbg(hw, "NVM write error: cannot spread over two sectors in a single write.\n");
274	else
275		ret_code = i40e_aq_update_nvm(hw, module_pointer,
276					      2 * offset,  /*bytes*/
277					      2 * words,   /*bytes*/
278					      data, last_command, NULL);
279
280	return ret_code;
281}
282
283/**
284 * i40e_calc_nvm_checksum - Calculates and returns the checksum
285 * @hw: pointer to hardware structure
286 * @checksum: pointer to the checksum
287 *
288 * This function calculates SW Checksum that covers the whole 64kB shadow RAM
289 * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
290 * is customer specific and unknown. Therefore, this function skips all maximum
291 * possible size of VPD (1kB).
292 **/
293static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw,
294						    u16 *checksum)
295{
296	i40e_status ret_code = 0;
297	u16 pcie_alt_module = 0;
298	u16 checksum_local = 0;
299	u16 vpd_module = 0;
300	u16 word = 0;
301	u32 i = 0;
302
303	/* read pointer to VPD area */
304	ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
305	if (ret_code) {
306		ret_code = I40E_ERR_NVM_CHECKSUM;
307		goto i40e_calc_nvm_checksum_exit;
308	}
309
310	/* read pointer to PCIe Alt Auto-load module */
311	ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
312				       &pcie_alt_module);
313	if (ret_code) {
314		ret_code = I40E_ERR_NVM_CHECKSUM;
315		goto i40e_calc_nvm_checksum_exit;
316	}
317
318	/* Calculate SW checksum that covers the whole 64kB shadow RAM
319	 * except the VPD and PCIe ALT Auto-load modules
320	 */
321	for (i = 0; i < hw->nvm.sr_size; i++) {
322		/* Skip Checksum word */
323		if (i == I40E_SR_SW_CHECKSUM_WORD)
324			i++;
325		/* Skip VPD module (convert byte size to word count) */
326		if (i == (u32)vpd_module) {
327			i += (I40E_SR_VPD_MODULE_MAX_SIZE / 2);
328			if (i >= hw->nvm.sr_size)
329				break;
330		}
331		/* Skip PCIe ALT module (convert byte size to word count) */
332		if (i == (u32)pcie_alt_module) {
333			i += (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2);
334			if (i >= hw->nvm.sr_size)
335				break;
336		}
337
338		ret_code = i40e_read_nvm_word(hw, (u16)i, &word);
339		if (ret_code) {
340			ret_code = I40E_ERR_NVM_CHECKSUM;
341			goto i40e_calc_nvm_checksum_exit;
342		}
343		checksum_local += word;
344	}
345
346	*checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local;
347
348i40e_calc_nvm_checksum_exit:
349	return ret_code;
350}
351
352/**
353 * i40e_update_nvm_checksum - Updates the NVM checksum
354 * @hw: pointer to hardware structure
355 *
356 * NVM ownership must be acquired before calling this function and released
357 * on ARQ completion event reception by caller.
358 * This function will commit SR to NVM.
359 **/
360i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw)
361{
362	i40e_status ret_code = 0;
363	u16 checksum;
364
365	ret_code = i40e_calc_nvm_checksum(hw, &checksum);
366	if (!ret_code)
367		ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD,
368					     1, &checksum, true);
369
370	return ret_code;
371}
372
373/**
374 * i40e_validate_nvm_checksum - Validate EEPROM checksum
375 * @hw: pointer to hardware structure
376 * @checksum: calculated checksum
377 *
378 * Performs checksum calculation and validates the NVM SW checksum. If the
379 * caller does not need checksum, the value can be NULL.
380 **/
381i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
382						 u16 *checksum)
383{
384	i40e_status ret_code = 0;
385	u16 checksum_sr = 0;
386	u16 checksum_local = 0;
387
388	ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
389	if (ret_code)
390		goto i40e_validate_nvm_checksum_exit;
391
392	/* Do not use i40e_read_nvm_word() because we do not want to take
393	 * the synchronization semaphores twice here.
394	 */
395	i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
396
397	/* Verify read checksum from EEPROM is the same as
398	 * calculated checksum
399	 */
400	if (checksum_local != checksum_sr)
401		ret_code = I40E_ERR_NVM_CHECKSUM;
402
403	/* If the user cares, return the calculated checksum */
404	if (checksum)
405		*checksum = checksum_local;
406
407i40e_validate_nvm_checksum_exit:
408	return ret_code;
409}
410
411static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw,
412					  struct i40e_nvm_access *cmd,
413					  u8 *bytes, int *errno);
414static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw,
415					     struct i40e_nvm_access *cmd,
416					     u8 *bytes, int *errno);
417static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,
418					     struct i40e_nvm_access *cmd,
419					     u8 *bytes, int *errno);
420static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
421						struct i40e_nvm_access *cmd,
422						int *errno);
423static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
424					 struct i40e_nvm_access *cmd,
425					 int *errno);
426static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw,
427					 struct i40e_nvm_access *cmd,
428					 u8 *bytes, int *errno);
429static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw,
430					struct i40e_nvm_access *cmd,
431					u8 *bytes, int *errno);
432static inline u8 i40e_nvmupd_get_module(u32 val)
433{
434	return (u8)(val & I40E_NVM_MOD_PNT_MASK);
435}
436static inline u8 i40e_nvmupd_get_transaction(u32 val)
437{
438	return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT);
439}
440
441/**
442 * i40e_nvmupd_command - Process an NVM update command
443 * @hw: pointer to hardware structure
444 * @cmd: pointer to nvm update command
445 * @bytes: pointer to the data buffer
446 * @errno: pointer to return error code
447 *
448 * Dispatches command depending on what update state is current
449 **/
450i40e_status i40e_nvmupd_command(struct i40e_hw *hw,
451				struct i40e_nvm_access *cmd,
452				u8 *bytes, int *errno)
453{
454	i40e_status status;
455
456	/* assume success */
457	*errno = 0;
458
459	switch (hw->nvmupd_state) {
460	case I40E_NVMUPD_STATE_INIT:
461		status = i40e_nvmupd_state_init(hw, cmd, bytes, errno);
462		break;
463
464	case I40E_NVMUPD_STATE_READING:
465		status = i40e_nvmupd_state_reading(hw, cmd, bytes, errno);
466		break;
467
468	case I40E_NVMUPD_STATE_WRITING:
469		status = i40e_nvmupd_state_writing(hw, cmd, bytes, errno);
470		break;
471
472	default:
473		/* invalid state, should never happen */
474		status = I40E_NOT_SUPPORTED;
475		*errno = -ESRCH;
476		break;
477	}
478	return status;
479}
480
481/**
482 * i40e_nvmupd_state_init - Handle NVM update state Init
483 * @hw: pointer to hardware structure
484 * @cmd: pointer to nvm update command buffer
485 * @bytes: pointer to the data buffer
486 * @errno: pointer to return error code
487 *
488 * Process legitimate commands of the Init state and conditionally set next
489 * state. Reject all other commands.
490 **/
491static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw,
492					  struct i40e_nvm_access *cmd,
493					  u8 *bytes, int *errno)
494{
495	i40e_status status = 0;
496	enum i40e_nvmupd_cmd upd_cmd;
497
498	upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
499
500	switch (upd_cmd) {
501	case I40E_NVMUPD_READ_SA:
502		status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
503		if (status) {
504			*errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
505		} else {
506			status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
507			i40e_release_nvm(hw);
508		}
509		break;
510
511	case I40E_NVMUPD_READ_SNT:
512		status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
513		if (status) {
514			*errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
515		} else {
516			status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
517			hw->nvmupd_state = I40E_NVMUPD_STATE_READING;
518		}
519		break;
520
521	case I40E_NVMUPD_WRITE_ERA:
522		status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
523		if (status) {
524			*errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
525		} else {
526			status = i40e_nvmupd_nvm_erase(hw, cmd, errno);
527			if (status)
528				i40e_release_nvm(hw);
529			else
530				hw->aq.nvm_release_on_done = true;
531		}
532		break;
533
534	case I40E_NVMUPD_WRITE_SA:
535		status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
536		if (status) {
537			*errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
538		} else {
539			status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
540			if (status)
541				i40e_release_nvm(hw);
542			else
543				hw->aq.nvm_release_on_done = true;
544		}
545		break;
546
547	case I40E_NVMUPD_WRITE_SNT:
548		status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
549		if (status) {
550			*errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
551		} else {
552			status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
553			hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING;
554		}
555		break;
556
557	case I40E_NVMUPD_CSUM_SA:
558		status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
559		if (status) {
560			*errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
561		} else {
562			status = i40e_update_nvm_checksum(hw);
563			if (status) {
564				*errno = hw->aq.asq_last_status ?
565				   i40e_aq_rc_to_posix(hw->aq.asq_last_status) :
566				   -EIO;
567				i40e_release_nvm(hw);
568			} else {
569				hw->aq.nvm_release_on_done = true;
570			}
571		}
572		break;
573
574	default:
575		status = I40E_ERR_NVM;
576		*errno = -ESRCH;
577		break;
578	}
579	return status;
580}
581
582/**
583 * i40e_nvmupd_state_reading - Handle NVM update state Reading
584 * @hw: pointer to hardware structure
585 * @cmd: pointer to nvm update command buffer
586 * @bytes: pointer to the data buffer
587 * @errno: pointer to return error code
588 *
589 * NVM ownership is already held.  Process legitimate commands and set any
590 * change in state; reject all other commands.
591 **/
592static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw,
593					     struct i40e_nvm_access *cmd,
594					     u8 *bytes, int *errno)
595{
596	i40e_status status;
597	enum i40e_nvmupd_cmd upd_cmd;
598
599	upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
600
601	switch (upd_cmd) {
602	case I40E_NVMUPD_READ_SA:
603	case I40E_NVMUPD_READ_CON:
604		status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
605		break;
606
607	case I40E_NVMUPD_READ_LCB:
608		status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
609		i40e_release_nvm(hw);
610		hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
611		break;
612
613	default:
614		status = I40E_NOT_SUPPORTED;
615		*errno = -ESRCH;
616		break;
617	}
618	return status;
619}
620
621/**
622 * i40e_nvmupd_state_writing - Handle NVM update state Writing
623 * @hw: pointer to hardware structure
624 * @cmd: pointer to nvm update command buffer
625 * @bytes: pointer to the data buffer
626 * @errno: pointer to return error code
627 *
628 * NVM ownership is already held.  Process legitimate commands and set any
629 * change in state; reject all other commands
630 **/
631static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,
632					     struct i40e_nvm_access *cmd,
633					     u8 *bytes, int *errno)
634{
635	i40e_status status;
636	enum i40e_nvmupd_cmd upd_cmd;
637
638	upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
639
640	switch (upd_cmd) {
641	case I40E_NVMUPD_WRITE_CON:
642		status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
643		break;
644
645	case I40E_NVMUPD_WRITE_LCB:
646		status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
647		if (!status) {
648			hw->aq.nvm_release_on_done = true;
649			hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
650		}
651		break;
652
653	case I40E_NVMUPD_CSUM_CON:
654		status = i40e_update_nvm_checksum(hw);
655		if (status)
656			*errno = hw->aq.asq_last_status ?
657				   i40e_aq_rc_to_posix(hw->aq.asq_last_status) :
658				   -EIO;
659		break;
660
661	case I40E_NVMUPD_CSUM_LCB:
662		status = i40e_update_nvm_checksum(hw);
663		if (status) {
664			*errno = hw->aq.asq_last_status ?
665				   i40e_aq_rc_to_posix(hw->aq.asq_last_status) :
666				   -EIO;
667		} else {
668			hw->aq.nvm_release_on_done = true;
669			hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
670		}
671		break;
672
673	default:
674		status = I40E_NOT_SUPPORTED;
675		*errno = -ESRCH;
676		break;
677	}
678	return status;
679}
680
681/**
682 * i40e_nvmupd_validate_command - Validate given command
683 * @hw: pointer to hardware structure
684 * @cmd: pointer to nvm update command buffer
685 * @errno: pointer to return error code
686 *
687 * Return one of the valid command types or I40E_NVMUPD_INVALID
688 **/
689static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
690						 struct i40e_nvm_access *cmd,
691						 int *errno)
692{
693	enum i40e_nvmupd_cmd upd_cmd;
694	u8 transaction, module;
695
696	/* anything that doesn't match a recognized case is an error */
697	upd_cmd = I40E_NVMUPD_INVALID;
698
699	transaction = i40e_nvmupd_get_transaction(cmd->config);
700	module = i40e_nvmupd_get_module(cmd->config);
701
702	/* limits on data size */
703	if ((cmd->data_size < 1) ||
704	    (cmd->data_size > I40E_NVMUPD_MAX_DATA)) {
705		hw_dbg(hw, "i40e_nvmupd_validate_command data_size %d\n",
706		       cmd->data_size);
707		*errno = -EFAULT;
708		return I40E_NVMUPD_INVALID;
709	}
710
711	switch (cmd->command) {
712	case I40E_NVM_READ:
713		switch (transaction) {
714		case I40E_NVM_CON:
715			upd_cmd = I40E_NVMUPD_READ_CON;
716			break;
717		case I40E_NVM_SNT:
718			upd_cmd = I40E_NVMUPD_READ_SNT;
719			break;
720		case I40E_NVM_LCB:
721			upd_cmd = I40E_NVMUPD_READ_LCB;
722			break;
723		case I40E_NVM_SA:
724			upd_cmd = I40E_NVMUPD_READ_SA;
725			break;
726		}
727		break;
728
729	case I40E_NVM_WRITE:
730		switch (transaction) {
731		case I40E_NVM_CON:
732			upd_cmd = I40E_NVMUPD_WRITE_CON;
733			break;
734		case I40E_NVM_SNT:
735			upd_cmd = I40E_NVMUPD_WRITE_SNT;
736			break;
737		case I40E_NVM_LCB:
738			upd_cmd = I40E_NVMUPD_WRITE_LCB;
739			break;
740		case I40E_NVM_SA:
741			upd_cmd = I40E_NVMUPD_WRITE_SA;
742			break;
743		case I40E_NVM_ERA:
744			upd_cmd = I40E_NVMUPD_WRITE_ERA;
745			break;
746		case I40E_NVM_CSUM:
747			upd_cmd = I40E_NVMUPD_CSUM_CON;
748			break;
749		case (I40E_NVM_CSUM|I40E_NVM_SA):
750			upd_cmd = I40E_NVMUPD_CSUM_SA;
751			break;
752		case (I40E_NVM_CSUM|I40E_NVM_LCB):
753			upd_cmd = I40E_NVMUPD_CSUM_LCB;
754			break;
755		}
756		break;
757	}
758
759	if (upd_cmd == I40E_NVMUPD_INVALID) {
760		*errno = -EFAULT;
761		hw_dbg(hw,
762		       "i40e_nvmupd_validate_command returns %d  errno: %d\n",
763		       upd_cmd, *errno);
764	}
765	return upd_cmd;
766}
767
768/**
769 * i40e_nvmupd_nvm_read - Read NVM
770 * @hw: pointer to hardware structure
771 * @cmd: pointer to nvm update command buffer
772 * @bytes: pointer to the data buffer
773 * @errno: pointer to return error code
774 *
775 * cmd structure contains identifiers and data buffer
776 **/
777static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw,
778					struct i40e_nvm_access *cmd,
779					u8 *bytes, int *errno)
780{
781	i40e_status status;
782	u8 module, transaction;
783	bool last;
784
785	transaction = i40e_nvmupd_get_transaction(cmd->config);
786	module = i40e_nvmupd_get_module(cmd->config);
787	last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA);
788	hw_dbg(hw, "i40e_nvmupd_nvm_read mod 0x%x  off 0x%x  len 0x%x\n",
789	       module, cmd->offset, cmd->data_size);
790
791	status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
792				  bytes, last, NULL);
793	hw_dbg(hw, "i40e_nvmupd_nvm_read status %d\n", status);
794	if (status)
795		*errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
796
797	return status;
798}
799
800/**
801 * i40e_nvmupd_nvm_erase - Erase an NVM module
802 * @hw: pointer to hardware structure
803 * @cmd: pointer to nvm update command buffer
804 * @errno: pointer to return error code
805 *
806 * module, offset, data_size and data are in cmd structure
807 **/
808static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
809					 struct i40e_nvm_access *cmd,
810					 int *errno)
811{
812	i40e_status status = 0;
813	u8 module, transaction;
814	bool last;
815
816	transaction = i40e_nvmupd_get_transaction(cmd->config);
817	module = i40e_nvmupd_get_module(cmd->config);
818	last = (transaction & I40E_NVM_LCB);
819	hw_dbg(hw, "i40e_nvmupd_nvm_erase mod 0x%x  off 0x%x  len 0x%x\n",
820	       module, cmd->offset, cmd->data_size);
821	status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
822				   last, NULL);
823	hw_dbg(hw, "i40e_nvmupd_nvm_erase status %d\n", status);
824	if (status)
825		*errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
826
827	return status;
828}
829
830/**
831 * i40e_nvmupd_nvm_write - Write NVM
832 * @hw: pointer to hardware structure
833 * @cmd: pointer to nvm update command buffer
834 * @bytes: pointer to the data buffer
835 * @errno: pointer to return error code
836 *
837 * module, offset, data_size and data are in cmd structure
838 **/
839static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw,
840					 struct i40e_nvm_access *cmd,
841					 u8 *bytes, int *errno)
842{
843	i40e_status status = 0;
844	u8 module, transaction;
845	bool last;
846
847	transaction = i40e_nvmupd_get_transaction(cmd->config);
848	module = i40e_nvmupd_get_module(cmd->config);
849	last = (transaction & I40E_NVM_LCB);
850	hw_dbg(hw, "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n",
851	       module, cmd->offset, cmd->data_size);
852	status = i40e_aq_update_nvm(hw, module, cmd->offset,
853				    (u16)cmd->data_size, bytes, last, NULL);
854	hw_dbg(hw, "i40e_nvmupd_nvm_write status %d\n", status);
855	if (status)
856		*errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
857
858	return status;
859}
860