From: Paul Greenwalt <paul.greenw...@intel.com>

Extend FW version reporting by displaying information from the iSCSI
or OEM block in the EEPROM.

This will allow us to more accurately identify the FW.

Signed-off-by: Paul Greenwalt <paul.greenw...@intel.com>
Tested-by: Andrew Bowers <andrewx.bow...@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirs...@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe.h         |   3 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_common.c  | 112 +++++++++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_common.h  |   6 ++
 drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c |   7 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c    |   7 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c    |  38 +++++++-
 drivers/net/ethernet/intel/ixgbe/ixgbe_type.h    |  39 ++++++++
 7 files changed, 198 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h 
b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 8611763d6129..08fb589399d2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -723,8 +723,7 @@ struct ixgbe_adapter {
 
        u16 bridge_mode;
 
-       u16 eeprom_verh;
-       u16 eeprom_verl;
+       char eeprom_id[NVM_VER_SIZE];
        u16 eeprom_cap;
 
        u32 interrupt_event;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index 9bef255f6a18..1948e4208fb4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -4028,6 +4028,118 @@ s32 ixgbe_init_thermal_sensor_thresh_generic(struct 
ixgbe_hw *hw)
        return 0;
 }
 
+/**
+ *  ixgbe_get_orom_version - Return option ROM from EEPROM
+ *
+ *  @hw: pointer to hardware structure
+ *  @nvm_ver: pointer to output structure
+ *
+ *  if valid option ROM version, nvm_ver->or_valid set to true
+ *  else nvm_ver->or_valid is false.
+ **/
+void ixgbe_get_orom_version(struct ixgbe_hw *hw,
+                           struct ixgbe_nvm_version *nvm_ver)
+{
+       u16 offset, eeprom_cfg_blkh, eeprom_cfg_blkl;
+
+       nvm_ver->or_valid = false;
+       /* Option Rom may or may not be present.  Start with pointer */
+       hw->eeprom.ops.read(hw, NVM_OROM_OFFSET, &offset);
+
+       /* make sure offset is valid */
+       if (offset == 0x0 || offset == NVM_INVALID_PTR)
+               return;
+
+       hw->eeprom.ops.read(hw, offset + NVM_OROM_BLK_HI, &eeprom_cfg_blkh);
+       hw->eeprom.ops.read(hw, offset + NVM_OROM_BLK_LOW, &eeprom_cfg_blkl);
+
+       /* option rom exists and is valid */
+       if ((eeprom_cfg_blkl | eeprom_cfg_blkh) == 0x0 ||
+           eeprom_cfg_blkl == NVM_VER_INVALID ||
+           eeprom_cfg_blkh == NVM_VER_INVALID)
+               return;
+
+       nvm_ver->or_valid = true;
+       nvm_ver->or_major = eeprom_cfg_blkl >> NVM_OROM_SHIFT;
+       nvm_ver->or_build = (eeprom_cfg_blkl << NVM_OROM_SHIFT) |
+                           (eeprom_cfg_blkh >> NVM_OROM_SHIFT);
+       nvm_ver->or_patch = eeprom_cfg_blkh & NVM_OROM_PATCH_MASK;
+}
+
+/**
+ *  ixgbe_get_oem_prod_version Etrack ID from EEPROM
+ *
+ *  @hw: pointer to hardware structure
+ *  @nvm_ver: pointer to output structure
+ *
+ *  if valid OEM product version, nvm_ver->oem_valid set to true
+ *  else nvm_ver->oem_valid is false.
+ **/
+void ixgbe_get_oem_prod_version(struct ixgbe_hw *hw,
+                               struct ixgbe_nvm_version *nvm_ver)
+{
+       u16 rel_num, prod_ver, mod_len, cap, offset;
+
+       nvm_ver->oem_valid = false;
+       hw->eeprom.ops.read(hw, NVM_OEM_PROD_VER_PTR, &offset);
+
+       /* Return is offset to OEM Product Version block is invalid */
+       if (offset == 0x0 && offset == NVM_INVALID_PTR)
+               return;
+
+       /* Read product version block */
+       hw->eeprom.ops.read(hw, offset, &mod_len);
+       hw->eeprom.ops.read(hw, offset + NVM_OEM_PROD_VER_CAP_OFF, &cap);
+
+       /* Return if OEM product version block is invalid */
+       if (mod_len != NVM_OEM_PROD_VER_MOD_LEN ||
+           (cap & NVM_OEM_PROD_VER_CAP_MASK) != 0x0)
+               return;
+
+       hw->eeprom.ops.read(hw, offset + NVM_OEM_PROD_VER_OFF_L, &prod_ver);
+       hw->eeprom.ops.read(hw, offset + NVM_OEM_PROD_VER_OFF_H, &rel_num);
+
+       /* Return if version is invalid */
+       if ((rel_num | prod_ver) == 0x0 ||
+           rel_num == NVM_VER_INVALID || prod_ver == NVM_VER_INVALID)
+               return;
+
+       nvm_ver->oem_major = prod_ver >> NVM_VER_SHIFT;
+       nvm_ver->oem_minor = prod_ver & NVM_VER_MASK;
+       nvm_ver->oem_release = rel_num;
+       nvm_ver->oem_valid = true;
+}
+
+/**
+ *  ixgbe_get_etk_id - Return Etrack ID from EEPROM
+ *
+ *  @hw: pointer to hardware structure
+ *  @nvm_ver: pointer to output structure
+ *
+ *  word read errors will return 0xFFFF
+ **/
+void ixgbe_get_etk_id(struct ixgbe_hw *hw,
+                     struct ixgbe_nvm_version *nvm_ver)
+{
+       u16 etk_id_l, etk_id_h;
+
+       if (hw->eeprom.ops.read(hw, NVM_ETK_OFF_LOW, &etk_id_l))
+               etk_id_l = NVM_VER_INVALID;
+       if (hw->eeprom.ops.read(hw, NVM_ETK_OFF_HI, &etk_id_h))
+               etk_id_h = NVM_VER_INVALID;
+
+       /* The word order for the version format is determined by high order
+        * word bit 15.
+        */
+       if ((etk_id_h & NVM_ETK_VALID) == 0) {
+               nvm_ver->etk_id = etk_id_h;
+               nvm_ver->etk_id |= (etk_id_l << NVM_ETK_SHIFT);
+       } else {
+               nvm_ver->etk_id = etk_id_l;
+               nvm_ver->etk_id |= (etk_id_h << NVM_ETK_SHIFT);
+       }
+}
+
 void ixgbe_disable_rx_generic(struct ixgbe_hw *hw)
 {
        u32 rxctrl;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
index a01409e2e06c..4d4c02366cb3 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
@@ -139,6 +139,12 @@ extern const u32 ixgbe_mvals_8259X[IXGBE_MVALS_IDX_LIMIT];
 
 s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw);
 s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw);
+void ixgbe_get_etk_id(struct ixgbe_hw *hw,
+                     struct ixgbe_nvm_version *nvm_ver);
+void ixgbe_get_oem_prod_version(struct ixgbe_hw *hw,
+                               struct ixgbe_nvm_version *nvm_ver);
+void ixgbe_get_orom_version(struct ixgbe_hw *hw,
+                           struct ixgbe_nvm_version *nvm_ver);
 void ixgbe_disable_rx_generic(struct ixgbe_hw *hw);
 void ixgbe_enable_rx_generic(struct ixgbe_hw *hw);
 s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 0aaf70b3cfcd..3bcf58b27d8b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -1014,16 +1014,13 @@ static void ixgbe_get_drvinfo(struct net_device *netdev,
                              struct ethtool_drvinfo *drvinfo)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
-       u32 nvm_track_id;
 
        strlcpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver));
        strlcpy(drvinfo->version, ixgbe_driver_version,
                sizeof(drvinfo->version));
 
-       nvm_track_id = (adapter->eeprom_verh << 16) |
-                       adapter->eeprom_verl;
-       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "0x%08x",
-                nvm_track_id);
+       strlcpy(drvinfo->fw_version, adapter->eeprom_id,
+               sizeof(drvinfo->fw_version));
 
        strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
                sizeof(drvinfo->bus_info));
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
index a23c2b5411a0..6e6b3c175267 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -1034,11 +1034,8 @@ int ixgbe_fcoe_get_hbainfo(struct net_device *netdev,
                 ixgbe_driver_name,
                 ixgbe_driver_version);
        /* Firmware Version */
-       snprintf(info->firmware_version,
-                sizeof(info->firmware_version),
-                "0x%08x",
-                (adapter->eeprom_verh << 16) |
-                 adapter->eeprom_verl);
+       strlcpy(info->firmware_version, adapter->eeprom_id,
+               sizeof(info->firmware_version));
 
        /* Model */
        if (hw->mac.type == ixgbe_mac_82599EB) {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 07d929bf4b50..cfe02893c875 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -10234,6 +10234,41 @@ bool ixgbe_wol_supported(struct ixgbe_adapter 
*adapter, u16 device_id,
        return false;
 }
 
+/**
+ * ixgbe_set_fw_version - Set FW version
+ * @adapter: the adapter private structure
+ *
+ * This function is used by probe and ethtool to determine the FW version to
+ * format to display. The FW version is taken from the EEPROM/NVM.
+ */
+static void ixgbe_set_fw_version(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct ixgbe_nvm_version nvm_ver;
+
+       ixgbe_get_oem_prod_version(hw, &nvm_ver);
+       if (nvm_ver.oem_valid) {
+               snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
+                        "%x.%x.%x", nvm_ver.oem_major, nvm_ver.oem_minor,
+                        nvm_ver.oem_release);
+               return;
+       }
+
+       ixgbe_get_etk_id(hw, &nvm_ver);
+       ixgbe_get_orom_version(hw, &nvm_ver);
+
+       if (nvm_ver.or_valid) {
+               snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
+                        "0x%08x, %d.%d.%d", nvm_ver.etk_id, nvm_ver.or_major,
+                        nvm_ver.or_build, nvm_ver.or_patch);
+               return;
+       }
+
+       /* Set ETrack ID format */
+       snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
+                "0x%08x", nvm_ver.etk_id);
+}
+
 /**
  * ixgbe_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -10570,8 +10605,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const 
struct pci_device_id *ent)
        device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
 
        /* save off EEPROM version number */
-       hw->eeprom.ops.read(hw, 0x2e, &adapter->eeprom_verh);
-       hw->eeprom.ops.read(hw, 0x2d, &adapter->eeprom_verl);
+       ixgbe_set_fw_version(adapter);
 
        /* pick up the PCI bus settings for reporting later */
        if (ixgbe_pcie_from_parent(hw))
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index ffa0ee5cd0f5..21eb79ae3c30 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -235,6 +235,45 @@ struct ixgbe_thermal_sensor_data {
        struct ixgbe_thermal_diode_data sensor[IXGBE_MAX_SENSORS];
 };
 
+#define NVM_OROM_OFFSET                0x17
+#define NVM_OROM_BLK_LOW       0x83
+#define NVM_OROM_BLK_HI                0x84
+#define NVM_OROM_PATCH_MASK    0xFF
+#define NVM_OROM_SHIFT         8
+
+#define NVM_VER_MASK           0x00FF  /* version mask */
+#define NVM_VER_SHIFT          8       /* version bit shift */
+#define NVM_OEM_PROD_VER_PTR   0x1B /* OEM Product version block pointer */
+#define NVM_OEM_PROD_VER_CAP_OFF 0x1 /* OEM Product version format offset */
+#define NVM_OEM_PROD_VER_OFF_L 0x2  /* OEM Product version offset low */
+#define NVM_OEM_PROD_VER_OFF_H 0x3  /* OEM Product version offset high */
+#define NVM_OEM_PROD_VER_CAP_MASK 0xF /* OEM Product version cap mask */
+#define NVM_OEM_PROD_VER_MOD_LEN 0x3 /* OEM Product version module length */
+#define NVM_ETK_OFF_LOW                0x2D /* version low order word */
+#define NVM_ETK_OFF_HI         0x2E /* version high order word */
+#define NVM_ETK_SHIFT          16   /* high version word shift */
+#define NVM_VER_INVALID                0xFFFF
+#define NVM_ETK_VALID          0x8000
+#define NVM_INVALID_PTR                0xFFFF
+#define NVM_VER_SIZE           32   /* version sting size */
+
+struct ixgbe_nvm_version {
+       u32 etk_id;
+       u8  nvm_major;
+       u16 nvm_minor;
+       u8  nvm_id;
+
+       bool oem_valid;
+       u8   oem_major;
+       u8   oem_minor;
+       u16  oem_release;
+
+       bool or_valid;
+       u8  or_major;
+       u16 or_build;
+       u8  or_patch;
+};
+
 /* Interrupt Registers */
 #define IXGBE_EICR      0x00800
 #define IXGBE_EICS      0x00808
-- 
2.15.1

Reply via email to