The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ixl/i40e_nvm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /******************************************************************************
    2 
    3   Copyright (c) 2013-2018, 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 /*$FreeBSD$*/
   34 
   35 #include "i40e_prototype.h"
   36 
   37 /**
   38  * i40e_init_nvm - Initialize NVM function pointers
   39  * @hw: pointer to the HW structure
   40  *
   41  * Setup the function pointers and the NVM info structure. Should be called
   42  * once per NVM initialization, e.g. inside the i40e_init_shared_code().
   43  * Please notice that the NVM term is used here (& in all methods covered
   44  * in this file) as an equivalent of the FLASH part mapped into the SR.
   45  * We are accessing FLASH always through the Shadow RAM.
   46  **/
   47 enum i40e_status_code i40e_init_nvm(struct i40e_hw *hw)
   48 {
   49         struct i40e_nvm_info *nvm = &hw->nvm;
   50         enum i40e_status_code ret_code = I40E_SUCCESS;
   51         u32 fla, gens;
   52         u8 sr_size;
   53 
   54         DEBUGFUNC("i40e_init_nvm");
   55 
   56         /* The SR size is stored regardless of the nvm programming mode
   57          * as the blank mode may be used in the factory line.
   58          */
   59         gens = rd32(hw, I40E_GLNVM_GENS);
   60         sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
   61                            I40E_GLNVM_GENS_SR_SIZE_SHIFT);
   62         /* Switching to words (sr_size contains power of 2KB) */
   63         nvm->sr_size = BIT(sr_size) * I40E_SR_WORDS_IN_1KB;
   64 
   65         /* Check if we are in the normal or blank NVM programming mode */
   66         fla = rd32(hw, I40E_GLNVM_FLA);
   67         if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
   68                 /* Max NVM timeout */
   69                 nvm->timeout = I40E_MAX_NVM_TIMEOUT;
   70                 nvm->blank_nvm_mode = FALSE;
   71         } else { /* Blank programming mode */
   72                 nvm->blank_nvm_mode = TRUE;
   73                 ret_code = I40E_ERR_NVM_BLANK_MODE;
   74                 i40e_debug(hw, I40E_DEBUG_NVM, "NVM init error: unsupported blank mode.\n");
   75         }
   76 
   77         return ret_code;
   78 }
   79 
   80 /**
   81  * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
   82  * @hw: pointer to the HW structure
   83  * @access: NVM access type (read or write)
   84  *
   85  * This function will request NVM ownership for reading
   86  * via the proper Admin Command.
   87  **/
   88 enum i40e_status_code i40e_acquire_nvm(struct i40e_hw *hw,
   89                                        enum i40e_aq_resource_access_type access)
   90 {
   91         enum i40e_status_code ret_code = I40E_SUCCESS;
   92         u64 gtime, timeout;
   93         u64 time_left = 0;
   94 
   95         DEBUGFUNC("i40e_acquire_nvm");
   96 
   97         if (hw->nvm.blank_nvm_mode)
   98                 goto i40e_i40e_acquire_nvm_exit;
   99 
  100         ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
  101                                             0, &time_left, NULL);
  102         /* Reading the Global Device Timer */
  103         gtime = rd32(hw, I40E_GLVFGEN_TIMER);
  104 
  105         /* Store the timeout */
  106         hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime;
  107 
  108         if (ret_code)
  109                 i40e_debug(hw, I40E_DEBUG_NVM,
  110                            "NVM acquire type %d failed time_left=%llu ret=%d aq_err=%d\n",
  111                            access, (unsigned long long)time_left, ret_code,
  112                            hw->aq.asq_last_status);
  113 
  114         if (ret_code && time_left) {
  115                 /* Poll until the current NVM owner timeouts */
  116                 timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime;
  117                 while ((gtime < timeout) && time_left) {
  118                         i40e_msec_delay(10);
  119                         gtime = rd32(hw, I40E_GLVFGEN_TIMER);
  120                         ret_code = i40e_aq_request_resource(hw,
  121                                                         I40E_NVM_RESOURCE_ID,
  122                                                         access, 0, &time_left,
  123                                                         NULL);
  124                         if (ret_code == I40E_SUCCESS) {
  125                                 hw->nvm.hw_semaphore_timeout =
  126                                             I40E_MS_TO_GTIME(time_left) + gtime;
  127                                 break;
  128                         }
  129                 }
  130                 if (ret_code != I40E_SUCCESS) {
  131                         hw->nvm.hw_semaphore_timeout = 0;
  132                         i40e_debug(hw, I40E_DEBUG_NVM,
  133                                    "NVM acquire timed out, wait %llu ms before trying again. status=%d aq_err=%d\n",
  134                                    (unsigned long long)time_left, ret_code,
  135                                    hw->aq.asq_last_status);
  136                 }
  137         }
  138 
  139 i40e_i40e_acquire_nvm_exit:
  140         return ret_code;
  141 }
  142 
  143 /**
  144  * i40e_release_nvm - Generic request for releasing the NVM ownership
  145  * @hw: pointer to the HW structure
  146  *
  147  * This function will release NVM resource via the proper Admin Command.
  148  **/
  149 void i40e_release_nvm(struct i40e_hw *hw)
  150 {
  151         enum i40e_status_code ret_code = I40E_SUCCESS;
  152         u32 total_delay = 0;
  153 
  154         DEBUGFUNC("i40e_release_nvm");
  155 
  156         if (hw->nvm.blank_nvm_mode)
  157                 return;
  158 
  159         ret_code = i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
  160 
  161         /* there are some rare cases when trying to release the resource
  162          * results in an admin Q timeout, so handle them correctly
  163          */
  164         while ((ret_code == I40E_ERR_ADMIN_QUEUE_TIMEOUT) &&
  165                (total_delay < hw->aq.asq_cmd_timeout)) {
  166                         i40e_msec_delay(1);
  167                         ret_code = i40e_aq_release_resource(hw,
  168                                                 I40E_NVM_RESOURCE_ID, 0, NULL);
  169                         total_delay++;
  170         }
  171 }
  172 
  173 /**
  174  * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
  175  * @hw: pointer to the HW structure
  176  *
  177  * Polls the SRCTL Shadow RAM register done bit.
  178  **/
  179 static enum i40e_status_code i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
  180 {
  181         enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
  182         u32 srctl, wait_cnt;
  183 
  184         DEBUGFUNC("i40e_poll_sr_srctl_done_bit");
  185 
  186         /* Poll the I40E_GLNVM_SRCTL until the done bit is set */
  187         for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
  188                 srctl = rd32(hw, I40E_GLNVM_SRCTL);
  189                 if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
  190                         ret_code = I40E_SUCCESS;
  191                         break;
  192                 }
  193                 i40e_usec_delay(5);
  194         }
  195         if (ret_code == I40E_ERR_TIMEOUT)
  196                 i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set");
  197         return ret_code;
  198 }
  199 
  200 /**
  201  * i40e_read_nvm_word_srctl - Reads Shadow RAM via SRCTL register
  202  * @hw: pointer to the HW structure
  203  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
  204  * @data: word read from the Shadow RAM
  205  *
  206  * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
  207  **/
  208 enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset,
  209                                                u16 *data)
  210 {
  211         enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
  212         u32 sr_reg;
  213 
  214         DEBUGFUNC("i40e_read_nvm_word_srctl");
  215 
  216         if (offset >= hw->nvm.sr_size) {
  217                 i40e_debug(hw, I40E_DEBUG_NVM,
  218                            "NVM read error: Offset %d beyond Shadow RAM limit %d\n",
  219                            offset, hw->nvm.sr_size);
  220                 ret_code = I40E_ERR_PARAM;
  221                 goto read_nvm_exit;
  222         }
  223 
  224         /* Poll the done bit first */
  225         ret_code = i40e_poll_sr_srctl_done_bit(hw);
  226         if (ret_code == I40E_SUCCESS) {
  227                 /* Write the address and start reading */
  228                 sr_reg = ((u32)offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
  229                          BIT(I40E_GLNVM_SRCTL_START_SHIFT);
  230                 wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
  231 
  232                 /* Poll I40E_GLNVM_SRCTL until the done bit is set */
  233                 ret_code = i40e_poll_sr_srctl_done_bit(hw);
  234                 if (ret_code == I40E_SUCCESS) {
  235                         sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
  236                         *data = (u16)((sr_reg &
  237                                        I40E_GLNVM_SRDATA_RDDATA_MASK)
  238                                     >> I40E_GLNVM_SRDATA_RDDATA_SHIFT);
  239                 }
  240         }
  241         if (ret_code != I40E_SUCCESS)
  242                 i40e_debug(hw, I40E_DEBUG_NVM,
  243                            "NVM read error: Couldn't access Shadow RAM address: 0x%x\n",
  244                            offset);
  245 
  246 read_nvm_exit:
  247         return ret_code;
  248 }
  249 
  250 /**
  251  * i40e_read_nvm_aq - Read Shadow RAM.
  252  * @hw: pointer to the HW structure.
  253  * @module_pointer: module pointer location in words from the NVM beginning
  254  * @offset: offset in words from module start
  255  * @words: number of words to write
  256  * @data: buffer with words to write to the Shadow RAM
  257  * @last_command: tells the AdminQ that this is the last command
  258  *
  259  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
  260  **/
  261 static enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw,
  262                                               u8 module_pointer, u32 offset,
  263                                               u16 words, void *data,
  264                                               bool last_command)
  265 {
  266         enum i40e_status_code ret_code = I40E_ERR_NVM;
  267         struct i40e_asq_cmd_details cmd_details;
  268 
  269         DEBUGFUNC("i40e_read_nvm_aq");
  270 
  271         memset(&cmd_details, 0, sizeof(cmd_details));
  272         cmd_details.wb_desc = &hw->nvm_wb_desc;
  273 
  274         /* Here we are checking the SR limit only for the flat memory model.
  275          * We cannot do it for the module-based model, as we did not acquire
  276          * the NVM resource yet (we cannot get the module pointer value).
  277          * Firmware will check the module-based model.
  278          */
  279         if ((offset + words) > hw->nvm.sr_size)
  280                 i40e_debug(hw, I40E_DEBUG_NVM,
  281                            "NVM write error: offset %d beyond Shadow RAM limit %d\n",
  282                            (offset + words), hw->nvm.sr_size);
  283         else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
  284                 /* We can write only up to 4KB (one sector), in one AQ write */
  285                 i40e_debug(hw, I40E_DEBUG_NVM,
  286                            "NVM write fail error: tried to write %d words, limit is %d.\n",
  287                            words, I40E_SR_SECTOR_SIZE_IN_WORDS);
  288         else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
  289                  != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
  290                 /* A single write cannot spread over two sectors */
  291                 i40e_debug(hw, I40E_DEBUG_NVM,
  292                            "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n",
  293                            offset, words);
  294         else
  295                 ret_code = i40e_aq_read_nvm(hw, module_pointer,
  296                                             2 * offset,  /*bytes*/
  297                                             2 * words,   /*bytes*/
  298                                             data, last_command, &cmd_details);
  299 
  300         return ret_code;
  301 }
  302 
  303 /**
  304  * i40e_read_nvm_word_aq - Reads Shadow RAM via AQ
  305  * @hw: pointer to the HW structure
  306  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
  307  * @data: word read from the Shadow RAM
  308  *
  309  * Reads one 16 bit word from the Shadow RAM using the AdminQ
  310  **/
  311 static enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
  312                                                    u16 *data)
  313 {
  314         enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
  315 
  316         DEBUGFUNC("i40e_read_nvm_word_aq");
  317 
  318         ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, TRUE);
  319         *data = LE16_TO_CPU(*(__le16 *)data);
  320 
  321         return ret_code;
  322 }
  323 
  324 /**
  325  * __i40e_read_nvm_word - Reads NVM word, assumes caller does the locking
  326  * @hw: pointer to the HW structure
  327  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
  328  * @data: word read from the Shadow RAM
  329  *
  330  * Reads one 16 bit word from the Shadow RAM.
  331  *
  332  * Do not use this function except in cases where the nvm lock is already
  333  * taken via i40e_acquire_nvm().
  334  **/
  335 enum i40e_status_code __i40e_read_nvm_word(struct i40e_hw *hw,
  336                                            u16 offset,
  337                                            u16 *data)
  338 {
  339 
  340         if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
  341                 return i40e_read_nvm_word_aq(hw, offset, data);
  342 
  343         return i40e_read_nvm_word_srctl(hw, offset, data);
  344 }
  345 
  346 /**
  347  * i40e_read_nvm_word - Reads NVM word, acquires lock if necessary
  348  * @hw: pointer to the HW structure
  349  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
  350  * @data: word read from the Shadow RAM
  351  *
  352  * Reads one 16 bit word from the Shadow RAM.
  353  **/
  354 enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
  355                                          u16 *data)
  356 {
  357         enum i40e_status_code ret_code = I40E_SUCCESS;
  358 
  359         if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
  360                 ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
  361 
  362         if (ret_code)
  363                 return ret_code;
  364         ret_code = __i40e_read_nvm_word(hw, offset, data);
  365 
  366         if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
  367                 i40e_release_nvm(hw);
  368         return ret_code;
  369 }
  370 
  371 /**
  372  * i40e_read_nvm_module_data - Reads NVM Buffer to specified memory location
  373  * @hw: Pointer to the HW structure
  374  * @module_ptr: Pointer to module in words with respect to NVM beginning
  375  * @module_offset: Offset in words from module start
  376  * @data_offset: Offset in words from reading data area start
  377  * @words_data_size: Words to read from NVM
  378  * @data_ptr: Pointer to memory location where resulting buffer will be stored
  379  **/
  380 enum i40e_status_code
  381 i40e_read_nvm_module_data(struct i40e_hw *hw, u8 module_ptr, u16 module_offset,
  382                           u16 data_offset, u16 words_data_size, u16 *data_ptr)
  383 {
  384         enum i40e_status_code status;
  385         u16 specific_ptr = 0;
  386         u16 ptr_value = 0;
  387         u16 offset = 0;
  388 
  389         if (module_ptr != 0) {
  390                 status = i40e_read_nvm_word(hw, module_ptr, &ptr_value);
  391                 if (status != I40E_SUCCESS) {
  392                         i40e_debug(hw, I40E_DEBUG_ALL,
  393                                    "Reading nvm word failed.Error code: %d.\n",
  394                                    status);
  395                         return I40E_ERR_NVM;
  396                 }
  397         }
  398 #define I40E_NVM_INVALID_PTR_VAL 0x7FFF
  399 #define I40E_NVM_INVALID_VAL 0xFFFF
  400 
  401         /* Pointer not initialized */
  402         if (ptr_value == I40E_NVM_INVALID_PTR_VAL ||
  403             ptr_value == I40E_NVM_INVALID_VAL) {
  404                 i40e_debug(hw, I40E_DEBUG_ALL, "Pointer not initialized.\n");
  405                 return I40E_ERR_BAD_PTR;
  406         }
  407 
  408         /* Check whether the module is in SR mapped area or outside */
  409         if (ptr_value & I40E_PTR_TYPE) {
  410                 /* Pointer points outside of the Shared RAM mapped area */
  411                 i40e_debug(hw, I40E_DEBUG_ALL,
  412                            "Reading nvm data failed. Pointer points outside of the Shared RAM mapped area.\n");
  413 
  414                 return I40E_ERR_PARAM;
  415         } else {
  416                 /* Read from the Shadow RAM */
  417 
  418                 status = i40e_read_nvm_word(hw, ptr_value + module_offset,
  419                                             &specific_ptr);
  420                 if (status != I40E_SUCCESS) {
  421                         i40e_debug(hw, I40E_DEBUG_ALL,
  422                                    "Reading nvm word failed.Error code: %d.\n",
  423                                    status);
  424                         return I40E_ERR_NVM;
  425                 }
  426 
  427                 offset = ptr_value + module_offset + specific_ptr +
  428                         data_offset;
  429 
  430                 status = i40e_read_nvm_buffer(hw, offset, &words_data_size,
  431                                               data_ptr);
  432                 if (status != I40E_SUCCESS) {
  433                         i40e_debug(hw, I40E_DEBUG_ALL,
  434                                    "Reading nvm buffer failed.Error code: %d.\n",
  435                                    status);
  436                 }
  437         }
  438 
  439         return status;
  440 }
  441 
  442 /**
  443  * i40e_read_nvm_buffer_srctl - Reads Shadow RAM buffer via SRCTL register
  444  * @hw: pointer to the HW structure
  445  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
  446  * @words: (in) number of words to read; (out) number of words actually read
  447  * @data: words read from the Shadow RAM
  448  *
  449  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
  450  * method. The buffer read is preceded by the NVM ownership take
  451  * and followed by the release.
  452  **/
  453 static enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset,
  454                                                         u16 *words, u16 *data)
  455 {
  456         enum i40e_status_code ret_code = I40E_SUCCESS;
  457         u16 index, word;
  458 
  459         DEBUGFUNC("i40e_read_nvm_buffer_srctl");
  460 
  461         /* Loop through the selected region */
  462         for (word = 0; word < *words; word++) {
  463                 index = offset + word;
  464                 ret_code = i40e_read_nvm_word_srctl(hw, index, &data[word]);
  465                 if (ret_code != I40E_SUCCESS)
  466                         break;
  467         }
  468 
  469         /* Update the number of words read from the Shadow RAM */
  470         *words = word;
  471 
  472         return ret_code;
  473 }
  474 
  475 /**
  476  * i40e_read_nvm_buffer_aq - Reads Shadow RAM buffer via AQ
  477  * @hw: pointer to the HW structure
  478  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
  479  * @words: (in) number of words to read; (out) number of words actually read
  480  * @data: words read from the Shadow RAM
  481  *
  482  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_aq()
  483  * method. The buffer read is preceded by the NVM ownership take
  484  * and followed by the release.
  485  **/
  486 static enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset,
  487                                                      u16 *words, u16 *data)
  488 {
  489         enum i40e_status_code ret_code;
  490         u16 read_size = *words;
  491         bool last_cmd = FALSE;
  492         u16 words_read = 0;
  493         u16 i = 0;
  494 
  495         DEBUGFUNC("i40e_read_nvm_buffer_aq");
  496 
  497         do {
  498                 /* Calculate number of bytes we should read in this step.
  499                  * FVL AQ do not allow to read more than one page at a time or
  500                  * to cross page boundaries.
  501                  */
  502                 if (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)
  503                         read_size = min(*words,
  504                                         (u16)(I40E_SR_SECTOR_SIZE_IN_WORDS -
  505                                       (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)));
  506                 else
  507                         read_size = min((*words - words_read),
  508                                         I40E_SR_SECTOR_SIZE_IN_WORDS);
  509 
  510                 /* Check if this is last command, if so set proper flag */
  511                 if ((words_read + read_size) >= *words)
  512                         last_cmd = TRUE;
  513 
  514                 ret_code = i40e_read_nvm_aq(hw, 0x0, offset, read_size,
  515                                             data + words_read, last_cmd);
  516                 if (ret_code != I40E_SUCCESS)
  517                         goto read_nvm_buffer_aq_exit;
  518 
  519                 /* Increment counter for words already read and move offset to
  520                  * new read location
  521                  */
  522                 words_read += read_size;
  523                 offset += read_size;
  524         } while (words_read < *words);
  525 
  526         for (i = 0; i < *words; i++)
  527                 data[i] = LE16_TO_CPU(((__le16 *)data)[i]);
  528 
  529 read_nvm_buffer_aq_exit:
  530         *words = words_read;
  531         return ret_code;
  532 }
  533 
  534 /**
  535  * __i40e_read_nvm_buffer - Reads NVM buffer, caller must acquire lock
  536  * @hw: pointer to the HW structure
  537  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
  538  * @words: (in) number of words to read; (out) number of words actually read
  539  * @data: words read from the Shadow RAM
  540  *
  541  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
  542  * method.
  543  **/
  544 enum i40e_status_code __i40e_read_nvm_buffer(struct i40e_hw *hw,
  545                                              u16 offset,
  546                                              u16 *words, u16 *data)
  547 {
  548         if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
  549                 return i40e_read_nvm_buffer_aq(hw, offset, words, data);
  550 
  551         return i40e_read_nvm_buffer_srctl(hw, offset, words, data);
  552 }
  553 
  554 /**
  555  * i40e_read_nvm_buffer - Reads Shadow RAM buffer and acquire lock if necessary
  556  * @hw: pointer to the HW structure
  557  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
  558  * @words: (in) number of words to read; (out) number of words actually read
  559  * @data: words read from the Shadow RAM
  560  *
  561  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
  562  * method. The buffer read is preceded by the NVM ownership take
  563  * and followed by the release.
  564  **/
  565 enum i40e_status_code i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
  566                                            u16 *words, u16 *data)
  567 {
  568         enum i40e_status_code ret_code = I40E_SUCCESS;
  569 
  570         if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
  571                 ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
  572                 if (!ret_code) {
  573                         ret_code = i40e_read_nvm_buffer_aq(hw, offset, words,
  574                                                          data);
  575                         i40e_release_nvm(hw);
  576                 }
  577         } else {
  578                 ret_code = i40e_read_nvm_buffer_srctl(hw, offset, words, data);
  579         }
  580 
  581         return ret_code;
  582 }
  583 
  584 /**
  585  * i40e_write_nvm_aq - Writes Shadow RAM.
  586  * @hw: pointer to the HW structure.
  587  * @module_pointer: module pointer location in words from the NVM beginning
  588  * @offset: offset in words from module start
  589  * @words: number of words to write
  590  * @data: buffer with words to write to the Shadow RAM
  591  * @last_command: tells the AdminQ that this is the last command
  592  *
  593  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
  594  **/
  595 enum i40e_status_code i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
  596                                         u32 offset, u16 words, void *data,
  597                                         bool last_command)
  598 {
  599         enum i40e_status_code ret_code = I40E_ERR_NVM;
  600         struct i40e_asq_cmd_details cmd_details;
  601 
  602         DEBUGFUNC("i40e_write_nvm_aq");
  603 
  604         memset(&cmd_details, 0, sizeof(cmd_details));
  605         cmd_details.wb_desc = &hw->nvm_wb_desc;
  606 
  607         /* Here we are checking the SR limit only for the flat memory model.
  608          * We cannot do it for the module-based model, as we did not acquire
  609          * the NVM resource yet (we cannot get the module pointer value).
  610          * Firmware will check the module-based model.
  611          */
  612         if ((offset + words) > hw->nvm.sr_size)
  613                 DEBUGOUT("NVM write error: offset beyond Shadow RAM limit.\n");
  614         else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
  615                 /* We can write only up to 4KB (one sector), in one AQ write */
  616                 DEBUGOUT("NVM write fail error: cannot write more than 4KB in a single write.\n");
  617         else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
  618                  != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
  619                 /* A single write cannot spread over two sectors */
  620                 DEBUGOUT("NVM write error: cannot spread over two sectors in a single write.\n");
  621         else
  622                 ret_code = i40e_aq_update_nvm(hw, module_pointer,
  623                                               2 * offset,  /*bytes*/
  624                                               2 * words,   /*bytes*/
  625                                               data, last_command, 0,
  626                                               &cmd_details);
  627 
  628         return ret_code;
  629 }
  630 
  631 /**
  632  * __i40e_write_nvm_word - Writes Shadow RAM word
  633  * @hw: pointer to the HW structure
  634  * @offset: offset of the Shadow RAM word to write
  635  * @data: word to write to the Shadow RAM
  636  *
  637  * Writes a 16 bit word to the SR using the i40e_write_nvm_aq() method.
  638  * NVM ownership have to be acquired and released (on ARQ completion event
  639  * reception) by caller. To commit SR to NVM update checksum function
  640  * should be called.
  641  **/
  642 enum i40e_status_code __i40e_write_nvm_word(struct i40e_hw *hw, u32 offset,
  643                                             void *data)
  644 {
  645         DEBUGFUNC("i40e_write_nvm_word");
  646 
  647         *((__le16 *)data) = CPU_TO_LE16(*((u16 *)data));
  648 
  649         /* Value 0x00 below means that we treat SR as a flat mem */
  650         return i40e_write_nvm_aq(hw, 0x00, offset, 1, data, FALSE);
  651 }
  652 
  653 /**
  654  * __i40e_write_nvm_buffer - Writes Shadow RAM buffer
  655  * @hw: pointer to the HW structure
  656  * @module_pointer: module pointer location in words from the NVM beginning
  657  * @offset: offset of the Shadow RAM buffer to write
  658  * @words: number of words to write
  659  * @data: words to write to the Shadow RAM
  660  *
  661  * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
  662  * NVM ownership must be acquired before calling this function and released
  663  * on ARQ completion event reception by caller. To commit SR to NVM update
  664  * checksum function should be called.
  665  **/
  666 enum i40e_status_code __i40e_write_nvm_buffer(struct i40e_hw *hw,
  667                                               u8 module_pointer, u32 offset,
  668                                               u16 words, void *data)
  669 {
  670         __le16 *le_word_ptr = (__le16 *)data;
  671         u16 *word_ptr = (u16 *)data;
  672         u32 i = 0;
  673 
  674         DEBUGFUNC("i40e_write_nvm_buffer");
  675 
  676         for (i = 0; i < words; i++)
  677                 le_word_ptr[i] = CPU_TO_LE16(word_ptr[i]);
  678 
  679         /* Here we will only write one buffer as the size of the modules
  680          * mirrored in the Shadow RAM is always less than 4K.
  681          */
  682         return i40e_write_nvm_aq(hw, module_pointer, offset, words,
  683                                  data, FALSE);
  684 }
  685 
  686 /**
  687  * i40e_calc_nvm_checksum - Calculates and returns the checksum
  688  * @hw: pointer to hardware structure
  689  * @checksum: pointer to the checksum
  690  *
  691  * This function calculates SW Checksum that covers the whole 64kB shadow RAM
  692  * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
  693  * is customer specific and unknown. Therefore, this function skips all maximum
  694  * possible size of VPD (1kB).
  695  **/
  696 enum i40e_status_code i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum)
  697 {
  698         enum i40e_status_code ret_code = I40E_SUCCESS;
  699         struct i40e_virt_mem vmem;
  700         u16 pcie_alt_module = 0;
  701         u16 checksum_local = 0;
  702         u16 vpd_module = 0;
  703         u16 *data;
  704         u16 i = 0;
  705 
  706         DEBUGFUNC("i40e_calc_nvm_checksum");
  707 
  708         ret_code = i40e_allocate_virt_mem(hw, &vmem,
  709                                     I40E_SR_SECTOR_SIZE_IN_WORDS * sizeof(u16));
  710         if (ret_code)
  711                 goto i40e_calc_nvm_checksum_exit;
  712         data = (u16 *)vmem.va;
  713 
  714         /* read pointer to VPD area */
  715         ret_code = __i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
  716         if (ret_code != I40E_SUCCESS) {
  717                 ret_code = I40E_ERR_NVM_CHECKSUM;
  718                 goto i40e_calc_nvm_checksum_exit;
  719         }
  720 
  721         /* read pointer to PCIe Alt Auto-load module */
  722         ret_code = __i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
  723                                         &pcie_alt_module);
  724         if (ret_code != I40E_SUCCESS) {
  725                 ret_code = I40E_ERR_NVM_CHECKSUM;
  726                 goto i40e_calc_nvm_checksum_exit;
  727         }
  728 
  729         /* Calculate SW checksum that covers the whole 64kB shadow RAM
  730          * except the VPD and PCIe ALT Auto-load modules
  731          */
  732         for (i = 0; i < hw->nvm.sr_size; i++) {
  733                 /* Read SR page */
  734                 if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) {
  735                         u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS;
  736 
  737                         ret_code = __i40e_read_nvm_buffer(hw, i, &words, data);
  738                         if (ret_code != I40E_SUCCESS) {
  739                                 ret_code = I40E_ERR_NVM_CHECKSUM;
  740                                 goto i40e_calc_nvm_checksum_exit;
  741                         }
  742                 }
  743 
  744                 /* Skip Checksum word */
  745                 if (i == I40E_SR_SW_CHECKSUM_WORD)
  746                         continue;
  747                 /* Skip VPD module (convert byte size to word count) */
  748                 if ((i >= (u32)vpd_module) &&
  749                     (i < ((u32)vpd_module +
  750                      (I40E_SR_VPD_MODULE_MAX_SIZE / 2)))) {
  751                         continue;
  752                 }
  753                 /* Skip PCIe ALT module (convert byte size to word count) */
  754                 if ((i >= (u32)pcie_alt_module) &&
  755                     (i < ((u32)pcie_alt_module +
  756                      (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2)))) {
  757                         continue;
  758                 }
  759 
  760                 checksum_local += data[i % I40E_SR_SECTOR_SIZE_IN_WORDS];
  761         }
  762 
  763         *checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local;
  764 
  765 i40e_calc_nvm_checksum_exit:
  766         i40e_free_virt_mem(hw, &vmem);
  767         return ret_code;
  768 }
  769 
  770 /**
  771  * i40e_update_nvm_checksum - Updates the NVM checksum
  772  * @hw: pointer to hardware structure
  773  *
  774  * NVM ownership must be acquired before calling this function and released
  775  * on ARQ completion event reception by caller.
  776  * This function will commit SR to NVM.
  777  **/
  778 enum i40e_status_code i40e_update_nvm_checksum(struct i40e_hw *hw)
  779 {
  780         enum i40e_status_code ret_code = I40E_SUCCESS;
  781         u16 checksum;
  782         __le16 le_sum;
  783 
  784         DEBUGFUNC("i40e_update_nvm_checksum");
  785 
  786         ret_code = i40e_calc_nvm_checksum(hw, &checksum);
  787         if (ret_code == I40E_SUCCESS) {
  788                 le_sum = CPU_TO_LE16(checksum);
  789                 ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD,
  790                                              1, &le_sum, TRUE);
  791         }
  792 
  793         return ret_code;
  794 }
  795 
  796 /**
  797  * i40e_validate_nvm_checksum - Validate EEPROM checksum
  798  * @hw: pointer to hardware structure
  799  * @checksum: calculated checksum
  800  *
  801  * Performs checksum calculation and validates the NVM SW checksum. If the
  802  * caller does not need checksum, the value can be NULL.
  803  **/
  804 enum i40e_status_code i40e_validate_nvm_checksum(struct i40e_hw *hw,
  805                                                  u16 *checksum)
  806 {
  807         enum i40e_status_code ret_code = I40E_SUCCESS;
  808         u16 checksum_sr = 0;
  809         u16 checksum_local = 0;
  810 
  811         DEBUGFUNC("i40e_validate_nvm_checksum");
  812 
  813         /* We must acquire the NVM lock in order to correctly synchronize the
  814          * NVM accesses across multiple PFs. Without doing so it is possible
  815          * for one of the PFs to read invalid data potentially indicating that
  816          * the checksum is invalid.
  817          */
  818         ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
  819         if (ret_code)
  820                 return ret_code;
  821         ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
  822         __i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
  823         i40e_release_nvm(hw);
  824         if (ret_code)
  825                 return ret_code;
  826 
  827         /* Verify read checksum from EEPROM is the same as
  828          * calculated checksum
  829          */
  830         if (checksum_local != checksum_sr)
  831                 ret_code = I40E_ERR_NVM_CHECKSUM;
  832 
  833         /* If the user cares, return the calculated checksum */
  834         if (checksum)
  835                 *checksum = checksum_local;
  836 
  837         return ret_code;
  838 }
  839 
  840 static enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw,
  841                                                     struct i40e_nvm_access *cmd,
  842                                                     u8 *bytes, int *perrno);
  843 static enum i40e_status_code i40e_nvmupd_state_reading(struct i40e_hw *hw,
  844                                                     struct i40e_nvm_access *cmd,
  845                                                     u8 *bytes, int *perrno);
  846 static enum i40e_status_code i40e_nvmupd_state_writing(struct i40e_hw *hw,
  847                                                     struct i40e_nvm_access *cmd,
  848                                                     u8 *bytes, int *perrno);
  849 static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
  850                                                     struct i40e_nvm_access *cmd,
  851                                                     int *perrno);
  852 static enum i40e_status_code i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
  853                                                    struct i40e_nvm_access *cmd,
  854                                                    int *perrno);
  855 static enum i40e_status_code i40e_nvmupd_nvm_write(struct i40e_hw *hw,
  856                                                    struct i40e_nvm_access *cmd,
  857                                                    u8 *bytes, int *perrno);
  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 static enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw,
  862                                                  struct i40e_nvm_access *cmd,
  863                                                  u8 *bytes, int *perrno);
  864 static enum i40e_status_code i40e_nvmupd_get_aq_result(struct i40e_hw *hw,
  865                                                     struct i40e_nvm_access *cmd,
  866                                                     u8 *bytes, int *perrno);
  867 static enum i40e_status_code i40e_nvmupd_get_aq_event(struct i40e_hw *hw,
  868                                                     struct i40e_nvm_access *cmd,
  869                                                     u8 *bytes, int *perrno);
  870 static INLINE u8 i40e_nvmupd_get_module(u32 val)
  871 {
  872         return (u8)(val & I40E_NVM_MOD_PNT_MASK);
  873 }
  874 static INLINE u8 i40e_nvmupd_get_transaction(u32 val)
  875 {
  876         return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT);
  877 }
  878 
  879 static INLINE u8 i40e_nvmupd_get_preservation_flags(u32 val)
  880 {
  881         return (u8)((val & I40E_NVM_PRESERVATION_FLAGS_MASK) >>
  882                     I40E_NVM_PRESERVATION_FLAGS_SHIFT);
  883 }
  884 
  885 static const char *i40e_nvm_update_state_str[] = {
  886         "I40E_NVMUPD_INVALID",
  887         "I40E_NVMUPD_READ_CON",
  888         "I40E_NVMUPD_READ_SNT",
  889         "I40E_NVMUPD_READ_LCB",
  890         "I40E_NVMUPD_READ_SA",
  891         "I40E_NVMUPD_WRITE_ERA",
  892         "I40E_NVMUPD_WRITE_CON",
  893         "I40E_NVMUPD_WRITE_SNT",
  894         "I40E_NVMUPD_WRITE_LCB",
  895         "I40E_NVMUPD_WRITE_SA",
  896         "I40E_NVMUPD_CSUM_CON",
  897         "I40E_NVMUPD_CSUM_SA",
  898         "I40E_NVMUPD_CSUM_LCB",
  899         "I40E_NVMUPD_STATUS",
  900         "I40E_NVMUPD_EXEC_AQ",
  901         "I40E_NVMUPD_GET_AQ_RESULT",
  902         "I40E_NVMUPD_GET_AQ_EVENT",
  903         "I40E_NVMUPD_GET_FEATURES",
  904 };
  905 
  906 /**
  907  * i40e_nvmupd_command - Process an NVM update command
  908  * @hw: pointer to hardware structure
  909  * @cmd: pointer to nvm update command
  910  * @bytes: pointer to the data buffer
  911  * @perrno: pointer to return error code
  912  *
  913  * Dispatches command depending on what update state is current
  914  **/
  915 enum i40e_status_code i40e_nvmupd_command(struct i40e_hw *hw,
  916                                           struct i40e_nvm_access *cmd,
  917                                           u8 *bytes, int *perrno)
  918 {
  919         enum i40e_status_code status;
  920         enum i40e_nvmupd_cmd upd_cmd;
  921 
  922         DEBUGFUNC("i40e_nvmupd_command");
  923 
  924         /* assume success */
  925         *perrno = 0;
  926 
  927         /* early check for status command and debug msgs */
  928         upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
  929 
  930         i40e_debug(hw, I40E_DEBUG_NVM, "%s state %d nvm_release_on_hold %d opc 0x%04x cmd 0x%08x config 0x%08x offset 0x%08x data_size 0x%08x\n",
  931                    i40e_nvm_update_state_str[upd_cmd],
  932                    hw->nvmupd_state,
  933                    hw->nvm_release_on_done, hw->nvm_wait_opcode,
  934                    cmd->command, cmd->config, cmd->offset, cmd->data_size);
  935 
  936         if (upd_cmd == I40E_NVMUPD_INVALID) {
  937                 *perrno = -EFAULT;
  938                 i40e_debug(hw, I40E_DEBUG_NVM,
  939                            "i40e_nvmupd_validate_command returns %d errno %d\n",
  940                            upd_cmd, *perrno);
  941         }
  942 
  943         /* a status request returns immediately rather than
  944          * going into the state machine
  945          */
  946         if (upd_cmd == I40E_NVMUPD_STATUS) {
  947                 if (!cmd->data_size) {
  948                         *perrno = -EFAULT;
  949                         return I40E_ERR_BUF_TOO_SHORT;
  950                 }
  951 
  952                 bytes[0] = hw->nvmupd_state;
  953 
  954                 if (cmd->data_size >= 4) {
  955                         bytes[1] = 0;
  956                         *((u16 *)&bytes[2]) = hw->nvm_wait_opcode;
  957                 }
  958 
  959                 /* Clear error status on read */
  960                 if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR)
  961                         hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
  962 
  963                 return I40E_SUCCESS;
  964         }
  965 
  966         /*
  967          * A supported features request returns immediately
  968          * rather than going into state machine
  969          */
  970         if (upd_cmd == I40E_NVMUPD_FEATURES) {
  971                 if (cmd->data_size < hw->nvmupd_features.size) {
  972                         *perrno = -EFAULT;
  973                         return I40E_ERR_BUF_TOO_SHORT;
  974                 }
  975 
  976                 /*
  977                  * If buffer is bigger than i40e_nvmupd_features structure,
  978                  * make sure the trailing bytes are set to 0x0.
  979                  */
  980                 if (cmd->data_size > hw->nvmupd_features.size)
  981                         i40e_memset(bytes + hw->nvmupd_features.size, 0x0,
  982                                     cmd->data_size - hw->nvmupd_features.size,
  983                                     I40E_NONDMA_MEM);
  984 
  985                 i40e_memcpy(bytes, &hw->nvmupd_features,
  986                             hw->nvmupd_features.size, I40E_NONDMA_MEM);
  987 
  988                 return I40E_SUCCESS;
  989         }
  990 
  991         /* Clear status even it is not read and log */
  992         if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR) {
  993                 i40e_debug(hw, I40E_DEBUG_NVM,
  994                            "Clearing I40E_NVMUPD_STATE_ERROR state without reading\n");
  995                 hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
  996         }
  997 
  998         /* Acquire lock to prevent race condition where adminq_task
  999          * can execute after i40e_nvmupd_nvm_read/write but before state
 1000          * variables (nvm_wait_opcode, nvm_release_on_done) are updated.
 1001          *
 1002          * During NVMUpdate, it is observed that lock could be held for
 1003          * ~5ms for most commands. However lock is held for ~60ms for
 1004          * NVMUPD_CSUM_LCB command.
 1005          */
 1006         i40e_acquire_spinlock(&hw->aq.arq_spinlock);
 1007         switch (hw->nvmupd_state) {
 1008         case I40E_NVMUPD_STATE_INIT:
 1009                 status = i40e_nvmupd_state_init(hw, cmd, bytes, perrno);
 1010                 break;
 1011 
 1012         case I40E_NVMUPD_STATE_READING:
 1013                 status = i40e_nvmupd_state_reading(hw, cmd, bytes, perrno);
 1014                 break;
 1015 
 1016         case I40E_NVMUPD_STATE_WRITING:
 1017                 status = i40e_nvmupd_state_writing(hw, cmd, bytes, perrno);
 1018                 break;
 1019 
 1020         case I40E_NVMUPD_STATE_INIT_WAIT:
 1021         case I40E_NVMUPD_STATE_WRITE_WAIT:
 1022                 /* if we need to stop waiting for an event, clear
 1023                  * the wait info and return before doing anything else
 1024                  */
 1025                 if (cmd->offset == 0xffff) {
 1026                         i40e_nvmupd_clear_wait_state(hw);
 1027                         status = I40E_SUCCESS;
 1028                         break;
 1029                 }
 1030 
 1031                 status = I40E_ERR_NOT_READY;
 1032                 *perrno = -EBUSY;
 1033                 break;
 1034 
 1035         default:
 1036                 /* invalid state, should never happen */
 1037                 i40e_debug(hw, I40E_DEBUG_NVM,
 1038                            "NVMUPD: no such state %d\n", hw->nvmupd_state);
 1039                 status = I40E_NOT_SUPPORTED;
 1040                 *perrno = -ESRCH;
 1041                 break;
 1042         }
 1043 
 1044         i40e_release_spinlock(&hw->aq.arq_spinlock);
 1045         return status;
 1046 }
 1047 
 1048 /**
 1049  * i40e_nvmupd_state_init - Handle NVM update state Init
 1050  * @hw: pointer to hardware structure
 1051  * @cmd: pointer to nvm update command buffer
 1052  * @bytes: pointer to the data buffer
 1053  * @perrno: pointer to return error code
 1054  *
 1055  * Process legitimate commands of the Init state and conditionally set next
 1056  * state. Reject all other commands.
 1057  **/
 1058 static enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw,
 1059                                                     struct i40e_nvm_access *cmd,
 1060                                                     u8 *bytes, int *perrno)
 1061 {
 1062         enum i40e_status_code status = I40E_SUCCESS;
 1063         enum i40e_nvmupd_cmd upd_cmd;
 1064 
 1065         DEBUGFUNC("i40e_nvmupd_state_init");
 1066 
 1067         upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
 1068 
 1069         switch (upd_cmd) {
 1070         case I40E_NVMUPD_READ_SA:
 1071                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
 1072                 if (status) {
 1073                         *perrno = i40e_aq_rc_to_posix(status,
 1074                                                      hw->aq.asq_last_status);
 1075                 } else {
 1076                         status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
 1077                         i40e_release_nvm(hw);
 1078                 }
 1079                 break;
 1080 
 1081         case I40E_NVMUPD_READ_SNT:
 1082                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
 1083                 if (status) {
 1084                         *perrno = i40e_aq_rc_to_posix(status,
 1085                                                      hw->aq.asq_last_status);
 1086                 } else {
 1087                         status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
 1088                         if (status)
 1089                                 i40e_release_nvm(hw);
 1090                         else
 1091                                 hw->nvmupd_state = I40E_NVMUPD_STATE_READING;
 1092                 }
 1093                 break;
 1094 
 1095         case I40E_NVMUPD_WRITE_ERA:
 1096                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
 1097                 if (status) {
 1098                         *perrno = i40e_aq_rc_to_posix(status,
 1099                                                      hw->aq.asq_last_status);
 1100                 } else {
 1101                         status = i40e_nvmupd_nvm_erase(hw, cmd, perrno);
 1102                         if (status) {
 1103                                 i40e_release_nvm(hw);
 1104                         } else {
 1105                                 hw->nvm_release_on_done = TRUE;
 1106                                 hw->nvm_wait_opcode = i40e_aqc_opc_nvm_erase;
 1107                                 hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
 1108                         }
 1109                 }
 1110                 break;
 1111 
 1112         case I40E_NVMUPD_WRITE_SA:
 1113                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
 1114                 if (status) {
 1115                         *perrno = i40e_aq_rc_to_posix(status,
 1116                                                      hw->aq.asq_last_status);
 1117                 } else {
 1118                         status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
 1119                         if (status) {
 1120                                 i40e_release_nvm(hw);
 1121                         } else {
 1122                                 hw->nvm_release_on_done = TRUE;
 1123                                 hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
 1124                                 hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
 1125                         }
 1126                 }
 1127                 break;
 1128 
 1129         case I40E_NVMUPD_WRITE_SNT:
 1130                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
 1131                 if (status) {
 1132                         *perrno = i40e_aq_rc_to_posix(status,
 1133                                                      hw->aq.asq_last_status);
 1134                 } else {
 1135                         status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
 1136                         if (status) {
 1137                                 i40e_release_nvm(hw);
 1138                         } else {
 1139                                 hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
 1140                                 hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT;
 1141                         }
 1142                 }
 1143                 break;
 1144 
 1145         case I40E_NVMUPD_CSUM_SA:
 1146                 status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
 1147                 if (status) {
 1148                         *perrno = i40e_aq_rc_to_posix(status,
 1149                                                      hw->aq.asq_last_status);
 1150                 } else {
 1151                         status = i40e_update_nvm_checksum(hw);
 1152                         if (status) {
 1153                                 *perrno = hw->aq.asq_last_status ?
 1154                                    i40e_aq_rc_to_posix(status,
 1155                                                        hw->aq.asq_last_status) :
 1156                                    -EIO;
 1157                                 i40e_release_nvm(hw);
 1158                         } else {
 1159                                 hw->nvm_release_on_done = TRUE;
 1160                                 hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
 1161                                 hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
 1162                         }
 1163                 }
 1164                 break;
 1165 
 1166         case I40E_NVMUPD_EXEC_AQ:
 1167                 status = i40e_nvmupd_exec_aq(hw, cmd, bytes, perrno);
 1168                 break;
 1169 
 1170         case I40E_NVMUPD_GET_AQ_RESULT:
 1171                 status = i40e_nvmupd_get_aq_result(hw, cmd, bytes, perrno);
 1172                 break;
 1173 
 1174         case I40E_NVMUPD_GET_AQ_EVENT:
 1175                 status = i40e_nvmupd_get_aq_event(hw, cmd, bytes, perrno);
 1176                 break;
 1177 
 1178         default:
 1179                 i40e_debug(hw, I40E_DEBUG_NVM,
 1180                            "NVMUPD: bad cmd %s in init state\n",
 1181                            i40e_nvm_update_state_str[upd_cmd]);
 1182                 status = I40E_ERR_NVM;
 1183                 *perrno = -ESRCH;
 1184                 break;
 1185         }
 1186         return status;
 1187 }
 1188 
 1189 /**
 1190  * i40e_nvmupd_state_reading - Handle NVM update state Reading
 1191  * @hw: pointer to hardware structure
 1192  * @cmd: pointer to nvm update command buffer
 1193  * @bytes: pointer to the data buffer
 1194  * @perrno: pointer to return error code
 1195  *
 1196  * NVM ownership is already held.  Process legitimate commands and set any
 1197  * change in state; reject all other commands.
 1198  **/
 1199 static enum i40e_status_code i40e_nvmupd_state_reading(struct i40e_hw *hw,
 1200                                                     struct i40e_nvm_access *cmd,
 1201                                                     u8 *bytes, int *perrno)
 1202 {
 1203         enum i40e_status_code status = I40E_SUCCESS;
 1204         enum i40e_nvmupd_cmd upd_cmd;
 1205 
 1206         DEBUGFUNC("i40e_nvmupd_state_reading");
 1207 
 1208         upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
 1209 
 1210         switch (upd_cmd) {
 1211         case I40E_NVMUPD_READ_SA:
 1212         case I40E_NVMUPD_READ_CON:
 1213                 status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
 1214                 break;
 1215 
 1216         case I40E_NVMUPD_READ_LCB:
 1217                 status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
 1218                 i40e_release_nvm(hw);
 1219                 hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
 1220                 break;
 1221 
 1222         default:
 1223                 i40e_debug(hw, I40E_DEBUG_NVM,
 1224                            "NVMUPD: bad cmd %s in reading state.\n",
 1225                            i40e_nvm_update_state_str[upd_cmd]);
 1226                 status = I40E_NOT_SUPPORTED;
 1227                 *perrno = -ESRCH;
 1228                 break;
 1229         }
 1230         return status;
 1231 }
 1232 
 1233 /**
 1234  * i40e_nvmupd_state_writing - Handle NVM update state Writing
 1235  * @hw: pointer to hardware structure
 1236  * @cmd: pointer to nvm update command buffer
 1237  * @bytes: pointer to the data buffer
 1238  * @perrno: pointer to return error code
 1239  *
 1240  * NVM ownership is already held.  Process legitimate commands and set any
 1241  * change in state; reject all other commands
 1242  **/
 1243 static enum i40e_status_code i40e_nvmupd_state_writing(struct i40e_hw *hw,
 1244                                                     struct i40e_nvm_access *cmd,
 1245                                                     u8 *bytes, int *perrno)
 1246 {
 1247         enum i40e_status_code status = I40E_SUCCESS;
 1248         enum i40e_nvmupd_cmd upd_cmd;
 1249         bool retry_attempt = FALSE;
 1250 
 1251         DEBUGFUNC("i40e_nvmupd_state_writing");
 1252 
 1253         upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
 1254 
 1255 retry:
 1256         switch (upd_cmd) {
 1257         case I40E_NVMUPD_WRITE_CON:
 1258                 status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
 1259                 if (!status) {
 1260                         hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
 1261                         hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT;
 1262                 }
 1263                 break;
 1264 
 1265         case I40E_NVMUPD_WRITE_LCB:
 1266                 status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
 1267                 if (status) {
 1268                         *perrno = hw->aq.asq_last_status ?
 1269                                    i40e_aq_rc_to_posix(status,
 1270                                                        hw->aq.asq_last_status) :
 1271                                    -EIO;
 1272                         hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
 1273                 } else {
 1274                         hw->nvm_release_on_done = TRUE;
 1275                         hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
 1276                         hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
 1277                 }
 1278                 break;
 1279 
 1280         case I40E_NVMUPD_CSUM_CON:
 1281                 /* Assumes the caller has acquired the nvm */
 1282                 status = i40e_update_nvm_checksum(hw);
 1283                 if (status) {
 1284                         *perrno = hw->aq.asq_last_status ?
 1285                                    i40e_aq_rc_to_posix(status,
 1286                                                        hw->aq.asq_last_status) :
 1287                                    -EIO;
 1288                         hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
 1289                 } else {
 1290                         hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
 1291                         hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT;
 1292                 }
 1293                 break;
 1294 
 1295         case I40E_NVMUPD_CSUM_LCB:
 1296                 /* Assumes the caller has acquired the nvm */
 1297                 status = i40e_update_nvm_checksum(hw);
 1298                 if (status) {
 1299                         *perrno = hw->aq.asq_last_status ?
 1300                                    i40e_aq_rc_to_posix(status,
 1301                                                        hw->aq.asq_last_status) :
 1302                                    -EIO;
 1303                         hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
 1304                 } else {
 1305                         hw->nvm_release_on_done = TRUE;
 1306                         hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
 1307                         hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
 1308                 }
 1309                 break;
 1310 
 1311         default:
 1312                 i40e_debug(hw, I40E_DEBUG_NVM,
 1313                            "NVMUPD: bad cmd %s in writing state.\n",
 1314                            i40e_nvm_update_state_str[upd_cmd]);
 1315                 status = I40E_NOT_SUPPORTED;
 1316                 *perrno = -ESRCH;
 1317                 break;
 1318         }
 1319 
 1320         /* In some circumstances, a multi-write transaction takes longer
 1321          * than the default 3 minute timeout on the write semaphore.  If
 1322          * the write failed with an EBUSY status, this is likely the problem,
 1323          * so here we try to reacquire the semaphore then retry the write.
 1324          * We only do one retry, then give up.
 1325          */
 1326         if (status && (hw->aq.asq_last_status == I40E_AQ_RC_EBUSY) &&
 1327             !retry_attempt) {
 1328                 enum i40e_status_code old_status = status;
 1329                 u32 old_asq_status = hw->aq.asq_last_status;
 1330                 u32 gtime;
 1331 
 1332                 gtime = rd32(hw, I40E_GLVFGEN_TIMER);
 1333                 if (gtime >= hw->nvm.hw_semaphore_timeout) {
 1334                         i40e_debug(hw, I40E_DEBUG_ALL,
 1335                                    "NVMUPD: write semaphore expired (%d >= %lld), retrying\n",
 1336                                    gtime, hw->nvm.hw_semaphore_timeout);
 1337                         i40e_release_nvm(hw);
 1338                         status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
 1339                         if (status) {
 1340                                 i40e_debug(hw, I40E_DEBUG_ALL,
 1341                                            "NVMUPD: write semaphore reacquire failed aq_err = %d\n",
 1342                                            hw->aq.asq_last_status);
 1343                                 status = old_status;
 1344                                 hw->aq.asq_last_status = old_asq_status;
 1345                         } else {
 1346                                 retry_attempt = TRUE;
 1347                                 goto retry;
 1348                         }
 1349                 }
 1350         }
 1351 
 1352         return status;
 1353 }
 1354 
 1355 /**
 1356  * i40e_nvmupd_clear_wait_state - clear wait state on hw
 1357  * @hw: pointer to the hardware structure
 1358  **/
 1359 void i40e_nvmupd_clear_wait_state(struct i40e_hw *hw)
 1360 {
 1361         i40e_debug(hw, I40E_DEBUG_NVM,
 1362                    "NVMUPD: clearing wait on opcode 0x%04x\n",
 1363                    hw->nvm_wait_opcode);
 1364 
 1365         if (hw->nvm_release_on_done) {
 1366                 i40e_release_nvm(hw);
 1367                 hw->nvm_release_on_done = FALSE;
 1368         }
 1369         hw->nvm_wait_opcode = 0;
 1370 
 1371         if (hw->aq.arq_last_status) {
 1372                 hw->nvmupd_state = I40E_NVMUPD_STATE_ERROR;
 1373                 return;
 1374         }
 1375 
 1376         switch (hw->nvmupd_state) {
 1377         case I40E_NVMUPD_STATE_INIT_WAIT:
 1378                 hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
 1379                 break;
 1380 
 1381         case I40E_NVMUPD_STATE_WRITE_WAIT:
 1382                 hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING;
 1383                 break;
 1384 
 1385         default:
 1386                 break;
 1387         }
 1388 }
 1389 
 1390 /**
 1391  * i40e_nvmupd_check_wait_event - handle NVM update operation events
 1392  * @hw: pointer to the hardware structure
 1393  * @opcode: the event that just happened
 1394  * @desc: AdminQ descriptor
 1395  **/
 1396 void i40e_nvmupd_check_wait_event(struct i40e_hw *hw, u16 opcode,
 1397                                   struct i40e_aq_desc *desc)
 1398 {
 1399         u32 aq_desc_len = sizeof(struct i40e_aq_desc);
 1400 
 1401         if (opcode == hw->nvm_wait_opcode) {
 1402                 i40e_memcpy(&hw->nvm_aq_event_desc, desc,
 1403                             aq_desc_len, I40E_NONDMA_TO_NONDMA);
 1404                 i40e_nvmupd_clear_wait_state(hw);
 1405         }
 1406 }
 1407 
 1408 /**
 1409  * i40e_nvmupd_validate_command - Validate given command
 1410  * @hw: pointer to hardware structure
 1411  * @cmd: pointer to nvm update command buffer
 1412  * @perrno: pointer to return error code
 1413  *
 1414  * Return one of the valid command types or I40E_NVMUPD_INVALID
 1415  **/
 1416 static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
 1417                                                     struct i40e_nvm_access *cmd,
 1418                                                     int *perrno)
 1419 {
 1420         enum i40e_nvmupd_cmd upd_cmd;
 1421         u8 module, transaction;
 1422 
 1423         DEBUGFUNC("i40e_nvmupd_validate_command\n");
 1424 
 1425         /* anything that doesn't match a recognized case is an error */
 1426         upd_cmd = I40E_NVMUPD_INVALID;
 1427 
 1428         transaction = i40e_nvmupd_get_transaction(cmd->config);
 1429         module = i40e_nvmupd_get_module(cmd->config);
 1430 
 1431         /* limits on data size */
 1432         if ((cmd->data_size < 1) ||
 1433             (cmd->data_size > I40E_NVMUPD_MAX_DATA)) {
 1434                 i40e_debug(hw, I40E_DEBUG_NVM,
 1435                            "i40e_nvmupd_validate_command data_size %d\n",
 1436                            cmd->data_size);
 1437                 *perrno = -EFAULT;
 1438                 return I40E_NVMUPD_INVALID;
 1439         }
 1440 
 1441         switch (cmd->command) {
 1442         case I40E_NVM_READ:
 1443                 switch (transaction) {
 1444                 case I40E_NVM_CON:
 1445                         upd_cmd = I40E_NVMUPD_READ_CON;
 1446                         break;
 1447                 case I40E_NVM_SNT:
 1448                         upd_cmd = I40E_NVMUPD_READ_SNT;
 1449                         break;
 1450                 case I40E_NVM_LCB:
 1451                         upd_cmd = I40E_NVMUPD_READ_LCB;
 1452                         break;
 1453                 case I40E_NVM_SA:
 1454                         upd_cmd = I40E_NVMUPD_READ_SA;
 1455                         break;
 1456                 case I40E_NVM_EXEC:
 1457                         switch (module) {
 1458                         case I40E_NVM_EXEC_GET_AQ_RESULT:
 1459                                 upd_cmd = I40E_NVMUPD_GET_AQ_RESULT;
 1460                                 break;
 1461                         case I40E_NVM_EXEC_FEATURES:
 1462                                 upd_cmd = I40E_NVMUPD_FEATURES;
 1463                                 break;
 1464                         case I40E_NVM_EXEC_STATUS:
 1465                                 upd_cmd = I40E_NVMUPD_STATUS;
 1466                                 break;
 1467                         default:
 1468                                 *perrno = -EFAULT;
 1469                                 return I40E_NVMUPD_INVALID;
 1470                         }
 1471                         break;
 1472                 case I40E_NVM_AQE:
 1473                         upd_cmd = I40E_NVMUPD_GET_AQ_EVENT;
 1474                         break;
 1475                 }
 1476                 break;
 1477 
 1478         case I40E_NVM_WRITE:
 1479                 switch (transaction) {
 1480                 case I40E_NVM_CON:
 1481                         upd_cmd = I40E_NVMUPD_WRITE_CON;
 1482                         break;
 1483                 case I40E_NVM_SNT:
 1484                         upd_cmd = I40E_NVMUPD_WRITE_SNT;
 1485                         break;
 1486                 case I40E_NVM_LCB:
 1487                         upd_cmd = I40E_NVMUPD_WRITE_LCB;
 1488                         break;
 1489                 case I40E_NVM_SA:
 1490                         upd_cmd = I40E_NVMUPD_WRITE_SA;
 1491                         break;
 1492                 case I40E_NVM_ERA:
 1493                         upd_cmd = I40E_NVMUPD_WRITE_ERA;
 1494                         break;
 1495                 case I40E_NVM_CSUM:
 1496                         upd_cmd = I40E_NVMUPD_CSUM_CON;
 1497                         break;
 1498                 case (I40E_NVM_CSUM|I40E_NVM_SA):
 1499                         upd_cmd = I40E_NVMUPD_CSUM_SA;
 1500                         break;
 1501                 case (I40E_NVM_CSUM|I40E_NVM_LCB):
 1502                         upd_cmd = I40E_NVMUPD_CSUM_LCB;
 1503                         break;
 1504                 case I40E_NVM_EXEC:
 1505                         if (module == 0)
 1506                                 upd_cmd = I40E_NVMUPD_EXEC_AQ;
 1507                         break;
 1508                 }
 1509                 break;
 1510         }
 1511 
 1512         return upd_cmd;
 1513 }
 1514 
 1515 /**
 1516  * i40e_nvmupd_exec_aq - Run an AQ command
 1517  * @hw: pointer to hardware structure
 1518  * @cmd: pointer to nvm update command buffer
 1519  * @bytes: pointer to the data buffer
 1520  * @perrno: pointer to return error code
 1521  *
 1522  * cmd structure contains identifiers and data buffer
 1523  **/
 1524 static enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw,
 1525                                                  struct i40e_nvm_access *cmd,
 1526                                                  u8 *bytes, int *perrno)
 1527 {
 1528         struct i40e_asq_cmd_details cmd_details;
 1529         enum i40e_status_code status;
 1530         struct i40e_aq_desc *aq_desc;
 1531         u32 buff_size = 0;
 1532         u8 *buff = NULL;
 1533         u32 aq_desc_len;
 1534         u32 aq_data_len;
 1535 
 1536         i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
 1537         if (cmd->offset == 0xffff)
 1538                 return I40E_SUCCESS;
 1539 
 1540         memset(&cmd_details, 0, sizeof(cmd_details));
 1541         cmd_details.wb_desc = &hw->nvm_wb_desc;
 1542 
 1543         aq_desc_len = sizeof(struct i40e_aq_desc);
 1544         memset(&hw->nvm_wb_desc, 0, aq_desc_len);
 1545 
 1546         /* get the aq descriptor */
 1547         if (cmd->data_size < aq_desc_len) {
 1548                 i40e_debug(hw, I40E_DEBUG_NVM,
 1549                            "NVMUPD: not enough aq desc bytes for exec, size %d < %d\n",
 1550                            cmd->data_size, aq_desc_len);
 1551                 *perrno = -EINVAL;
 1552                 return I40E_ERR_PARAM;
 1553         }
 1554         aq_desc = (struct i40e_aq_desc *)bytes;
 1555 
 1556         /* if data buffer needed, make sure it's ready */
 1557         aq_data_len = cmd->data_size - aq_desc_len;
 1558         buff_size = max(aq_data_len, (u32)LE16_TO_CPU(aq_desc->datalen));
 1559         if (buff_size) {
 1560                 if (!hw->nvm_buff.va) {
 1561                         status = i40e_allocate_virt_mem(hw, &hw->nvm_buff,
 1562                                                         hw->aq.asq_buf_size);
 1563                         if (status)
 1564                                 i40e_debug(hw, I40E_DEBUG_NVM,
 1565                                            "NVMUPD: i40e_allocate_virt_mem for exec buff failed, %d\n",
 1566                                            status);
 1567                 }
 1568 
 1569                 if (hw->nvm_buff.va) {
 1570                         buff = hw->nvm_buff.va;
 1571                         i40e_memcpy(buff, &bytes[aq_desc_len], aq_data_len,
 1572                                 I40E_NONDMA_TO_NONDMA);
 1573                 }
 1574         }
 1575 
 1576         if (cmd->offset)
 1577                 memset(&hw->nvm_aq_event_desc, 0, aq_desc_len);
 1578 
 1579         /* and away we go! */
 1580         status = i40e_asq_send_command(hw, aq_desc, buff,
 1581                                        buff_size, &cmd_details);
 1582         if (status) {
 1583                 i40e_debug(hw, I40E_DEBUG_NVM,
 1584                            "i40e_nvmupd_exec_aq err %s aq_err %s\n",
 1585                            i40e_stat_str(hw, status),
 1586                            i40e_aq_str(hw, hw->aq.asq_last_status));
 1587                 *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
 1588                 return status;
 1589         }
 1590 
 1591         /* should we wait for a followup event? */
 1592         if (cmd->offset) {
 1593                 hw->nvm_wait_opcode = cmd->offset;
 1594                 hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
 1595         }
 1596 
 1597         return status;
 1598 }
 1599 
 1600 /**
 1601  * i40e_nvmupd_get_aq_result - Get the results from the previous exec_aq
 1602  * @hw: pointer to hardware structure
 1603  * @cmd: pointer to nvm update command buffer
 1604  * @bytes: pointer to the data buffer
 1605  * @perrno: pointer to return error code
 1606  *
 1607  * cmd structure contains identifiers and data buffer
 1608  **/
 1609 static enum i40e_status_code i40e_nvmupd_get_aq_result(struct i40e_hw *hw,
 1610                                                     struct i40e_nvm_access *cmd,
 1611                                                     u8 *bytes, int *perrno)
 1612 {
 1613         u32 aq_total_len;
 1614         u32 aq_desc_len;
 1615         int remainder;
 1616         u8 *buff;
 1617 
 1618         i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
 1619 
 1620         aq_desc_len = sizeof(struct i40e_aq_desc);
 1621         aq_total_len = aq_desc_len + LE16_TO_CPU(hw->nvm_wb_desc.datalen);
 1622 
 1623         /* check offset range */
 1624         if (cmd->offset > aq_total_len) {
 1625                 i40e_debug(hw, I40E_DEBUG_NVM, "%s: offset too big %d > %d\n",
 1626                            __func__, cmd->offset, aq_total_len);
 1627                 *perrno = -EINVAL;
 1628                 return I40E_ERR_PARAM;
 1629         }
 1630 
 1631         /* check copylength range */
 1632         if (cmd->data_size > (aq_total_len - cmd->offset)) {
 1633                 int new_len = aq_total_len - cmd->offset;
 1634 
 1635                 i40e_debug(hw, I40E_DEBUG_NVM, "%s: copy length %d too big, trimming to %d\n",
 1636                            __func__, cmd->data_size, new_len);
 1637                 cmd->data_size = new_len;
 1638         }
 1639 
 1640         remainder = cmd->data_size;
 1641         if (cmd->offset < aq_desc_len) {
 1642                 u32 len = aq_desc_len - cmd->offset;
 1643 
 1644                 len = min(len, cmd->data_size);
 1645                 i40e_debug(hw, I40E_DEBUG_NVM, "%s: aq_desc bytes %d to %d\n",
 1646                            __func__, cmd->offset, cmd->offset + len);
 1647 
 1648                 buff = ((u8 *)&hw->nvm_wb_desc) + cmd->offset;
 1649                 i40e_memcpy(bytes, buff, len, I40E_NONDMA_TO_NONDMA);
 1650 
 1651                 bytes += len;
 1652                 remainder -= len;
 1653                 buff = hw->nvm_buff.va;
 1654         } else {
 1655                 buff = (u8 *)hw->nvm_buff.va + (cmd->offset - aq_desc_len);
 1656         }
 1657 
 1658         if (remainder > 0) {
 1659                 int start_byte = buff - (u8 *)hw->nvm_buff.va;
 1660 
 1661                 i40e_debug(hw, I40E_DEBUG_NVM, "%s: databuf bytes %d to %d\n",
 1662                            __func__, start_byte, start_byte + remainder);
 1663                 i40e_memcpy(bytes, buff, remainder, I40E_NONDMA_TO_NONDMA);
 1664         }
 1665 
 1666         return I40E_SUCCESS;
 1667 }
 1668 
 1669 /**
 1670  * i40e_nvmupd_get_aq_event - Get the Admin Queue event from previous exec_aq
 1671  * @hw: pointer to hardware structure
 1672  * @cmd: pointer to nvm update command buffer
 1673  * @bytes: pointer to the data buffer
 1674  * @perrno: pointer to return error code
 1675  *
 1676  * cmd structure contains identifiers and data buffer
 1677  **/
 1678 static enum i40e_status_code i40e_nvmupd_get_aq_event(struct i40e_hw *hw,
 1679                                                     struct i40e_nvm_access *cmd,
 1680                                                     u8 *bytes, int *perrno)
 1681 {
 1682         u32 aq_total_len;
 1683         u32 aq_desc_len;
 1684 
 1685         i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
 1686 
 1687         aq_desc_len = sizeof(struct i40e_aq_desc);
 1688         aq_total_len = aq_desc_len + LE16_TO_CPU(hw->nvm_aq_event_desc.datalen);
 1689 
 1690         /* check copylength range */
 1691         if (cmd->data_size > aq_total_len) {
 1692                 i40e_debug(hw, I40E_DEBUG_NVM,
 1693                            "%s: copy length %d too big, trimming to %d\n",
 1694                            __func__, cmd->data_size, aq_total_len);
 1695                 cmd->data_size = aq_total_len;
 1696         }
 1697 
 1698         i40e_memcpy(bytes, &hw->nvm_aq_event_desc, cmd->data_size,
 1699                     I40E_NONDMA_TO_NONDMA);
 1700 
 1701         return I40E_SUCCESS;
 1702 }
 1703 
 1704 /**
 1705  * i40e_nvmupd_nvm_read - Read NVM
 1706  * @hw: pointer to hardware structure
 1707  * @cmd: pointer to nvm update command buffer
 1708  * @bytes: pointer to the data buffer
 1709  * @perrno: pointer to return error code
 1710  *
 1711  * cmd structure contains identifiers and data buffer
 1712  **/
 1713 static enum i40e_status_code i40e_nvmupd_nvm_read(struct i40e_hw *hw,
 1714                                                   struct i40e_nvm_access *cmd,
 1715                                                   u8 *bytes, int *perrno)
 1716 {
 1717         struct i40e_asq_cmd_details cmd_details;
 1718         enum i40e_status_code status;
 1719         u8 module, transaction;
 1720         bool last;
 1721 
 1722         transaction = i40e_nvmupd_get_transaction(cmd->config);
 1723         module = i40e_nvmupd_get_module(cmd->config);
 1724         last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA);
 1725 
 1726         memset(&cmd_details, 0, sizeof(cmd_details));
 1727         cmd_details.wb_desc = &hw->nvm_wb_desc;
 1728 
 1729         status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
 1730                                   bytes, last, &cmd_details);
 1731         if (status) {
 1732                 i40e_debug(hw, I40E_DEBUG_NVM,
 1733                            "i40e_nvmupd_nvm_read mod 0x%x  off 0x%x  len 0x%x\n",
 1734                            module, cmd->offset, cmd->data_size);
 1735                 i40e_debug(hw, I40E_DEBUG_NVM,
 1736                            "i40e_nvmupd_nvm_read status %d aq %d\n",
 1737                            status, hw->aq.asq_last_status);
 1738                 *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
 1739         }
 1740 
 1741         return status;
 1742 }
 1743 
 1744 /**
 1745  * i40e_nvmupd_nvm_erase - Erase an NVM module
 1746  * @hw: pointer to hardware structure
 1747  * @cmd: pointer to nvm update command buffer
 1748  * @perrno: pointer to return error code
 1749  *
 1750  * module, offset, data_size and data are in cmd structure
 1751  **/
 1752 static enum i40e_status_code i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
 1753                                                    struct i40e_nvm_access *cmd,
 1754                                                    int *perrno)
 1755 {
 1756         enum i40e_status_code status = I40E_SUCCESS;
 1757         struct i40e_asq_cmd_details cmd_details;
 1758         u8 module, transaction;
 1759         bool last;
 1760 
 1761         transaction = i40e_nvmupd_get_transaction(cmd->config);
 1762         module = i40e_nvmupd_get_module(cmd->config);
 1763         last = (transaction & I40E_NVM_LCB);
 1764 
 1765         memset(&cmd_details, 0, sizeof(cmd_details));
 1766         cmd_details.wb_desc = &hw->nvm_wb_desc;
 1767 
 1768         status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
 1769                                    last, &cmd_details);
 1770         if (status) {
 1771                 i40e_debug(hw, I40E_DEBUG_NVM,
 1772                            "i40e_nvmupd_nvm_erase mod 0x%x  off 0x%x len 0x%x\n",
 1773                            module, cmd->offset, cmd->data_size);
 1774                 i40e_debug(hw, I40E_DEBUG_NVM,
 1775                            "i40e_nvmupd_nvm_erase status %d aq %d\n",
 1776                            status, hw->aq.asq_last_status);
 1777                 *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
 1778         }
 1779 
 1780         return status;
 1781 }
 1782 
 1783 /**
 1784  * i40e_nvmupd_nvm_write - Write NVM
 1785  * @hw: pointer to hardware structure
 1786  * @cmd: pointer to nvm update command buffer
 1787  * @bytes: pointer to the data buffer
 1788  * @perrno: pointer to return error code
 1789  *
 1790  * module, offset, data_size and data are in cmd structure
 1791  **/
 1792 static enum i40e_status_code i40e_nvmupd_nvm_write(struct i40e_hw *hw,
 1793                                                    struct i40e_nvm_access *cmd,
 1794                                                    u8 *bytes, int *perrno)
 1795 {
 1796         enum i40e_status_code status = I40E_SUCCESS;
 1797         struct i40e_asq_cmd_details cmd_details;
 1798         u8 module, transaction;
 1799         u8 preservation_flags;
 1800         bool last;
 1801 
 1802         transaction = i40e_nvmupd_get_transaction(cmd->config);
 1803         module = i40e_nvmupd_get_module(cmd->config);
 1804         last = (transaction & I40E_NVM_LCB);
 1805         preservation_flags = i40e_nvmupd_get_preservation_flags(cmd->config);
 1806 
 1807         memset(&cmd_details, 0, sizeof(cmd_details));
 1808         cmd_details.wb_desc = &hw->nvm_wb_desc;
 1809 
 1810         status = i40e_aq_update_nvm(hw, module, cmd->offset,
 1811                                     (u16)cmd->data_size, bytes, last,
 1812                                     preservation_flags, &cmd_details);
 1813         if (status) {
 1814                 i40e_debug(hw, I40E_DEBUG_NVM,
 1815                            "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n",
 1816                            module, cmd->offset, cmd->data_size);
 1817                 i40e_debug(hw, I40E_DEBUG_NVM,
 1818                            "i40e_nvmupd_nvm_write status %d aq %d\n",
 1819                            status, hw->aq.asq_last_status);
 1820                 *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
 1821         }
 1822 
 1823         return status;
 1824 }

Cache object: 89ea7b4172080beee4c96bdfad504656


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.