net/i40e: fix parsing packet type for NEON
[dpdk.git] / drivers / net / i40e / base / i40e_nvm.c
index 773ccf5..561ed21 100644 (file)
@@ -1,35 +1,8 @@
-/*******************************************************************************
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2001-2020 Intel Corporation
+ */
 
-Copyright (c) 2013 - 2015, Intel Corporation
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
-    this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
-    notice, this list of conditions and the following disclaimer in the
-    documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the Intel Corporation nor the names of its
-    contributors may be used to endorse or promote products derived from
-    this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-***************************************************************************/
+#include <inttypes.h>
 
 #include "i40e_prototype.h"
 
@@ -106,7 +79,7 @@ enum i40e_status_code i40e_acquire_nvm(struct i40e_hw *hw,
 
        if (ret_code)
                i40e_debug(hw, I40E_DEBUG_NVM,
-                          "NVM acquire type %d failed time_left=%llu ret=%d aq_err=%d\n",
+                          "NVM acquire type %d failed time_left=%" PRIu64 " ret=%d aq_err=%d\n",
                           access, time_left, ret_code, hw->aq.asq_last_status);
 
        if (ret_code && time_left) {
@@ -128,7 +101,7 @@ enum i40e_status_code i40e_acquire_nvm(struct i40e_hw *hw,
                if (ret_code != I40E_SUCCESS) {
                        hw->nvm.hw_semaphore_timeout = 0;
                        i40e_debug(hw, I40E_DEBUG_NVM,
-                                  "NVM acquire timed out, wait %llu ms before trying again. status=%d aq_err=%d\n",
+                                  "NVM acquire timed out, wait %" PRIu64 " ms before trying again. status=%d aq_err=%d\n",
                                   time_left, ret_code, hw->aq.asq_last_status);
                }
        }
@@ -366,6 +339,77 @@ enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
        return ret_code;
 }
 
+/**
+ * i40e_read_nvm_module_data - Reads NVM Buffer to specified memory location
+ * @hw: Pointer to the HW structure
+ * @module_ptr: Pointer to module in words with respect to NVM beginning
+ * @module_offset: Offset in words from module start
+ * @data_offset: Offset in words from reading data area start
+ * @words_data_size: Words to read from NVM
+ * @data_ptr: Pointer to memory location where resulting buffer will be stored
+ **/
+enum i40e_status_code
+i40e_read_nvm_module_data(struct i40e_hw *hw, u8 module_ptr, u16 module_offset,
+                         u16 data_offset, u16 words_data_size, u16 *data_ptr)
+{
+       enum i40e_status_code status;
+       u16 specific_ptr = 0;
+       u16 ptr_value = 0;
+       u16 offset = 0;
+
+       if (module_ptr != 0) {
+               status = i40e_read_nvm_word(hw, module_ptr, &ptr_value);
+               if (status != I40E_SUCCESS) {
+                       i40e_debug(hw, I40E_DEBUG_ALL,
+                                  "Reading nvm word failed.Error code: %d.\n",
+                                  status);
+                       return I40E_ERR_NVM;
+               }
+       }
+#define I40E_NVM_INVALID_PTR_VAL 0x7FFF
+#define I40E_NVM_INVALID_VAL 0xFFFF
+
+       /* Pointer not initialized */
+       if (ptr_value == I40E_NVM_INVALID_PTR_VAL ||
+           ptr_value == I40E_NVM_INVALID_VAL) {
+               i40e_debug(hw, I40E_DEBUG_ALL, "Pointer not initialized.\n");
+               return I40E_ERR_BAD_PTR;
+       }
+
+       /* Check whether the module is in SR mapped area or outside */
+       if (ptr_value & I40E_PTR_TYPE) {
+               /* Pointer points outside of the Shared RAM mapped area */
+               i40e_debug(hw, I40E_DEBUG_ALL,
+                          "Reading nvm data failed. Pointer points outside of the Shared RAM mapped area.\n");
+
+               return I40E_ERR_PARAM;
+       } else {
+               /* Read from the Shadow RAM */
+
+               status = i40e_read_nvm_word(hw, ptr_value + module_offset,
+                                           &specific_ptr);
+               if (status != I40E_SUCCESS) {
+                       i40e_debug(hw, I40E_DEBUG_ALL,
+                                  "Reading nvm word failed.Error code: %d.\n",
+                                  status);
+                       return I40E_ERR_NVM;
+               }
+
+               offset = ptr_value + module_offset + specific_ptr +
+                       data_offset;
+
+               status = i40e_read_nvm_buffer(hw, offset, &words_data_size,
+                                             data_ptr);
+               if (status != I40E_SUCCESS) {
+                       i40e_debug(hw, I40E_DEBUG_ALL,
+                                  "Reading nvm buffer failed.Error code: %d.\n",
+                                  status);
+               }
+       }
+
+       return status;
+}
+
 /**
  * i40e_read_nvm_buffer_srctl - Reads Shadow RAM buffer via SRCTL register
  * @hw: pointer to the HW structure
@@ -790,6 +834,9 @@ STATIC enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw,
 STATIC enum i40e_status_code i40e_nvmupd_get_aq_result(struct i40e_hw *hw,
                                                    struct i40e_nvm_access *cmd,
                                                    u8 *bytes, int *perrno);
+STATIC enum i40e_status_code i40e_nvmupd_get_aq_event(struct i40e_hw *hw,
+                                                   struct i40e_nvm_access *cmd,
+                                                   u8 *bytes, int *perrno);
 STATIC INLINE u8 i40e_nvmupd_get_module(u32 val)
 {
        return (u8)(val & I40E_NVM_MOD_PNT_MASK);
@@ -822,6 +869,8 @@ STATIC const char *i40e_nvm_update_state_str[] = {
        "I40E_NVMUPD_STATUS",
        "I40E_NVMUPD_EXEC_AQ",
        "I40E_NVMUPD_GET_AQ_RESULT",
+       "I40E_NVMUPD_GET_AQ_EVENT",
+       "I40E_NVMUPD_GET_FEATURES",
 };
 
 /**
@@ -884,6 +933,31 @@ enum i40e_status_code i40e_nvmupd_command(struct i40e_hw *hw,
                return I40E_SUCCESS;
        }
 
+       /*
+        * A supported features request returns immediately
+        * rather than going into state machine
+        */
+       if (upd_cmd == I40E_NVMUPD_FEATURES) {
+               if (cmd->data_size < hw->nvmupd_features.size) {
+                       *perrno = -EFAULT;
+                       return I40E_ERR_BUF_TOO_SHORT;
+               }
+
+               /*
+                * If buffer is bigger than i40e_nvmupd_features structure,
+                * make sure the trailing bytes are set to 0x0.
+                */
+               if (cmd->data_size > hw->nvmupd_features.size)
+                       i40e_memset(bytes + hw->nvmupd_features.size, 0x0,
+                                   cmd->data_size - hw->nvmupd_features.size,
+                                   I40E_NONDMA_MEM);
+
+               i40e_memcpy(bytes, &hw->nvmupd_features,
+                           hw->nvmupd_features.size, I40E_NONDMA_MEM);
+
+               return I40E_SUCCESS;
+       }
+
        /* Clear status even it is not read and log */
        if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR) {
                i40e_debug(hw, I40E_DEBUG_NVM,
@@ -919,9 +993,9 @@ enum i40e_status_code i40e_nvmupd_command(struct i40e_hw *hw,
                 * the wait info and return before doing anything else
                 */
                if (cmd->offset == 0xffff) {
-                       i40e_nvmupd_check_wait_event(hw, hw->nvm_wait_opcode);
+                       i40e_nvmupd_clear_wait_state(hw);
                        status = I40E_SUCCESS;
-                       goto exit;
+                       break;
                }
 
                status = I40E_ERR_NOT_READY;
@@ -936,7 +1010,7 @@ enum i40e_status_code i40e_nvmupd_command(struct i40e_hw *hw,
                *perrno = -ESRCH;
                break;
        }
-exit:
+
        i40e_release_spinlock(&hw->aq.arq_spinlock);
        return status;
 }
@@ -1067,6 +1141,10 @@ STATIC enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw,
                status = i40e_nvmupd_get_aq_result(hw, cmd, bytes, perrno);
                break;
 
+       case I40E_NVMUPD_GET_AQ_EVENT:
+               status = i40e_nvmupd_get_aq_event(hw, cmd, bytes, perrno);
+               break;
+
        default:
                i40e_debug(hw, I40E_DEBUG_NVM,
                           "NVMUPD: bad cmd %s in init state\n",
@@ -1224,7 +1302,7 @@ retry:
                gtime = rd32(hw, I40E_GLVFGEN_TIMER);
                if (gtime >= hw->nvm.hw_semaphore_timeout) {
                        i40e_debug(hw, I40E_DEBUG_ALL,
-                                  "NVMUPD: write semaphore expired (%d >= %lld), retrying\n",
+                                  "NVMUPD: write semaphore expired (%d >= %" PRIu64 "), retrying\n",
                                   gtime, hw->nvm.hw_semaphore_timeout);
                        i40e_release_nvm(hw);
                        status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
@@ -1245,39 +1323,55 @@ retry:
 }
 
 /**
- * i40e_nvmupd_check_wait_event - handle NVM update operation events
+ * i40e_nvmupd_clear_wait_state - clear wait state on hw
  * @hw: pointer to the hardware structure
- * @opcode: the event that just happened
  **/
-void i40e_nvmupd_check_wait_event(struct i40e_hw *hw, u16 opcode)
+void i40e_nvmupd_clear_wait_state(struct i40e_hw *hw)
 {
-       if (opcode == hw->nvm_wait_opcode) {
+       i40e_debug(hw, I40E_DEBUG_NVM,
+                  "NVMUPD: clearing wait on opcode 0x%04x\n",
+                  hw->nvm_wait_opcode);
 
-               i40e_debug(hw, I40E_DEBUG_NVM,
-                          "NVMUPD: clearing wait on opcode 0x%04x\n", opcode);
-               if (hw->nvm_release_on_done) {
-                       i40e_release_nvm(hw);
-                       hw->nvm_release_on_done = false;
-               }
-               hw->nvm_wait_opcode = 0;
+       if (hw->nvm_release_on_done) {
+               i40e_release_nvm(hw);
+               hw->nvm_release_on_done = false;
+       }
+       hw->nvm_wait_opcode = 0;
 
-               if (hw->aq.arq_last_status) {
-                       hw->nvmupd_state = I40E_NVMUPD_STATE_ERROR;
-                       return;
-               }
+       if (hw->aq.arq_last_status) {
+               hw->nvmupd_state = I40E_NVMUPD_STATE_ERROR;
+               return;
+       }
 
-               switch (hw->nvmupd_state) {
-               case I40E_NVMUPD_STATE_INIT_WAIT:
-                       hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
-                       break;
+       switch (hw->nvmupd_state) {
+       case I40E_NVMUPD_STATE_INIT_WAIT:
+               hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
+               break;
 
-               case I40E_NVMUPD_STATE_WRITE_WAIT:
-                       hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING;
-                       break;
+       case I40E_NVMUPD_STATE_WRITE_WAIT:
+               hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING;
+               break;
 
-               default:
-                       break;
-               }
+       default:
+               break;
+       }
+}
+
+/**
+ * i40e_nvmupd_check_wait_event - handle NVM update operation events
+ * @hw: pointer to the hardware structure
+ * @opcode: the event that just happened
+ * @desc: AdminQ descriptor
+ **/
+void i40e_nvmupd_check_wait_event(struct i40e_hw *hw, u16 opcode,
+                                 struct i40e_aq_desc *desc)
+{
+       u32 aq_desc_len = sizeof(struct i40e_aq_desc);
+
+       if (opcode == hw->nvm_wait_opcode) {
+               i40e_memcpy(&hw->nvm_aq_event_desc, desc,
+                           aq_desc_len, I40E_NONDMA_TO_NONDMA);
+               i40e_nvmupd_clear_wait_state(hw);
        }
 }
 
@@ -1330,10 +1424,23 @@ STATIC enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
                        upd_cmd = I40E_NVMUPD_READ_SA;
                        break;
                case I40E_NVM_EXEC:
-                       if (module == 0xf)
-                               upd_cmd = I40E_NVMUPD_STATUS;
-                       else if (module == 0)
+                       switch (module) {
+                       case I40E_NVM_EXEC_GET_AQ_RESULT:
                                upd_cmd = I40E_NVMUPD_GET_AQ_RESULT;
+                               break;
+                       case I40E_NVM_EXEC_FEATURES:
+                               upd_cmd = I40E_NVMUPD_FEATURES;
+                               break;
+                       case I40E_NVM_EXEC_STATUS:
+                               upd_cmd = I40E_NVMUPD_STATUS;
+                               break;
+                       default:
+                               *perrno = -EFAULT;
+                               return I40E_NVMUPD_INVALID;
+                       }
+                       break;
+               case I40E_NVM_AQE:
+                       upd_cmd = I40E_NVMUPD_GET_AQ_EVENT;
                        break;
                }
                break;
@@ -1397,6 +1504,9 @@ STATIC enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw,
        u32 aq_data_len;
 
        i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
+       if (cmd->offset == 0xffff)
+               return I40E_SUCCESS;
+
        memset(&cmd_details, 0, sizeof(cmd_details));
        cmd_details.wb_desc = &hw->nvm_wb_desc;
 
@@ -1433,6 +1543,9 @@ STATIC enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw,
                }
        }
 
+       if (cmd->offset)
+               memset(&hw->nvm_aq_event_desc, 0, aq_desc_len);
+
        /* and away we go! */
        status = i40e_asq_send_command(hw, aq_desc, buff,
                                       buff_size, &cmd_details);
@@ -1442,6 +1555,7 @@ STATIC enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw,
                           i40e_stat_str(hw, status),
                           i40e_aq_str(hw, hw->aq.asq_last_status));
                *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
+               return status;
        }
 
        /* should we wait for a followup event? */
@@ -1522,6 +1636,41 @@ STATIC enum i40e_status_code i40e_nvmupd_get_aq_result(struct i40e_hw *hw,
        return I40E_SUCCESS;
 }
 
+/**
+ * i40e_nvmupd_get_aq_event - Get the Admin Queue event from previous exec_aq
+ * @hw: pointer to hardware structure
+ * @cmd: pointer to nvm update command buffer
+ * @bytes: pointer to the data buffer
+ * @perrno: pointer to return error code
+ *
+ * cmd structure contains identifiers and data buffer
+ **/
+STATIC enum i40e_status_code i40e_nvmupd_get_aq_event(struct i40e_hw *hw,
+                                                   struct i40e_nvm_access *cmd,
+                                                   u8 *bytes, int *perrno)
+{
+       u32 aq_total_len;
+       u32 aq_desc_len;
+
+       i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
+
+       aq_desc_len = sizeof(struct i40e_aq_desc);
+       aq_total_len = aq_desc_len + LE16_TO_CPU(hw->nvm_aq_event_desc.datalen);
+
+       /* check copylength range */
+       if (cmd->data_size > aq_total_len) {
+               i40e_debug(hw, I40E_DEBUG_NVM,
+                          "%s: copy length %d too big, trimming to %d\n",
+                          __func__, cmd->data_size, aq_total_len);
+               cmd->data_size = aq_total_len;
+       }
+
+       i40e_memcpy(bytes, &hw->nvm_aq_event_desc, cmd->data_size,
+                   I40E_NONDMA_TO_NONDMA);
+
+       return I40E_SUCCESS;
+}
+
 /**
  * i40e_nvmupd_nvm_read - Read NVM
  * @hw: pointer to hardware structure