net/bnxt: support get/set EEPROM
authorSomnath Kotur <somnath.kotur@broadcom.com>
Thu, 28 Sep 2017 21:43:44 +0000 (16:43 -0500)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 6 Oct 2017 00:49:49 +0000 (02:49 +0200)
Add support for get/set_eeprom, get_eeprom_length dev_ops.
Defined the structures required to get/set the eeprom length/data
in hsi_struct_defs hdr file along with implementation.

Signed-off-by: Somnath Kotur <somnath.kotur@broadcom.com>
Signed-off-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
doc/guides/nics/features/bnxt.ini
drivers/net/bnxt/bnxt_ethdev.c
drivers/net/bnxt/bnxt_hwrm.c
drivers/net/bnxt/bnxt_hwrm.h
drivers/net/bnxt/bnxt_nvm_defs.h [new file with mode: 0644]
drivers/net/bnxt/hsi_struct_def_dpdk.h

index dce5d8d..db01c10 100644 (file)
@@ -22,6 +22,7 @@ Tx descriptor status = Y
 Basic stats          = Y
 Extended stats       = Y
 FW version           = Y
+EEPROM dump          = Y
 LED                  = Y
 Linux UIO            = Y
 Linux VFIO           = Y
index 33fc542..4b5ebd8 100644 (file)
@@ -53,6 +53,7 @@
 #include "bnxt_txr.h"
 #include "bnxt_vnic.h"
 #include "hsi_struct_def_dpdk.h"
+#include "bnxt_nvm_defs.h"
 
 #define DRV_MODULE_NAME                "bnxt"
 static const char bnxt_version[] =
@@ -1854,6 +1855,142 @@ bnxt_dev_supported_ptypes_get_op(struct rte_eth_dev *dev)
 }
 
 
+
+static int
+bnxt_get_eeprom_length_op(struct rte_eth_dev *dev)
+{
+       struct bnxt *bp = (struct bnxt *)dev->data->dev_private;
+       int rc;
+       uint32_t dir_entries;
+       uint32_t entry_length;
+
+       RTE_LOG(INFO, PMD, "%s(): %04x:%02x:%02x:%02x\n",
+               __func__, bp->pdev->addr.domain, bp->pdev->addr.bus,
+               bp->pdev->addr.devid, bp->pdev->addr.function);
+
+       rc = bnxt_hwrm_nvm_get_dir_info(bp, &dir_entries, &entry_length);
+       if (rc != 0)
+               return rc;
+
+       return dir_entries * entry_length;
+}
+
+static int
+bnxt_get_eeprom_op(struct rte_eth_dev *dev,
+               struct rte_dev_eeprom_info *in_eeprom)
+{
+       struct bnxt *bp = (struct bnxt *)dev->data->dev_private;
+       uint32_t index;
+       uint32_t offset;
+
+       RTE_LOG(INFO, PMD, "%s(): %04x:%02x:%02x:%02x in_eeprom->offset = %d "
+               "len = %d\n", __func__, bp->pdev->addr.domain,
+               bp->pdev->addr.bus, bp->pdev->addr.devid,
+               bp->pdev->addr.function, in_eeprom->offset, in_eeprom->length);
+
+       if (in_eeprom->offset == 0) /* special offset value to get directory */
+               return bnxt_get_nvram_directory(bp, in_eeprom->length,
+                                               in_eeprom->data);
+
+       index = in_eeprom->offset >> 24;
+       offset = in_eeprom->offset & 0xffffff;
+
+       if (index != 0)
+               return bnxt_hwrm_get_nvram_item(bp, index - 1, offset,
+                                          in_eeprom->length, in_eeprom->data);
+
+       return 0;
+}
+
+static bool bnxt_dir_type_is_ape_bin_format(uint16_t dir_type)
+{
+       switch (dir_type) {
+       case BNX_DIR_TYPE_CHIMP_PATCH:
+       case BNX_DIR_TYPE_BOOTCODE:
+       case BNX_DIR_TYPE_BOOTCODE_2:
+       case BNX_DIR_TYPE_APE_FW:
+       case BNX_DIR_TYPE_APE_PATCH:
+       case BNX_DIR_TYPE_KONG_FW:
+       case BNX_DIR_TYPE_KONG_PATCH:
+       case BNX_DIR_TYPE_BONO_FW:
+       case BNX_DIR_TYPE_BONO_PATCH:
+               return true;
+       }
+
+       return false;
+}
+
+static bool bnxt_dir_type_is_other_exec_format(uint16_t dir_type)
+{
+       switch (dir_type) {
+       case BNX_DIR_TYPE_AVS:
+       case BNX_DIR_TYPE_EXP_ROM_MBA:
+       case BNX_DIR_TYPE_PCIE:
+       case BNX_DIR_TYPE_TSCF_UCODE:
+       case BNX_DIR_TYPE_EXT_PHY:
+       case BNX_DIR_TYPE_CCM:
+       case BNX_DIR_TYPE_ISCSI_BOOT:
+       case BNX_DIR_TYPE_ISCSI_BOOT_IPV6:
+       case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6:
+               return true;
+       }
+
+       return false;
+}
+
+static bool bnxt_dir_type_is_executable(uint16_t dir_type)
+{
+       return bnxt_dir_type_is_ape_bin_format(dir_type) ||
+               bnxt_dir_type_is_other_exec_format(dir_type);
+}
+
+static int
+bnxt_set_eeprom_op(struct rte_eth_dev *dev,
+               struct rte_dev_eeprom_info *in_eeprom)
+{
+       struct bnxt *bp = (struct bnxt *)dev->data->dev_private;
+       uint8_t index, dir_op;
+       uint16_t type, ext, ordinal, attr;
+
+       RTE_LOG(INFO, PMD, "%s(): %04x:%02x:%02x:%02x in_eeprom->offset = %d "
+               "len = %d\n", __func__, bp->pdev->addr.domain,
+               bp->pdev->addr.bus, bp->pdev->addr.devid,
+               bp->pdev->addr.function, in_eeprom->offset, in_eeprom->length);
+
+       if (!BNXT_PF(bp)) {
+               RTE_LOG(ERR, PMD, "NVM write not supported from a VF\n");
+               return -EINVAL;
+       }
+
+       type = in_eeprom->magic >> 16;
+
+       if (type == 0xffff) { /* special value for directory operations */
+               index = in_eeprom->magic & 0xff;
+               dir_op = in_eeprom->magic >> 8;
+               if (index == 0)
+                       return -EINVAL;
+               switch (dir_op) {
+               case 0x0e: /* erase */
+                       if (in_eeprom->offset != ~in_eeprom->magic)
+                               return -EINVAL;
+                       return bnxt_hwrm_erase_nvram_directory(bp, index - 1);
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       /* Create or re-write an NVM item: */
+       if (bnxt_dir_type_is_executable(type) == true)
+               return -EOPNOTSUPP;
+       ext = in_eeprom->magic & 0xffff;
+       ordinal = in_eeprom->offset >> 16;
+       attr = in_eeprom->offset & 0xffff;
+
+       return bnxt_hwrm_flash_nvram(bp, type, ordinal, ext, attr,
+                                    in_eeprom->data, in_eeprom->length);
+       return 0;
+}
+
 /*
  * Initialization
  */
@@ -1908,6 +2045,9 @@ static const struct eth_dev_ops bnxt_dev_ops = {
        .tx_descriptor_status = bnxt_tx_descriptor_status_op,
        .filter_ctrl = bnxt_filter_ctrl_op,
        .dev_supported_ptypes_get = bnxt_dev_supported_ptypes_get_op,
+       .get_eeprom_length    = bnxt_get_eeprom_length_op,
+       .get_eeprom           = bnxt_get_eeprom_op,
+       .set_eeprom           = bnxt_set_eeprom_op,
 };
 
 static bool bnxt_vf_pciid(uint16_t id)
index 7f146d6..d379850 100644 (file)
@@ -2975,6 +2975,167 @@ int bnxt_hwrm_port_led_cfg(struct bnxt *bp, bool led_on)
        return rc;
 }
 
+int bnxt_hwrm_nvm_get_dir_info(struct bnxt *bp, uint32_t *entries,
+                              uint32_t *length)
+{
+       int rc;
+       struct hwrm_nvm_get_dir_info_input req = {0};
+       struct hwrm_nvm_get_dir_info_output *resp = bp->hwrm_cmd_resp_addr;
+
+       HWRM_PREP(req, NVM_GET_DIR_INFO);
+
+       rc = bnxt_hwrm_send_message(bp, &req, sizeof(req));
+
+       HWRM_CHECK_RESULT();
+       HWRM_UNLOCK();
+
+       if (!rc) {
+               *entries = rte_le_to_cpu_32(resp->entries);
+               *length = rte_le_to_cpu_32(resp->entry_length);
+       }
+       return rc;
+}
+
+int bnxt_get_nvram_directory(struct bnxt *bp, uint32_t len, uint8_t *data)
+{
+       int rc;
+       uint32_t dir_entries;
+       uint32_t entry_length;
+       uint8_t *buf;
+       size_t buflen;
+       phys_addr_t dma_handle;
+       struct hwrm_nvm_get_dir_entries_input req = {0};
+       struct hwrm_nvm_get_dir_entries_output *resp = bp->hwrm_cmd_resp_addr;
+
+       rc = bnxt_hwrm_nvm_get_dir_info(bp, &dir_entries, &entry_length);
+       if (rc != 0)
+               return rc;
+
+       *data++ = dir_entries;
+       *data++ = entry_length;
+       len -= 2;
+       memset(data, 0xff, len);
+
+       buflen = dir_entries * entry_length;
+       buf = rte_malloc("nvm_dir", buflen, 0);
+       rte_mem_lock_page(buf);
+       if (buf == NULL)
+               return -ENOMEM;
+       dma_handle = rte_mem_virt2phy(buf);
+       if (dma_handle == 0) {
+               RTE_LOG(ERR, PMD,
+                       "unable to map response address to physical memory\n");
+               return -ENOMEM;
+       }
+       HWRM_PREP(req, NVM_GET_DIR_ENTRIES);
+       req.host_dest_addr = rte_cpu_to_le_64(dma_handle);
+       rc = bnxt_hwrm_send_message(bp, &req, sizeof(req));
+
+       HWRM_CHECK_RESULT();
+       HWRM_UNLOCK();
+
+       if (rc == 0)
+               memcpy(data, buf, len > buflen ? buflen : len);
+
+       rte_free(buf);
+
+       return rc;
+}
+
+int bnxt_hwrm_get_nvram_item(struct bnxt *bp, uint32_t index,
+                            uint32_t offset, uint32_t length,
+                            uint8_t *data)
+{
+       int rc;
+       uint8_t *buf;
+       phys_addr_t dma_handle;
+       struct hwrm_nvm_read_input req = {0};
+       struct hwrm_nvm_read_output *resp = bp->hwrm_cmd_resp_addr;
+
+       buf = rte_malloc("nvm_item", length, 0);
+       rte_mem_lock_page(buf);
+       if (!buf)
+               return -ENOMEM;
+
+       dma_handle = rte_mem_virt2phy(buf);
+       if (dma_handle == 0) {
+               RTE_LOG(ERR, PMD,
+                       "unable to map response address to physical memory\n");
+               return -ENOMEM;
+       }
+       HWRM_PREP(req, NVM_READ);
+       req.host_dest_addr = rte_cpu_to_le_64(dma_handle);
+       req.dir_idx = rte_cpu_to_le_16(index);
+       req.offset = rte_cpu_to_le_32(offset);
+       req.len = rte_cpu_to_le_32(length);
+       rc = bnxt_hwrm_send_message(bp, &req, sizeof(req));
+       HWRM_CHECK_RESULT();
+       HWRM_UNLOCK();
+       if (rc == 0)
+               memcpy(data, buf, length);
+
+       rte_free(buf);
+       return rc;
+}
+
+int bnxt_hwrm_erase_nvram_directory(struct bnxt *bp, uint8_t index)
+{
+       int rc;
+       struct hwrm_nvm_erase_dir_entry_input req = {0};
+       struct hwrm_nvm_erase_dir_entry_output *resp = bp->hwrm_cmd_resp_addr;
+
+       HWRM_PREP(req, NVM_ERASE_DIR_ENTRY);
+       req.dir_idx = rte_cpu_to_le_16(index);
+       rc = bnxt_hwrm_send_message(bp, &req, sizeof(req));
+       HWRM_CHECK_RESULT();
+       HWRM_UNLOCK();
+
+       return rc;
+}
+
+
+int bnxt_hwrm_flash_nvram(struct bnxt *bp, uint16_t dir_type,
+                         uint16_t dir_ordinal, uint16_t dir_ext,
+                         uint16_t dir_attr, const uint8_t *data,
+                         size_t data_len)
+{
+       int rc;
+       struct hwrm_nvm_write_input req = {0};
+       struct hwrm_nvm_write_output *resp = bp->hwrm_cmd_resp_addr;
+       phys_addr_t dma_handle;
+       uint8_t *buf;
+
+       HWRM_PREP(req, NVM_WRITE);
+
+       req.dir_type = rte_cpu_to_le_16(dir_type);
+       req.dir_ordinal = rte_cpu_to_le_16(dir_ordinal);
+       req.dir_ext = rte_cpu_to_le_16(dir_ext);
+       req.dir_attr = rte_cpu_to_le_16(dir_attr);
+       req.dir_data_length = rte_cpu_to_le_32(data_len);
+
+       buf = rte_malloc("nvm_write", data_len, 0);
+       rte_mem_lock_page(buf);
+       if (!buf)
+               return -ENOMEM;
+
+       dma_handle = rte_mem_virt2phy(buf);
+       if (dma_handle == 0) {
+               RTE_LOG(ERR, PMD,
+                       "unable to map response address to physical memory\n");
+               return -ENOMEM;
+       }
+       memcpy(buf, data, data_len);
+       req.host_src_addr = rte_cpu_to_le_64(dma_handle);
+
+       rc = bnxt_hwrm_send_message(bp, &req, sizeof(req));
+
+       HWRM_CHECK_RESULT();
+       HWRM_UNLOCK();
+
+       rte_free(buf);
+       return rc;
+}
+
 static void
 bnxt_vnic_count(struct bnxt_vnic_info *vnic __rte_unused, void *cbdata)
 {
index b41cc5a..85083e6 100644 (file)
@@ -164,4 +164,15 @@ int bnxt_hwrm_set_ntuple_filter(struct bnxt *bp, uint16_t dst_id,
                         struct bnxt_filter_info *filter);
 int bnxt_hwrm_clear_ntuple_filter(struct bnxt *bp,
                                struct bnxt_filter_info *filter);
+int bnxt_get_nvram_directory(struct bnxt *bp, uint32_t len, uint8_t *data);
+int bnxt_hwrm_nvm_get_dir_info(struct bnxt *bp, uint32_t *entries,
+                              uint32_t *length);
+int bnxt_hwrm_get_nvram_item(struct bnxt *bp, uint32_t index,
+                            uint32_t offset, uint32_t length,
+                            uint8_t *data);
+int bnxt_hwrm_erase_nvram_directory(struct bnxt *bp, uint8_t index);
+int bnxt_hwrm_flash_nvram(struct bnxt *bp, uint16_t dir_type,
+                         uint16_t dir_ordinal, uint16_t dir_ext,
+                         uint16_t dir_attr, const uint8_t *data,
+                         size_t data_len);
 #endif
diff --git a/drivers/net/bnxt/bnxt_nvm_defs.h b/drivers/net/bnxt/bnxt_nvm_defs.h
new file mode 100644 (file)
index 0000000..c5ccc9b
--- /dev/null
@@ -0,0 +1,75 @@
+/* Broadcom NetXtreme-C/E network driver.
+ *
+ * Copyright (c) 2014-2016 Broadcom Corporation
+ * Copyright (c) 2016-2017 Broadcom Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _BNXT_NVM_DEFS_H_
+#define _BNXT_NVM_DEFS_H_
+
+enum bnxt_nvm_directory_type {
+       BNX_DIR_TYPE_UNUSED = 0,
+       BNX_DIR_TYPE_PKG_LOG = 1,
+       BNX_DIR_TYPE_UPDATE = 2,
+       BNX_DIR_TYPE_CHIMP_PATCH = 3,
+       BNX_DIR_TYPE_BOOTCODE = 4,
+       BNX_DIR_TYPE_VPD = 5,
+       BNX_DIR_TYPE_EXP_ROM_MBA = 6,
+       BNX_DIR_TYPE_AVS = 7,
+       BNX_DIR_TYPE_PCIE = 8,
+       BNX_DIR_TYPE_PORT_MACRO = 9,
+       BNX_DIR_TYPE_APE_FW = 10,
+       BNX_DIR_TYPE_APE_PATCH = 11,
+       BNX_DIR_TYPE_KONG_FW = 12,
+       BNX_DIR_TYPE_KONG_PATCH = 13,
+       BNX_DIR_TYPE_BONO_FW = 14,
+       BNX_DIR_TYPE_BONO_PATCH = 15,
+       BNX_DIR_TYPE_TANG_FW = 16,
+       BNX_DIR_TYPE_TANG_PATCH = 17,
+       BNX_DIR_TYPE_BOOTCODE_2 = 18,
+       BNX_DIR_TYPE_CCM = 19,
+       BNX_DIR_TYPE_PCI_CFG = 20,
+       BNX_DIR_TYPE_TSCF_UCODE = 21,
+       BNX_DIR_TYPE_ISCSI_BOOT = 22,
+       BNX_DIR_TYPE_ISCSI_BOOT_IPV6 = 24,
+       BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6 = 25,
+       BNX_DIR_TYPE_ISCSI_BOOT_CFG6 = 26,
+       BNX_DIR_TYPE_EXT_PHY = 27,
+       BNX_DIR_TYPE_SHARED_CFG = 40,
+       BNX_DIR_TYPE_PORT_CFG = 41,
+       BNX_DIR_TYPE_FUNC_CFG = 42,
+       BNX_DIR_TYPE_MGMT_CFG = 48,
+       BNX_DIR_TYPE_MGMT_DATA = 49,
+       BNX_DIR_TYPE_MGMT_WEB_DATA = 50,
+       BNX_DIR_TYPE_MGMT_WEB_META = 51,
+       BNX_DIR_TYPE_MGMT_EVENT_LOG = 52,
+       BNX_DIR_TYPE_MGMT_AUDIT_LOG = 53
+};
+
+#define BNX_DIR_ORDINAL_FIRST                  0
+
+#define BNX_DIR_EXT_NONE                       0
+#define BNX_DIR_EXT_INACTIVE                   (1 << 0)
+#define BNX_DIR_EXT_UPDATE                     (1 << 1)
+
+#define BNX_DIR_ATTR_NONE                      0
+#define BNX_DIR_ATTR_NO_CHKSUM                 (1 << 0)
+#define BNX_DIR_ATTR_PROP_STREAM               (1 << 1)
+
+#define BNX_PKG_LOG_MAX_LENGTH                 4096
+
+enum bnxnvm_pkglog_field_index {
+       BNX_PKG_LOG_FIELD_IDX_INSTALLED_TIMESTAMP       = 0,
+       BNX_PKG_LOG_FIELD_IDX_PKG_DESCRIPTION           = 1,
+       BNX_PKG_LOG_FIELD_IDX_PKG_VERSION               = 2,
+       BNX_PKG_LOG_FIELD_IDX_PKG_TIMESTAMP             = 3,
+       BNX_PKG_LOG_FIELD_IDX_PKG_CHECKSUM              = 4,
+       BNX_PKG_LOG_FIELD_IDX_INSTALLED_ITEMS           = 5,
+       BNX_PKG_LOG_FIELD_IDX_INSTALLED_MASK            = 6
+};
+
+#endif                         /* Don't add anything after this line */
index a5f871b..1b35466 100644 (file)
@@ -11315,6 +11315,144 @@ struct hwrm_reject_fwd_resp_output {
         */
 } __attribute__((packed));
 
+/* hwrm_nvm_get_dir_entries */
+/* Input (24 bytes) */
+struct hwrm_nvm_get_dir_entries_input {
+       uint16_t req_type;
+       uint16_t cmpl_ring;
+       uint16_t seq_id;
+       uint16_t target_id;
+       uint64_t resp_addr;
+       uint64_t host_dest_addr;
+} __attribute__((packed));
+
+/* Output (16 bytes) */
+struct hwrm_nvm_get_dir_entries_output {
+       uint16_t error_code;
+       uint16_t req_type;
+       uint16_t seq_id;
+       uint16_t resp_len;
+       uint32_t unused_0;
+       uint8_t unused_1;
+       uint8_t unused_2;
+       uint8_t unused_3;
+       uint8_t valid;
+} __attribute__((packed));
+
+
+/* hwrm_nvm_erase_dir_entry */
+/* Input (24 bytes) */
+struct hwrm_nvm_erase_dir_entry_input {
+       uint16_t req_type;
+       uint16_t cmpl_ring;
+       uint16_t seq_id;
+       uint16_t target_id;
+       uint64_t resp_addr;
+       uint16_t dir_idx;
+       uint16_t unused_0[3];
+};
+
+/* Output (16 bytes) */
+struct hwrm_nvm_erase_dir_entry_output {
+       uint16_t error_code;
+       uint16_t req_type;
+       uint16_t seq_id;
+       uint16_t resp_len;
+       uint32_t unused_0;
+       uint8_t unused_1;
+       uint8_t unused_2;
+       uint8_t unused_3;
+       uint8_t valid;
+};
+
+/* hwrm_nvm_get_dir_info */
+/* Input (16 bytes) */
+struct hwrm_nvm_get_dir_info_input {
+       uint16_t req_type;
+       uint16_t cmpl_ring;
+       uint16_t seq_id;
+       uint16_t target_id;
+       uint64_t resp_addr;
+} __attribute__((packed));
+
+/* Output (24 bytes) */
+struct hwrm_nvm_get_dir_info_output {
+       uint16_t error_code;
+       uint16_t req_type;
+       uint16_t seq_id;
+       uint16_t resp_len;
+       uint32_t entries;
+       uint32_t entry_length;
+       uint32_t unused_0;
+       uint8_t unused_1;
+       uint8_t unused_2;
+       uint8_t unused_3;
+       uint8_t valid;
+} __attribute__((packed));
+
+
+/* hwrm_nvm_write */
+/* Input (48 bytes) */
+struct hwrm_nvm_write_input {
+       uint16_t req_type;
+       uint16_t cmpl_ring;
+       uint16_t seq_id;
+       uint16_t target_id;
+       uint64_t resp_addr;
+       uint64_t host_src_addr;
+       uint16_t dir_type;
+       uint16_t dir_ordinal;
+       uint16_t dir_ext;
+       uint16_t dir_attr;
+       uint32_t dir_data_length;
+       uint16_t option;
+       uint16_t flags;
+       #define NVM_WRITE_REQ_FLAGS_KEEP_ORIG_ACTIVE_IMG            0x1UL
+       uint32_t dir_item_length;
+       uint32_t unused_0;
+};
+
+/* Output (16 bytes) */
+struct hwrm_nvm_write_output {
+       uint16_t error_code;
+       uint16_t req_type;
+       uint16_t seq_id;
+       uint16_t resp_len;
+       uint32_t dir_item_length;
+       uint16_t dir_idx;
+       uint8_t unused_0;
+       uint8_t valid;
+};
+/* hwrm_nvm_read */
+/* Input (40 bytes) */
+struct hwrm_nvm_read_input {
+       uint16_t req_type;
+       uint16_t cmpl_ring;
+       uint16_t seq_id;
+       uint16_t target_id;
+       uint64_t resp_addr;
+       uint64_t host_dest_addr;
+       uint16_t dir_idx;
+       uint8_t unused_0;
+       uint8_t unused_1;
+       uint32_t offset;
+       uint32_t len;
+       uint32_t unused_2;
+} __attribute__((packed));
+
+/* Output (16 bytes) */
+struct hwrm_nvm_read_output {
+       uint16_t error_code;
+       uint16_t req_type;
+       uint16_t seq_id;
+       uint16_t resp_len;
+       uint32_t unused_0;
+       uint8_t unused_1;
+       uint8_t unused_2;
+       uint8_t unused_3;
+       uint8_t valid;
+} __attribute__((packed));
+
 /* Hardware Resource Manager Specification */
 /* Description: This structure is used to specify port description. */
 /*