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