ixgbe/base: move phy sfp detection in a function
[dpdk.git] / lib / librte_pmd_i40e / i40e / i40e_nvm.c
1 /*******************************************************************************
2
3 Copyright (c) 2013 - 2014, 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 #ifdef I40E_NVMUPD_SUPPORT
482
483 STATIC enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw,
484                                                     struct i40e_nvm_access *cmd,
485                                                     u8 *bytes, int *errno);
486 STATIC enum i40e_status_code i40e_nvmupd_state_reading(struct i40e_hw *hw,
487                                                     struct i40e_nvm_access *cmd,
488                                                     u8 *bytes, int *errno);
489 STATIC enum i40e_status_code i40e_nvmupd_state_writing(struct i40e_hw *hw,
490                                                     struct i40e_nvm_access *cmd,
491                                                     u8 *bytes, int *errno);
492 STATIC enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
493                                                     struct i40e_nvm_access *cmd,
494                                                     int *errno);
495 STATIC enum i40e_status_code i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
496                                                    struct i40e_nvm_access *cmd,
497                                                    int *errno);
498 STATIC enum i40e_status_code i40e_nvmupd_nvm_write(struct i40e_hw *hw,
499                                                    struct i40e_nvm_access *cmd,
500                                                    u8 *bytes, int *errno);
501 STATIC enum i40e_status_code i40e_nvmupd_nvm_read(struct i40e_hw *hw,
502                                                   struct i40e_nvm_access *cmd,
503                                                   u8 *bytes, int *errno);
504 STATIC inline u8 i40e_nvmupd_get_module(u32 val)
505 {
506         return (u8)(val & I40E_NVM_MOD_PNT_MASK);
507 }
508 STATIC inline u8 i40e_nvmupd_get_transaction(u32 val)
509 {
510         return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT);
511 }
512
513 /**
514  * i40e_nvmupd_command - Process an NVM update command
515  * @hw: pointer to hardware structure
516  * @cmd: pointer to nvm update command
517  * @bytes: pointer to the data buffer
518  * @errno: pointer to return error code
519  *
520  * Dispatches command depending on what update state is current
521  **/
522 enum i40e_status_code i40e_nvmupd_command(struct i40e_hw *hw,
523                                           struct i40e_nvm_access *cmd,
524                                           u8 *bytes, int *errno)
525 {
526         enum i40e_status_code status;
527
528         DEBUGFUNC("i40e_nvmupd_command");
529
530         /* assume success */
531         *errno = 0;
532
533         switch (hw->nvmupd_state) {
534         case I40E_NVMUPD_STATE_INIT:
535                 status = i40e_nvmupd_state_init(hw, cmd, bytes, errno);
536                 break;
537
538         case I40E_NVMUPD_STATE_READING:
539                 status = i40e_nvmupd_state_reading(hw, cmd, bytes, errno);
540                 break;
541
542         case I40E_NVMUPD_STATE_WRITING:
543                 status = i40e_nvmupd_state_writing(hw, cmd, bytes, errno);
544                 break;
545
546         default:
547                 /* invalid state, should never happen */
548                 status = I40E_NOT_SUPPORTED;
549                 *errno = -ESRCH;
550                 break;
551         }
552         return status;
553 }
554
555 /**
556  * i40e_nvmupd_state_init - Handle NVM update state Init
557  * @hw: pointer to hardware structure
558  * @cmd: pointer to nvm update command buffer
559  * @bytes: pointer to the data buffer
560  * @errno: pointer to return error code
561  *
562  * Process legitimate commands of the Init state and conditionally set next
563  * state. Reject all other commands.
564  **/
565 STATIC enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw,
566                                                     struct i40e_nvm_access *cmd,
567                                                     u8 *bytes, int *errno)
568 {
569         enum i40e_status_code status = I40E_SUCCESS;
570         enum i40e_nvmupd_cmd upd_cmd;
571
572         DEBUGFUNC("i40e_nvmupd_state_init");
573
574         upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
575
576         switch (upd_cmd) {
577         case I40E_NVMUPD_READ_SA:
578                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
579                 if (status) {
580                         *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
581                 } else {
582                         status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
583                         i40e_release_nvm(hw);
584                 }
585                 break;
586
587         case I40E_NVMUPD_READ_SNT:
588                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
589                 if (status) {
590                         *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
591                 } else {
592                         status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
593                         hw->nvmupd_state = I40E_NVMUPD_STATE_READING;
594                 }
595                 break;
596
597         case I40E_NVMUPD_WRITE_ERA:
598                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
599                 if (status) {
600                         *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
601                 } else {
602                         status = i40e_nvmupd_nvm_erase(hw, cmd, errno);
603                         if (status)
604                                 i40e_release_nvm(hw);
605                         else
606                                 hw->aq.nvm_release_on_done = true;
607                 }
608                 break;
609
610         case I40E_NVMUPD_WRITE_SA:
611                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
612                 if (status) {
613                         *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
614                 } else {
615                         status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
616                         if (status)
617                                 i40e_release_nvm(hw);
618                         else
619                                 hw->aq.nvm_release_on_done = true;
620                 }
621                 break;
622
623         case I40E_NVMUPD_WRITE_SNT:
624                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
625                 if (status) {
626                         *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
627                 } else {
628                         status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
629                         hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING;
630                 }
631                 break;
632
633         case I40E_NVMUPD_CSUM_SA:
634                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
635                 if (status) {
636                         *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
637                 } else {
638                         status = i40e_update_nvm_checksum(hw);
639                         if (status) {
640                                 *errno = hw->aq.asq_last_status ?
641                                    i40e_aq_rc_to_posix(hw->aq.asq_last_status) :
642                                    -EIO;
643                                 i40e_release_nvm(hw);
644                         } else {
645                                 hw->aq.nvm_release_on_done = true;
646                         }
647                 }
648                 break;
649
650         default:
651                 status = I40E_ERR_NVM;
652                 *errno = -ESRCH;
653                 break;
654         }
655         return status;
656 }
657
658 /**
659  * i40e_nvmupd_state_reading - Handle NVM update state Reading
660  * @hw: pointer to hardware structure
661  * @cmd: pointer to nvm update command buffer
662  * @bytes: pointer to the data buffer
663  * @errno: pointer to return error code
664  *
665  * NVM ownership is already held.  Process legitimate commands and set any
666  * change in state; reject all other commands.
667  **/
668 STATIC enum i40e_status_code i40e_nvmupd_state_reading(struct i40e_hw *hw,
669                                                     struct i40e_nvm_access *cmd,
670                                                     u8 *bytes, int *errno)
671 {
672         enum i40e_status_code status;
673         enum i40e_nvmupd_cmd upd_cmd;
674
675         DEBUGFUNC("i40e_nvmupd_state_reading");
676
677         upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
678
679         switch (upd_cmd) {
680         case I40E_NVMUPD_READ_SA:
681         case I40E_NVMUPD_READ_CON:
682                 status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
683                 break;
684
685         case I40E_NVMUPD_READ_LCB:
686                 status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
687                 i40e_release_nvm(hw);
688                 hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
689                 break;
690
691         default:
692                 status = I40E_NOT_SUPPORTED;
693                 *errno = -ESRCH;
694                 break;
695         }
696         return status;
697 }
698
699 /**
700  * i40e_nvmupd_state_writing - Handle NVM update state Writing
701  * @hw: pointer to hardware structure
702  * @cmd: pointer to nvm update command buffer
703  * @bytes: pointer to the data buffer
704  * @errno: pointer to return error code
705  *
706  * NVM ownership is already held.  Process legitimate commands and set any
707  * change in state; reject all other commands
708  **/
709 STATIC enum i40e_status_code i40e_nvmupd_state_writing(struct i40e_hw *hw,
710                                                     struct i40e_nvm_access *cmd,
711                                                     u8 *bytes, int *errno)
712 {
713         enum i40e_status_code status;
714         enum i40e_nvmupd_cmd upd_cmd;
715
716         DEBUGFUNC("i40e_nvmupd_state_writing");
717
718         upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
719
720         switch (upd_cmd) {
721         case I40E_NVMUPD_WRITE_CON:
722                 status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
723                 break;
724
725         case I40E_NVMUPD_WRITE_LCB:
726                 status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
727                 if (!status) {
728                         hw->aq.nvm_release_on_done = true;
729                         hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
730                 }
731                 break;
732
733         case I40E_NVMUPD_CSUM_CON:
734                 status = i40e_update_nvm_checksum(hw);
735                 if (status)
736                         *errno = hw->aq.asq_last_status ?
737                                    i40e_aq_rc_to_posix(hw->aq.asq_last_status) :
738                                    -EIO;
739                 break;
740
741         case I40E_NVMUPD_CSUM_LCB:
742                 status = i40e_update_nvm_checksum(hw);
743                 if (status) {
744                         *errno = hw->aq.asq_last_status ?
745                                    i40e_aq_rc_to_posix(hw->aq.asq_last_status) :
746                                    -EIO;
747                 } else {
748                         hw->aq.nvm_release_on_done = true;
749                         hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
750                 }
751                 break;
752
753         default:
754                 status = I40E_NOT_SUPPORTED;
755                 *errno = -ESRCH;
756                 break;
757         }
758         return status;
759 }
760
761 /**
762  * i40e_nvmupd_validate_command - Validate given command
763  * @hw: pointer to hardware structure
764  * @cmd: pointer to nvm update command buffer
765  * @errno: pointer to return error code
766  *
767  * Return one of the valid command types or I40E_NVMUPD_INVALID
768  **/
769 STATIC enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
770                                                     struct i40e_nvm_access *cmd,
771                                                     int *errno)
772 {
773         enum i40e_nvmupd_cmd upd_cmd;
774         u8 transaction, module;
775
776         DEBUGFUNC("i40e_nvmupd_validate_command\n");
777
778         /* anything that doesn't match a recognized case is an error */
779         upd_cmd = I40E_NVMUPD_INVALID;
780
781         transaction = i40e_nvmupd_get_transaction(cmd->config);
782         module = i40e_nvmupd_get_module(cmd->config);
783
784         /* limits on data size */
785         if ((cmd->data_size < 1) ||
786             (cmd->data_size > I40E_NVMUPD_MAX_DATA)) {
787                 DEBUGOUT1("i40e_nvmupd_validate_command data_size %d\n",
788                         cmd->data_size);
789                 *errno = -EFAULT;
790                 return I40E_NVMUPD_INVALID;
791         }
792
793         switch (cmd->command) {
794         case I40E_NVM_READ:
795                 switch (transaction) {
796                 case I40E_NVM_CON:
797                         upd_cmd = I40E_NVMUPD_READ_CON;
798                         break;
799                 case I40E_NVM_SNT:
800                         upd_cmd = I40E_NVMUPD_READ_SNT;
801                         break;
802                 case I40E_NVM_LCB:
803                         upd_cmd = I40E_NVMUPD_READ_LCB;
804                         break;
805                 case I40E_NVM_SA:
806                         upd_cmd = I40E_NVMUPD_READ_SA;
807                         break;
808                 }
809                 break;
810
811         case I40E_NVM_WRITE:
812                 switch (transaction) {
813                 case I40E_NVM_CON:
814                         upd_cmd = I40E_NVMUPD_WRITE_CON;
815                         break;
816                 case I40E_NVM_SNT:
817                         upd_cmd = I40E_NVMUPD_WRITE_SNT;
818                         break;
819                 case I40E_NVM_LCB:
820                         upd_cmd = I40E_NVMUPD_WRITE_LCB;
821                         break;
822                 case I40E_NVM_SA:
823                         upd_cmd = I40E_NVMUPD_WRITE_SA;
824                         break;
825                 case I40E_NVM_ERA:
826                         upd_cmd = I40E_NVMUPD_WRITE_ERA;
827                         break;
828                 case I40E_NVM_CSUM:
829                         upd_cmd = I40E_NVMUPD_CSUM_CON;
830                         break;
831                 case (I40E_NVM_CSUM|I40E_NVM_SA):
832                         upd_cmd = I40E_NVMUPD_CSUM_SA;
833                         break;
834                 case (I40E_NVM_CSUM|I40E_NVM_LCB):
835                         upd_cmd = I40E_NVMUPD_CSUM_LCB;
836                         break;
837                 }
838                 break;
839         }
840
841         if (upd_cmd == I40E_NVMUPD_INVALID) {
842                 *errno = -EFAULT;
843                 DEBUGOUT2(
844                         "i40e_nvmupd_validate_command returns %d  errno: %d\n",
845                         upd_cmd, *errno);
846         }
847         return upd_cmd;
848 }
849
850 /**
851  * i40e_nvmupd_nvm_read - Read NVM
852  * @hw: pointer to hardware structure
853  * @cmd: pointer to nvm update command buffer
854  * @bytes: pointer to the data buffer
855  * @errno: pointer to return error code
856  *
857  * cmd structure contains identifiers and data buffer
858  **/
859 STATIC enum i40e_status_code i40e_nvmupd_nvm_read(struct i40e_hw *hw,
860                                                   struct i40e_nvm_access *cmd,
861                                                   u8 *bytes, int *errno)
862 {
863         enum i40e_status_code status;
864         u8 module, transaction;
865         bool last;
866
867         transaction = i40e_nvmupd_get_transaction(cmd->config);
868         module = i40e_nvmupd_get_module(cmd->config);
869         last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA);
870         DEBUGOUT3("i40e_nvmupd_nvm_read mod 0x%x  off 0x%x  len 0x%x\n",
871                 module, cmd->offset, cmd->data_size);
872
873         status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
874                                   bytes, last, NULL);
875         DEBUGOUT1("i40e_nvmupd_nvm_read status %d\n", status);
876         if (status != I40E_SUCCESS)
877                 *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
878
879         return status;
880 }
881
882 /**
883  * i40e_nvmupd_nvm_erase - Erase an NVM module
884  * @hw: pointer to hardware structure
885  * @cmd: pointer to nvm update command buffer
886  * @errno: pointer to return error code
887  *
888  * module, offset, data_size and data are in cmd structure
889  **/
890 STATIC enum i40e_status_code i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
891                                                    struct i40e_nvm_access *cmd,
892                                                    int *errno)
893 {
894         enum i40e_status_code status = I40E_SUCCESS;
895         u8 module, transaction;
896         bool last;
897
898         transaction = i40e_nvmupd_get_transaction(cmd->config);
899         module = i40e_nvmupd_get_module(cmd->config);
900         last = (transaction & I40E_NVM_LCB);
901         DEBUGOUT3("i40e_nvmupd_nvm_erase mod 0x%x  off 0x%x  len 0x%x\n",
902                 module, cmd->offset, cmd->data_size);
903         status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
904                                    last, NULL);
905         DEBUGOUT1("i40e_nvmupd_nvm_erase status %d\n", status);
906         if (status != I40E_SUCCESS)
907                 *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
908
909         return status;
910 }
911
912 /**
913  * i40e_nvmupd_nvm_write - Write NVM
914  * @hw: pointer to hardware structure
915  * @cmd: pointer to nvm update command buffer
916  * @bytes: pointer to the data buffer
917  * @errno: pointer to return error code
918  *
919  * module, offset, data_size and data are in cmd structure
920  **/
921 STATIC enum i40e_status_code i40e_nvmupd_nvm_write(struct i40e_hw *hw,
922                                                    struct i40e_nvm_access *cmd,
923                                                    u8 *bytes, int *errno)
924 {
925         enum i40e_status_code status = I40E_SUCCESS;
926         u8 module, transaction;
927         bool last;
928
929         transaction = i40e_nvmupd_get_transaction(cmd->config);
930         module = i40e_nvmupd_get_module(cmd->config);
931         last = (transaction & I40E_NVM_LCB);
932         DEBUGOUT3("i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n",
933                   module, cmd->offset, cmd->data_size);
934         status = i40e_aq_update_nvm(hw, module, cmd->offset,
935                                     (u16)cmd->data_size, bytes, last, NULL);
936         DEBUGOUT1("i40e_nvmupd_nvm_write status %d\n", status);
937         if (status != I40E_SUCCESS)
938                 *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
939
940         return status;
941 }
942 #endif