e1000e: check return code from NVM accesses and fix bank detection
[safe/jmp/linux-2.6] / drivers / net / e1000e / ich8lan.c
index e358a77..92f2ace 100644 (file)
@@ -27,6 +27,7 @@
 *******************************************************************************/
 
 /*
+ * 82562G 10/100 Network Connection
  * 82562G-2 10/100 Network Connection
  * 82562GT 10/100 Network Connection
  * 82562GT-2 10/100 Network Connection
  * 82566DM Gigabit Network Connection
  * 82566MC Gigabit Network Connection
  * 82566MM Gigabit Network Connection
+ * 82567LM Gigabit Network Connection
+ * 82567LF Gigabit Network Connection
+ * 82567V Gigabit Network Connection
+ * 82567LM-2 Gigabit Network Connection
+ * 82567LF-2 Gigabit Network Connection
+ * 82567V-2 Gigabit Network Connection
+ * 82567LF-3 Gigabit Network Connection
+ * 82567LM-3 Gigabit Network Connection
+ * 82567LM-4 Gigabit Network Connection
  */
 
 #include <linux/netdevice.h>
@@ -52,6 +62,7 @@
 #define ICH_FLASH_HSFCTL               0x0006
 #define ICH_FLASH_FADDR                        0x0008
 #define ICH_FLASH_FDATA0               0x0010
+#define ICH_FLASH_PR0                  0x0074
 
 #define ICH_FLASH_READ_COMMAND_TIMEOUT 500
 #define ICH_FLASH_WRITE_COMMAND_TIMEOUT        500
@@ -83,6 +94,8 @@
 
 #define E1000_ICH_NVM_SIG_WORD         0x13
 #define E1000_ICH_NVM_SIG_MASK         0xC000
+#define E1000_ICH_NVM_VALID_SIG_MASK    0xC0
+#define E1000_ICH_NVM_SIG_VALUE         0x80
 
 #define E1000_ICH8_LAN_INIT_TIMEOUT    1500
 
@@ -144,6 +157,19 @@ union ich8_hws_flash_regacc {
        u16 regval;
 };
 
+/* ICH Flash Protected Region */
+union ich8_flash_protected_range {
+       struct ich8_pr {
+               u32 base:13;     /* 0:12 Protected Range Base */
+               u32 reserved1:2; /* 13:14 Reserved */
+               u32 rpe:1;       /* 15 Read Protection Enable */
+               u32 limit:13;    /* 16:28 Protected Range Limit */
+               u32 reserved2:2; /* 29:30 Reserved */
+               u32 wpe:1;       /* 31 Write Protection Enable */
+       } range;
+       u32 regval;
+};
+
 static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
 static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
@@ -151,12 +177,15 @@ static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw);
 static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
 static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
                                                u32 offset, u8 byte);
+static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+                                        u8 *data);
 static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
                                         u16 *data);
 static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
                                         u8 size, u16 *data);
 static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
 static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
+static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
 
 static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
 {
@@ -198,6 +227,19 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
        phy->addr                       = 1;
        phy->reset_delay_us             = 100;
 
+       /*
+        * We may need to do this twice - once for IGP and if that fails,
+        * we'll set BM func pointers and try again
+        */
+       ret_val = e1000e_determine_phy_address(hw);
+       if (ret_val) {
+               hw->phy.ops.write_phy_reg = e1000e_write_phy_reg_bm;
+               hw->phy.ops.read_phy_reg  = e1000e_read_phy_reg_bm;
+               ret_val = e1000e_determine_phy_address(hw);
+               if (ret_val)
+                       return ret_val;
+       }
+
        phy->id = 0;
        while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
               (i++ < 100)) {
@@ -219,6 +261,13 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
                phy->type = e1000_phy_ife;
                phy->autoneg_mask = E1000_ALL_NOT_GIG;
                break;
+       case BME1000_E_PHY_ID:
+               phy->type = e1000_phy_bm;
+               phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+               hw->phy.ops.read_phy_reg = e1000e_read_phy_reg_bm;
+               hw->phy.ops.write_phy_reg = e1000e_write_phy_reg_bm;
+               hw->phy.ops.commit_phy = e1000e_phy_sw_reset;
+               break;
        default:
                return -E1000_ERR_PHY;
                break;
@@ -316,7 +365,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
        return 0;
 }
 
-static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter)
+static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
        s32 rc;
@@ -340,6 +389,9 @@ static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter)
        return 0;
 }
 
+static DEFINE_MUTEX(nvm_mutex);
+static pid_t nvm_owner = -1;
+
 /**
  *  e1000_acquire_swflag_ich8lan - Acquire software control flag
  *  @hw: pointer to the HW structure
@@ -353,6 +405,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
        u32 extcnf_ctrl;
        u32 timeout = PHY_CFG_TIMEOUT;
 
+       might_sleep();
+
+       if (!mutex_trylock(&nvm_mutex)) {
+               WARN(1, KERN_ERR "e1000e mutex contention. Owned by pid %d\n",
+                    nvm_owner);
+               mutex_lock(&nvm_mutex);
+       }
+       nvm_owner = current->pid;
+
        while (timeout) {
                extcnf_ctrl = er32(EXTCNF_CTRL);
                extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
@@ -367,6 +428,10 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
 
        if (!timeout) {
                hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
+               extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+               ew32(EXTCNF_CTRL, extcnf_ctrl);
+               nvm_owner = -1;
+               mutex_unlock(&nvm_mutex);
                return -E1000_ERR_CONFIG;
        }
 
@@ -388,6 +453,25 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
        extcnf_ctrl = er32(EXTCNF_CTRL);
        extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
        ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+       nvm_owner = -1;
+       mutex_unlock(&nvm_mutex);
+}
+
+/**
+ *  e1000_check_mng_mode_ich8lan - Checks management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks if the adapter has manageability enabled.
+ *  This is a function pointer entry point only called by read/write
+ *  routines for the PHY and NVM parts.
+ **/
+static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
+{
+       u32 fwsm = er32(FWSM);
+
+       return (fwsm & E1000_FWSM_MODE_MASK) ==
+               (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
 }
 
 /**
@@ -664,6 +748,7 @@ static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
                return e1000_get_phy_info_ife_ich8lan(hw);
                break;
        case e1000_phy_igp_3:
+       case e1000_phy_bm:
                return e1000e_get_phy_info_igp(hw);
                break;
        default:
@@ -728,7 +813,7 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
        s32 ret_val = 0;
        u16 data;
 
-       if (phy->type != e1000_phy_igp_3)
+       if (phy->type == e1000_phy_ife)
                return ret_val;
 
        phy_ctrl = er32(PHY_CTRL);
@@ -870,6 +955,73 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
 }
 
 /**
+ *  e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
+ *  @hw: pointer to the HW structure
+ *  @bank:  pointer to the variable that returns the active bank
+ *
+ *  Reads signature byte from the NVM using the flash access registers.
+ *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
+ **/
+static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
+{
+       u32 eecd;
+       struct e1000_nvm_info *nvm = &hw->nvm;
+       u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
+       u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
+       u8 sig_byte = 0;
+       s32 ret_val = 0;
+
+       switch (hw->mac.type) {
+       case e1000_ich8lan:
+       case e1000_ich9lan:
+               eecd = er32(EECD);
+               if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
+                   E1000_EECD_SEC1VAL_VALID_MASK) {
+                       if (eecd & E1000_EECD_SEC1VAL)
+                               *bank = 1;
+                       else
+                               *bank = 0;
+
+                       return 0;
+               }
+               hw_dbg(hw, "Unable to determine valid NVM bank via EEC - "
+                      "reading flash signature\n");
+               /* fall-thru */
+       default:
+               /* set bank to 0 in case flash read fails */
+               *bank = 0;
+
+               /* Check bank 0 */
+               ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
+                                                       &sig_byte);
+               if (ret_val)
+                       return ret_val;
+               if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+                   E1000_ICH_NVM_SIG_VALUE) {
+                       *bank = 0;
+                       return 0;
+               }
+
+               /* Check bank 1 */
+               ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
+                                                       bank1_offset,
+                                                       &sig_byte);
+               if (ret_val)
+                       return ret_val;
+               if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+                   E1000_ICH_NVM_SIG_VALUE) {
+                       *bank = 1;
+                       return 0;
+               }
+
+               hw_dbg(hw, "ERROR: No valid NVM bank present\n");
+               return -E1000_ERR_NVM;
+       }
+
+       return 0;
+}
+
+/**
  *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
  *  @hw: pointer to the HW structure
  *  @offset: The offset (in bytes) of the word(s) to read.
@@ -885,6 +1037,7 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
        struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
        u32 act_offset;
        s32 ret_val;
+       u32 bank = 0;
        u16 i, word;
 
        if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
@@ -895,12 +1048,13 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
 
        ret_val = e1000_acquire_swflag_ich8lan(hw);
        if (ret_val)
-               return ret_val;
+               goto out;
+
+       ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+       if (ret_val)
+               goto release;
 
-       /* Start with the bank offset, then add the relative offset. */
-       act_offset = (er32(EECD) & E1000_EECD_SEC1VAL)
-                    ? nvm->flash_bank_size
-                    : 0;
+       act_offset = (bank) ? nvm->flash_bank_size : 0;
        act_offset += offset;
 
        for (i = 0; i < words; i++) {
@@ -917,8 +1071,13 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
                }
        }
 
+release:
        e1000_release_swflag_ich8lan(hw);
 
+out:
+       if (ret_val)
+               hw_dbg(hw, "NVM read error: %d\n", ret_val);
+
        return ret_val;
 }
 
@@ -1048,6 +1207,29 @@ static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
 }
 
 /**
+ *  e1000_read_flash_byte_ich8lan - Read byte from flash
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset of the byte to read.
+ *  @data: Pointer to a byte to store the value read.
+ *
+ *  Reads a single byte from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+                                        u8 *data)
+{
+       s32 ret_val;
+       u16 word = 0;
+
+       ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
+       if (ret_val)
+               return ret_val;
+
+       *data = (u8)word;
+
+       return 0;
+}
+
+/**
  *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
  *  @hw: pointer to the HW structure
  *  @offset: The offset (in bytes) of the byte or word to read.
@@ -1178,34 +1360,48 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
 {
        struct e1000_nvm_info *nvm = &hw->nvm;
        struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-       u32 i, act_offset, new_bank_offset, old_bank_offset;
+       u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
        s32 ret_val;
        u16 data;
 
        ret_val = e1000e_update_nvm_checksum_generic(hw);
        if (ret_val)
-               return ret_val;
+               goto out;
 
        if (nvm->type != e1000_nvm_flash_sw)
-               return ret_val;
+               goto out;
 
        ret_val = e1000_acquire_swflag_ich8lan(hw);
        if (ret_val)
-               return ret_val;
+               goto out;
 
        /*
         * We're writing to the opposite bank so if we're on bank 1,
         * write to bank 0 etc.  We also need to erase the segment that
         * is going to be written
         */
-       if (!(er32(EECD) & E1000_EECD_SEC1VAL)) {
+       ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+       if (ret_val) {
+               e1000_release_swflag_ich8lan(hw);
+               goto out;
+       }
+
+       if (bank == 0) {
                new_bank_offset = nvm->flash_bank_size;
                old_bank_offset = 0;
-               e1000_erase_flash_bank_ich8lan(hw, 1);
+               ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
+               if (ret_val) {
+                       e1000_release_swflag_ich8lan(hw);
+                       goto out;
+               }
        } else {
                old_bank_offset = nvm->flash_bank_size;
                new_bank_offset = 0;
-               e1000_erase_flash_bank_ich8lan(hw, 0);
+               ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
+               if (ret_val) {
+                       e1000_release_swflag_ich8lan(hw);
+                       goto out;
+               }
        }
 
        for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
@@ -1217,9 +1413,11 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
                if (dev_spec->shadow_ram[i].modified) {
                        data = dev_spec->shadow_ram[i].value;
                } else {
-                       e1000_read_flash_word_ich8lan(hw,
-                                                     i + old_bank_offset,
-                                                     &data);
+                       ret_val = e1000_read_flash_word_ich8lan(hw, i +
+                                                               old_bank_offset,
+                                                               &data);
+                       if (ret_val)
+                               break;
                }
 
                /*
@@ -1257,9 +1455,10 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
         * programming failed.
         */
        if (ret_val) {
+               /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
                hw_dbg(hw, "Flash commit failed.\n");
                e1000_release_swflag_ich8lan(hw);
-               return ret_val;
+               goto out;
        }
 
        /*
@@ -1269,14 +1468,18 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
         * and we need to change bit 14 to 0b
         */
        act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
-       e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+       ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+       if (ret_val) {
+               e1000_release_swflag_ich8lan(hw);
+               goto out;
+       }
        data &= 0xBFFF;
        ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
                                                       act_offset * 2 + 1,
                                                       (u8)(data >> 8));
        if (ret_val) {
                e1000_release_swflag_ich8lan(hw);
-               return ret_val;
+               goto out;
        }
 
        /*
@@ -1289,7 +1492,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
        ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
        if (ret_val) {
                e1000_release_swflag_ich8lan(hw);
-               return ret_val;
+               goto out;
        }
 
        /* Great!  Everything worked, we can now clear the cached entries. */
@@ -1307,6 +1510,10 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
        e1000e_reload_nvm(hw);
        msleep(10);
 
+out:
+       if (ret_val)
+               hw_dbg(hw, "NVM update error: %d\n", ret_val);
+
        return ret_val;
 }
 
@@ -1347,6 +1554,49 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000e_write_protect_nvm_ich8lan - Make the NVM read-only
+ *  @hw: pointer to the HW structure
+ *
+ *  To prevent malicious write/erase of the NVM, set it to be read-only
+ *  so that the hardware ignores all write/erase cycles of the NVM via
+ *  the flash control registers.  The shadow-ram copy of the NVM will
+ *  still be updated, however any updates to this copy will not stick
+ *  across driver reloads.
+ **/
+void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
+{
+       union ich8_flash_protected_range pr0;
+       union ich8_hws_flash_status hsfsts;
+       u32 gfpreg;
+       s32 ret_val;
+
+       ret_val = e1000_acquire_swflag_ich8lan(hw);
+       if (ret_val)
+               return;
+
+       gfpreg = er32flash(ICH_FLASH_GFPREG);
+
+       /* Write-protect GbE Sector of NVM */
+       pr0.regval = er32flash(ICH_FLASH_PR0);
+       pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK;
+       pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK);
+       pr0.range.wpe = true;
+       ew32flash(ICH_FLASH_PR0, pr0.regval);
+
+       /*
+        * Lock down a subset of GbE Flash Control Registers, e.g.
+        * PR0 to prevent the write-protection from being lifted.
+        * Once FLOCKDN is set, the registers protected by it cannot
+        * be written until FLOCKDN is cleared by a hardware reset.
+        */
+       hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+       hsfsts.hsf_status.flockdn = true;
+       ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+
+       e1000_release_swflag_ich8lan(hw);
+}
+
+/**
  *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
  *  @hw: pointer to the HW structure
  *  @offset: The offset (in bytes) of the byte/word to read.
@@ -1689,10 +1939,13 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
                ctrl |= E1000_CTRL_PHY_RST;
        }
        ret_val = e1000_acquire_swflag_ich8lan(hw);
-       hw_dbg(hw, "Issuing a global reset to ich8lan");
+       hw_dbg(hw, "Issuing a global reset to ich8lan\n");
        ew32(CTRL, (ctrl | E1000_CTRL_RST));
        msleep(20);
 
+       /* release the swflag because it is not reset by hardware reset */
+       e1000_release_swflag_ich8lan(hw);
+
        ret_val = e1000e_get_auto_rd_done(hw);
        if (ret_val) {
                /*
@@ -1753,18 +2006,18 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
        ret_val = e1000_setup_link_ich8lan(hw);
 
        /* Set the transmit descriptor write-back policy for both queues */
-       txdctl = er32(TXDCTL);
+       txdctl = er32(TXDCTL(0));
        txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
                 E1000_TXDCTL_FULL_TX_DESC_WB;
        txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
                 E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
-       ew32(TXDCTL, txdctl);
-       txdctl = er32(TXDCTL1);
+       ew32(TXDCTL(0), txdctl);
+       txdctl = er32(TXDCTL(1));
        txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
                 E1000_TXDCTL_FULL_TX_DESC_WB;
        txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
                 E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
-       ew32(TXDCTL1, txdctl);
+       ew32(TXDCTL(1), txdctl);
 
        /*
         * ICH8 has opposite polarity of no_snoop bits.
@@ -1807,30 +2060,30 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
        ew32(CTRL_EXT, reg);
 
        /* Transmit Descriptor Control 0 */
-       reg = er32(TXDCTL);
+       reg = er32(TXDCTL(0));
        reg |= (1 << 22);
-       ew32(TXDCTL, reg);
+       ew32(TXDCTL(0), reg);
 
        /* Transmit Descriptor Control 1 */
-       reg = er32(TXDCTL1);
+       reg = er32(TXDCTL(1));
        reg |= (1 << 22);
-       ew32(TXDCTL1, reg);
+       ew32(TXDCTL(1), reg);
 
        /* Transmit Arbitration Control 0 */
-       reg = er32(TARC0);
+       reg = er32(TARC(0));
        if (hw->mac.type == e1000_ich8lan)
                reg |= (1 << 28) | (1 << 29);
        reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
-       ew32(TARC0, reg);
+       ew32(TARC(0), reg);
 
        /* Transmit Arbitration Control 1 */
-       reg = er32(TARC1);
+       reg = er32(TARC(1));
        if (er32(TCTL) & E1000_TCTL_MULR)
                reg &= ~(1 << 28);
        else
                reg |= (1 << 28);
        reg |= (1 << 24) | (1 << 26) | (1 << 30);
-       ew32(TARC1, reg);
+       ew32(TARC(1), reg);
 
        /* Device Status */
        if (hw->mac.type == e1000_ich8lan) {
@@ -1862,12 +2115,17 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
         * the default flow control setting, so we explicitly
         * set it to full.
         */
-       if (hw->fc.type == e1000_fc_default)
-               hw->fc.type = e1000_fc_full;
+       if (hw->fc.requested_mode == e1000_fc_default)
+               hw->fc.requested_mode = e1000_fc_full;
 
-       hw->fc.original_type = hw->fc.type;
+       /*
+        * Save off the requested flow control mode for use later.  Depending
+        * on the link partner's capabilities, we may or may not use this mode.
+        */
+       hw->fc.current_mode = hw->fc.requested_mode;
 
-       hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type);
+       hw_dbg(hw, "After fix-ups FlowControl is now = %x\n",
+               hw->fc.current_mode);
 
        /* Continue to configure the copper link. */
        ret_val = e1000_setup_copper_link_ich8lan(hw);
@@ -1918,8 +2176,35 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
                ret_val = e1000e_copper_link_setup_igp(hw);
                if (ret_val)
                        return ret_val;
+       } else if (hw->phy.type == e1000_phy_bm) {
+               ret_val = e1000e_copper_link_setup_m88(hw);
+               if (ret_val)
+                       return ret_val;
        }
 
+       if (hw->phy.type == e1000_phy_ife) {
+               ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &reg_data);
+               if (ret_val)
+                       return ret_val;
+
+               reg_data &= ~IFE_PMC_AUTO_MDIX;
+
+               switch (hw->phy.mdix) {
+               case 1:
+                       reg_data &= ~IFE_PMC_FORCE_MDIX;
+                       break;
+               case 2:
+                       reg_data |= IFE_PMC_FORCE_MDIX;
+                       break;
+               case 0:
+               default:
+                       reg_data |= IFE_PMC_AUTO_MDIX;
+                       break;
+               }
+               ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, reg_data);
+               if (ret_val)
+                       return ret_val;
+       }
        return e1000e_setup_copper_link(hw);
 }
 
@@ -2127,6 +2412,32 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000e_disable_gig_wol_ich8lan - disable gig during WoL
+ *  @hw: pointer to the HW structure
+ *
+ *  During S0 to Sx transition, it is possible the link remains at gig
+ *  instead of negotiating to a lower speed.  Before going to Sx, set
+ *  'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
+ *  to a lower speed.
+ *
+ *  Should only be called for ICH9 and ICH10 devices.
+ **/
+void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
+{
+       u32 phy_ctrl;
+
+       if ((hw->mac.type == e1000_ich10lan) ||
+           (hw->mac.type == e1000_ich9lan)) {
+               phy_ctrl = er32(PHY_CTRL);
+               phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
+                           E1000_PHY_CTRL_GBE_DISABLE;
+               ew32(PHY_CTRL, phy_ctrl);
+       }
+
+       return;
+}
+
+/**
  *  e1000_cleanup_led_ich8lan - Restore the default LED operation
  *  @hw: pointer to the HW structure
  *
@@ -2174,6 +2485,39 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000_get_cfg_done_ich8lan - Read config done bit
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the management control register for the config done bit for
+ *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
+ *  to read the config done bit, so an error is *ONLY* logged and returns
+ *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
+ *  would not be able to be reset or change link.
+ **/
+static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
+{
+       u32 bank = 0;
+
+       e1000e_get_cfg_done(hw);
+
+       /* If EEPROM is not marked present, init the IGP 3 PHY manually */
+       if (hw->mac.type != e1000_ich10lan) {
+               if (((er32(EECD) & E1000_EECD_PRES) == 0) &&
+                   (hw->phy.type == e1000_phy_igp_3)) {
+                       e1000e_phy_init_script_igp3(hw);
+               }
+       } else {
+               if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
+                       /* Maybe we should do a basic PHY config */
+                       hw_dbg(hw, "EEPROM not present\n");
+                       return -E1000_ERR_CONFIG;
+               }
+       }
+
+       return 0;
+}
+
+/**
  *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
  *  @hw: pointer to the HW structure
  *
@@ -2203,7 +2547,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
 }
 
 static struct e1000_mac_operations ich8_mac_ops = {
-       .mng_mode_enab          = E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+       .check_mng_mode         = e1000_check_mng_mode_ich8lan,
        .check_for_link         = e1000e_check_for_copper_link,
        .cleanup_led            = e1000_cleanup_led_ich8lan,
        .clear_hw_cntrs         = e1000_clear_hw_cntrs_ich8lan,
@@ -2223,7 +2567,7 @@ static struct e1000_phy_operations ich8_phy_ops = {
        .check_reset_block      = e1000_check_reset_block_ich8lan,
        .commit_phy             = NULL,
        .force_speed_duplex     = e1000_phy_force_speed_duplex_ich8lan,
-       .get_cfg_done           = e1000e_get_cfg_done,
+       .get_cfg_done           = e1000_get_cfg_done_ich8lan,
        .get_cable_length       = e1000e_get_cable_length_igp_2,
        .get_phy_info           = e1000_get_phy_info_ich8lan,
        .read_phy_reg           = e1000e_read_phy_reg_igp,
@@ -2247,13 +2591,14 @@ static struct e1000_nvm_operations ich8_nvm_ops = {
 struct e1000_info e1000_ich8_info = {
        .mac                    = e1000_ich8lan,
        .flags                  = FLAG_HAS_WOL
+                                 | FLAG_IS_ICH
                                  | FLAG_RX_CSUM_ENABLED
                                  | FLAG_HAS_CTRLEXT_ON_LOAD
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_FLASH
                                  | FLAG_APME_IN_WUC,
        .pba                    = 8,
-       .get_invariants         = e1000_get_invariants_ich8lan,
+       .get_variants           = e1000_get_variants_ich8lan,
        .mac_ops                = &ich8_mac_ops,
        .phy_ops                = &ich8_phy_ops,
        .nvm_ops                = &ich8_nvm_ops,
@@ -2262,6 +2607,7 @@ struct e1000_info e1000_ich8_info = {
 struct e1000_info e1000_ich9_info = {
        .mac                    = e1000_ich9lan,
        .flags                  = FLAG_HAS_JUMBO_FRAMES
+                                 | FLAG_IS_ICH
                                  | FLAG_HAS_WOL
                                  | FLAG_RX_CSUM_ENABLED
                                  | FLAG_HAS_CTRLEXT_ON_LOAD
@@ -2270,9 +2616,26 @@ struct e1000_info e1000_ich9_info = {
                                  | FLAG_HAS_FLASH
                                  | FLAG_APME_IN_WUC,
        .pba                    = 10,
-       .get_invariants         = e1000_get_invariants_ich8lan,
+       .get_variants           = e1000_get_variants_ich8lan,
        .mac_ops                = &ich8_mac_ops,
        .phy_ops                = &ich8_phy_ops,
        .nvm_ops                = &ich8_nvm_ops,
 };
 
+struct e1000_info e1000_ich10_info = {
+       .mac                    = e1000_ich10lan,
+       .flags                  = FLAG_HAS_JUMBO_FRAMES
+                                 | FLAG_IS_ICH
+                                 | FLAG_HAS_WOL
+                                 | FLAG_RX_CSUM_ENABLED
+                                 | FLAG_HAS_CTRLEXT_ON_LOAD
+                                 | FLAG_HAS_AMT
+                                 | FLAG_HAS_ERT
+                                 | FLAG_HAS_FLASH
+                                 | FLAG_APME_IN_WUC,
+       .pba                    = 10,
+       .get_variants           = e1000_get_variants_ich8lan,
+       .mac_ops                = &ich8_mac_ops,
+       .phy_ops                = &ich8_phy_ops,
+       .nvm_ops                = &ich8_nvm_ops,
+};