/* NVM Word Offsets */
 #define NVM_COMPAT                 0x0003
 #define NVM_ID_LED_SETTINGS        0x0004 /* SERDES output amplitude */
+#define NVM_VERSION                0x0005
 #define NVM_INIT_CONTROL2_REG      0x000F
 #define NVM_INIT_CONTROL3_PORT_B   0x0014
 #define NVM_INIT_CONTROL3_PORT_A   0x0024
 #define NVM_LED_1_CFG              0x001C
 #define NVM_LED_0_2_CFG            0x001F
 
+/* NVM version defines */
+#define NVM_ETRACK_WORD            0x0042
+#define NVM_COMB_VER_OFF           0x0083
+#define NVM_COMB_VER_PTR           0x003d
+#define NVM_MAJOR_MASK             0xF000
+#define NVM_MINOR_MASK             0x0FF0
+#define NVM_BUILD_MASK             0x000F
+#define NVM_COMB_VER_MASK          0x00FF
+#define NVM_MAJOR_SHIFT                12
+#define NVM_MINOR_SHIFT                 4
+#define NVM_COMB_VER_SHFT               8
+#define NVM_VER_INVALID            0xFFFF
+#define NVM_ETRACK_SHIFT               16
 
 #define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
 #define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
 
 out:
        return ret_val;
 }
+
+/**
+ *  igb_get_fw_version - Get firmware version information
+ *  @hw: pointer to the HW structure
+ *  @fw_vers: pointer to output structure
+ *
+ *  unsupported MAC types will return all 0 version structure
+ **/
+void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
+{
+       u16 eeprom_verh, eeprom_verl, comb_verh, comb_verl, comb_offset;
+       u16 fw_version;
+
+       memset(fw_vers, 0, sizeof(struct e1000_fw_version));
+
+       switch (hw->mac.type) {
+       case e1000_i211:
+               return;
+       case e1000_82575:
+       case e1000_82576:
+       case e1000_82580:
+       case e1000_i350:
+       case e1000_i210:
+               break;
+       default:
+               return;
+       }
+       /* basic eeprom version numbers */
+       hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version);
+       fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK) >> NVM_MAJOR_SHIFT;
+       fw_vers->eep_minor = (fw_version & NVM_MINOR_MASK);
+
+       /* etrack id */
+       hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verl);
+       hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verh);
+       fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT) | eeprom_verl;
+
+       switch (hw->mac.type) {
+       case e1000_i210:
+       case e1000_i350:
+               /* find combo image version */
+               hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset);
+               if ((comb_offset != 0x0) && (comb_offset != NVM_VER_INVALID)) {
+
+                       hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset
+                                        + 1), 1, &comb_verh);
+                       hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset),
+                                        1, &comb_verl);
+
+                       /* get Option Rom version if it exists and is valid */
+                       if ((comb_verh && comb_verl) &&
+                           ((comb_verh != NVM_VER_INVALID) &&
+                            (comb_verl != NVM_VER_INVALID))) {
+
+                               fw_vers->or_valid = true;
+                               fw_vers->or_major =
+                                       comb_verl >> NVM_COMB_VER_SHFT;
+                               fw_vers->or_build =
+                                       ((comb_verl << NVM_COMB_VER_SHFT)
+                                       | (comb_verh >> NVM_COMB_VER_SHFT));
+                               fw_vers->or_patch =
+                                       comb_verh & NVM_COMB_VER_MASK;
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+       return;
+}
 
 void igb_set_fw_version(struct igb_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
-       u16 eeprom_verh, eeprom_verl, comb_verh, comb_verl, comb_offset;
-       u16 major, build, patch, fw_version;
-       u32 etrack_id;
-
-       hw->nvm.ops.read(hw, 5, 1, &fw_version);
-       if (adapter->hw.mac.type != e1000_i211) {
-               hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verh);
-               hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verl);
-               etrack_id = (eeprom_verh << IGB_ETRACK_SHIFT) | eeprom_verl;
-
-               /* combo image version needs to be found */
-               hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset);
-               if ((comb_offset != 0x0) &&
-                   (comb_offset != IGB_NVM_VER_INVALID)) {
-                       hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset
-                                        + 1), 1, &comb_verh);
-                       hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset),
-                                        1, &comb_verl);
-
-                       /* Only display Option Rom if it exists and is valid */
-                       if ((comb_verh && comb_verl) &&
-                           ((comb_verh != IGB_NVM_VER_INVALID) &&
-                            (comb_verl != IGB_NVM_VER_INVALID))) {
-                               major = comb_verl >> IGB_COMB_VER_SHFT;
-                               build = (comb_verl << IGB_COMB_VER_SHFT) |
-                                       (comb_verh >> IGB_COMB_VER_SHFT);
-                               patch = comb_verh & IGB_COMB_VER_MASK;
-                               snprintf(adapter->fw_version,
-                                        sizeof(adapter->fw_version),
-                                        "%d.%d%d, 0x%08x, %d.%d.%d",
-                                        (fw_version & IGB_MAJOR_MASK) >>
-                                        IGB_MAJOR_SHIFT,
-                                        (fw_version & IGB_MINOR_MASK) >>
-                                        IGB_MINOR_SHIFT,
-                                        (fw_version & IGB_BUILD_MASK),
-                                        etrack_id, major, build, patch);
-                               goto out;
-                       }
-               }
-               snprintf(adapter->fw_version, sizeof(adapter->fw_version),
-                        "%d.%d%d, 0x%08x",
-                        (fw_version & IGB_MAJOR_MASK) >> IGB_MAJOR_SHIFT,
-                        (fw_version & IGB_MINOR_MASK) >> IGB_MINOR_SHIFT,
-                        (fw_version & IGB_BUILD_MASK), etrack_id);
-       } else {
+       struct e1000_fw_version fw;
+
+       igb_get_fw_version(hw, &fw);
+
+       switch (hw->mac.type) {
+       case e1000_i211:
                snprintf(adapter->fw_version, sizeof(adapter->fw_version),
-                        "%d.%d%d",
-                        (fw_version & IGB_MAJOR_MASK) >> IGB_MAJOR_SHIFT,
-                        (fw_version & IGB_MINOR_MASK) >> IGB_MINOR_SHIFT,
-                        (fw_version & IGB_BUILD_MASK));
+                        "%2d.%2d-%d",
+                        fw.invm_major, fw.invm_minor, fw.invm_img_type);
+               break;
+
+       default:
+               /* if option is rom valid, display its version too */
+               if (fw.or_valid) {
+                       snprintf(adapter->fw_version,
+                                sizeof(adapter->fw_version),
+                                "%d.%d, 0x%08x, %d.%d.%d",
+                                fw.eep_major, fw.eep_minor, fw.etrack_id,
+                                fw.or_major, fw.or_build, fw.or_patch);
+               /* no option rom */
+               } else {
+                       snprintf(adapter->fw_version,
+                                sizeof(adapter->fw_version),
+                                "%d.%d, 0x%08x",
+                                fw.eep_major, fw.eep_minor, fw.etrack_id);
+               }
+               break;
        }
-out:
        return;
 }