qlcnic: fix caching window register
[safe/jmp/linux-2.6] / drivers / net / e1000e / ich8lan.c
index 0ae3955..b2507d9 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2009 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -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
+ * 82577LM Gigabit Network Connection
+ * 82577LC Gigabit Network Connection
+ * 82578DM Gigabit Network Connection
+ * 82578DC Gigabit Network Connection
  */
 
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
 #include "e1000.h"
 
 #define ICH_FLASH_GFPREG               0x0000
@@ -52,6 +61,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
@@ -73,6 +83,8 @@
 
 
 #define E1000_ICH_FWSM_RSPCIPHY        0x00000040 /* Reset PHY on PCI Reset */
+/* FW established a valid mode */
+#define E1000_ICH_FWSM_FW_VALID                0x00008000
 
 #define E1000_ICH_MNG_IAMT_MODE                0x2
 
@@ -83,6 +95,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
 
 #define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
 #define IGP3_VR_CTRL_MODE_SHUTDOWN     0x0200
 
+#define HV_LED_CONFIG          PHY_REG(768, 30) /* LED Configuration */
+
+#define SW_FLAG_TIMEOUT    1000 /* SW Semaphore flag timeout in milliseconds */
+
+/* SMBus Address Phy Register */
+#define HV_SMB_ADDR            PHY_REG(768, 26)
+#define HV_SMB_ADDR_PEC_EN     0x0200
+#define HV_SMB_ADDR_VALID      0x0080
+
+/* Strapping Option Register - RO */
+#define E1000_STRAP                     0x0000C
+#define E1000_STRAP_SMBUS_ADDRESS_MASK  0x00FE0000
+#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17
+
+/* OEM Bits Phy Register */
+#define HV_OEM_BITS            PHY_REG(768, 25)
+#define HV_OEM_BITS_LPLU       0x0004 /* Low Power Link Up */
+#define HV_OEM_BITS_GBE_DIS    0x0040 /* Gigabit Disable */
+#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
+
+#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */
+#define E1000_NVM_K1_ENABLE 0x1  /* NVM Enable K1 bit */
+
+/* KMRN Mode Control */
+#define HV_KMRN_MODE_CTRL      PHY_REG(769, 16)
+#define HV_KMRN_MDIO_SLOW      0x0400
+
 /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
 /* Offset 04h HSFSTS */
 union ich8_hws_flash_status {
@@ -144,19 +185,47 @@ 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);
-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 s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
+static s32 e1000_led_on_ich8lan(struct e1000_hw *hw);
+static s32 e1000_led_off_ich8lan(struct e1000_hw *hw);
+static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
+static s32 e1000_setup_led_pchlan(struct e1000_hw *hw);
+static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw);
+static s32 e1000_led_on_pchlan(struct e1000_hw *hw);
+static s32 e1000_led_off_pchlan(struct e1000_hw *hw);
+static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
+static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
+static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
+static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
+static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
 
 static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
 {
@@ -184,6 +253,100 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
 #define ew32flash(reg,val)     __ew32flash(hw, (reg), (val))
 
 /**
+ *  e1000_init_phy_params_pchlan - Initialize PHY function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific PHY parameters and function pointers.
+ **/
+static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       u32 ctrl;
+       s32 ret_val = 0;
+
+       phy->addr                     = 1;
+       phy->reset_delay_us           = 100;
+
+       phy->ops.read_reg             = e1000_read_phy_reg_hv;
+       phy->ops.read_reg_locked      = e1000_read_phy_reg_hv_locked;
+       phy->ops.set_d0_lplu_state    = e1000_set_lplu_state_pchlan;
+       phy->ops.set_d3_lplu_state    = e1000_set_lplu_state_pchlan;
+       phy->ops.write_reg            = e1000_write_phy_reg_hv;
+       phy->ops.write_reg_locked     = e1000_write_phy_reg_hv_locked;
+       phy->ops.power_up             = e1000_power_up_phy_copper;
+       phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
+       phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+       if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
+               /*
+                * The MAC-PHY interconnect may still be in SMBus mode
+                * after Sx->S0.  Toggle the LANPHYPC Value bit to force
+                * the interconnect to PCIe mode, but only if there is no
+                * firmware present otherwise firmware will have done it.
+                */
+               ctrl = er32(CTRL);
+               ctrl |=  E1000_CTRL_LANPHYPC_OVERRIDE;
+               ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
+               ew32(CTRL, ctrl);
+               udelay(10);
+               ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
+               ew32(CTRL, ctrl);
+               msleep(50);
+       }
+
+       /*
+        * Reset the PHY before any acccess to it.  Doing so, ensures that
+        * the PHY is in a known good state before we read/write PHY registers.
+        * The generic reset is sufficient here, because we haven't determined
+        * the PHY type yet.
+        */
+       ret_val = e1000e_phy_hw_reset_generic(hw);
+       if (ret_val)
+               goto out;
+
+       phy->id = e1000_phy_unknown;
+       ret_val = e1000e_get_phy_id(hw);
+       if (ret_val)
+               goto out;
+       if ((phy->id == 0) || (phy->id == PHY_REVISION_MASK)) {
+               /*
+                * In case the PHY needs to be in mdio slow mode (eg. 82577),
+                * set slow mode and try to get the PHY id again.
+                */
+               ret_val = e1000_set_mdio_slow_mode_hv(hw);
+               if (ret_val)
+                       goto out;
+               ret_val = e1000e_get_phy_id(hw);
+               if (ret_val)
+                       goto out;
+       }
+       phy->type = e1000e_get_phy_type_from_id(phy->id);
+
+       switch (phy->type) {
+       case e1000_phy_82577:
+               phy->ops.check_polarity = e1000_check_polarity_82577;
+               phy->ops.force_speed_duplex =
+                       e1000_phy_force_speed_duplex_82577;
+               phy->ops.get_cable_length = e1000_get_cable_length_82577;
+               phy->ops.get_info = e1000_get_phy_info_82577;
+               phy->ops.commit = e1000e_phy_sw_reset;
+               break;
+       case e1000_phy_82578:
+               phy->ops.check_polarity = e1000_check_polarity_m88;
+               phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88;
+               phy->ops.get_cable_length = e1000e_get_cable_length_m88;
+               phy->ops.get_info = e1000e_get_phy_info_m88;
+               break;
+       default:
+               ret_val = -E1000_ERR_PHY;
+               break;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
  *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
  *  @hw: pointer to the HW structure
  *
@@ -198,6 +361,24 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
        phy->addr                       = 1;
        phy->reset_delay_us             = 100;
 
+       phy->ops.power_up               = e1000_power_up_phy_copper;
+       phy->ops.power_down             = e1000_power_down_phy_copper_ich8lan;
+
+       /*
+        * 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) {
+               phy->ops.write_reg = e1000e_write_phy_reg_bm;
+               phy->ops.read_reg  = e1000e_read_phy_reg_bm;
+               ret_val = e1000e_determine_phy_address(hw);
+               if (ret_val) {
+                       e_dbg("Cannot determine PHY addr. Erroring out\n");
+                       return ret_val;
+               }
+       }
+
        phy->id = 0;
        while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
               (i++ < 100)) {
@@ -212,12 +393,30 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
        case IGP03E1000_E_PHY_ID:
                phy->type = e1000_phy_igp_3;
                phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+               phy->ops.read_reg_locked = e1000e_read_phy_reg_igp_locked;
+               phy->ops.write_reg_locked = e1000e_write_phy_reg_igp_locked;
+               phy->ops.get_info = e1000e_get_phy_info_igp;
+               phy->ops.check_polarity = e1000_check_polarity_igp;
+               phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_igp;
                break;
        case IFE_E_PHY_ID:
        case IFE_PLUS_E_PHY_ID:
        case IFE_C_E_PHY_ID:
                phy->type = e1000_phy_ife;
                phy->autoneg_mask = E1000_ALL_NOT_GIG;
+               phy->ops.get_info = e1000_get_phy_info_ife;
+               phy->ops.check_polarity = e1000_check_polarity_ife;
+               phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
+               break;
+       case BME1000_E_PHY_ID:
+               phy->type = e1000_phy_bm;
+               phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+               phy->ops.read_reg = e1000e_read_phy_reg_bm;
+               phy->ops.write_reg = e1000e_write_phy_reg_bm;
+               phy->ops.commit = e1000e_phy_sw_reset;
+               phy->ops.get_info = e1000e_get_phy_info_m88;
+               phy->ops.check_polarity = e1000_check_polarity_m88;
+               phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88;
                break;
        default:
                return -E1000_ERR_PHY;
@@ -238,15 +437,12 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
 {
        struct e1000_nvm_info *nvm = &hw->nvm;
        struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-       u32 gfpreg;
-       u32 sector_base_addr;
-       u32 sector_end_addr;
+       u32 gfpreg, sector_base_addr, sector_end_addr;
        u16 i;
 
-       /* Can't read flash registers if the register set isn't mapped.
-        */
+       /* Can't read flash registers if the register set isn't mapped. */
        if (!hw->flash_address) {
-               hw_dbg(hw, "ERROR: Flash registers not mapped\n");
+               e_dbg("ERROR: Flash registers not mapped\n");
                return -E1000_ERR_CONFIG;
        }
 
@@ -254,17 +450,21 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
 
        gfpreg = er32flash(ICH_FLASH_GFPREG);
 
-       /* sector_X_addr is a "sector"-aligned address (4096 bytes)
+       /*
+        * sector_X_addr is a "sector"-aligned address (4096 bytes)
         * Add 1 to sector_end_addr since this sector is included in
-        * the overall size. */
+        * the overall size.
+        */
        sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
        sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
 
        /* flash_base_addr is byte-aligned */
        nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
 
-       /* find total size of the NVM, then cut in half since the total
-        * size represents two separate NVM banks. */
+       /*
+        * find total size of the NVM, then cut in half since the total
+        * size represents two separate NVM banks.
+        */
        nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
                                << FLASH_SECTOR_ADDR_SHIFT;
        nvm->flash_bank_size /= 2;
@@ -275,7 +475,7 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
 
        /* Clear shadow ram */
        for (i = 0; i < nvm->word_size; i++) {
-               dev_spec->shadow_ram[i].modified = 0;
+               dev_spec->shadow_ram[i].modified = false;
                dev_spec->shadow_ram[i].value    = 0xFFFF;
        }
 
@@ -295,7 +495,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
        struct e1000_mac_info *mac = &hw->mac;
 
        /* Set media type function pointer */
-       hw->media_type = e1000_media_type_copper;
+       hw->phy.media_type = e1000_media_type_copper;
 
        /* Set mta register count */
        mac->mta_reg_count = 32;
@@ -303,17 +503,138 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
        mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
        if (mac->type == e1000_ich8lan)
                mac->rar_entry_count--;
-       /* Set if manageability features are enabled. */
-       mac->arc_subsystem_valid = 1;
+       /* FWSM register */
+       mac->has_fwsm = true;
+       /* ARC subsystem not supported */
+       mac->arc_subsystem_valid = false;
+       /* Adaptive IFS supported */
+       mac->adaptive_ifs = true;
+
+       /* LED operations */
+       switch (mac->type) {
+       case e1000_ich8lan:
+       case e1000_ich9lan:
+       case e1000_ich10lan:
+               /* ID LED init */
+               mac->ops.id_led_init = e1000e_id_led_init;
+               /* setup LED */
+               mac->ops.setup_led = e1000e_setup_led_generic;
+               /* cleanup LED */
+               mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
+               /* turn on/off LED */
+               mac->ops.led_on = e1000_led_on_ich8lan;
+               mac->ops.led_off = e1000_led_off_ich8lan;
+               break;
+       case e1000_pchlan:
+               /* ID LED init */
+               mac->ops.id_led_init = e1000_id_led_init_pchlan;
+               /* setup LED */
+               mac->ops.setup_led = e1000_setup_led_pchlan;
+               /* cleanup LED */
+               mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
+               /* turn on/off LED */
+               mac->ops.led_on = e1000_led_on_pchlan;
+               mac->ops.led_off = e1000_led_off_pchlan;
+               break;
+       default:
+               break;
+       }
 
        /* Enable PCS Lock-loss workaround for ICH8 */
        if (mac->type == e1000_ich8lan)
-               e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1);
+               e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
 
        return 0;
 }
 
-static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter)
+/**
+ *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks to see of the link status of the hardware has changed.  If a
+ *  change in link status has been detected, then we read the PHY registers
+ *  to get the current speed/duplex if link exists.
+ **/
+static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       s32 ret_val;
+       bool link;
+
+       /*
+        * We only want to go out to the PHY registers to see if Auto-Neg
+        * has completed and/or if our link status has changed.  The
+        * get_link_status flag is set upon receiving a Link Status
+        * Change or Rx Sequence Error interrupt.
+        */
+       if (!mac->get_link_status) {
+               ret_val = 0;
+               goto out;
+       }
+
+       /*
+        * First we want to see if the MII Status Register reports
+        * link.  If so, then we want to get the current speed/duplex
+        * of the PHY.
+        */
+       ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+       if (ret_val)
+               goto out;
+
+       if (hw->mac.type == e1000_pchlan) {
+               ret_val = e1000_k1_gig_workaround_hv(hw, link);
+               if (ret_val)
+                       goto out;
+       }
+
+       if (!link)
+               goto out; /* No link detected */
+
+       mac->get_link_status = false;
+
+       if (hw->phy.type == e1000_phy_82578) {
+               ret_val = e1000_link_stall_workaround_hv(hw);
+               if (ret_val)
+                       goto out;
+       }
+
+       /*
+        * Check if there was DownShift, must be checked
+        * immediately after link-up
+        */
+       e1000e_check_downshift(hw);
+
+       /*
+        * If we are forcing speed/duplex, then we simply return since
+        * we have already determined whether we have link or not.
+        */
+       if (!mac->autoneg) {
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+       /*
+        * Auto-Neg is enabled.  Auto Speed Detection takes care
+        * of MAC speed/duplex configuration.  So we only need to
+        * configure Collision Distance in the MAC.
+        */
+       e1000e_config_collision_dist(hw);
+
+       /*
+        * Configure Flow Control now that Auto-Neg has completed.
+        * First, we need to restore the desired flow control
+        * settings because we may have had to re-autoneg with a
+        * different link partner.
+        */
+       ret_val = e1000e_config_fc_after_link_up(hw);
+       if (ret_val)
+               e_dbg("Error configuring flow control\n");
+
+out:
+       return ret_val;
+}
+
+static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
        s32 rc;
@@ -326,10 +647,18 @@ static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter)
        if (rc)
                return rc;
 
-       rc = e1000_init_phy_params_ich8lan(hw);
+       if (hw->mac.type == e1000_pchlan)
+               rc = e1000_init_phy_params_pchlan(hw);
+       else
+               rc = e1000_init_phy_params_ich8lan(hw);
        if (rc)
                return rc;
 
+       if (adapter->hw.phy.type == e1000_phy_ife) {
+               adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
+               adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
+       }
+
        if ((adapter->hw.mac.type == e1000_ich8lan) &&
            (adapter->hw.phy.type == e1000_phy_igp_3))
                adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
@@ -337,46 +666,98 @@ static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter)
        return 0;
 }
 
+static DEFINE_MUTEX(nvm_mutex);
+
+/**
+ *  e1000_acquire_nvm_ich8lan - Acquire NVM mutex
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquires the mutex for performing NVM operations.
+ **/
+static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
+{
+       mutex_lock(&nvm_mutex);
+
+       return 0;
+}
+
+/**
+ *  e1000_release_nvm_ich8lan - Release NVM mutex
+ *  @hw: pointer to the HW structure
+ *
+ *  Releases the mutex used while performing NVM operations.
+ **/
+static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
+{
+       mutex_unlock(&nvm_mutex);
+}
+
+static DEFINE_MUTEX(swflag_mutex);
+
 /**
  *  e1000_acquire_swflag_ich8lan - Acquire software control flag
  *  @hw: pointer to the HW structure
  *
- *  Acquires the software control flag for performing NVM and PHY
- *  operations.  This is a function pointer entry point only called by
- *  read/write routines for the PHY and NVM parts.
+ *  Acquires the software control flag for performing PHY and select
+ *  MAC CSR accesses.
  **/
 static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
 {
-       u32 extcnf_ctrl;
-       u32 timeout = PHY_CFG_TIMEOUT;
+       u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
+       s32 ret_val = 0;
+
+       mutex_lock(&swflag_mutex);
 
        while (timeout) {
                extcnf_ctrl = er32(EXTCNF_CTRL);
-               extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
-               ew32(EXTCNF_CTRL, extcnf_ctrl);
+               if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
+                       break;
+
+               mdelay(1);
+               timeout--;
+       }
+
+       if (!timeout) {
+               e_dbg("SW/FW/HW has locked the resource for too long.\n");
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+       timeout = SW_FLAG_TIMEOUT;
+
+       extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+       ew32(EXTCNF_CTRL, extcnf_ctrl);
 
+       while (timeout) {
                extcnf_ctrl = er32(EXTCNF_CTRL);
                if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
                        break;
+
                mdelay(1);
                timeout--;
        }
 
        if (!timeout) {
-               hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
-               return -E1000_ERR_CONFIG;
+               e_dbg("Failed to acquire the semaphore.\n");
+               extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+               ew32(EXTCNF_CTRL, extcnf_ctrl);
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
        }
 
-       return 0;
+out:
+       if (ret_val)
+               mutex_unlock(&swflag_mutex);
+
+       return ret_val;
 }
 
 /**
  *  e1000_release_swflag_ich8lan - Release software control flag
  *  @hw: pointer to the HW structure
  *
- *  Releases the software control flag for performing NVM and PHY operations.
- *  This is a function pointer entry point only called by read/write
- *  routines for the PHY and NVM parts.
+ *  Releases the software control flag for performing PHY and select
+ *  MAC CSR accesses.
  **/
 static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
 {
@@ -385,6 +766,26 @@ 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);
+
+       mutex_unlock(&swflag_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;
+
+       fwsm = er32(FWSM);
+
+       return (fwsm & E1000_FWSM_MODE_MASK) ==
+               (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
 }
 
 /**
@@ -405,307 +806,549 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
 }
 
 /**
- *  e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex
- *  @hw: pointer to the HW structure
+ *  e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
+ *  @hw:   pointer to the HW structure
  *
- *  Forces the speed and duplex settings of the PHY.
- *  This is a function pointer entry point only called by
- *  PHY setup routines.
+ *  SW should configure the LCD from the NVM extended configuration region
+ *  as a workaround for certain parts.
  **/
-static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw)
+static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
 {
+       struct e1000_adapter *adapter = hw->adapter;
        struct e1000_phy_info *phy = &hw->phy;
-       s32 ret_val;
-       u16 data;
-       bool link;
+       u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
+       s32 ret_val = 0;
+       u16 word_addr, reg_data, reg_addr, phy_page = 0;
 
-       if (phy->type != e1000_phy_ife) {
-               ret_val = e1000e_phy_force_speed_duplex_igp(hw);
+       if (!(hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) &&
+               !(hw->mac.type == e1000_pchlan))
                return ret_val;
-       }
 
-       ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
+       ret_val = hw->phy.ops.acquire(hw);
        if (ret_val)
                return ret_val;
 
-       e1000e_phy_force_speed_duplex_setup(hw, &data);
+       /*
+        * Initialize the PHY from the NVM on ICH platforms.  This
+        * is needed due to an issue where the NVM configuration is
+        * not properly autoloaded after power transitions.
+        * Therefore, after each PHY reset, we will load the
+        * configuration data out of the NVM manually.
+        */
+       if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
+           (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M) ||
+           (hw->mac.type == e1000_pchlan))
+               sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
+       else
+               sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
 
-       ret_val = e1e_wphy(hw, PHY_CONTROL, data);
-       if (ret_val)
-               return ret_val;
+       data = er32(FEXTNVM);
+       if (!(data & sw_cfg_mask))
+               goto out;
 
-       /* Disable MDI-X support for 10/100 */
-       ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
-       if (ret_val)
-               return ret_val;
+       /*
+        * Make sure HW does not configure LCD from PHY
+        * extended configuration before SW configuration
+        */
+       data = er32(EXTCNF_CTRL);
+       if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+               goto out;
 
-       data &= ~IFE_PMC_AUTO_MDIX;
-       data &= ~IFE_PMC_FORCE_MDIX;
+       cnf_size = er32(EXTCNF_SIZE);
+       cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
+       cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
+       if (!cnf_size)
+               goto out;
 
-       ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data);
-       if (ret_val)
-               return ret_val;
+       cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
+       cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
 
-       hw_dbg(hw, "IFE PMC: %X\n", data);
+       if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
+           (hw->mac.type == e1000_pchlan)) {
+               /*
+                * HW configures the SMBus address and LEDs when the
+                * OEM and LCD Write Enable bits are set in the NVM.
+                * When both NVM bits are cleared, SW will configure
+                * them instead.
+                */
+               data = er32(STRAP);
+               data &= E1000_STRAP_SMBUS_ADDRESS_MASK;
+               reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT;
+               reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
+               ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR,
+                                                       reg_data);
+               if (ret_val)
+                       goto out;
 
-       udelay(1);
+               data = er32(LEDCTL);
+               ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG,
+                                                       (u16)data);
+               if (ret_val)
+                       goto out;
+       }
 
-       if (phy->wait_for_link) {
-               hw_dbg(hw, "Waiting for forced speed/duplex link on IFE phy.\n");
+       /* Configure LCD from extended configuration region. */
 
-               ret_val = e1000e_phy_has_link_generic(hw,
-                                                    PHY_FORCE_LIMIT,
-                                                    100000,
-                                                    &link);
+       /* cnf_base_addr is in DWORD */
+       word_addr = (u16)(cnf_base_addr << 1);
+
+       for (i = 0; i < cnf_size; i++) {
+               ret_val = e1000_read_nvm(hw, (word_addr + i * 2), 1,
+                                        &reg_data);
                if (ret_val)
-                       return ret_val;
+                       goto out;
+
+               ret_val = e1000_read_nvm(hw, (word_addr + i * 2 + 1),
+                                        1, &reg_addr);
+               if (ret_val)
+                       goto out;
+
+               /* Save off the PHY page for future writes. */
+               if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
+                       phy_page = reg_data;
+                       continue;
+               }
 
-               if (!link)
-                       hw_dbg(hw, "Link taking longer than expected.\n");
+               reg_addr &= PHY_REG_MASK;
+               reg_addr |= phy_page;
 
-               /* Try once more */
-               ret_val = e1000e_phy_has_link_generic(hw,
-                                                    PHY_FORCE_LIMIT,
-                                                    100000,
-                                                    &link);
+               ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
+                                                   reg_data);
                if (ret_val)
-                       return ret_val;
+                       goto out;
        }
 
-       return 0;
+out:
+       hw->phy.ops.release(hw);
+       return ret_val;
 }
 
 /**
- *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
- *  @hw: pointer to the HW structure
+ *  e1000_k1_gig_workaround_hv - K1 Si workaround
+ *  @hw:   pointer to the HW structure
+ *  @link: link up bool flag
  *
- *  Resets the PHY
- *  This is a function pointer entry point called by drivers
- *  or other shared routines.
+ *  If K1 is enabled for 1Gbps, the MAC might stall when transitioning
+ *  from a lower speed.  This workaround disables K1 whenever link is at 1Gig
+ *  If link is down, the function will restore the default K1 setting located
+ *  in the NVM.
  **/
-static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
 {
-       struct e1000_phy_info *phy = &hw->phy;
-       u32 i;
-       u32 data, cnf_size, cnf_base_addr, sw_cfg_mask;
-       s32 ret_val;
-       u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT;
-       u16 word_addr, reg_data, reg_addr, phy_page = 0;
+       s32 ret_val = 0;
+       u16 status_reg = 0;
+       bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
 
-       ret_val = e1000e_phy_hw_reset_generic(hw);
+       if (hw->mac.type != e1000_pchlan)
+               goto out;
+
+       /* Wrap the whole flow with the sw flag */
+       ret_val = hw->phy.ops.acquire(hw);
        if (ret_val)
-               return ret_val;
+               goto out;
 
-       /* Initialize the PHY from the NVM on ICH platforms.  This
-        * is needed due to an issue where the NVM configuration is
-        * not properly autoloaded after power transitions.
-        * Therefore, after each PHY reset, we will load the
-        * configuration data out of the NVM manually.
-        */
-       if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) {
-               struct e1000_adapter *adapter = hw->adapter;
+       /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
+       if (link) {
+               if (hw->phy.type == e1000_phy_82578) {
+                       ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
+                                                                 &status_reg);
+                       if (ret_val)
+                               goto release;
 
-               /* Check if SW needs configure the PHY */
-               if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
-                   (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M))
-                       sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
-               else
-                       sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+                       status_reg &= BM_CS_STATUS_LINK_UP |
+                                     BM_CS_STATUS_RESOLVED |
+                                     BM_CS_STATUS_SPEED_MASK;
 
-               data = er32(FEXTNVM);
-               if (!(data & sw_cfg_mask))
-                       return 0;
+                       if (status_reg == (BM_CS_STATUS_LINK_UP |
+                                          BM_CS_STATUS_RESOLVED |
+                                          BM_CS_STATUS_SPEED_1000))
+                               k1_enable = false;
+               }
 
-               /* Wait for basic configuration completes before proceeding*/
-               do {
-                       data = er32(STATUS);
-                       data &= E1000_STATUS_LAN_INIT_DONE;
-                       udelay(100);
-               } while ((!data) && --loop);
-
-               /* If basic configuration is incomplete before the above loop
-                * count reaches 0, loading the configuration from NVM will
-                * leave the PHY in a bad state possibly resulting in no link.
-                */
-               if (loop == 0) {
-                       hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n");
+               if (hw->phy.type == e1000_phy_82577) {
+                       ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
+                                                                 &status_reg);
+                       if (ret_val)
+                               goto release;
+
+                       status_reg &= HV_M_STATUS_LINK_UP |
+                                     HV_M_STATUS_AUTONEG_COMPLETE |
+                                     HV_M_STATUS_SPEED_MASK;
+
+                       if (status_reg == (HV_M_STATUS_LINK_UP |
+                                          HV_M_STATUS_AUTONEG_COMPLETE |
+                                          HV_M_STATUS_SPEED_1000))
+                               k1_enable = false;
                }
 
-               /* Clear the Init Done bit for the next init event */
-               data = er32(STATUS);
-               data &= ~E1000_STATUS_LAN_INIT_DONE;
-               ew32(STATUS, data);
+               /* Link stall fix for link up */
+               ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
+                                                          0x0100);
+               if (ret_val)
+                       goto release;
 
-               /* Make sure HW does not configure LCD from PHY
-                * extended configuration before SW configuration */
-               data = er32(EXTCNF_CTRL);
-               if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
-                       return 0;
+       } else {
+               /* Link stall fix for link down */
+               ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
+                                                          0x4100);
+               if (ret_val)
+                       goto release;
+       }
 
-               cnf_size = er32(EXTCNF_SIZE);
-               cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
-               cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
-               if (!cnf_size)
-                       return 0;
+       ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
+
+release:
+       hw->phy.ops.release(hw);
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_configure_k1_ich8lan - Configure K1 power state
+ *  @hw: pointer to the HW structure
+ *  @enable: K1 state to configure
+ *
+ *  Configure the K1 power state based on the provided parameter.
+ *  Assumes semaphore already acquired.
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ **/
+s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
+{
+       s32 ret_val = 0;
+       u32 ctrl_reg = 0;
+       u32 ctrl_ext = 0;
+       u32 reg = 0;
+       u16 kmrn_reg = 0;
+
+       ret_val = e1000e_read_kmrn_reg_locked(hw,
+                                            E1000_KMRNCTRLSTA_K1_CONFIG,
+                                            &kmrn_reg);
+       if (ret_val)
+               goto out;
 
-               cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
-               cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
+       if (k1_enable)
+               kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
+       else
+               kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
 
-               /* Configure LCD from extended configuration
-                * region. */
+       ret_val = e1000e_write_kmrn_reg_locked(hw,
+                                             E1000_KMRNCTRLSTA_K1_CONFIG,
+                                             kmrn_reg);
+       if (ret_val)
+               goto out;
 
-               /* cnf_base_addr is in DWORD */
-               word_addr = (u16)(cnf_base_addr << 1);
+       udelay(20);
+       ctrl_ext = er32(CTRL_EXT);
+       ctrl_reg = er32(CTRL);
 
-               for (i = 0; i < cnf_size; i++) {
-                       ret_val = e1000_read_nvm(hw,
-                                               (word_addr + i * 2),
-                                               1,
-                                               &reg_data);
-                       if (ret_val)
-                               return ret_val;
+       reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+       reg |= E1000_CTRL_FRCSPD;
+       ew32(CTRL, reg);
 
-                       ret_val = e1000_read_nvm(hw,
-                                               (word_addr + i * 2 + 1),
-                                               1,
-                                               &reg_addr);
-                       if (ret_val)
-                               return ret_val;
+       ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
+       udelay(20);
+       ew32(CTRL, ctrl_reg);
+       ew32(CTRL_EXT, ctrl_ext);
+       udelay(20);
 
-                       /* Save off the PHY page for future writes. */
-                       if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
-                               phy_page = reg_data;
-                               continue;
-                       }
+out:
+       return ret_val;
+}
 
-                       reg_addr |= phy_page;
+/**
+ *  e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
+ *  @hw:       pointer to the HW structure
+ *  @d0_state: boolean if entering d0 or d3 device state
+ *
+ *  SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
+ *  collectively called OEM bits.  The OEM Write Enable bit and SW Config bit
+ *  in NVM determines whether HW should configure LPLU and Gbe Disable.
+ **/
+static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
+{
+       s32 ret_val = 0;
+       u32 mac_reg;
+       u16 oem_reg;
 
-                       ret_val = e1e_wphy(hw, (u32)reg_addr, reg_data);
-                       if (ret_val)
-                               return ret_val;
-               }
+       if (hw->mac.type != e1000_pchlan)
+               return ret_val;
+
+       ret_val = hw->phy.ops.acquire(hw);
+       if (ret_val)
+               return ret_val;
+
+       mac_reg = er32(EXTCNF_CTRL);
+       if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+               goto out;
+
+       mac_reg = er32(FEXTNVM);
+       if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
+               goto out;
+
+       mac_reg = er32(PHY_CTRL);
+
+       ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
+       if (ret_val)
+               goto out;
+
+       oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
+
+       if (d0_state) {
+               if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
+                       oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+               if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
+                       oem_reg |= HV_OEM_BITS_LPLU;
+       } else {
+               if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE)
+                       oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+               if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU)
+                       oem_reg |= HV_OEM_BITS_LPLU;
        }
+       /* Restart auto-neg to activate the bits */
+       if (!e1000_check_reset_block(hw))
+               oem_reg |= HV_OEM_BITS_RESTART_AN;
+       ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
 
-       return 0;
+out:
+       hw->phy.ops.release(hw);
+
+       return ret_val;
 }
 
+
 /**
- *  e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
- *  @hw: pointer to the HW structure
- *
- *  Populates "phy" structure with various feature states.
- *  This function is only called by other family-specific
- *  routines.
+ *  e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
+ *  @hw:   pointer to the HW structure
  **/
-static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
+static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw)
 {
-       struct e1000_phy_info *phy = &hw->phy;
        s32 ret_val;
        u16 data;
-       bool link;
 
-       ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+       ret_val = e1e_rphy(hw, HV_KMRN_MODE_CTRL, &data);
        if (ret_val)
                return ret_val;
 
-       if (!link) {
-               hw_dbg(hw, "Phy info is only valid if link is up\n");
-               return -E1000_ERR_CONFIG;
-       }
+       data |= HV_KMRN_MDIO_SLOW;
 
-       ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data);
-       if (ret_val)
+       ret_val = e1e_wphy(hw, HV_KMRN_MODE_CTRL, data);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ *  done after every PHY reset.
+ **/
+static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+       u16 phy_data;
+
+       if (hw->mac.type != e1000_pchlan)
                return ret_val;
-       phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE));
 
-       if (phy->polarity_correction) {
-               ret_val = e1000_check_polarity_ife_ich8lan(hw);
+       /* Set MDIO slow mode before any other MDIO access */
+       if (hw->phy.type == e1000_phy_82577) {
+               ret_val = e1000_set_mdio_slow_mode_hv(hw);
+               if (ret_val)
+                       goto out;
+       }
+
+       if (((hw->phy.type == e1000_phy_82577) &&
+            ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
+           ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
+               /* Disable generation of early preamble */
+               ret_val = e1e_wphy(hw, PHY_REG(769, 25), 0x4431);
+               if (ret_val)
+                       return ret_val;
+
+               /* Preamble tuning for SSC */
+               ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204);
                if (ret_val)
                        return ret_val;
-       } else {
-               /* Polarity is forced */
-               phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
-                                     ? e1000_rev_polarity_reversed
-                                     : e1000_rev_polarity_normal;
        }
 
-       ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+       if (hw->phy.type == e1000_phy_82578) {
+               /*
+                * Return registers to default by doing a soft reset then
+                * writing 0x3140 to the control register.
+                */
+               if (hw->phy.revision < 2) {
+                       e1000e_phy_sw_reset(hw);
+                       ret_val = e1e_wphy(hw, PHY_CONTROL, 0x3140);
+               }
+       }
+
+       /* Select page 0 */
+       ret_val = hw->phy.ops.acquire(hw);
        if (ret_val)
                return ret_val;
 
-       phy->is_mdix = (data & IFE_PMC_MDIX_STATUS);
+       hw->phy.addr = 1;
+       ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
+       hw->phy.ops.release(hw);
+       if (ret_val)
+               goto out;
 
-       /* The following parameters are undefined for 10/100 operation. */
-       phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-       phy->local_rx = e1000_1000t_rx_status_undefined;
-       phy->remote_rx = e1000_1000t_rx_status_undefined;
+       /*
+        * Configure the K1 Si workaround during phy reset assuming there is
+        * link so that it disables K1 if link is in 1Gbps.
+        */
+       ret_val = e1000_k1_gig_workaround_hv(hw, true);
+       if (ret_val)
+               goto out;
 
-       return 0;
+       /* Workaround for link disconnects on a busy hub in half duplex */
+       ret_val = hw->phy.ops.acquire(hw);
+       if (ret_val)
+               goto out;
+       ret_val = hw->phy.ops.read_reg_locked(hw,
+                                             PHY_REG(BM_PORT_CTRL_PAGE, 17),
+                                             &phy_data);
+       if (ret_val)
+               goto release;
+       ret_val = hw->phy.ops.write_reg_locked(hw,
+                                              PHY_REG(BM_PORT_CTRL_PAGE, 17),
+                                              phy_data & 0x00FF);
+release:
+       hw->phy.ops.release(hw);
+out:
+       return ret_val;
 }
 
 /**
- *  e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
+ *  e1000_lan_init_done_ich8lan - Check for PHY config completion
  *  @hw: pointer to the HW structure
  *
- *  Wrapper for calling the get_phy_info routines for the appropriate phy type.
- *  This is a function pointer entry point called by drivers
- *  or other shared routines.
+ *  Check the appropriate indication the MAC has finished configuring the
+ *  PHY after a software reset.
  **/
-static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
+static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
 {
-       switch (hw->phy.type) {
-       case e1000_phy_ife:
-               return e1000_get_phy_info_ife_ich8lan(hw);
-               break;
-       case e1000_phy_igp_3:
-               return e1000e_get_phy_info_igp(hw);
+       u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
+
+       /* Wait for basic configuration completes before proceeding */
+       do {
+               data = er32(STATUS);
+               data &= E1000_STATUS_LAN_INIT_DONE;
+               udelay(100);
+       } while ((!data) && --loop);
+
+       /*
+        * If basic configuration is incomplete before the above loop
+        * count reaches 0, loading the configuration from NVM will
+        * leave the PHY in a bad state possibly resulting in no link.
+        */
+       if (loop == 0)
+               e_dbg("LAN_INIT_DONE not set, increase timeout\n");
+
+       /* Clear the Init Done bit for the next init event */
+       data = er32(STATUS);
+       data &= ~E1000_STATUS_LAN_INIT_DONE;
+       ew32(STATUS, data);
+}
+
+/**
+ *  e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+       u16 reg;
+
+       if (e1000_check_reset_block(hw))
+               goto out;
+
+       /* Perform any necessary post-reset workarounds */
+       switch (hw->mac.type) {
+       case e1000_pchlan:
+               ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
+               if (ret_val)
+                       goto out;
                break;
        default:
                break;
        }
 
-       return -E1000_ERR_PHY_TYPE;
+       /* Dummy read to clear the phy wakeup bit after lcd reset */
+       if (hw->mac.type == e1000_pchlan)
+               e1e_rphy(hw, BM_WUC, &reg);
+
+       /* Configure the LCD with the extended configuration region in NVM */
+       ret_val = e1000_sw_lcd_config_ich8lan(hw);
+       if (ret_val)
+               goto out;
+
+       /* Configure the LCD with the OEM bits in NVM */
+       ret_val = e1000_oem_bits_config_ich8lan(hw, true);
+
+out:
+       return ret_val;
 }
 
 /**
- *  e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY
+ *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
  *  @hw: pointer to the HW structure
  *
- *  Polarity is determined on the polarity reversal feature being enabled.
- *  This function is only called by other family-specific
- *  routines.
+ *  Resets the PHY
+ *  This is a function pointer entry point called by drivers
+ *  or other shared routines.
  **/
-static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw)
+static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
 {
-       struct e1000_phy_info *phy = &hw->phy;
-       s32 ret_val;
-       u16 phy_data, offset, mask;
+       s32 ret_val = 0;
 
-       /* Polarity is determined based on the reversal feature
-        * being enabled.
-        */
-       if (phy->polarity_correction) {
-               offset  = IFE_PHY_EXTENDED_STATUS_CONTROL;
-               mask    = IFE_PESC_POLARITY_REVERSED;
-       } else {
-               offset  = IFE_PHY_SPECIAL_CONTROL;
-               mask    = IFE_PSC_FORCE_POLARITY;
-       }
+       ret_val = e1000e_phy_hw_reset_generic(hw);
+       if (ret_val)
+               goto out;
 
-       ret_val = e1e_rphy(hw, offset, &phy_data);
+       ret_val = e1000_post_phy_reset_ich8lan(hw);
 
-       if (!ret_val)
-               phy->cable_polarity = (phy_data & mask)
-                                     ? e1000_rev_polarity_reversed
-                                     : e1000_rev_polarity_normal;
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_set_lplu_state_pchlan - Set Low Power Link Up state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU state according to the active flag.  For PCH, if OEM write
+ *  bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
+ *  the phy speed. This function will manually set the LPLU bit and restart
+ *  auto-neg as hw would do. D3 and D0 LPLU will call the same function
+ *  since it configures the same bit.
+ **/
+static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
+{
+       s32 ret_val = 0;
+       u16 oem_reg;
+
+       ret_val = e1e_rphy(hw, HV_OEM_BITS, &oem_reg);
+       if (ret_val)
+               goto out;
+
+       if (active)
+               oem_reg |= HV_OEM_BITS_LPLU;
+       else
+               oem_reg &= ~HV_OEM_BITS_LPLU;
+
+       oem_reg |= HV_OEM_BITS_RESTART_AN;
+       ret_val = e1e_wphy(hw, HV_OEM_BITS, oem_reg);
 
+out:
        return ret_val;
 }
 
 /**
  *  e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
  *  @hw: pointer to the HW structure
- *  @active: TRUE to enable LPLU, FALSE to disable
+ *  @active: true to enable LPLU, false to disable
  *
  *  Sets the LPLU D0 state according to the active flag.  When
  *  activating LPLU this function also disables smart speed
@@ -722,7 +1365,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);
@@ -731,10 +1374,14 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
                phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
                ew32(PHY_CTRL, phy_ctrl);
 
-               /* Call gig speed drop workaround on LPLU before accessing
-                * any PHY registers */
-               if ((hw->mac.type == e1000_ich8lan) &&
-                   (hw->phy.type == e1000_phy_igp_3))
+               if (phy->type != e1000_phy_igp_3)
+                       return 0;
+
+               /*
+                * Call gig speed drop workaround on LPLU before accessing
+                * any PHY registers
+                */
+               if (hw->mac.type == e1000_ich8lan)
                        e1000e_gig_downshift_workaround_ich8lan(hw);
 
                /* When LPLU is enabled, we should disable SmartSpeed */
@@ -747,30 +1394,35 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
                phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
                ew32(PHY_CTRL, phy_ctrl);
 
-               /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+               if (phy->type != e1000_phy_igp_3)
+                       return 0;
+
+               /*
+                * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
                 * during Dx states where the power conservation is most
                 * important.  During driver activity we should enable
-                * SmartSpeed, so performance is maintained. */
+                * SmartSpeed, so performance is maintained.
+                */
                if (phy->smart_speed == e1000_smart_speed_on) {
                        ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                                   &data);
+                                          &data);
                        if (ret_val)
                                return ret_val;
 
                        data |= IGP01E1000_PSCFR_SMART_SPEED;
                        ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                                    data);
+                                          data);
                        if (ret_val)
                                return ret_val;
                } else if (phy->smart_speed == e1000_smart_speed_off) {
                        ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                                   &data);
+                                          &data);
                        if (ret_val)
                                return ret_val;
 
                        data &= ~IGP01E1000_PSCFR_SMART_SPEED;
                        ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                                    data);
+                                          data);
                        if (ret_val)
                                return ret_val;
                }
@@ -782,7 +1434,7 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
 /**
  *  e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
  *  @hw: pointer to the HW structure
- *  @active: TRUE to enable LPLU, FALSE to disable
+ *  @active: true to enable LPLU, false to disable
  *
  *  Sets the LPLU D3 state according to the active flag.  When
  *  activating LPLU this function also disables smart speed
@@ -804,34 +1456,36 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
        if (!active) {
                phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
                ew32(PHY_CTRL, phy_ctrl);
-               /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+
+               if (phy->type != e1000_phy_igp_3)
+                       return 0;
+
+               /*
+                * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
                 * during Dx states where the power conservation is most
                 * important.  During driver activity we should enable
-                * SmartSpeed, so performance is maintained. */
+                * SmartSpeed, so performance is maintained.
+                */
                if (phy->smart_speed == e1000_smart_speed_on) {
-                       ret_val = e1e_rphy(hw,
-                                                   IGP01E1000_PHY_PORT_CONFIG,
-                                                   &data);
+                       ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          &data);
                        if (ret_val)
                                return ret_val;
 
                        data |= IGP01E1000_PSCFR_SMART_SPEED;
-                       ret_val = e1e_wphy(hw,
-                                                    IGP01E1000_PHY_PORT_CONFIG,
-                                                    data);
+                       ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          data);
                        if (ret_val)
                                return ret_val;
                } else if (phy->smart_speed == e1000_smart_speed_off) {
-                       ret_val = e1e_rphy(hw,
-                                                   IGP01E1000_PHY_PORT_CONFIG,
-                                                   &data);
+                       ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          &data);
                        if (ret_val)
                                return ret_val;
 
                        data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-                       ret_val = e1e_wphy(hw,
-                                                    IGP01E1000_PHY_PORT_CONFIG,
-                                                    data);
+                       ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          data);
                        if (ret_val)
                                return ret_val;
                }
@@ -841,23 +1495,90 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
                phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
                ew32(PHY_CTRL, phy_ctrl);
 
-               /* Call gig speed drop workaround on LPLU before accessing
-                * any PHY registers */
-               if ((hw->mac.type == e1000_ich8lan) &&
-                   (hw->phy.type == e1000_phy_igp_3))
+               if (phy->type != e1000_phy_igp_3)
+                       return 0;
+
+               /*
+                * Call gig speed drop workaround on LPLU before accessing
+                * any PHY registers
+                */
+               if (hw->mac.type == e1000_ich8lan)
                        e1000e_gig_downshift_workaround_ich8lan(hw);
 
                /* When LPLU is enabled, we should disable SmartSpeed */
-               ret_val = e1e_rphy(hw,
-                                           IGP01E1000_PHY_PORT_CONFIG,
-                                           &data);
+               ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
                if (ret_val)
                        return ret_val;
 
                data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-               ret_val = e1e_wphy(hw,
-                                            IGP01E1000_PHY_PORT_CONFIG,
-                                            data);
+               ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
+       }
+
+       return 0;
+}
+
+/**
+ *  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;
+               }
+               e_dbg("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;
+               }
+
+               e_dbg("ERROR: No valid NVM bank present\n");
+               return -E1000_ERR_NVM;
        }
 
        return 0;
@@ -878,25 +1599,29 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
        struct e1000_nvm_info *nvm = &hw->nvm;
        struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
        u32 act_offset;
-       s32 ret_val;
+       s32 ret_val = 0;
+       u32 bank = 0;
        u16 i, word;
 
        if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
            (words == 0)) {
-               hw_dbg(hw, "nvm parameter(s) out of bounds\n");
-               return -E1000_ERR_NVM;
+               e_dbg("nvm parameter(s) out of bounds\n");
+               ret_val = -E1000_ERR_NVM;
+               goto out;
        }
 
-       ret_val = e1000_acquire_swflag_ich8lan(hw);
-       if (ret_val)
-               return ret_val;
+       nvm->ops.acquire(hw);
+
+       ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+       if (ret_val) {
+               e_dbg("Could not detect valid bank, assuming bank 0\n");
+               bank = 0;
+       }
 
-       /* 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;
 
+       ret_val = 0;
        for (i = 0; i < words; i++) {
                if ((dev_spec->shadow_ram) &&
                    (dev_spec->shadow_ram[offset+i].modified)) {
@@ -911,7 +1636,11 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
                }
        }
 
-       e1000_release_swflag_ich8lan(hw);
+       nvm->ops.release(hw);
+
+out:
+       if (ret_val)
+               e_dbg("NVM read error: %d\n", ret_val);
 
        return ret_val;
 }
@@ -933,8 +1662,8 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
 
        /* Check if the flash descriptor is valid */
        if (hsfsts.hsf_status.fldesvalid == 0) {
-               hw_dbg(hw, "Flash descriptor invalid.  "
-                        "SW Sequencing must be used.");
+               e_dbg("Flash descriptor invalid.  "
+                        "SW Sequencing must be used.\n");
                return -E1000_ERR_NVM;
        }
 
@@ -944,7 +1673,8 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
 
        ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
 
-       /* Either we should have a hardware SPI cycle in progress
+       /*
+        * Either we should have a hardware SPI cycle in progress
         * bit to check against, in order to start a new cycle or
         * FDONE bit should be changed in the hardware so that it
         * is 1 after hardware reset, which can then be used as an
@@ -953,15 +1683,19 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
         */
 
        if (hsfsts.hsf_status.flcinprog == 0) {
-               /* There is no cycle running at present,
-                * so we can start a cycle */
-               /* Begin by setting Flash Cycle Done. */
+               /*
+                * There is no cycle running at present,
+                * so we can start a cycle.
+                * Begin by setting Flash Cycle Done.
+                */
                hsfsts.hsf_status.flcdone = 1;
                ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
                ret_val = 0;
        } else {
-               /* otherwise poll for sometime so the current
-                * cycle has a chance to end before giving up. */
+               /*
+                * Otherwise poll for sometime so the current
+                * cycle has a chance to end before giving up.
+                */
                for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
                        hsfsts.regval = __er16flash(hw, ICH_FLASH_HSFSTS);
                        if (hsfsts.hsf_status.flcinprog == 0) {
@@ -971,12 +1705,14 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
                        udelay(1);
                }
                if (ret_val == 0) {
-                       /* Successful in waiting for previous cycle to timeout,
-                        * now set the Flash Cycle Done. */
+                       /*
+                        * Successful in waiting for previous cycle to timeout,
+                        * now set the Flash Cycle Done.
+                        */
                        hsfsts.hsf_status.flcdone = 1;
                        ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
                } else {
-                       hw_dbg(hw, "Flash controller busy, cannot get access");
+                       e_dbg("Flash controller busy, cannot get access\n");
                }
        }
 
@@ -1035,6 +1771,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.
@@ -1077,10 +1836,12 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
                ret_val = e1000_flash_cycle_ich8lan(hw,
                                                ICH_FLASH_READ_COMMAND_TIMEOUT);
 
-               /* Check if FCERR is set to 1, if set to 1, clear it
+               /*
+                * Check if FCERR is set to 1, if set to 1, clear it
                 * and try the whole sequence a few more times, else
                 * read in (shift in) the Flash Data0, the order is
-                * least significant byte first msb to lsb */
+                * least significant byte first msb to lsb
+                */
                if (ret_val == 0) {
                        flash_data = er32flash(ICH_FLASH_FDATA0);
                        if (size == 1) {
@@ -1090,7 +1851,8 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
                        }
                        break;
                } else {
-                       /* If we've gotten here, then things are probably
+                       /*
+                        * If we've gotten here, then things are probably
                         * completely hosed, but if the error condition is
                         * detected, it won't hurt to give it another try...
                         * ICH_FLASH_CYCLE_REPEAT_COUNT times.
@@ -1100,8 +1862,8 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
                                /* Repeat for some time before giving up. */
                                continue;
                        } else if (hsfsts.hsf_status.flcdone == 0) {
-                               hw_dbg(hw, "Timeout error - flash cycle "
-                                        "did not complete.");
+                               e_dbg("Timeout error - flash cycle "
+                                        "did not complete.\n");
                                break;
                        }
                }
@@ -1124,25 +1886,22 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
 {
        struct e1000_nvm_info *nvm = &hw->nvm;
        struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-       s32 ret_val;
        u16 i;
 
        if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
            (words == 0)) {
-               hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+               e_dbg("nvm parameter(s) out of bounds\n");
                return -E1000_ERR_NVM;
        }
 
-       ret_val = e1000_acquire_swflag_ich8lan(hw);
-       if (ret_val)
-               return ret_val;
+       nvm->ops.acquire(hw);
 
        for (i = 0; i < words; i++) {
-               dev_spec->shadow_ram[offset+i].modified = 1;
+               dev_spec->shadow_ram[offset+i].modified = true;
                dev_spec->shadow_ram[offset+i].value = data[i];
        }
 
-       e1000_release_swflag_ich8lan(hw);
+       nvm->ops.release(hw);
 
        return 0;
 }
@@ -1162,52 +1921,68 @@ 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;;
+       nvm->ops.acquire(hw);
 
-       /* We're writing to the opposite bank so if we're on bank 1,
+       /*
+        * 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)) {
+        * is going to be written
+        */
+       ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+       if (ret_val) {
+               e_dbg("Could not detect valid bank, assuming bank 0\n");
+               bank = 0;
+       }
+
+       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)
+                       goto release;
        } 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)
+                       goto release;
        }
 
        for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
-               /* Determine whether to write the value stored
+               /*
+                * Determine whether to write the value stored
                 * in the other NVM bank or a modified value stored
-                * in the shadow RAM */
+                * in the shadow RAM
+                */
                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;
                }
 
-               /* If the word is 0x13, then make sure the signature bits
+               /*
+                * If the word is 0x13, then make sure the signature bits
                 * (15:14) are 11b until the commit has completed.
                 * This will allow us to write 10b which indicates the
                 * signature is valid.  We want to do this after the write
                 * has completed so that we don't mark the segment valid
-                * while the write is still in progress */
+                * while the write is still in progress
+                */
                if (i == E1000_ICH_NVM_SIG_WORD)
                        data |= E1000_ICH_NVM_SIG_MASK;
 
@@ -1230,53 +2005,66 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
                        break;
        }
 
-       /* Don't bother writing the segment valid bits if sector
-        * programming failed. */
+       /*
+        * Don't bother writing the segment valid bits if sector
+        * programming failed.
+        */
        if (ret_val) {
-               hw_dbg(hw, "Flash commit failed.\n");
-               e1000_release_swflag_ich8lan(hw);
-               return ret_val;
+               /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
+               e_dbg("Flash commit failed.\n");
+               goto release;
        }
 
-       /* Finally validate the new segment by setting bit 15:14
+       /*
+        * Finally validate the new segment by setting bit 15:14
         * to 10b in word 0x13 , this can be done without an
         * erase as well since these bits are 11 to start with
-        * and we need to change bit 14 to 0b */
+        * 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)
+               goto release;
+
        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;
-       }
+       if (ret_val)
+               goto release;
 
-       /* And invalidate the previously valid segment by setting
+       /*
+        * And invalidate the previously valid segment by setting
         * its signature word (0x13) high_byte to 0b. This can be
         * done without an erase because flash erase sets all bits
-        * to 1's. We can write 1's to 0's without an erase */
+        * to 1's. We can write 1's to 0's without an erase
+        */
        act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
        ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
-       if (ret_val) {
-               e1000_release_swflag_ich8lan(hw);
-               return ret_val;
-       }
+       if (ret_val)
+               goto release;
 
        /* Great!  Everything worked, we can now clear the cached entries. */
        for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
-               dev_spec->shadow_ram[i].modified = 0;
+               dev_spec->shadow_ram[i].modified = false;
                dev_spec->shadow_ram[i].value = 0xFFFF;
        }
 
-       e1000_release_swflag_ich8lan(hw);
+release:
+       nvm->ops.release(hw);
 
-       /* Reload the EEPROM, or else modifications will not appear
+       /*
+        * Reload the EEPROM, or else modifications will not appear
         * until after the next adapter reset.
         */
-       e1000e_reload_nvm(hw);
-       msleep(10);
+       if (!ret_val) {
+               e1000e_reload_nvm(hw);
+               msleep(10);
+       }
+
+out:
+       if (ret_val)
+               e_dbg("NVM update error: %d\n", ret_val);
 
        return ret_val;
 }
@@ -1294,7 +2082,8 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
        s32 ret_val;
        u16 data;
 
-       /* Read 0x19 and check bit 6.  If this bit is 0, the checksum
+       /*
+        * Read 0x19 and check bit 6.  If this bit is 0, the checksum
         * needs to be fixed.  This bit is an indication that the NVM
         * was prepared by OEM software and did not calculate the
         * checksum...a likely scenario.
@@ -1317,6 +2106,47 @@ 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)
+{
+       struct e1000_nvm_info *nvm = &hw->nvm;
+       union ich8_flash_protected_range pr0;
+       union ich8_hws_flash_status hsfsts;
+       u32 gfpreg;
+
+       nvm->ops.acquire(hw);
+
+       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);
+
+       nvm->ops.release(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.
@@ -1364,14 +2194,17 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
 
                ew32flash(ICH_FLASH_FDATA0, flash_data);
 
-               /* check if FCERR is set to 1 , if set to 1, clear it
-                * and try the whole sequence a few more times else done */
+               /*
+                * check if FCERR is set to 1 , if set to 1, clear it
+                * and try the whole sequence a few more times else done
+                */
                ret_val = e1000_flash_cycle_ich8lan(hw,
                                               ICH_FLASH_WRITE_COMMAND_TIMEOUT);
                if (!ret_val)
                        break;
 
-               /* If we're here, then things are most likely
+               /*
+                * If we're here, then things are most likely
                 * completely hosed, but if the error condition
                 * is detected, it won't hurt to give it another
                 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
@@ -1381,7 +2214,7 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
                        /* Repeat for some time before giving up. */
                        continue;
                if (hsfsts.hsf_status.flcdone == 0) {
-                       hw_dbg(hw, "Timeout error - flash cycle "
+                       e_dbg("Timeout error - flash cycle "
                                 "did not complete.");
                        break;
                }
@@ -1426,7 +2259,7 @@ static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
                return ret_val;
 
        for (program_retries = 0; program_retries < 100; program_retries++) {
-               hw_dbg(hw, "Retrying Byte %2.2X at offset %u\n", byte, offset);
+               e_dbg("Retrying Byte %2.2X at offset %u\n", byte, offset);
                udelay(100);
                ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
                if (!ret_val)
@@ -1456,15 +2289,14 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
        u32 flash_bank_size = nvm->flash_bank_size * 2;
        s32 ret_val;
        s32 count = 0;
-       s32 iteration;
-       s32 sector_size;
-       s32 j;
+       s32 j, iteration, sector_size;
 
        hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
 
-       /* Determine HW Sector size: Read BERASE bits of hw flash status
-        * register */
-       /* 00: The Hw sector is 256 bytes, hence we need to erase 16
+       /*
+        * Determine HW Sector size: Read BERASE bits of hw flash status
+        * register
+        * 00: The Hw sector is 256 bytes, hence we need to erase 16
         *     consecutive sectors.  The start index for the nth Hw sector
         *     can be calculated as = bank * 4096 + n * 256
         * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
@@ -1482,19 +2314,15 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
                break;
        case 1:
                sector_size = ICH_FLASH_SEG_SIZE_4K;
-               iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K;
+               iteration = 1;
                break;
        case 2:
-               if (hw->mac.type == e1000_ich9lan) {
-                       sector_size = ICH_FLASH_SEG_SIZE_8K;
-                       iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K;
-               } else {
-                       return -E1000_ERR_NVM;
-               }
+               sector_size = ICH_FLASH_SEG_SIZE_8K;
+               iteration = 1;
                break;
        case 3:
                sector_size = ICH_FLASH_SEG_SIZE_64K;
-               iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K;
+               iteration = 1;
                break;
        default:
                return -E1000_ERR_NVM;
@@ -1502,7 +2330,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
 
        /* Start with the base address, then add the sector offset. */
        flash_linear_addr = hw->nvm.flash_base_addr;
-       flash_linear_addr += (bank) ? (sector_size * iteration) : 0;
+       flash_linear_addr += (bank) ? flash_bank_size : 0;
 
        for (j = 0; j < iteration ; j++) {
                do {
@@ -1511,13 +2339,16 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
                        if (ret_val)
                                return ret_val;
 
-                       /* Write a value 11 (block Erase) in Flash
-                        * Cycle field in hw flash control */
+                       /*
+                        * Write a value 11 (block Erase) in Flash
+                        * Cycle field in hw flash control
+                        */
                        hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
                        hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
                        ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
 
-                       /* Write the last 24 bits of an index within the
+                       /*
+                        * Write the last 24 bits of an index within the
                         * block into Flash Linear address field in Flash
                         * Address.
                         */
@@ -1529,13 +2360,14 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
                        if (ret_val == 0)
                                break;
 
-                       /* Check if FCERR is set to 1.  If 1,
+                       /*
+                        * Check if FCERR is set to 1.  If 1,
                         * clear it and try the whole sequence
-                        * a few more times else Done */
+                        * a few more times else Done
+                        */
                        hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
                        if (hsfsts.hsf_status.flcerr == 1)
-                               /* repeat for some time before
-                                * giving up */
+                               /* repeat for some time before giving up */
                                continue;
                        else if (hsfsts.hsf_status.flcdone == 0)
                                return ret_val;
@@ -1560,7 +2392,7 @@ static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
 
        ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
        if (ret_val) {
-               hw_dbg(hw, "NVM Read Error\n");
+               e_dbg("NVM Read Error\n");
                return ret_val;
        }
 
@@ -1572,6 +2404,79 @@ static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
 }
 
 /**
+ *  e1000_id_led_init_pchlan - store LED configurations
+ *  @hw: pointer to the HW structure
+ *
+ *  PCH does not control LEDs via the LEDCTL register, rather it uses
+ *  the PHY LED configuration register.
+ *
+ *  PCH also does not have an "always on" or "always off" mode which
+ *  complicates the ID feature.  Instead of using the "on" mode to indicate
+ *  in ledctl_mode2 the LEDs to use for ID (see e1000e_id_led_init()),
+ *  use "link_up" mode.  The LEDs will still ID on request if there is no
+ *  link based on logic in e1000_led_[on|off]_pchlan().
+ **/
+static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       s32 ret_val;
+       const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
+       const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
+       u16 data, i, temp, shift;
+
+       /* Get default ID LED modes */
+       ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+       if (ret_val)
+               goto out;
+
+       mac->ledctl_default = er32(LEDCTL);
+       mac->ledctl_mode1 = mac->ledctl_default;
+       mac->ledctl_mode2 = mac->ledctl_default;
+
+       for (i = 0; i < 4; i++) {
+               temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
+               shift = (i * 5);
+               switch (temp) {
+               case ID_LED_ON1_DEF2:
+               case ID_LED_ON1_ON2:
+               case ID_LED_ON1_OFF2:
+                       mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+                       mac->ledctl_mode1 |= (ledctl_on << shift);
+                       break;
+               case ID_LED_OFF1_DEF2:
+               case ID_LED_OFF1_ON2:
+               case ID_LED_OFF1_OFF2:
+                       mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+                       mac->ledctl_mode1 |= (ledctl_off << shift);
+                       break;
+               default:
+                       /* Do nothing */
+                       break;
+               }
+               switch (temp) {
+               case ID_LED_DEF1_ON2:
+               case ID_LED_ON1_ON2:
+               case ID_LED_OFF1_ON2:
+                       mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+                       mac->ledctl_mode2 |= (ledctl_on << shift);
+                       break;
+               case ID_LED_DEF1_OFF2:
+               case ID_LED_ON1_OFF2:
+               case ID_LED_OFF1_OFF2:
+                       mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+                       mac->ledctl_mode2 |= (ledctl_off << shift);
+                       break;
+               default:
+                       /* Do nothing */
+                       break;
+               }
+       }
+
+out:
+       return ret_val;
+}
+
+/**
  *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
  *  @hw: pointer to the HW structure
  *
@@ -1585,7 +2490,8 @@ static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
 
        ret_val = e1000e_get_bus_info_pcie(hw);
 
-       /* ICH devices are "PCI Express"-ish.  They have
+       /*
+        * ICH devices are "PCI Express"-ish.  They have
         * a configuration space, but do not contain
         * PCI Express Capability registers, so bus width
         * must be hardcoded.
@@ -1605,21 +2511,24 @@ static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
  **/
 static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
 {
+       struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+       u16 reg;
        u32 ctrl, icr, kab;
        s32 ret_val;
 
-       /* Prevent the PCI-E bus from sticking if there is no TLP connection
+       /*
+        * Prevent the PCI-E bus from sticking if there is no TLP connection
         * on the last TLP read/write transaction when MAC is reset.
         */
        ret_val = e1000e_disable_pcie_master(hw);
-       if (ret_val) {
-               hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
-       }
+       if (ret_val)
+               e_dbg("PCI-E Master disable polling has failed.\n");
 
-       hw_dbg(hw, "Masking off all interrupts\n");
+       e_dbg("Masking off all interrupts\n");
        ew32(IMC, 0xffffffff);
 
-       /* Disable the Transmit and Receive units.  Then delay to allow
+       /*
+        * Disable the Transmit and Receive units.  Then delay to allow
         * any pending transactions to complete before we hit the MAC
         * with the global reset.
         */
@@ -1637,30 +2546,54 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
                ew32(PBS, E1000_PBS_16K);
        }
 
+       if (hw->mac.type == e1000_pchlan) {
+               /* Save the NVM K1 bit setting*/
+               ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &reg);
+               if (ret_val)
+                       return ret_val;
+
+               if (reg & E1000_NVM_K1_ENABLE)
+                       dev_spec->nvm_k1_enabled = true;
+               else
+                       dev_spec->nvm_k1_enabled = false;
+       }
+
        ctrl = er32(CTRL);
 
        if (!e1000_check_reset_block(hw)) {
-               /* PHY HW reset requires MAC CORE reset at the same
+               /*
+                * Full-chip reset requires MAC and PHY reset at the same
                 * time to make sure the interface between MAC and the
                 * external PHY is reset.
                 */
                ctrl |= E1000_CTRL_PHY_RST;
        }
        ret_val = e1000_acquire_swflag_ich8lan(hw);
-       hw_dbg(hw, "Issuing a global reset to ich8lan");
+       e_dbg("Issuing a global reset to ich8lan\n");
        ew32(CTRL, (ctrl | E1000_CTRL_RST));
        msleep(20);
 
-       ret_val = e1000e_get_auto_rd_done(hw);
-       if (ret_val) {
-               /*
-                * When auto config read does not complete, do not
-                * return with an error. This can happen in situations
-                * where there is no eeprom and prevents getting link.
-                */
-               hw_dbg(hw, "Auto Read Done did not complete\n");
+       if (!ret_val)
+               e1000_release_swflag_ich8lan(hw);
+
+       if (ctrl & E1000_CTRL_PHY_RST) {
+               ret_val = hw->phy.ops.get_cfg_done(hw);
+               if (ret_val)
+                       goto out;
+
+               ret_val = e1000_post_phy_reset_ich8lan(hw);
+               if (ret_val)
+                       goto out;
        }
 
+       /*
+        * For PCH, this write will make sure that any noise
+        * will be detected as a CRC error and be dropped rather than show up
+        * as a bad packet to the DMA engine.
+        */
+       if (hw->mac.type == e1000_pchlan)
+               ew32(CRC_OFFSET, 0x65656565);
+
        ew32(IMC, 0xffffffff);
        icr = er32(ICR);
 
@@ -1668,6 +2601,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
        kab |= E1000_KABGTXD_BGSQLBIAS;
        ew32(KABGTXD, kab);
 
+out:
        return ret_val;
 }
 
@@ -1693,39 +2627,52 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
        e1000_initialize_hw_bits_ich8lan(hw);
 
        /* Initialize identification LED */
-       ret_val = e1000e_id_led_init(hw);
-       if (ret_val) {
-               hw_dbg(hw, "Error initializing identification LED\n");
-               return ret_val;
-       }
+       ret_val = mac->ops.id_led_init(hw);
+       if (ret_val)
+               e_dbg("Error initializing identification LED\n");
+               /* This is not fatal and we should not stop init due to this */
 
        /* Setup the receive address. */
        e1000e_init_rx_addrs(hw, mac->rar_entry_count);
 
        /* Zero out the Multicast HASH table */
-       hw_dbg(hw, "Zeroing the MTA\n");
+       e_dbg("Zeroing the MTA\n");
        for (i = 0; i < mac->mta_reg_count; i++)
                E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
 
+       /*
+        * The 82578 Rx buffer will stall if wakeup is enabled in host and
+        * the ME.  Reading the BM_WUC register will clear the host wakeup bit.
+        * Reset the phy after disabling host wakeup to reset the Rx buffer.
+        */
+       if (hw->phy.type == e1000_phy_82578) {
+               hw->phy.ops.read_reg(hw, BM_WUC, &i);
+               ret_val = e1000_phy_hw_reset_ich8lan(hw);
+               if (ret_val)
+                       return ret_val;
+       }
+
        /* Setup link and flow control */
        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.
-        * By default, we should use snoop behavior. */
+       /*
+        * ICH8 has opposite polarity of no_snoop bits.
+        * By default, we should use snoop behavior.
+        */
        if (mac->type == e1000_ich8lan)
                snoop = PCIE_ICH8_SNOOP_ALL;
        else
@@ -1736,7 +2683,8 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
        ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
        ew32(CTRL_EXT, ctrl_ext);
 
-       /* Clear all of the statistics registers (clear on read).  It is
+       /*
+        * Clear all of the statistics registers (clear on read).  It is
         * important that we do this after we have tried to establish link
         * because the symbol error count will increment wildly if there
         * is no link.
@@ -1759,33 +2707,36 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
        /* Extended Device Control */
        reg = er32(CTRL_EXT);
        reg |= (1 << 22);
+       /* Enable PHY low-power state when MAC is at D3 w/o WoL */
+       if (hw->mac.type >= e1000_pchlan)
+               reg |= E1000_CTRL_EXT_PHYPDEN;
        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) {
@@ -1793,6 +2744,14 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
                reg &= ~(1 << 31);
                ew32(STATUS, reg);
        }
+
+       /*
+        * work-around descriptor data corruption issue during nfs v2 udp
+        * traffic, just disable the nfs filtering capability
+        */
+       reg = er32(RFCTL);
+       reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
+       ew32(RFCTL, reg);
 }
 
 /**
@@ -1807,29 +2766,49 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
  **/
 static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
 {
-       struct e1000_mac_info *mac = &hw->mac;
        s32 ret_val;
 
        if (e1000_check_reset_block(hw))
                return 0;
 
-       /* ICH parts do not have a word in the NVM to determine
+       /*
+        * ICH parts do not have a word in the NVM to determine
         * the default flow control setting, so we explicitly
         * set it to full.
         */
-       if (mac->fc == e1000_fc_default)
-               mac->fc = e1000_fc_full;
+       if (hw->fc.requested_mode == e1000_fc_default) {
+               /* Workaround h/w hang when Tx flow control enabled */
+               if (hw->mac.type == e1000_pchlan)
+                       hw->fc.requested_mode = e1000_fc_rx_pause;
+               else
+                       hw->fc.requested_mode = e1000_fc_full;
+       }
 
-       mac->original_fc = mac->fc;
+       /*
+        * 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", mac->fc);
+       e_dbg("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);
        if (ret_val)
                return ret_val;
 
-       ew32(FCTTV, mac->fc_pause_time);
+       ew32(FCTTV, hw->fc.pause_time);
+       if ((hw->phy.type == e1000_phy_82578) ||
+           (hw->phy.type == e1000_phy_82577)) {
+               ew32(FCRTV_PCH, hw->fc.refresh_time);
+
+               ret_val = hw->phy.ops.write_reg(hw,
+                                            PHY_REG(BM_PORT_CTRL_PAGE, 27),
+                                            hw->fc.pause_time);
+               if (ret_val)
+                       return ret_val;
+       }
 
        return e1000e_set_fc_watermarks(hw);
 }
@@ -1853,26 +2832,69 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
        ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
        ew32(CTRL, ctrl);
 
-       /* Set the mac to wait the maximum time between each iteration
+       /*
+        * Set the mac to wait the maximum time between each iteration
         * and increase the max iterations when polling the phy;
-        * this fixes erroneous timeouts at 10Mbps. */
-       ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+        * this fixes erroneous timeouts at 10Mbps.
+        */
+       ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_TIMEOUTS, 0xFFFF);
        if (ret_val)
                return ret_val;
-       ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+       ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
+                                      &reg_data);
        if (ret_val)
                return ret_val;
        reg_data |= 0x3F;
-       ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+       ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
+                                       reg_data);
        if (ret_val)
                return ret_val;
 
-       if (hw->phy.type == e1000_phy_igp_3) {
+       switch (hw->phy.type) {
+       case e1000_phy_igp_3:
                ret_val = e1000e_copper_link_setup_igp(hw);
                if (ret_val)
                        return ret_val;
-       }
+               break;
+       case e1000_phy_bm:
+       case e1000_phy_82578:
+               ret_val = e1000e_copper_link_setup_m88(hw);
+               if (ret_val)
+                       return ret_val;
+               break;
+       case e1000_phy_82577:
+               ret_val = e1000_copper_link_setup_82577(hw);
+               if (ret_val)
+                       return ret_val;
+               break;
+       case e1000_phy_ife:
+               ret_val = hw->phy.ops.read_reg(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 = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
+                                               reg_data);
+               if (ret_val)
+                       return ret_val;
+               break;
+       default:
+               break;
+       }
        return e1000e_setup_copper_link(hw);
 }
 
@@ -1882,7 +2904,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
  *  @speed: pointer to store current link speed
  *  @duplex: pointer to store the current link duplex
  *
- *  Calls the generic get_speed_and_duplex to retreive the current link
+ *  Calls the generic get_speed_and_duplex to retrieve the current link
  *  information and then calls the Kumeran lock loss workaround for links at
  *  gigabit speeds.
  **/
@@ -1930,9 +2952,11 @@ static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
        if (!dev_spec->kmrn_lock_loss_workaround_enabled)
                return 0;
 
-       /* Make sure link is up before proceeding.  If not just return.
+       /*
+        * Make sure link is up before proceeding.  If not just return.
         * Attempting this while link is negotiating fouled up link
-        * stability */
+        * stability
+        */
        ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
        if (!link)
                return 0;
@@ -1961,8 +2985,10 @@ static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
                     E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
        ew32(PHY_CTRL, phy_ctrl);
 
-       /* Call gig speed drop workaround on Gig disable before accessing
-        * any PHY registers */
+       /*
+        * Call gig speed drop workaround on Gig disable before accessing
+        * any PHY registers
+        */
        e1000e_gig_downshift_workaround_ich8lan(hw);
 
        /* unable to acquire PCS lock */
@@ -1970,12 +2996,12 @@ static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
 }
 
 /**
- *  e1000_set_kmrn_lock_loss_workaound_ich8lan - Set Kumeran workaround state
+ *  e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
  *  @hw: pointer to the HW structure
  *  @state: boolean value used to set the current Kumeran workaround state
  *
- *  If ICH8, set the current Kumeran workaround state (enabled - TRUE
- *  /disabled - FALSE).
+ *  If ICH8, set the current Kumeran workaround state (enabled - true
+ *  /disabled - false).
  **/
 void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
                                                 bool state)
@@ -1983,7 +3009,7 @@ void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
        struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
 
        if (hw->mac.type != e1000_ich8lan) {
-               hw_dbg(hw, "Workaround applies to ICH8 only.\n");
+               e_dbg("Workaround applies to ICH8 only.\n");
                return;
        }
 
@@ -2017,8 +3043,10 @@ void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
                        E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
                ew32(PHY_CTRL, reg);
 
-               /* Call gig speed drop workaround on Gig disable before
-                * accessing any PHY registers */
+               /*
+                * Call gig speed drop workaround on Gig disable before
+                * accessing any PHY registers
+                */
                if (hw->mac.type == e1000_ich8lan)
                        e1000e_gig_downshift_workaround_ich8lan(hw);
 
@@ -2074,6 +3102,38 @@ 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 applicable parts.
+ **/
+void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
+{
+       u32 phy_ctrl;
+
+       switch (hw->mac.type) {
+       case e1000_ich8lan:
+       case e1000_ich9lan:
+       case e1000_ich10lan:
+       case e1000_pchlan:
+               phy_ctrl = er32(PHY_CTRL);
+               phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
+                           E1000_PHY_CTRL_GBE_DISABLE;
+               ew32(PHY_CTRL, phy_ctrl);
+
+               if (hw->mac.type == e1000_pchlan)
+                       e1000_phy_hw_reset_ich8lan(hw);
+       default:
+               break;
+       }
+}
+
+/**
  *  e1000_cleanup_led_ich8lan - Restore the default LED operation
  *  @hw: pointer to the HW structure
  *
@@ -2121,6 +3181,167 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000_setup_led_pchlan - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use.
+ **/
+static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
+{
+       return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
+                                       (u16)hw->mac.ledctl_mode1);
+}
+
+/**
+ *  e1000_cleanup_led_pchlan - Restore the default LED operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the LED back to the default configuration.
+ **/
+static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
+{
+       return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
+                                       (u16)hw->mac.ledctl_default);
+}
+
+/**
+ *  e1000_led_on_pchlan - Turn LEDs on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn on the LEDs.
+ **/
+static s32 e1000_led_on_pchlan(struct e1000_hw *hw)
+{
+       u16 data = (u16)hw->mac.ledctl_mode2;
+       u32 i, led;
+
+       /*
+        * If no link, then turn LED on by setting the invert bit
+        * for each LED that's mode is "link_up" in ledctl_mode2.
+        */
+       if (!(er32(STATUS) & E1000_STATUS_LU)) {
+               for (i = 0; i < 3; i++) {
+                       led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+                       if ((led & E1000_PHY_LED0_MODE_MASK) !=
+                           E1000_LEDCTL_MODE_LINK_UP)
+                               continue;
+                       if (led & E1000_PHY_LED0_IVRT)
+                               data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+                       else
+                               data |= (E1000_PHY_LED0_IVRT << (i * 5));
+               }
+       }
+
+       return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
+}
+
+/**
+ *  e1000_led_off_pchlan - Turn LEDs off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn off the LEDs.
+ **/
+static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
+{
+       u16 data = (u16)hw->mac.ledctl_mode1;
+       u32 i, led;
+
+       /*
+        * If no link, then turn LED off by clearing the invert bit
+        * for each LED that's mode is "link_up" in ledctl_mode1.
+        */
+       if (!(er32(STATUS) & E1000_STATUS_LU)) {
+               for (i = 0; i < 3; i++) {
+                       led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+                       if ((led & E1000_PHY_LED0_MODE_MASK) !=
+                           E1000_LEDCTL_MODE_LINK_UP)
+                               continue;
+                       if (led & E1000_PHY_LED0_IVRT)
+                               data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+                       else
+                               data |= (E1000_PHY_LED0_IVRT << (i * 5));
+               }
+       }
+
+       return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
+}
+
+/**
+ *  e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Read appropriate register for the config done bit for completion status
+ *  and configure the PHY through s/w for EEPROM-less parts.
+ *
+ *  NOTE: some silicon which is EEPROM-less will fail trying to read the
+ *  config done bit, so only an error is logged and continues.  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)
+{
+       s32 ret_val = 0;
+       u32 bank = 0;
+       u32 status;
+
+       e1000e_get_cfg_done(hw);
+
+       /* Wait for indication from h/w that it has completed basic config */
+       if (hw->mac.type >= e1000_ich10lan) {
+               e1000_lan_init_done_ich8lan(hw);
+       } else {
+               ret_val = e1000e_get_auto_rd_done(hw);
+               if (ret_val) {
+                       /*
+                        * When auto config read does not complete, do not
+                        * return with an error. This can happen in situations
+                        * where there is no eeprom and prevents getting link.
+                        */
+                       e_dbg("Auto Read Done did not complete\n");
+                       ret_val = 0;
+               }
+       }
+
+       /* Clear PHY Reset Asserted bit */
+       status = er32(STATUS);
+       if (status & E1000_STATUS_PHYRA)
+               ew32(STATUS, status & ~E1000_STATUS_PHYRA);
+       else
+               e_dbg("PHY Reset Asserted not set - needs delay\n");
+
+       /* If EEPROM is not marked present, init the IGP 3 PHY manually */
+       if (hw->mac.type <= e1000_ich9lan) {
+               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 */
+                       e_dbg("EEPROM not present\n");
+                       ret_val = -E1000_ERR_CONFIG;
+               }
+       }
+
+       return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
+{
+       /* If the management interface is not enabled, then power down */
+       if (!(hw->mac.ops.check_mng_mode(hw) ||
+             hw->phy.ops.check_reset_block(hw)))
+               e1000_power_down_phy_copper(hw);
+}
+
+/**
  *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
  *  @hw: pointer to the HW structure
  *
@@ -2129,78 +3350,99 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
  **/
 static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
 {
-       u32 temp;
+       u16 phy_data;
 
        e1000e_clear_hw_cntrs_base(hw);
 
-       temp = er32(ALGNERRC);
-       temp = er32(RXERRC);
-       temp = er32(TNCRS);
-       temp = er32(CEXTERR);
-       temp = er32(TSCTC);
-       temp = er32(TSCTFC);
-
-       temp = er32(MGTPRC);
-       temp = er32(MGTPDC);
-       temp = er32(MGTPTC);
-
-       temp = er32(IAC);
-       temp = er32(ICRXOC);
-
+       er32(ALGNERRC);
+       er32(RXERRC);
+       er32(TNCRS);
+       er32(CEXTERR);
+       er32(TSCTC);
+       er32(TSCTFC);
+
+       er32(MGTPRC);
+       er32(MGTPDC);
+       er32(MGTPTC);
+
+       er32(IAC);
+       er32(ICRXOC);
+
+       /* Clear PHY statistics registers */
+       if ((hw->phy.type == e1000_phy_82578) ||
+           (hw->phy.type == e1000_phy_82577)) {
+               hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_ECOL_UPPER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_ECOL_LOWER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_MCC_UPPER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_MCC_LOWER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_LATECOL_UPPER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_LATECOL_LOWER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_COLC_UPPER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_COLC_LOWER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_DC_UPPER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_DC_LOWER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_TNCRS_UPPER, &phy_data);
+               hw->phy.ops.read_reg(hw, HV_TNCRS_LOWER, &phy_data);
+       }
 }
 
 static struct e1000_mac_operations ich8_mac_ops = {
-       .mng_mode_enab          = E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
-       .check_for_link         = e1000e_check_for_copper_link,
-       .cleanup_led            = e1000_cleanup_led_ich8lan,
+       .id_led_init            = e1000e_id_led_init,
+       .check_mng_mode         = e1000_check_mng_mode_ich8lan,
+       .check_for_link         = e1000_check_for_copper_link_ich8lan,
+       /* cleanup_led dependent on mac type */
        .clear_hw_cntrs         = e1000_clear_hw_cntrs_ich8lan,
        .get_bus_info           = e1000_get_bus_info_ich8lan,
+       .set_lan_id             = e1000_set_lan_id_single_port,
        .get_link_up_info       = e1000_get_link_up_info_ich8lan,
-       .led_on                 = e1000_led_on_ich8lan,
-       .led_off                = e1000_led_off_ich8lan,
-       .mc_addr_list_update    = e1000e_mc_addr_list_update_generic,
+       /* led_on dependent on mac type */
+       /* led_off dependent on mac type */
+       .update_mc_addr_list    = e1000e_update_mc_addr_list_generic,
        .reset_hw               = e1000_reset_hw_ich8lan,
        .init_hw                = e1000_init_hw_ich8lan,
        .setup_link             = e1000_setup_link_ich8lan,
        .setup_physical_interface= e1000_setup_copper_link_ich8lan,
+       /* id_led_init dependent on mac type */
 };
 
 static struct e1000_phy_operations ich8_phy_ops = {
-       .acquire_phy            = e1000_acquire_swflag_ich8lan,
+       .acquire                = e1000_acquire_swflag_ich8lan,
        .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,
+       .commit                 = NULL,
+       .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,
-       .release_phy            = e1000_release_swflag_ich8lan,
-       .reset_phy              = e1000_phy_hw_reset_ich8lan,
+       .read_reg               = e1000e_read_phy_reg_igp,
+       .release                = e1000_release_swflag_ich8lan,
+       .reset                  = e1000_phy_hw_reset_ich8lan,
        .set_d0_lplu_state      = e1000_set_d0_lplu_state_ich8lan,
        .set_d3_lplu_state      = e1000_set_d3_lplu_state_ich8lan,
-       .write_phy_reg          = e1000e_write_phy_reg_igp,
+       .write_reg              = e1000e_write_phy_reg_igp,
 };
 
 static struct e1000_nvm_operations ich8_nvm_ops = {
-       .acquire_nvm            = e1000_acquire_swflag_ich8lan,
-       .read_nvm               = e1000_read_nvm_ich8lan,
-       .release_nvm            = e1000_release_swflag_ich8lan,
-       .update_nvm             = e1000_update_nvm_checksum_ich8lan,
+       .acquire                = e1000_acquire_nvm_ich8lan,
+       .read                   = e1000_read_nvm_ich8lan,
+       .release                = e1000_release_nvm_ich8lan,
+       .update                 = e1000_update_nvm_checksum_ich8lan,
        .valid_led_default      = e1000_valid_led_default_ich8lan,
-       .validate_nvm           = e1000_validate_nvm_checksum_ich8lan,
-       .write_nvm              = e1000_write_nvm_ich8lan,
+       .validate               = e1000_validate_nvm_checksum_ich8lan,
+       .write                  = e1000_write_nvm_ich8lan,
 };
 
 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,
+       .max_hw_frame_size      = ETH_FRAME_LEN + ETH_FCS_LEN,
+       .get_variants           = e1000_get_variants_ich8lan,
        .mac_ops                = &ich8_mac_ops,
        .phy_ops                = &ich8_phy_ops,
        .nvm_ops                = &ich8_nvm_ops,
@@ -2209,6 +3451,26 @@ 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
+                                 | FLAG_HAS_AMT
+                                 | FLAG_HAS_ERT
+                                 | FLAG_HAS_FLASH
+                                 | FLAG_APME_IN_WUC,
+       .pba                    = 10,
+       .max_hw_frame_size      = DEFAULT_JUMBO,
+       .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
@@ -2217,9 +3479,28 @@ struct e1000_info e1000_ich9_info = {
                                  | FLAG_HAS_FLASH
                                  | FLAG_APME_IN_WUC,
        .pba                    = 10,
-       .get_invariants         = e1000_get_invariants_ich8lan,
+       .max_hw_frame_size      = DEFAULT_JUMBO,
+       .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_pch_info = {
+       .mac                    = e1000_pchlan,
+       .flags                  = FLAG_IS_ICH
+                                 | FLAG_HAS_WOL
+                                 | FLAG_RX_CSUM_ENABLED
+                                 | FLAG_HAS_CTRLEXT_ON_LOAD
+                                 | FLAG_HAS_AMT
+                                 | FLAG_HAS_FLASH
+                                 | FLAG_HAS_JUMBO_FRAMES
+                                 | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
+                                 | FLAG_APME_IN_WUC,
+       .pba                    = 26,
+       .max_hw_frame_size      = 4096,
+       .get_variants           = e1000_get_variants_ich8lan,
+       .mac_ops                = &ich8_mac_ops,
+       .phy_ops                = &ich8_phy_ops,
+       .nvm_ops                = &ich8_nvm_ops,
+};