OSDN Git Service

ixgbe: extend firmware version support
authorPaul Greenwalt <paul.greenwalt@intel.com>
Fri, 27 Oct 2017 14:32:40 +0000 (10:32 -0400)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Tue, 9 Jan 2018 16:36:34 +0000 (08:36 -0800)
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.greenwalt@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h

index 8611763..08fb589 100644 (file)
@@ -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;
index 9bef255..1948e42 100644 (file)
@@ -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;
index a01409e..4d4c023 100644 (file)
@@ -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,
index 0aaf70b..3bcf58b 100644 (file)
@@ -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));
index a23c2b5..6e6b3c1 100644 (file)
@@ -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) {
index 07d929b..cfe0289 100644 (file)
@@ -10235,6 +10235,41 @@ bool ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
 }
 
 /**
+ * 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
  * @ent: entry in ixgbe_pci_tbl
@@ -10570,8 +10605,7 @@ skip_sriov:
        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))
index ffa0ee5..21eb79a 100644 (file)
@@ -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