omap_hsmmc: fix out of bounds array access
[oweals/u-boot.git] / drivers / net / e1000.c
index 4a7225202c179216529b0e3cdaf0bb910c68287c..8ba98b27d52283be000f0896f838ca5e13eba591 100644 (file)
@@ -21,7 +21,7 @@ tested on both gig copper and gig fiber boards
 
   You should have received a copy of the GNU General Public License along with
   this program; if not, write to the Free Software Foundation, Inc., 59
 
   You should have received a copy of the GNU General Public License along with
   this program; if not, write to the Free Software Foundation, Inc., 59
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
   The full GNU General Public License is included in this distribution in the
   file called LICENSE.
 
   The full GNU General Public License is included in this distribution in the
   file called LICENSE.
@@ -40,21 +40,19 @@ tested on both gig copper and gig fiber boards
  *  Copyright (C) Linux Networx.
  *  Massive upgrade to work with the new intel gigabit NICs.
  *  <ebiederman at lnxi dot com>
  *  Copyright (C) Linux Networx.
  *  Massive upgrade to work with the new intel gigabit NICs.
  *  <ebiederman at lnxi dot com>
+ *
+ *  Copyright 2011 Freescale Semiconductor, Inc.
  */
 
 #include "e1000.h"
 
  */
 
 #include "e1000.h"
 
-#if defined(CONFIG_CMD_NET) \
-       && defined(CONFIG_NET_MULTI) && defined(CONFIG_E1000)
-
 #define TOUT_LOOP   100000
 
 #define TOUT_LOOP   100000
 
-#undef virt_to_bus
-#define        virt_to_bus(x)  ((unsigned long)x)
+#define virt_to_bus(devno, v)  pci_virt_to_mem(devno, (void *) (v))
 #define bus_to_phys(devno, a)  pci_mem_to_phys(devno, a)
 #define bus_to_phys(devno, a)  pci_mem_to_phys(devno, a)
-#define mdelay(n)       udelay((n)*1000)
 
 
-#define E1000_DEFAULT_PBA    0x00000030
+#define E1000_DEFAULT_PCI_PBA  0x00000030
+#define E1000_DEFAULT_PCIE_PBA 0x000a0026
 
 /* NIC specific static variables go here */
 
 
 /* NIC specific static variables go here */
 
@@ -68,7 +66,7 @@ static struct e1000_rx_desc *rx_base;
 static int tx_tail;
 static int rx_tail, rx_last;
 
 static int tx_tail;
 static int rx_tail, rx_last;
 
-static struct pci_device_id supported[] = {
+static struct pci_device_id e1000_supported[] = {
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82542},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82543GC_FIBER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82543GC_COPPER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82542},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82543GC_FIBER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82543GC_COPPER},
@@ -78,11 +76,38 @@ static struct pci_device_id supported[] = {
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544GC_LOM},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_COPPER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544GC_LOM},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_COPPER},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545GM_COPPER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_COPPER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_FIBER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_FIBER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_COPPER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_FIBER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_FIBER},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546GB_COPPER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM_LOM},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541ER},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM_LOM},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541ER},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541GI_LF},
+       /* E1000 PCIe card */
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_COPPER},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_FIBER      },
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_SERDES     },
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_QUAD_COPPER},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571PT_QUAD_COPPER},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_QUAD_FIBER},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_QUAD_COPPER_LOWPROFILE},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_SERDES_DUAL},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82571EB_SERDES_QUAD},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI_COPPER},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI_FIBER},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI_SERDES},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82572EI},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82573E},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82573E_IAMT},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82573L},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82574L},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546GB_QUAD_COPPER_KSP3},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_COPPER_DPT},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_SERDES_DPT},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_COPPER_SPT},
+       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80003ES2LAN_SERDES_SPT},
+       {}
 };
 
 /* Function forward declarations */
 };
 
 /* Function forward declarations */
@@ -95,33 +120,31 @@ static int e1000_config_mac_to_phy(struct e1000_hw *hw);
 static int e1000_config_fc_after_link_up(struct e1000_hw *hw);
 static int e1000_check_for_link(struct eth_device *nic);
 static int e1000_wait_autoneg(struct e1000_hw *hw);
 static int e1000_config_fc_after_link_up(struct e1000_hw *hw);
 static int e1000_check_for_link(struct eth_device *nic);
 static int e1000_wait_autoneg(struct e1000_hw *hw);
-static void e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed,
+static int e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed,
                                       uint16_t * duplex);
 static int e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
                              uint16_t * phy_data);
 static int e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
                               uint16_t phy_data);
                                       uint16_t * duplex);
 static int e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
                              uint16_t * phy_data);
 static int e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
                               uint16_t phy_data);
-static void e1000_phy_hw_reset(struct e1000_hw *hw);
+static int32_t e1000_phy_hw_reset(struct e1000_hw *hw);
 static int e1000_phy_reset(struct e1000_hw *hw);
 static int e1000_detect_gig_phy(struct e1000_hw *hw);
 static int e1000_phy_reset(struct e1000_hw *hw);
 static int e1000_detect_gig_phy(struct e1000_hw *hw);
+static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw);
+static void e1000_set_media_type(struct e1000_hw *hw);
 
 
-#define E1000_WRITE_REG(a, reg, value) (writel((value), ((a)->hw_addr + E1000_##reg)))
-#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + E1000_##reg))
-#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) (\
-                       writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))))
-#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
-       readl((a)->hw_addr + E1000_##reg + ((offset) << 2)))
-#define E1000_WRITE_FLUSH(a) {uint32_t x; x = E1000_READ_REG(a, STATUS);}
+static int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
+static int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
 
 
-#ifndef CONFIG_AP1000 /* remove for warnings */
+static int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
+               uint16_t words,
+               uint16_t *data);
 /******************************************************************************
  * Raises the EEPROM's clock input.
  *
  * hw - Struct containing variables accessed by shared code
  * eecd - EECD's current value
  *****************************************************************************/
 /******************************************************************************
  * Raises the EEPROM's clock input.
  *
  * hw - Struct containing variables accessed by shared code
  * eecd - EECD's current value
  *****************************************************************************/
-static void
-e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t * eecd)
+void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t * eecd)
 {
        /* Raise the clock input to the EEPROM (by setting the SK bit), and then
         * wait 50 microseconds.
 {
        /* Raise the clock input to the EEPROM (by setting the SK bit), and then
         * wait 50 microseconds.
@@ -138,8 +161,7 @@ e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t * eecd)
  * hw - Struct containing variables accessed by shared code
  * eecd - EECD's current value
  *****************************************************************************/
  * hw - Struct containing variables accessed by shared code
  * eecd - EECD's current value
  *****************************************************************************/
-static void
-e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t * eecd)
+void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t * eecd)
 {
        /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
         * wait 50 microseconds.
 {
        /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
         * wait 50 microseconds.
@@ -204,17 +226,17 @@ e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count)
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
 static uint16_t
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
 static uint16_t
-e1000_shift_in_ee_bits(struct e1000_hw *hw)
+e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count)
 {
        uint32_t eecd;
        uint32_t i;
        uint16_t data;
 
 {
        uint32_t eecd;
        uint32_t i;
        uint16_t data;
 
-       /* In order to read a register from the EEPROM, we need to shift 16 bits
-        * in from the EEPROM. Bits are "shifted in" by raising the clock input to
-        * the EEPROM (setting the SK bit), and then reading the value of the "DO"
-        * bit.  During this "shifting in" process the "DI" bit should always be
-        * clear..
+       /* In order to read a register from the EEPROM, we need to shift 'count'
+        * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+        * input to the EEPROM (setting the SK bit), and then reading the
+        * value of the "DO" bit.  During this "shifting in" process the
+        * "DI" bit should always be clear.
         */
 
        eecd = E1000_READ_REG(hw, EECD);
         */
 
        eecd = E1000_READ_REG(hw, EECD);
@@ -222,7 +244,7 @@ e1000_shift_in_ee_bits(struct e1000_hw *hw)
        eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
        data = 0;
 
        eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
        data = 0;
 
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < count; i++) {
                data = data << 1;
                e1000_raise_ee_clk(hw, &eecd);
 
                data = data << 1;
                e1000_raise_ee_clk(hw, &eecd);
 
@@ -239,309 +261,892 @@ e1000_shift_in_ee_bits(struct e1000_hw *hw)
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
- * Prepares EEPROM for access
+ * Returns EEPROM to a "standby" state
  *
  * hw - Struct containing variables accessed by shared code
  *
  * hw - Struct containing variables accessed by shared code
- *
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
- * function should be called before issuing a command to the EEPROM.
  *****************************************************************************/
  *****************************************************************************/
-static void
-e1000_setup_eeprom(struct e1000_hw *hw)
+void e1000_standby_eeprom(struct e1000_hw *hw)
 {
 {
+       struct e1000_eeprom_info *eeprom = &hw->eeprom;
        uint32_t eecd;
 
        eecd = E1000_READ_REG(hw, EECD);
 
        uint32_t eecd;
 
        eecd = E1000_READ_REG(hw, EECD);
 
-       /* Clear SK and DI */
-       eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
-       E1000_WRITE_REG(hw, EECD, eecd);
+       if (eeprom->type == e1000_eeprom_microwire) {
+               eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+               E1000_WRITE_REG(hw, EECD, eecd);
+               E1000_WRITE_FLUSH(hw);
+               udelay(eeprom->delay_usec);
 
 
-       /* Set CS */
-       eecd |= E1000_EECD_CS;
-       E1000_WRITE_REG(hw, EECD, eecd);
+               /* Clock high */
+               eecd |= E1000_EECD_SK;
+               E1000_WRITE_REG(hw, EECD, eecd);
+               E1000_WRITE_FLUSH(hw);
+               udelay(eeprom->delay_usec);
+
+               /* Select EEPROM */
+               eecd |= E1000_EECD_CS;
+               E1000_WRITE_REG(hw, EECD, eecd);
+               E1000_WRITE_FLUSH(hw);
+               udelay(eeprom->delay_usec);
+
+               /* Clock low */
+               eecd &= ~E1000_EECD_SK;
+               E1000_WRITE_REG(hw, EECD, eecd);
+               E1000_WRITE_FLUSH(hw);
+               udelay(eeprom->delay_usec);
+       } else if (eeprom->type == e1000_eeprom_spi) {
+               /* Toggle CS to flush commands */
+               eecd |= E1000_EECD_CS;
+               E1000_WRITE_REG(hw, EECD, eecd);
+               E1000_WRITE_FLUSH(hw);
+               udelay(eeprom->delay_usec);
+               eecd &= ~E1000_EECD_CS;
+               E1000_WRITE_REG(hw, EECD, eecd);
+               E1000_WRITE_FLUSH(hw);
+               udelay(eeprom->delay_usec);
+       }
+}
+
+/***************************************************************************
+* Description:     Determines if the onboard NVM is FLASH or EEPROM.
+*
+* hw - Struct containing variables accessed by shared code
+****************************************************************************/
+static boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw)
+{
+       uint32_t eecd = 0;
+
+       DEBUGFUNC();
+
+       if (hw->mac_type == e1000_ich8lan)
+               return FALSE;
+
+       if (hw->mac_type == e1000_82573 || hw->mac_type == e1000_82574) {
+               eecd = E1000_READ_REG(hw, EECD);
+
+               /* Isolate bits 15 & 16 */
+               eecd = ((eecd >> 15) & 0x03);
+
+               /* If both bits are set, device is Flash type */
+               if (eecd == 0x03)
+                       return FALSE;
+       }
+       return TRUE;
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
- * Returns EEPROM to a "standby" state
+ * Prepares EEPROM for access
  *
  * hw - Struct containing variables accessed by shared code
  *
  * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
+ * function should be called before issuing a command to the EEPROM.
  *****************************************************************************/
  *****************************************************************************/
-static void
-e1000_standby_eeprom(struct e1000_hw *hw)
+int32_t e1000_acquire_eeprom(struct e1000_hw *hw)
 {
 {
-       uint32_t eecd;
+       struct e1000_eeprom_info *eeprom = &hw->eeprom;
+       uint32_t eecd, i = 0;
+
+       DEBUGFUNC();
 
 
+       if (e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM))
+               return -E1000_ERR_SWFW_SYNC;
        eecd = E1000_READ_REG(hw, EECD);
 
        eecd = E1000_READ_REG(hw, EECD);
 
-       /* Deselct EEPROM */
-       eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
-       E1000_WRITE_REG(hw, EECD, eecd);
-       E1000_WRITE_FLUSH(hw);
-       udelay(50);
+       if (hw->mac_type != e1000_82573 || hw->mac_type != e1000_82574) {
+               /* Request EEPROM Access */
+               if (hw->mac_type > e1000_82544) {
+                       eecd |= E1000_EECD_REQ;
+                       E1000_WRITE_REG(hw, EECD, eecd);
+                       eecd = E1000_READ_REG(hw, EECD);
+                       while ((!(eecd & E1000_EECD_GNT)) &&
+                               (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+                               i++;
+                               udelay(5);
+                               eecd = E1000_READ_REG(hw, EECD);
+                       }
+                       if (!(eecd & E1000_EECD_GNT)) {
+                               eecd &= ~E1000_EECD_REQ;
+                               E1000_WRITE_REG(hw, EECD, eecd);
+                               DEBUGOUT("Could not acquire EEPROM grant\n");
+                               return -E1000_ERR_EEPROM;
+                       }
+               }
+       }
 
 
-       /* Clock high */
-       eecd |= E1000_EECD_SK;
-       E1000_WRITE_REG(hw, EECD, eecd);
-       E1000_WRITE_FLUSH(hw);
-       udelay(50);
+       /* Setup EEPROM for Read/Write */
 
 
-       /* Select EEPROM */
-       eecd |= E1000_EECD_CS;
-       E1000_WRITE_REG(hw, EECD, eecd);
-       E1000_WRITE_FLUSH(hw);
-       udelay(50);
+       if (eeprom->type == e1000_eeprom_microwire) {
+               /* Clear SK and DI */
+               eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+               E1000_WRITE_REG(hw, EECD, eecd);
 
 
-       /* Clock low */
-       eecd &= ~E1000_EECD_SK;
-       E1000_WRITE_REG(hw, EECD, eecd);
-       E1000_WRITE_FLUSH(hw);
-       udelay(50);
+               /* Set CS */
+               eecd |= E1000_EECD_CS;
+               E1000_WRITE_REG(hw, EECD, eecd);
+       } else if (eeprom->type == e1000_eeprom_spi) {
+               /* Clear SK and CS */
+               eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+               E1000_WRITE_REG(hw, EECD, eecd);
+               udelay(1);
+       }
+
+       return E1000_SUCCESS;
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
- * Reads a 16 bit word from the EEPROM.
+ * Sets up eeprom variables in the hw struct.  Must be called after mac_type
+ * is configured.  Additionally, if this is ICH8, the flash controller GbE
+ * registers must be mapped, or this will crash.
  *
  * hw - Struct containing variables accessed by shared code
  *
  * hw - Struct containing variables accessed by shared code
- * offset - offset of  word in the EEPROM to read
- * data - word read from the EEPROM
  *****************************************************************************/
  *****************************************************************************/
-static int
-e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, uint16_t * data)
+static int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
 {
 {
-       uint32_t eecd;
-       uint32_t i = 0;
-       int large_eeprom = FALSE;
+       struct e1000_eeprom_info *eeprom = &hw->eeprom;
+       uint32_t eecd = E1000_READ_REG(hw, EECD);
+       int32_t ret_val = E1000_SUCCESS;
+       uint16_t eeprom_size;
 
 
-       /* Request EEPROM Access */
-       if (hw->mac_type > e1000_82544) {
-               eecd = E1000_READ_REG(hw, EECD);
-               if (eecd & E1000_EECD_SIZE)
-                       large_eeprom = TRUE;
-               eecd |= E1000_EECD_REQ;
-               E1000_WRITE_REG(hw, EECD, eecd);
-               eecd = E1000_READ_REG(hw, EECD);
-               while ((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
-                       i++;
-                       udelay(10);
-                       eecd = E1000_READ_REG(hw, EECD);
+       DEBUGFUNC();
+
+       switch (hw->mac_type) {
+       case e1000_82542_rev2_0:
+       case e1000_82542_rev2_1:
+       case e1000_82543:
+       case e1000_82544:
+               eeprom->type = e1000_eeprom_microwire;
+               eeprom->word_size = 64;
+               eeprom->opcode_bits = 3;
+               eeprom->address_bits = 6;
+               eeprom->delay_usec = 50;
+               eeprom->use_eerd = FALSE;
+               eeprom->use_eewr = FALSE;
+       break;
+       case e1000_82540:
+       case e1000_82545:
+       case e1000_82545_rev_3:
+       case e1000_82546:
+       case e1000_82546_rev_3:
+               eeprom->type = e1000_eeprom_microwire;
+               eeprom->opcode_bits = 3;
+               eeprom->delay_usec = 50;
+               if (eecd & E1000_EECD_SIZE) {
+                       eeprom->word_size = 256;
+                       eeprom->address_bits = 8;
+               } else {
+                       eeprom->word_size = 64;
+                       eeprom->address_bits = 6;
+               }
+               eeprom->use_eerd = FALSE;
+               eeprom->use_eewr = FALSE;
+               break;
+       case e1000_82541:
+       case e1000_82541_rev_2:
+       case e1000_82547:
+       case e1000_82547_rev_2:
+               if (eecd & E1000_EECD_TYPE) {
+                       eeprom->type = e1000_eeprom_spi;
+                       eeprom->opcode_bits = 8;
+                       eeprom->delay_usec = 1;
+                       if (eecd & E1000_EECD_ADDR_BITS) {
+                               eeprom->page_size = 32;
+                               eeprom->address_bits = 16;
+                       } else {
+                               eeprom->page_size = 8;
+                               eeprom->address_bits = 8;
+                       }
+               } else {
+                       eeprom->type = e1000_eeprom_microwire;
+                       eeprom->opcode_bits = 3;
+                       eeprom->delay_usec = 50;
+                       if (eecd & E1000_EECD_ADDR_BITS) {
+                               eeprom->word_size = 256;
+                               eeprom->address_bits = 8;
+                       } else {
+                               eeprom->word_size = 64;
+                               eeprom->address_bits = 6;
+                       }
+               }
+               eeprom->use_eerd = FALSE;
+               eeprom->use_eewr = FALSE;
+               break;
+       case e1000_82571:
+       case e1000_82572:
+               eeprom->type = e1000_eeprom_spi;
+               eeprom->opcode_bits = 8;
+               eeprom->delay_usec = 1;
+               if (eecd & E1000_EECD_ADDR_BITS) {
+                       eeprom->page_size = 32;
+                       eeprom->address_bits = 16;
+               } else {
+                       eeprom->page_size = 8;
+                       eeprom->address_bits = 8;
+               }
+               eeprom->use_eerd = FALSE;
+               eeprom->use_eewr = FALSE;
+               break;
+       case e1000_82573:
+       case e1000_82574:
+               eeprom->type = e1000_eeprom_spi;
+               eeprom->opcode_bits = 8;
+               eeprom->delay_usec = 1;
+               if (eecd & E1000_EECD_ADDR_BITS) {
+                       eeprom->page_size = 32;
+                       eeprom->address_bits = 16;
+               } else {
+                       eeprom->page_size = 8;
+                       eeprom->address_bits = 8;
                }
                }
-               if (!(eecd & E1000_EECD_GNT)) {
-                       eecd &= ~E1000_EECD_REQ;
+               eeprom->use_eerd = TRUE;
+               eeprom->use_eewr = TRUE;
+               if (e1000_is_onboard_nvm_eeprom(hw) == FALSE) {
+                       eeprom->type = e1000_eeprom_flash;
+                       eeprom->word_size = 2048;
+
+               /* Ensure that the Autonomous FLASH update bit is cleared due to
+                * Flash update issue on parts which use a FLASH for NVM. */
+                       eecd &= ~E1000_EECD_AUPDEN;
                        E1000_WRITE_REG(hw, EECD, eecd);
                        E1000_WRITE_REG(hw, EECD, eecd);
-                       DEBUGOUT("Could not acquire EEPROM grant\n");
-                       return -E1000_ERR_EEPROM;
                }
                }
-       }
+               break;
+       case e1000_80003es2lan:
+               eeprom->type = e1000_eeprom_spi;
+               eeprom->opcode_bits = 8;
+               eeprom->delay_usec = 1;
+               if (eecd & E1000_EECD_ADDR_BITS) {
+                       eeprom->page_size = 32;
+                       eeprom->address_bits = 16;
+               } else {
+                       eeprom->page_size = 8;
+                       eeprom->address_bits = 8;
+               }
+               eeprom->use_eerd = TRUE;
+               eeprom->use_eewr = FALSE;
+               break;
 
 
-       /*  Prepare the EEPROM for reading  */
-       e1000_setup_eeprom(hw);
+       /* ich8lan does not support currently. if needed, please
+        * add corresponding code and functions.
+        */
+#if 0
+       case e1000_ich8lan:
+               {
+               int32_t  i = 0;
+
+               eeprom->type = e1000_eeprom_ich8;
+               eeprom->use_eerd = FALSE;
+               eeprom->use_eewr = FALSE;
+               eeprom->word_size = E1000_SHADOW_RAM_WORDS;
+               uint32_t flash_size = E1000_READ_ICH_FLASH_REG(hw,
+                               ICH_FLASH_GFPREG);
+               /* Zero the shadow RAM structure. But don't load it from NVM
+                * so as to save time for driver init */
+               if (hw->eeprom_shadow_ram != NULL) {
+                       for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+                               hw->eeprom_shadow_ram[i].modified = FALSE;
+                               hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+                       }
+               }
 
 
-       /*  Send the READ command (opcode + addr)  */
-       e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3);
-       e1000_shift_out_ee_bits(hw, offset, (large_eeprom) ? 8 : 6);
+               hw->flash_base_addr = (flash_size & ICH_GFPREG_BASE_MASK) *
+                               ICH_FLASH_SECTOR_SIZE;
 
 
-       /* Read the data */
-       *data = e1000_shift_in_ee_bits(hw);
+               hw->flash_bank_size = ((flash_size >> 16)
+                               & ICH_GFPREG_BASE_MASK) + 1;
+               hw->flash_bank_size -= (flash_size & ICH_GFPREG_BASE_MASK);
 
 
-       /* End this read operation */
-       e1000_standby_eeprom(hw);
+               hw->flash_bank_size *= ICH_FLASH_SECTOR_SIZE;
 
 
-       /* Stop requesting EEPROM access */
-       if (hw->mac_type > e1000_82544) {
-               eecd = E1000_READ_REG(hw, EECD);
-               eecd &= ~E1000_EECD_REQ;
-               E1000_WRITE_REG(hw, EECD, eecd);
+               hw->flash_bank_size /= 2 * sizeof(uint16_t);
+               break;
+               }
+#endif
+       default:
+               break;
        }
 
        }
 
-       return 0;
+       if (eeprom->type == e1000_eeprom_spi) {
+               /* eeprom_size will be an enum [0..8] that maps
+                * to eeprom sizes 128B to
+                * 32KB (incremented by powers of 2).
+                */
+               if (hw->mac_type <= e1000_82547_rev_2) {
+                       /* Set to default value for initial eeprom read. */
+                       eeprom->word_size = 64;
+                       ret_val = e1000_read_eeprom(hw, EEPROM_CFG, 1,
+                                       &eeprom_size);
+                       if (ret_val)
+                               return ret_val;
+                       eeprom_size = (eeprom_size & EEPROM_SIZE_MASK)
+                               >> EEPROM_SIZE_SHIFT;
+                       /* 256B eeprom size was not supported in earlier
+                        * hardware, so we bump eeprom_size up one to
+                        * ensure that "1" (which maps to 256B) is never
+                        * the result used in the shifting logic below. */
+                       if (eeprom_size)
+                               eeprom_size++;
+               } else {
+                       eeprom_size = (uint16_t)((eecd &
+                               E1000_EECD_SIZE_EX_MASK) >>
+                               E1000_EECD_SIZE_EX_SHIFT);
+               }
+
+               eeprom->word_size = 1 << (eeprom_size + EEPROM_WORD_SIZE_SHIFT);
+       }
+       return ret_val;
 }
 
 }
 
-#if 0
-static void
-e1000_eeprom_cleanup(struct e1000_hw *hw)
+/******************************************************************************
+ * Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t
+e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd)
 {
 {
-       uint32_t eecd;
+       uint32_t attempts = 100000;
+       uint32_t i, reg = 0;
+       int32_t done = E1000_ERR_EEPROM;
 
 
-       eecd = E1000_READ_REG(hw, EECD);
-       eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
-       E1000_WRITE_REG(hw, EECD, eecd);
-       e1000_raise_ee_clk(hw, &eecd);
-       e1000_lower_ee_clk(hw, &eecd);
+       for (i = 0; i < attempts; i++) {
+               if (eerd == E1000_EEPROM_POLL_READ)
+                       reg = E1000_READ_REG(hw, EERD);
+               else
+                       reg = E1000_READ_REG(hw, EEWR);
+
+               if (reg & E1000_EEPROM_RW_REG_DONE) {
+                       done = E1000_SUCCESS;
+                       break;
+               }
+               udelay(5);
+       }
+
+       return done;
 }
 
 }
 
-static uint16_t
-e1000_wait_eeprom_done(struct e1000_hw *hw)
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+static int32_t
+e1000_read_eeprom_eerd(struct e1000_hw *hw,
+                       uint16_t offset,
+                       uint16_t words,
+                       uint16_t *data)
 {
 {
-       uint32_t eecd;
-       uint32_t i;
+       uint32_t i, eerd = 0;
+       int32_t error = 0;
+
+       for (i = 0; i < words; i++) {
+               eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) +
+                       E1000_EEPROM_RW_REG_START;
+
+               E1000_WRITE_REG(hw, EERD, eerd);
+               error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
+
+               if (error)
+                       break;
+               data[i] = (E1000_READ_REG(hw, EERD) >>
+                               E1000_EEPROM_RW_REG_DATA);
 
 
-       e1000_standby_eeprom(hw);
-       for (i = 0; i < 200; i++) {
-               eecd = E1000_READ_REG(hw, EECD);
-               if (eecd & E1000_EECD_DO)
-                       return (TRUE);
-               udelay(5);
        }
        }
-       return (FALSE);
+
+       return error;
 }
 
 }
 
-static int
-e1000_write_eeprom(struct e1000_hw *hw, uint16_t Reg, uint16_t Data)
+void e1000_release_eeprom(struct e1000_hw *hw)
 {
        uint32_t eecd;
 {
        uint32_t eecd;
-       int large_eeprom = FALSE;
-       int i = 0;
 
 
-       /* Request EEPROM Access */
-       if (hw->mac_type > e1000_82544) {
-               eecd = E1000_READ_REG(hw, EECD);
-               if (eecd & E1000_EECD_SIZE)
-                       large_eeprom = TRUE;
-               eecd |= E1000_EECD_REQ;
+       DEBUGFUNC();
+
+       eecd = E1000_READ_REG(hw, EECD);
+
+       if (hw->eeprom.type == e1000_eeprom_spi) {
+               eecd |= E1000_EECD_CS;  /* Pull CS high */
+               eecd &= ~E1000_EECD_SK; /* Lower SCK */
+
                E1000_WRITE_REG(hw, EECD, eecd);
                E1000_WRITE_REG(hw, EECD, eecd);
-               eecd = E1000_READ_REG(hw, EECD);
-               while ((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
-                       i++;
-                       udelay(5);
-                       eecd = E1000_READ_REG(hw, EECD);
-               }
-               if (!(eecd & E1000_EECD_GNT)) {
-                       eecd &= ~E1000_EECD_REQ;
-                       E1000_WRITE_REG(hw, EECD, eecd);
-                       DEBUGOUT("Could not acquire EEPROM grant\n");
-                       return FALSE;
-               }
-       }
-       e1000_setup_eeprom(hw);
-       e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5);
-       e1000_shift_out_ee_bits(hw, Reg, (large_eeprom) ? 6 : 4);
-       e1000_standby_eeprom(hw);
-       e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3);
-       e1000_shift_out_ee_bits(hw, Reg, (large_eeprom) ? 8 : 6);
-       e1000_shift_out_ee_bits(hw, Data, 16);
-       if (!e1000_wait_eeprom_done(hw)) {
-               return FALSE;
+
+               udelay(hw->eeprom.delay_usec);
+       } else if (hw->eeprom.type == e1000_eeprom_microwire) {
+               /* cleanup eeprom */
+
+               /* CS on Microwire is active-high */
+               eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+               E1000_WRITE_REG(hw, EECD, eecd);
+
+               /* Rising edge of clock */
+               eecd |= E1000_EECD_SK;
+               E1000_WRITE_REG(hw, EECD, eecd);
+               E1000_WRITE_FLUSH(hw);
+               udelay(hw->eeprom.delay_usec);
+
+               /* Falling edge of clock */
+               eecd &= ~E1000_EECD_SK;
+               E1000_WRITE_REG(hw, EECD, eecd);
+               E1000_WRITE_FLUSH(hw);
+               udelay(hw->eeprom.delay_usec);
        }
        }
-       e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5);
-       e1000_shift_out_ee_bits(hw, Reg, (large_eeprom) ? 6 : 4);
-       e1000_eeprom_cleanup(hw);
 
        /* Stop requesting EEPROM access */
        if (hw->mac_type > e1000_82544) {
 
        /* Stop requesting EEPROM access */
        if (hw->mac_type > e1000_82544) {
-               eecd = E1000_READ_REG(hw, EECD);
                eecd &= ~E1000_EECD_REQ;
                E1000_WRITE_REG(hw, EECD, eecd);
        }
                eecd &= ~E1000_EECD_REQ;
                E1000_WRITE_REG(hw, EECD, eecd);
        }
-       i = 0;
-       eecd = E1000_READ_REG(hw, EECD);
-       while (((eecd & E1000_EECD_GNT)) && (i < 500)) {
-               i++;
-               udelay(10);
-               eecd = E1000_READ_REG(hw, EECD);
-       }
-       if ((eecd & E1000_EECD_GNT)) {
-               DEBUGOUT("Could not release EEPROM grant\n");
-       }
-       return TRUE;
 }
 }
-#endif
-
 /******************************************************************************
 /******************************************************************************
- * Verifies that the EEPROM has a valid checksum
+ * Reads a 16 bit word from the EEPROM.
  *
  * hw - Struct containing variables accessed by shared code
  *
  * hw - Struct containing variables accessed by shared code
- *
- * Reads the first 64 16 bit words of the EEPROM and sums the values read.
- * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
- * valid.
  *****************************************************************************/
  *****************************************************************************/
-static int
-e1000_validate_eeprom_checksum(struct eth_device *nic)
+static int32_t
+e1000_spi_eeprom_ready(struct e1000_hw *hw)
 {
 {
-       struct e1000_hw *hw = nic->priv;
-       uint16_t checksum = 0;
-       uint16_t i, eeprom_data;
+       uint16_t retry_count = 0;
+       uint8_t spi_stat_reg;
 
        DEBUGFUNC();
 
 
        DEBUGFUNC();
 
-       for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
-               if (e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
-                       DEBUGOUT("EEPROM Read Error\n");
-                       return -E1000_ERR_EEPROM;
-               }
-               checksum += eeprom_data;
-       }
+       /* Read "Status Register" repeatedly until the LSB is cleared.  The
+        * EEPROM will signal that the command has been completed by clearing
+        * bit 0 of the internal status register.  If it's not cleared within
+        * 5 milliseconds, then error out.
+        */
+       retry_count = 0;
+       do {
+               e1000_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
+                       hw->eeprom.opcode_bits);
+               spi_stat_reg = (uint8_t)e1000_shift_in_ee_bits(hw, 8);
+               if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
+                       break;
 
 
-       if (checksum == (uint16_t) EEPROM_SUM) {
-               return 0;
-       } else {
-               DEBUGOUT("EEPROM Checksum Invalid\n");
+               udelay(5);
+               retry_count += 5;
+
+               e1000_standby_eeprom(hw);
+       } while (retry_count < EEPROM_MAX_RETRY_SPI);
+
+       /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
+        * only 0-5mSec on 5V devices)
+        */
+       if (retry_count >= EEPROM_MAX_RETRY_SPI) {
+               DEBUGOUT("SPI EEPROM Status error\n");
                return -E1000_ERR_EEPROM;
        }
                return -E1000_ERR_EEPROM;
        }
+
+       return E1000_SUCCESS;
 }
 }
-#endif /* #ifndef CONFIG_AP1000 */
 
 /******************************************************************************
 
 /******************************************************************************
- * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
- * second function of dual function devices
+ * Reads a 16 bit word from the EEPROM.
  *
  *
- * nic - Struct containing variables accessed by shared code
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
  *****************************************************************************/
  *****************************************************************************/
-static int
-e1000_read_mac_addr(struct eth_device *nic)
+static int32_t
+e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
+               uint16_t words, uint16_t *data)
 {
 {
-#ifndef CONFIG_AP1000
-       struct e1000_hw *hw = nic->priv;
-       uint16_t offset;
-       uint16_t eeprom_data;
-       int i;
+       struct e1000_eeprom_info *eeprom = &hw->eeprom;
+       uint32_t i = 0;
 
        DEBUGFUNC();
 
 
        DEBUGFUNC();
 
-       for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
-               offset = i >> 1;
-               if (e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
-                       DEBUGOUT("EEPROM Read Error\n");
-                       return -E1000_ERR_EEPROM;
-               }
-               nic->enetaddr[i] = eeprom_data & 0xff;
-               nic->enetaddr[i + 1] = (eeprom_data >> 8) & 0xff;
-       }
-       if ((hw->mac_type == e1000_82546) &&
-           (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
-               /* Invert the last bit if this is the second device */
-               nic->enetaddr[5] += 1;
+       /* If eeprom is not yet detected, do so now */
+       if (eeprom->word_size == 0)
+               e1000_init_eeprom_params(hw);
+
+       /* A check for invalid values:  offset too large, too many words,
+        * and not enough words.
+        */
+       if ((offset >= eeprom->word_size) ||
+               (words > eeprom->word_size - offset) ||
+               (words == 0)) {
+               DEBUGOUT("\"words\" parameter out of bounds."
+                       "Words = %d, size = %d\n", offset, eeprom->word_size);
+               return -E1000_ERR_EEPROM;
        }
        }
-#ifdef CONFIG_E1000_FALLBACK_MAC
-       if ( *(u32*)(nic->enetaddr) == 0 || *(u32*)(nic->enetaddr) == ~0 )
-               for ( i=0; i < NODE_ADDRESS_SIZE; i++ )
-                       nic->enetaddr[i] = (CONFIG_E1000_FALLBACK_MAC >> (8*(5-i))) & 0xff;
-#endif
-#else
-       /*
-        * The AP1000's e1000 has no eeprom; the MAC address is stored in the
-        * environment variables.  Currently this does not support the addition
-        * of a PMC e1000 card, which is certainly a possibility, so this should
-        * be updated to properly use the env variable only for the onboard e1000
+
+       /* EEPROM's that don't use EERD to read require us to bit-bang the SPI
+        * directly. In this case, we need to acquire the EEPROM so that
+        * FW or other port software does not interrupt.
+        */
+       if (e1000_is_onboard_nvm_eeprom(hw) == TRUE &&
+               hw->eeprom.use_eerd == FALSE) {
+
+               /* Prepare the EEPROM for bit-bang reading */
+               if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+                       return -E1000_ERR_EEPROM;
+       }
+
+       /* Eerd register EEPROM access requires no eeprom aquire/release */
+       if (eeprom->use_eerd == TRUE)
+               return e1000_read_eeprom_eerd(hw, offset, words, data);
+
+       /* ich8lan does not support currently. if needed, please
+        * add corresponding code and functions.
         */
         */
+#if 0
+       /* ICH EEPROM access is done via the ICH flash controller */
+       if (eeprom->type == e1000_eeprom_ich8)
+               return e1000_read_eeprom_ich8(hw, offset, words, data);
+#endif
+       /* Set up the SPI or Microwire EEPROM for bit-bang reading.  We have
+        * acquired the EEPROM at this point, so any returns should relase it */
+       if (eeprom->type == e1000_eeprom_spi) {
+               uint16_t word_in;
+               uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
+
+               if (e1000_spi_eeprom_ready(hw)) {
+                       e1000_release_eeprom(hw);
+                       return -E1000_ERR_EEPROM;
+               }
 
 
-       int ii;
-       char *s, *e;
+               e1000_standby_eeprom(hw);
+
+               /* Some SPI eeproms use the 8th address bit embedded in
+                * the opcode */
+               if ((eeprom->address_bits == 8) && (offset >= 128))
+                       read_opcode |= EEPROM_A8_OPCODE_SPI;
+
+               /* Send the READ command (opcode + addr)  */
+               e1000_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
+               e1000_shift_out_ee_bits(hw, (uint16_t)(offset*2),
+                               eeprom->address_bits);
+
+               /* Read the data.  The address of the eeprom internally
+                * increments with each byte (spi) being read, saving on the
+                * overhead of eeprom setup and tear-down.  The address
+                * counter will roll over if reading beyond the size of
+                * the eeprom, thus allowing the entire memory to be read
+                * starting from any offset. */
+               for (i = 0; i < words; i++) {
+                       word_in = e1000_shift_in_ee_bits(hw, 16);
+                       data[i] = (word_in >> 8) | (word_in << 8);
+               }
+       } else if (eeprom->type == e1000_eeprom_microwire) {
+               for (i = 0; i < words; i++) {
+                       /* Send the READ command (opcode + addr)  */
+                       e1000_shift_out_ee_bits(hw,
+                               EEPROM_READ_OPCODE_MICROWIRE,
+                               eeprom->opcode_bits);
+                       e1000_shift_out_ee_bits(hw, (uint16_t)(offset + i),
+                               eeprom->address_bits);
+
+                       /* Read the data.  For microwire, each word requires
+                        * the overhead of eeprom setup and tear-down. */
+                       data[i] = e1000_shift_in_ee_bits(hw, 16);
+                       e1000_standby_eeprom(hw);
+               }
+       }
+
+       /* End this read operation */
+       e1000_release_eeprom(hw);
+
+       return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+static int e1000_validate_eeprom_checksum(struct e1000_hw *hw)
+{
+       uint16_t i, checksum, checksum_reg, *buf;
 
        DEBUGFUNC();
 
 
        DEBUGFUNC();
 
-       s = getenv ("ethaddr");
-       if (s == NULL){
+       /* Allocate a temporary buffer */
+       buf = malloc(sizeof(buf[0]) * (EEPROM_CHECKSUM_REG + 1));
+       if (!buf) {
+               E1000_ERR(hw->nic, "Unable to allocate EEPROM buffer!\n");
                return -E1000_ERR_EEPROM;
        }
                return -E1000_ERR_EEPROM;
        }
-       else{
-               for(ii = 0; ii < 6; ii++) {
-                       nic->enetaddr[ii] = s ? simple_strtoul (s, &e, 16) : 0;
-                       if (s){
-                               s = (*e) ? e + 1 : e;
-                       }
+
+       /* Read the EEPROM */
+       if (e1000_read_eeprom(hw, 0, EEPROM_CHECKSUM_REG + 1, buf) < 0) {
+               E1000_ERR(hw->nic, "Unable to read EEPROM!\n");
+               return -E1000_ERR_EEPROM;
+       }
+
+       /* Compute the checksum */
+       checksum = 0;
+       for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
+               checksum += buf[i];
+       checksum = ((uint16_t)EEPROM_SUM) - checksum;
+       checksum_reg = buf[i];
+
+       /* Verify it! */
+       if (checksum == checksum_reg)
+               return 0;
+
+       /* Hrm, verification failed, print an error */
+       E1000_ERR(hw->nic, "EEPROM checksum is incorrect!\n");
+       E1000_ERR(hw->nic, "  ...register was 0x%04hx, calculated 0x%04hx\n",
+                       checksum_reg, checksum);
+
+       return -E1000_ERR_EEPROM;
+}
+
+/*****************************************************************************
+ * Set PHY to class A mode
+ * Assumes the following operations will follow to enable the new class mode.
+ *  1. Do a PHY soft reset
+ *  2. Restart auto-negotiation or force link.
+ *
+ * hw - Struct containing variables accessed by shared code
+ ****************************************************************************/
+static int32_t
+e1000_set_phy_mode(struct e1000_hw *hw)
+{
+       int32_t ret_val;
+       uint16_t eeprom_data;
+
+       DEBUGFUNC();
+
+       if ((hw->mac_type == e1000_82545_rev_3) &&
+               (hw->media_type == e1000_media_type_copper)) {
+               ret_val = e1000_read_eeprom(hw, EEPROM_PHY_CLASS_WORD,
+                               1, &eeprom_data);
+               if (ret_val)
+                       return ret_val;
+
+               if ((eeprom_data != EEPROM_RESERVED_WORD) &&
+                       (eeprom_data & EEPROM_PHY_CLASS_A)) {
+                       ret_val = e1000_write_phy_reg(hw,
+                                       M88E1000_PHY_PAGE_SELECT, 0x000B);
+                       if (ret_val)
+                               return ret_val;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       M88E1000_PHY_GEN_CONTROL, 0x8104);
+                       if (ret_val)
+                               return ret_val;
+
+                       hw->phy_reset_disable = FALSE;
+               }
+       }
+
+       return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Obtaining software semaphore bit (SMBI) before resetting PHY.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to obtain semaphore.
+ *            E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+static int32_t
+e1000_get_software_semaphore(struct e1000_hw *hw)
+{
+        int32_t timeout = hw->eeprom.word_size + 1;
+        uint32_t swsm;
+
+       DEBUGFUNC();
+
+       if (hw->mac_type != e1000_80003es2lan)
+               return E1000_SUCCESS;
+
+       while (timeout) {
+               swsm = E1000_READ_REG(hw, SWSM);
+               /* If SMBI bit cleared, it is now set and we hold
+                * the semaphore */
+               if (!(swsm & E1000_SWSM_SMBI))
+                       break;
+               mdelay(1);
+               timeout--;
+       }
+
+       if (!timeout) {
+               DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+               return -E1000_ERR_RESET;
+       }
+
+       return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * This function clears HW semaphore bits.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - None.
+ *
+ ***************************************************************************/
+static void
+e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
+{
+        uint32_t swsm;
+
+       DEBUGFUNC();
+
+       if (!hw->eeprom_semaphore_present)
+               return;
+
+       swsm = E1000_READ_REG(hw, SWSM);
+       if (hw->mac_type == e1000_80003es2lan) {
+               /* Release both semaphores. */
+               swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+       } else
+               swsm &= ~(E1000_SWSM_SWESMBI);
+       E1000_WRITE_REG(hw, SWSM, swsm);
+}
+
+/***************************************************************************
+ *
+ * Using the combination of SMBI and SWESMBI semaphore bits when resetting
+ * adapter or Eeprom access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_EEPROM if fail to access EEPROM.
+ *            E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+static int32_t
+e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw)
+{
+       int32_t timeout;
+       uint32_t swsm;
+
+       DEBUGFUNC();
+
+       if (!hw->eeprom_semaphore_present)
+               return E1000_SUCCESS;
+
+       if (hw->mac_type == e1000_80003es2lan) {
+               /* Get the SW semaphore. */
+               if (e1000_get_software_semaphore(hw) != E1000_SUCCESS)
+                       return -E1000_ERR_EEPROM;
+       }
+
+       /* Get the FW semaphore. */
+       timeout = hw->eeprom.word_size + 1;
+       while (timeout) {
+               swsm = E1000_READ_REG(hw, SWSM);
+               swsm |= E1000_SWSM_SWESMBI;
+               E1000_WRITE_REG(hw, SWSM, swsm);
+               /* if we managed to set the bit we got the semaphore. */
+               swsm = E1000_READ_REG(hw, SWSM);
+               if (swsm & E1000_SWSM_SWESMBI)
+                       break;
+
+               udelay(50);
+               timeout--;
+       }
+
+       if (!timeout) {
+               /* Release semaphores */
+               e1000_put_hw_eeprom_semaphore(hw);
+               DEBUGOUT("Driver can't access the Eeprom - "
+                               "SWESMBI bit is set.\n");
+               return -E1000_ERR_EEPROM;
+       }
+
+       return E1000_SUCCESS;
+}
+
+static int32_t
+e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
+{
+       uint32_t swfw_sync = 0;
+       uint32_t swmask = mask;
+       uint32_t fwmask = mask << 16;
+       int32_t timeout = 200;
+
+       DEBUGFUNC();
+       while (timeout) {
+               if (e1000_get_hw_eeprom_semaphore(hw))
+                       return -E1000_ERR_SWFW_SYNC;
+
+               swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC);
+               if (!(swfw_sync & (fwmask | swmask)))
+                       break;
+
+               /* firmware currently using resource (fwmask) */
+               /* or other software thread currently using resource (swmask) */
+               e1000_put_hw_eeprom_semaphore(hw);
+               mdelay(5);
+               timeout--;
+       }
+
+       if (!timeout) {
+               DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+               return -E1000_ERR_SWFW_SYNC;
+       }
+
+       swfw_sync |= swmask;
+       E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync);
+
+       e1000_put_hw_eeprom_semaphore(hw);
+       return E1000_SUCCESS;
+}
+
+static boolean_t e1000_is_second_port(struct e1000_hw *hw)
+{
+       switch (hw->mac_type) {
+       case e1000_80003es2lan:
+       case e1000_82546:
+       case e1000_82571:
+               if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+                       return TRUE;
+               /* Fallthrough */
+       default:
+               return FALSE;
+       }
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * nic - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int
+e1000_read_mac_addr(struct eth_device *nic)
+{
+       struct e1000_hw *hw = nic->priv;
+       uint16_t offset;
+       uint16_t eeprom_data;
+       int i;
+
+       DEBUGFUNC();
+
+       for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+               offset = i >> 1;
+               if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+                       DEBUGOUT("EEPROM Read Error\n");
+                       return -E1000_ERR_EEPROM;
                }
                }
+               nic->enetaddr[i] = eeprom_data & 0xff;
+               nic->enetaddr[i + 1] = (eeprom_data >> 8) & 0xff;
+       }
+
+       /* Invert the last bit if this is the second device */
+       if (e1000_is_second_port(hw))
+               nic->enetaddr[5] ^= 1;
+
+#ifdef CONFIG_E1000_FALLBACK_MAC
+       if (!is_valid_ether_addr(nic->enetaddr)) {
+               unsigned char fb_mac[NODE_ADDRESS_SIZE] = CONFIG_E1000_FALLBACK_MAC;
+
+               memcpy (nic->enetaddr, fb_mac, NODE_ADDRESS_SIZE);
        }
 #endif
        return 0;
        }
 #endif
        return 0;
@@ -604,7 +1209,7 @@ e1000_clear_vfta(struct e1000_hw *hw)
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
-static int
+int32_t
 e1000_set_mac_type(struct e1000_hw *hw)
 {
        DEBUGFUNC();
 e1000_set_mac_type(struct e1000_hw *hw)
 {
        DEBUGFUNC();
@@ -635,19 +1240,91 @@ e1000_set_mac_type(struct e1000_hw *hw)
                break;
        case E1000_DEV_ID_82540EM:
        case E1000_DEV_ID_82540EM_LOM:
                break;
        case E1000_DEV_ID_82540EM:
        case E1000_DEV_ID_82540EM_LOM:
+       case E1000_DEV_ID_82540EP:
+       case E1000_DEV_ID_82540EP_LOM:
+       case E1000_DEV_ID_82540EP_LP:
                hw->mac_type = e1000_82540;
                break;
        case E1000_DEV_ID_82545EM_COPPER:
        case E1000_DEV_ID_82545EM_FIBER:
                hw->mac_type = e1000_82545;
                break;
                hw->mac_type = e1000_82540;
                break;
        case E1000_DEV_ID_82545EM_COPPER:
        case E1000_DEV_ID_82545EM_FIBER:
                hw->mac_type = e1000_82545;
                break;
+       case E1000_DEV_ID_82545GM_COPPER:
+       case E1000_DEV_ID_82545GM_FIBER:
+       case E1000_DEV_ID_82545GM_SERDES:
+               hw->mac_type = e1000_82545_rev_3;
+               break;
        case E1000_DEV_ID_82546EB_COPPER:
        case E1000_DEV_ID_82546EB_FIBER:
        case E1000_DEV_ID_82546EB_COPPER:
        case E1000_DEV_ID_82546EB_FIBER:
+       case E1000_DEV_ID_82546EB_QUAD_COPPER:
                hw->mac_type = e1000_82546;
                break;
                hw->mac_type = e1000_82546;
                break;
+       case E1000_DEV_ID_82546GB_COPPER:
+       case E1000_DEV_ID_82546GB_FIBER:
+       case E1000_DEV_ID_82546GB_SERDES:
+       case E1000_DEV_ID_82546GB_PCIE:
+       case E1000_DEV_ID_82546GB_QUAD_COPPER:
+       case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+               hw->mac_type = e1000_82546_rev_3;
+               break;
+       case E1000_DEV_ID_82541EI:
+       case E1000_DEV_ID_82541EI_MOBILE:
+       case E1000_DEV_ID_82541ER_LOM:
+               hw->mac_type = e1000_82541;
+               break;
        case E1000_DEV_ID_82541ER:
        case E1000_DEV_ID_82541ER:
-               hw->mac_type = e1000_82541_rev_2;
-               break;
+       case E1000_DEV_ID_82541GI:
+       case E1000_DEV_ID_82541GI_LF:
+       case E1000_DEV_ID_82541GI_MOBILE:
+               hw->mac_type = e1000_82541_rev_2;
+               break;
+       case E1000_DEV_ID_82547EI:
+       case E1000_DEV_ID_82547EI_MOBILE:
+               hw->mac_type = e1000_82547;
+               break;
+       case E1000_DEV_ID_82547GI:
+               hw->mac_type = e1000_82547_rev_2;
+               break;
+       case E1000_DEV_ID_82571EB_COPPER:
+       case E1000_DEV_ID_82571EB_FIBER:
+       case E1000_DEV_ID_82571EB_SERDES:
+       case E1000_DEV_ID_82571EB_SERDES_DUAL:
+       case E1000_DEV_ID_82571EB_SERDES_QUAD:
+       case E1000_DEV_ID_82571EB_QUAD_COPPER:
+       case E1000_DEV_ID_82571PT_QUAD_COPPER:
+       case E1000_DEV_ID_82571EB_QUAD_FIBER:
+       case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
+               hw->mac_type = e1000_82571;
+               break;
+       case E1000_DEV_ID_82572EI_COPPER:
+       case E1000_DEV_ID_82572EI_FIBER:
+       case E1000_DEV_ID_82572EI_SERDES:
+       case E1000_DEV_ID_82572EI:
+               hw->mac_type = e1000_82572;
+               break;
+       case E1000_DEV_ID_82573E:
+       case E1000_DEV_ID_82573E_IAMT:
+       case E1000_DEV_ID_82573L:
+               hw->mac_type = e1000_82573;
+               break;
+       case E1000_DEV_ID_82574L:
+               hw->mac_type = e1000_82574;
+               break;
+       case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
+       case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
+       case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
+       case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+               hw->mac_type = e1000_80003es2lan;
+               break;
+       case E1000_DEV_ID_ICH8_IGP_M_AMT:
+       case E1000_DEV_ID_ICH8_IGP_AMT:
+       case E1000_DEV_ID_ICH8_IGP_C:
+       case E1000_DEV_ID_ICH8_IFE:
+       case E1000_DEV_ID_ICH8_IFE_GT:
+       case E1000_DEV_ID_ICH8_IFE_G:
+       case E1000_DEV_ID_ICH8_IGP_M:
+               hw->mac_type = e1000_ich8lan;
+               break;
        default:
                /* Should never have loaded on this device */
                return -E1000_ERR_MAC_TYPE;
        default:
                /* Should never have loaded on this device */
                return -E1000_ERR_MAC_TYPE;
@@ -665,17 +1342,22 @@ e1000_reset_hw(struct e1000_hw *hw)
 {
        uint32_t ctrl;
        uint32_t ctrl_ext;
 {
        uint32_t ctrl;
        uint32_t ctrl_ext;
-       uint32_t icr;
        uint32_t manc;
        uint32_t manc;
+       uint32_t pba = 0;
 
        DEBUGFUNC();
 
 
        DEBUGFUNC();
 
+       /* get the correct pba value for both PCI and PCIe*/
+       if (hw->mac_type <  e1000_82571)
+               pba = E1000_DEFAULT_PCI_PBA;
+       else
+               pba = E1000_DEFAULT_PCIE_PBA;
+
        /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
        if (hw->mac_type == e1000_82542_rev2_0) {
                DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
                pci_write_config_word(hw->pdev, PCI_COMMAND,
        /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
        if (hw->mac_type == e1000_82542_rev2_0) {
                DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
                pci_write_config_word(hw->pdev, PCI_COMMAND,
-                                     hw->
-                                     pci_cmd_word & ~PCI_COMMAND_INVALIDATE);
+                               hw->pci_cmd_word & ~PCI_COMMAND_INVALIDATE);
        }
 
        /* Clear interrupt mask to stop board from generating interrupts */
        }
 
        /* Clear interrupt mask to stop board from generating interrupts */
@@ -706,12 +1388,7 @@ e1000_reset_hw(struct e1000_hw *hw)
        DEBUGOUT("Issuing a global reset to MAC\n");
        ctrl = E1000_READ_REG(hw, CTRL);
 
        DEBUGOUT("Issuing a global reset to MAC\n");
        ctrl = E1000_READ_REG(hw, CTRL);
 
-#if 0
-       if (hw->mac_type > e1000_82543)
-               E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
-       else
-#endif
-               E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+       E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
 
        /* Force a reload from the EEPROM if necessary */
        if (hw->mac_type < e1000_82540) {
 
        /* Force a reload from the EEPROM if necessary */
        if (hw->mac_type < e1000_82540) {
@@ -737,12 +1414,134 @@ e1000_reset_hw(struct e1000_hw *hw)
        E1000_WRITE_REG(hw, IMC, 0xffffffff);
 
        /* Clear any pending interrupt events. */
        E1000_WRITE_REG(hw, IMC, 0xffffffff);
 
        /* Clear any pending interrupt events. */
-       icr = E1000_READ_REG(hw, ICR);
+       E1000_READ_REG(hw, ICR);
 
        /* If MWI was previously enabled, reenable it. */
        if (hw->mac_type == e1000_82542_rev2_0) {
                pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word);
        }
 
        /* If MWI was previously enabled, reenable it. */
        if (hw->mac_type == e1000_82542_rev2_0) {
                pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word);
        }
+       E1000_WRITE_REG(hw, PBA, pba);
+}
+
+/******************************************************************************
+ *
+ * Initialize a number of hardware-dependent bits
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * This function contains hardware limitation workarounds for PCI-E adapters
+ *
+ *****************************************************************************/
+static void
+e1000_initialize_hardware_bits(struct e1000_hw *hw)
+{
+       if ((hw->mac_type >= e1000_82571) &&
+                       (!hw->initialize_hw_bits_disable)) {
+               /* Settings common to all PCI-express silicon */
+               uint32_t reg_ctrl, reg_ctrl_ext;
+               uint32_t reg_tarc0, reg_tarc1;
+               uint32_t reg_tctl;
+               uint32_t reg_txdctl, reg_txdctl1;
+
+               /* link autonegotiation/sync workarounds */
+               reg_tarc0 = E1000_READ_REG(hw, TARC0);
+               reg_tarc0 &= ~((1 << 30)|(1 << 29)|(1 << 28)|(1 << 27));
+
+               /* Enable not-done TX descriptor counting */
+               reg_txdctl = E1000_READ_REG(hw, TXDCTL);
+               reg_txdctl |= E1000_TXDCTL_COUNT_DESC;
+               E1000_WRITE_REG(hw, TXDCTL, reg_txdctl);
+
+               reg_txdctl1 = E1000_READ_REG(hw, TXDCTL1);
+               reg_txdctl1 |= E1000_TXDCTL_COUNT_DESC;
+               E1000_WRITE_REG(hw, TXDCTL1, reg_txdctl1);
+
+               switch (hw->mac_type) {
+               case e1000_82571:
+               case e1000_82572:
+                       /* Clear PHY TX compatible mode bits */
+                       reg_tarc1 = E1000_READ_REG(hw, TARC1);
+                       reg_tarc1 &= ~((1 << 30)|(1 << 29));
+
+                       /* link autonegotiation/sync workarounds */
+                       reg_tarc0 |= ((1 << 26)|(1 << 25)|(1 << 24)|(1 << 23));
+
+                       /* TX ring control fixes */
+                       reg_tarc1 |= ((1 << 26)|(1 << 25)|(1 << 24));
+
+                       /* Multiple read bit is reversed polarity */
+                       reg_tctl = E1000_READ_REG(hw, TCTL);
+                       if (reg_tctl & E1000_TCTL_MULR)
+                               reg_tarc1 &= ~(1 << 28);
+                       else
+                               reg_tarc1 |= (1 << 28);
+
+                       E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+                       break;
+               case e1000_82573:
+               case e1000_82574:
+                       reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+                       reg_ctrl_ext &= ~(1 << 23);
+                       reg_ctrl_ext |= (1 << 22);
+
+                       /* TX byte count fix */
+                       reg_ctrl = E1000_READ_REG(hw, CTRL);
+                       reg_ctrl &= ~(1 << 29);
+
+                       E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
+                       E1000_WRITE_REG(hw, CTRL, reg_ctrl);
+                       break;
+               case e1000_80003es2lan:
+       /* improve small packet performace for fiber/serdes */
+                       if ((hw->media_type == e1000_media_type_fiber)
+                       || (hw->media_type ==
+                               e1000_media_type_internal_serdes)) {
+                               reg_tarc0 &= ~(1 << 20);
+                       }
+
+               /* Multiple read bit is reversed polarity */
+                       reg_tctl = E1000_READ_REG(hw, TCTL);
+                       reg_tarc1 = E1000_READ_REG(hw, TARC1);
+                       if (reg_tctl & E1000_TCTL_MULR)
+                               reg_tarc1 &= ~(1 << 28);
+                       else
+                               reg_tarc1 |= (1 << 28);
+
+                       E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+                       break;
+               case e1000_ich8lan:
+                       /* Reduce concurrent DMA requests to 3 from 4 */
+                       if ((hw->revision_id < 3) ||
+                       ((hw->device_id != E1000_DEV_ID_ICH8_IGP_M_AMT) &&
+                               (hw->device_id != E1000_DEV_ID_ICH8_IGP_M)))
+                               reg_tarc0 |= ((1 << 29)|(1 << 28));
+
+                       reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+                       reg_ctrl_ext |= (1 << 22);
+                       E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
+
+                       /* workaround TX hang with TSO=on */
+                       reg_tarc0 |= ((1 << 27)|(1 << 26)|(1 << 24)|(1 << 23));
+
+                       /* Multiple read bit is reversed polarity */
+                       reg_tctl = E1000_READ_REG(hw, TCTL);
+                       reg_tarc1 = E1000_READ_REG(hw, TARC1);
+                       if (reg_tctl & E1000_TCTL_MULR)
+                               reg_tarc1 &= ~(1 << 28);
+                       else
+                               reg_tarc1 |= (1 << 28);
+
+                       /* workaround TX hang with TSO=on */
+                       reg_tarc1 |= ((1 << 30)|(1 << 26)|(1 << 24));
+
+                       E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+                       break;
+               default:
+                       break;
+               }
+
+               E1000_WRITE_REG(hw, TARC0, reg_tarc0);
+       }
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
@@ -760,49 +1559,43 @@ static int
 e1000_init_hw(struct eth_device *nic)
 {
        struct e1000_hw *hw = nic->priv;
 e1000_init_hw(struct eth_device *nic)
 {
        struct e1000_hw *hw = nic->priv;
-       uint32_t ctrl, status;
+       uint32_t ctrl;
        uint32_t i;
        int32_t ret_val;
        uint16_t pcix_cmd_word;
        uint16_t pcix_stat_hi_word;
        uint16_t cmd_mmrbc;
        uint16_t stat_mmrbc;
        uint32_t i;
        int32_t ret_val;
        uint16_t pcix_cmd_word;
        uint16_t pcix_stat_hi_word;
        uint16_t cmd_mmrbc;
        uint16_t stat_mmrbc;
-       e1000_bus_type bus_type = e1000_bus_type_unknown;
-
+       uint32_t mta_size;
+       uint32_t reg_data;
+       uint32_t ctrl_ext;
        DEBUGFUNC();
        DEBUGFUNC();
-#if 0
-       /* Initialize Identification LED */
-       ret_val = e1000_id_led_init(hw);
-       if (ret_val < 0) {
-               DEBUGOUT("Error Initializing Identification LED\n");
-               return ret_val;
-       }
-#endif
-       /* Set the Media Type and exit with error if it is not valid. */
-       if (hw->mac_type != e1000_82543) {
-               /* tbi_compatibility is only valid on 82543 */
-               hw->tbi_compatibility_en = FALSE;
+       /* force full DMA clock frequency for 10/100 on ICH8 A0-B0 */
+       if ((hw->mac_type == e1000_ich8lan) &&
+               ((hw->revision_id < 3) ||
+               ((hw->device_id != E1000_DEV_ID_ICH8_IGP_M_AMT) &&
+               (hw->device_id != E1000_DEV_ID_ICH8_IGP_M)))) {
+                       reg_data = E1000_READ_REG(hw, STATUS);
+                       reg_data &= ~0x80000000;
+                       E1000_WRITE_REG(hw, STATUS, reg_data);
        }
        }
+       /* Do not need initialize Identification LED */
 
 
-       if (hw->mac_type >= e1000_82543) {
-               status = E1000_READ_REG(hw, STATUS);
-               if (status & E1000_STATUS_TBIMODE) {
-                       hw->media_type = e1000_media_type_fiber;
-                       /* tbi_compatibility not valid on fiber */
-                       hw->tbi_compatibility_en = FALSE;
-               } else {
-                       hw->media_type = e1000_media_type_copper;
-               }
-       } else {
-               /* This is an 82542 (fiber only) */
-               hw->media_type = e1000_media_type_fiber;
-       }
+       /* Set the media type and TBI compatibility */
+       e1000_set_media_type(hw);
+
+       /* Must be called after e1000_set_media_type
+        * because media_type is used */
+       e1000_initialize_hardware_bits(hw);
 
        /* Disabling VLAN filtering. */
        DEBUGOUT("Initializing the IEEE VLAN\n");
 
        /* Disabling VLAN filtering. */
        DEBUGOUT("Initializing the IEEE VLAN\n");
-       E1000_WRITE_REG(hw, VET, 0);
-
-       e1000_clear_vfta(hw);
+       /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */
+       if (hw->mac_type != e1000_ich8lan) {
+               if (hw->mac_type < e1000_82545_rev_3)
+                       E1000_WRITE_REG(hw, VET, 0);
+               e1000_clear_vfta(hw);
+       }
 
        /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
        if (hw->mac_type == e1000_82542_rev2_0) {
 
        /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
        if (hw->mac_type == e1000_82542_rev2_0) {
@@ -830,26 +1623,33 @@ e1000_init_hw(struct eth_device *nic)
 
        /* Zero out the Multicast HASH table */
        DEBUGOUT("Zeroing the MTA\n");
 
        /* Zero out the Multicast HASH table */
        DEBUGOUT("Zeroing the MTA\n");
-       for (i = 0; i < E1000_MC_TBL_SIZE; i++)
+       mta_size = E1000_MC_TBL_SIZE;
+       if (hw->mac_type == e1000_ich8lan)
+               mta_size = E1000_MC_TBL_SIZE_ICH8LAN;
+       for (i = 0; i < mta_size; i++) {
                E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
                E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
-
+               /* use write flush to prevent Memory Write Block (MWB) from
+                * occuring when accessing our register space */
+               E1000_WRITE_FLUSH(hw);
+       }
 #if 0
        /* Set the PCI priority bit correctly in the CTRL register.  This
         * determines if the adapter gives priority to receives, or if it
 #if 0
        /* Set the PCI priority bit correctly in the CTRL register.  This
         * determines if the adapter gives priority to receives, or if it
-        * gives equal priority to transmits and receives.
+        * gives equal priority to transmits and receives.  Valid only on
+        * 82542 and 82543 silicon.
         */
         */
-       if (hw->dma_fairness) {
+       if (hw->dma_fairness && hw->mac_type <= e1000_82543) {
                ctrl = E1000_READ_REG(hw, CTRL);
                E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
        }
 #endif
                ctrl = E1000_READ_REG(hw, CTRL);
                E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
        }
 #endif
-       if (hw->mac_type >= e1000_82543) {
-               status = E1000_READ_REG(hw, STATUS);
-               bus_type = (status & E1000_STATUS_PCIX_MODE) ?
-                   e1000_bus_type_pcix : e1000_bus_type_pci;
-       }
+       switch (hw->mac_type) {
+       case e1000_82545_rev_3:
+       case e1000_82546_rev_3:
+               break;
+       default:
        /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
        /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
-       if (bus_type == e1000_bus_type_pcix) {
+       if (hw->bus_type == e1000_bus_type_pcix) {
                pci_read_config_word(hw->pdev, PCIX_COMMAND_REGISTER,
                                     &pcix_cmd_word);
                pci_read_config_word(hw->pdev, PCIX_STATUS_REGISTER_HI,
                pci_read_config_word(hw->pdev, PCIX_COMMAND_REGISTER,
                                     &pcix_cmd_word);
                pci_read_config_word(hw->pdev, PCIX_STATUS_REGISTER_HI,
@@ -869,6 +1669,12 @@ e1000_init_hw(struct eth_device *nic)
                                              pcix_cmd_word);
                }
        }
                                              pcix_cmd_word);
                }
        }
+               break;
+       }
+
+       /* More time needed for PHY to initialize */
+       if (hw->mac_type == e1000_ich8lan)
+               mdelay(15);
 
        /* Call a subroutine to configure the link and setup flow control. */
        ret_val = e1000_setup_link(nic);
 
        /* Call a subroutine to configure the link and setup flow control. */
        ret_val = e1000_setup_link(nic);
@@ -881,17 +1687,82 @@ e1000_init_hw(struct eth_device *nic)
                    E1000_TXDCTL_FULL_TX_DESC_WB;
                E1000_WRITE_REG(hw, TXDCTL, ctrl);
        }
                    E1000_TXDCTL_FULL_TX_DESC_WB;
                E1000_WRITE_REG(hw, TXDCTL, ctrl);
        }
-#if 0
-       /* 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.
-        */
-       e1000_clear_hw_cntrs(hw);
-#endif
 
 
-       return ret_val;
-}
+       /* Set the receive descriptor write back policy */
+
+       if (hw->mac_type >= e1000_82571) {
+               ctrl = E1000_READ_REG(hw, RXDCTL);
+               ctrl =
+                   (ctrl & ~E1000_RXDCTL_WTHRESH) |
+                   E1000_RXDCTL_FULL_RX_DESC_WB;
+               E1000_WRITE_REG(hw, RXDCTL, ctrl);
+       }
+
+       switch (hw->mac_type) {
+       default:
+               break;
+       case e1000_80003es2lan:
+               /* Enable retransmit on late collisions */
+               reg_data = E1000_READ_REG(hw, TCTL);
+               reg_data |= E1000_TCTL_RTLC;
+               E1000_WRITE_REG(hw, TCTL, reg_data);
+
+               /* Configure Gigabit Carry Extend Padding */
+               reg_data = E1000_READ_REG(hw, TCTL_EXT);
+               reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+               reg_data |= DEFAULT_80003ES2LAN_TCTL_EXT_GCEX;
+               E1000_WRITE_REG(hw, TCTL_EXT, reg_data);
+
+               /* Configure Transmit Inter-Packet Gap */
+               reg_data = E1000_READ_REG(hw, TIPG);
+               reg_data &= ~E1000_TIPG_IPGT_MASK;
+               reg_data |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
+               E1000_WRITE_REG(hw, TIPG, reg_data);
+
+               reg_data = E1000_READ_REG_ARRAY(hw, FFLT, 0x0001);
+               reg_data &= ~0x00100000;
+               E1000_WRITE_REG_ARRAY(hw, FFLT, 0x0001, reg_data);
+               /* Fall through */
+       case e1000_82571:
+       case e1000_82572:
+       case e1000_ich8lan:
+               ctrl = E1000_READ_REG(hw, TXDCTL1);
+               ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH)
+                       | E1000_TXDCTL_FULL_TX_DESC_WB;
+               E1000_WRITE_REG(hw, TXDCTL1, ctrl);
+               break;
+       case e1000_82573:
+       case e1000_82574:
+               reg_data = E1000_READ_REG(hw, GCR);
+               reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+               E1000_WRITE_REG(hw, GCR, reg_data);
+       }
+
+#if 0
+       /* 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.
+        */
+       e1000_clear_hw_cntrs(hw);
+
+       /* ICH8 No-snoop bits are opposite polarity.
+        * Set to snoop by default after reset. */
+       if (hw->mac_type == e1000_ich8lan)
+               e1000_set_pci_ex_no_snoop(hw, PCI_EX_82566_SNOOP_ALL);
+#endif
+
+       if (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER ||
+               hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) {
+               ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+               /* Relaxed ordering must be disabled to avoid a parity
+                * error crash in a PCI slot. */
+               ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+               E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+       }
+
+       return ret_val;
+}
 
 /******************************************************************************
  * Configures flow control and link settings.
 
 /******************************************************************************
  * Configures flow control and link settings.
@@ -914,7 +1785,11 @@ e1000_setup_link(struct eth_device *nic)
 
        DEBUGFUNC();
 
 
        DEBUGFUNC();
 
-#ifndef CONFIG_AP1000
+       /* In the case of the phy reset being blocked, we already have a link.
+        * We do not have to set it up again. */
+       if (e1000_check_phy_reset_block(hw))
+               return E1000_SUCCESS;
+
        /* Read and store word 0x0F of the EEPROM. This word contains bits
         * that determine the hardware's default PAUSE (flow control) mode,
         * a bit that determines whether the HW defaults to enabling or
        /* Read and store word 0x0F of the EEPROM. This word contains bits
         * that determine the hardware's default PAUSE (flow control) mode,
         * a bit that determines whether the HW defaults to enabling or
@@ -923,24 +1798,35 @@ e1000_setup_link(struct eth_device *nic)
         * control setting, then the variable hw->fc will
         * be initialized based on a value in the EEPROM.
         */
         * control setting, then the variable hw->fc will
         * be initialized based on a value in the EEPROM.
         */
-       if (e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) {
+       if (e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1,
+                               &eeprom_data) < 0) {
                DEBUGOUT("EEPROM Read Error\n");
                return -E1000_ERR_EEPROM;
        }
                DEBUGOUT("EEPROM Read Error\n");
                return -E1000_ERR_EEPROM;
        }
-#else
-       /* we have to hardcode the proper value for our hardware. */
-       /* this value is for the 82540EM pci card used for prototyping, and it works. */
-       eeprom_data = 0xb220;
-#endif
 
        if (hw->fc == e1000_fc_default) {
 
        if (hw->fc == e1000_fc_default) {
-               if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
-                       hw->fc = e1000_fc_none;
-               else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
-                        EEPROM_WORD0F_ASM_DIR)
-                       hw->fc = e1000_fc_tx_pause;
-               else
+               switch (hw->mac_type) {
+               case e1000_ich8lan:
+               case e1000_82573:
+               case e1000_82574:
                        hw->fc = e1000_fc_full;
                        hw->fc = e1000_fc_full;
+                       break;
+               default:
+                       ret_val = e1000_read_eeprom(hw,
+                               EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data);
+                       if (ret_val) {
+                               DEBUGOUT("EEPROM Read Error\n");
+                               return -E1000_ERR_EEPROM;
+                       }
+                       if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+                               hw->fc = e1000_fc_none;
+                       else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
+                                   EEPROM_WORD0F_ASM_DIR)
+                               hw->fc = e1000_fc_tx_pause;
+                       else
+                               hw->fc = e1000_fc_full;
+                       break;
+               }
        }
 
        /* We want to save off the original Flow Control configuration just
        }
 
        /* We want to save off the original Flow Control configuration just
@@ -982,12 +1868,16 @@ e1000_setup_link(struct eth_device *nic)
         * control is disabled, because it does not hurt anything to
         * initialize these registers.
         */
         * control is disabled, because it does not hurt anything to
         * initialize these registers.
         */
-       DEBUGOUT
-           ("Initializing the Flow Control address, type and timer regs\n");
+       DEBUGOUT("Initializing the Flow Control address, type"
+                       "and timer regs\n");
+
+       /* FCAL/H and FCT are hardcoded to standard values in e1000_ich8lan. */
+       if (hw->mac_type != e1000_ich8lan) {
+               E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+               E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+               E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+       }
 
 
-       E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
-       E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
-       E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
        E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
 
        /* Set the flow control receive threshold registers.  Normally,
        E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
 
        /* Set the flow control receive threshold registers.  Normally,
@@ -1061,12 +1951,12 @@ e1000_setup_fiber_link(struct eth_device *nic)
         * configure the two flow control enable bits in the CTRL register.
         *
         * The possible values of the "fc" parameter are:
         * configure the two flow control enable bits in the CTRL register.
         *
         * The possible values of the "fc" parameter are:
-        *      0:  Flow control is completely disabled
-        *      1:  Rx flow control is enabled (we can receive pause frames, but
-        *          not send pause frames).
-        *      2:  Tx flow control is enabled (we can send pause frames but we do
-        *          not support receiving pause frames).
-        *      3:  Both Rx and TX flow control (symmetric) are enabled.
+        *      0:  Flow control is completely disabled
+        *      1:  Rx flow control is enabled (we can receive pause frames, but
+        *          not send pause frames).
+        *      2:  Tx flow control is enabled (we can send pause frames but we do
+        *          not support receiving pause frames).
+        *      3:  Both Rx and TX flow control (symmetric) are enabled.
         */
        switch (hw->fc) {
        case e1000_fc_none:
         */
        switch (hw->fc) {
        case e1000_fc_none:
@@ -1152,17 +2042,15 @@ e1000_setup_fiber_link(struct eth_device *nic)
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
-* Detects which PHY is present and the speed and duplex
+* Make sure we have a valid PHY and change PHY mode before link setup.
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
-static int
-e1000_setup_copper_link(struct eth_device *nic)
+static int32_t
+e1000_copper_link_preconfig(struct e1000_hw *hw)
 {
 {
-       struct e1000_hw *hw = nic->priv;
        uint32_t ctrl;
        int32_t ret_val;
        uint32_t ctrl;
        int32_t ret_val;
-       uint16_t i;
        uint16_t phy_data;
 
        DEBUGFUNC();
        uint16_t phy_data;
 
        DEBUGFUNC();
@@ -1177,28 +2065,676 @@ e1000_setup_copper_link(struct eth_device *nic)
                ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
                E1000_WRITE_REG(hw, CTRL, ctrl);
        } else {
                ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
                E1000_WRITE_REG(hw, CTRL, ctrl);
        } else {
-               ctrl |=
-                   (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+               ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX
+                               | E1000_CTRL_SLU);
                E1000_WRITE_REG(hw, CTRL, ctrl);
                E1000_WRITE_REG(hw, CTRL, ctrl);
-               e1000_phy_hw_reset(hw);
+               ret_val = e1000_phy_hw_reset(hw);
+               if (ret_val)
+                       return ret_val;
        }
 
        /* Make sure we have a valid PHY */
        ret_val = e1000_detect_gig_phy(hw);
        }
 
        /* Make sure we have a valid PHY */
        ret_val = e1000_detect_gig_phy(hw);
-       if (ret_val < 0) {
+       if (ret_val) {
                DEBUGOUT("Error, did not detect valid phy.\n");
                return ret_val;
        }
        DEBUGOUT("Phy ID = %x \n", hw->phy_id);
 
                DEBUGOUT("Error, did not detect valid phy.\n");
                return ret_val;
        }
        DEBUGOUT("Phy ID = %x \n", hw->phy_id);
 
-       /* Enable CRS on TX. This must be set for half-duplex operation. */
-       if (e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
-               DEBUGOUT("PHY Read Error\n");
-               return -E1000_ERR_PHY;
+       /* Set PHY to class A mode (if necessary) */
+       ret_val = e1000_set_phy_mode(hw);
+       if (ret_val)
+               return ret_val;
+       if ((hw->mac_type == e1000_82545_rev_3) ||
+               (hw->mac_type == e1000_82546_rev_3)) {
+               ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                               &phy_data);
+               phy_data |= 0x00000008;
+               ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                               phy_data);
+       }
+
+       if (hw->mac_type <= e1000_82543 ||
+               hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547 ||
+               hw->mac_type == e1000_82541_rev_2
+               || hw->mac_type == e1000_82547_rev_2)
+                       hw->phy_reset_disable = FALSE;
+
+       return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu state according to the active flag.  When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ *            E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+static int32_t
+e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active)
+{
+       uint32_t phy_ctrl = 0;
+       int32_t ret_val;
+       uint16_t phy_data;
+       DEBUGFUNC();
+
+       if (hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2
+           && hw->phy_type != e1000_phy_igp_3)
+               return E1000_SUCCESS;
+
+       /* During driver activity LPLU should not be used or it will attain link
+        * from the lowest speeds starting from 10Mbps. The capability is used
+        * for Dx transitions and states */
+       if (hw->mac_type == e1000_82541_rev_2
+                       || hw->mac_type == e1000_82547_rev_2) {
+               ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                               &phy_data);
+               if (ret_val)
+                       return ret_val;
+       } else if (hw->mac_type == e1000_ich8lan) {
+               /* MAC writes into PHY register based on the state transition
+                * and start auto-negotiation. SW driver can overwrite the
+                * settings in CSR PHY power control E1000_PHY_CTRL register. */
+               phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+       } else {
+               ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+                               &phy_data);
+               if (ret_val)
+                       return ret_val;
+       }
+
+       if (!active) {
+               if (hw->mac_type == e1000_82541_rev_2 ||
+                       hw->mac_type == e1000_82547_rev_2) {
+                       phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
+                       ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                       phy_data);
+                       if (ret_val)
+                               return ret_val;
+               } else {
+                       if (hw->mac_type == e1000_ich8lan) {
+                               phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+                               E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+                       } else {
+                               phy_data &= ~IGP02E1000_PM_D3_LPLU;
+                               ret_val = e1000_write_phy_reg(hw,
+                                       IGP02E1000_PHY_POWER_MGMT, phy_data);
+                               if (ret_val)
+                                       return ret_val;
+                       }
+               }
+
+       /* 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. */
+               if (hw->smart_speed == e1000_smart_speed_on) {
+                       ret_val = e1000_read_phy_reg(hw,
+                                       IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+                       if (ret_val)
+                               return ret_val;
+
+                       phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       IGP01E1000_PHY_PORT_CONFIG, phy_data);
+                       if (ret_val)
+                               return ret_val;
+               } else if (hw->smart_speed == e1000_smart_speed_off) {
+                       ret_val = e1000_read_phy_reg(hw,
+                                       IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+                       if (ret_val)
+                               return ret_val;
+
+                       phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       IGP01E1000_PHY_PORT_CONFIG, phy_data);
+                       if (ret_val)
+                               return ret_val;
+               }
+
+       } else if ((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT)
+               || (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL) ||
+               (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
+
+               if (hw->mac_type == e1000_82541_rev_2 ||
+                   hw->mac_type == e1000_82547_rev_2) {
+                       phy_data |= IGP01E1000_GMII_FLEX_SPD;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       IGP01E1000_GMII_FIFO, phy_data);
+                       if (ret_val)
+                               return ret_val;
+               } else {
+                       if (hw->mac_type == e1000_ich8lan) {
+                               phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+                               E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+                       } else {
+                               phy_data |= IGP02E1000_PM_D3_LPLU;
+                               ret_val = e1000_write_phy_reg(hw,
+                                       IGP02E1000_PHY_POWER_MGMT, phy_data);
+                               if (ret_val)
+                                       return ret_val;
+                       }
+               }
+
+               /* When LPLU is enabled we should disable SmartSpeed */
+               ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                               &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+               ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                               phy_data);
+               if (ret_val)
+                       return ret_val;
+       }
+       return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu d0 state according to the active flag.  When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ *            E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+static int32_t
+e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active)
+{
+       uint32_t phy_ctrl = 0;
+       int32_t ret_val;
+       uint16_t phy_data;
+       DEBUGFUNC();
+
+       if (hw->mac_type <= e1000_82547_rev_2)
+               return E1000_SUCCESS;
+
+       if (hw->mac_type == e1000_ich8lan) {
+               phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+       } else {
+               ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+                               &phy_data);
+               if (ret_val)
+                       return ret_val;
+       }
+
+       if (!active) {
+               if (hw->mac_type == e1000_ich8lan) {
+                       phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+                       E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+               } else {
+                       phy_data &= ~IGP02E1000_PM_D0_LPLU;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       IGP02E1000_PHY_POWER_MGMT, phy_data);
+                       if (ret_val)
+                               return ret_val;
+               }
+
+       /* 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. */
+               if (hw->smart_speed == e1000_smart_speed_on) {
+                       ret_val = e1000_read_phy_reg(hw,
+                                       IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+                       if (ret_val)
+                               return ret_val;
+
+                       phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       IGP01E1000_PHY_PORT_CONFIG, phy_data);
+                       if (ret_val)
+                               return ret_val;
+               } else if (hw->smart_speed == e1000_smart_speed_off) {
+                       ret_val = e1000_read_phy_reg(hw,
+                                       IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+                       if (ret_val)
+                               return ret_val;
+
+                       phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       IGP01E1000_PHY_PORT_CONFIG, phy_data);
+                       if (ret_val)
+                               return ret_val;
+               }
+
+
+       } else {
+
+               if (hw->mac_type == e1000_ich8lan) {
+                       phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+                       E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+               } else {
+                       phy_data |= IGP02E1000_PM_D0_LPLU;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       IGP02E1000_PHY_POWER_MGMT, phy_data);
+                       if (ret_val)
+                               return ret_val;
+               }
+
+               /* When LPLU is enabled we should disable SmartSpeed */
+               ret_val = e1000_read_phy_reg(hw,
+                               IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+               ret_val = e1000_write_phy_reg(hw,
+                               IGP01E1000_PHY_PORT_CONFIG, phy_data);
+               if (ret_val)
+                       return ret_val;
+
+       }
+       return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Copper link setup for e1000_phy_igp series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_igp_setup(struct e1000_hw *hw)
+{
+       uint32_t led_ctrl;
+       int32_t ret_val;
+       uint16_t phy_data;
+
+       DEBUGFUNC();
+
+       if (hw->phy_reset_disable)
+               return E1000_SUCCESS;
+
+       ret_val = e1000_phy_reset(hw);
+       if (ret_val) {
+               DEBUGOUT("Error Resetting the PHY\n");
+               return ret_val;
+       }
+
+       /* Wait 15ms for MAC to configure PHY from eeprom settings */
+       mdelay(15);
+       if (hw->mac_type != e1000_ich8lan) {
+               /* Configure activity LED after PHY reset */
+               led_ctrl = E1000_READ_REG(hw, LEDCTL);
+               led_ctrl &= IGP_ACTIVITY_LED_MASK;
+               led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+               E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+       }
+
+       /* The NVM settings will configure LPLU in D3 for IGP2 and IGP3 PHYs */
+       if (hw->phy_type == e1000_phy_igp) {
+               /* disable lplu d3 during driver init */
+               ret_val = e1000_set_d3_lplu_state(hw, FALSE);
+               if (ret_val) {
+                       DEBUGOUT("Error Disabling LPLU D3\n");
+                       return ret_val;
+               }
+       }
+
+       /* disable lplu d0 during driver init */
+       ret_val = e1000_set_d0_lplu_state(hw, FALSE);
+       if (ret_val) {
+               DEBUGOUT("Error Disabling LPLU D0\n");
+               return ret_val;
+       }
+       /* Configure mdi-mdix settings */
+       ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+       if (ret_val)
+               return ret_val;
+
+       if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+               hw->dsp_config_state = e1000_dsp_config_disabled;
+               /* Force MDI for earlier revs of the IGP PHY */
+               phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX
+                               | IGP01E1000_PSCR_FORCE_MDI_MDIX);
+               hw->mdix = 1;
+
+       } else {
+               hw->dsp_config_state = e1000_dsp_config_enabled;
+               phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+               switch (hw->mdix) {
+               case 1:
+                       phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+                       break;
+               case 2:
+                       phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+                       break;
+               case 0:
+               default:
+                       phy_data |= IGP01E1000_PSCR_AUTO_MDIX;
+                       break;
+               }
+       }
+       ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+       if (ret_val)
+               return ret_val;
+
+       /* set auto-master slave resolution settings */
+       if (hw->autoneg) {
+               e1000_ms_type phy_ms_setting = hw->master_slave;
+
+               if (hw->ffe_config_state == e1000_ffe_config_active)
+                       hw->ffe_config_state = e1000_ffe_config_enabled;
+
+               if (hw->dsp_config_state == e1000_dsp_config_activated)
+                       hw->dsp_config_state = e1000_dsp_config_enabled;
+
+               /* when autonegotiation advertisment is only 1000Mbps then we
+                 * should disable SmartSpeed and enable Auto MasterSlave
+                 * resolution as hardware default. */
+               if (hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+                       /* Disable SmartSpeed */
+                       ret_val = e1000_read_phy_reg(hw,
+                                       IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+                       if (ret_val)
+                               return ret_val;
+                       phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       IGP01E1000_PHY_PORT_CONFIG, phy_data);
+                       if (ret_val)
+                               return ret_val;
+                       /* Set auto Master/Slave resolution process */
+                       ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
+                                       &phy_data);
+                       if (ret_val)
+                               return ret_val;
+                       phy_data &= ~CR_1000T_MS_ENABLE;
+                       ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
+                                       phy_data);
+                       if (ret_val)
+                               return ret_val;
+               }
+
+               ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               /* load defaults for future use */
+               hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ?
+                               ((phy_data & CR_1000T_MS_VALUE) ?
+                               e1000_ms_force_master :
+                               e1000_ms_force_slave) :
+                               e1000_ms_auto;
+
+               switch (phy_ms_setting) {
+               case e1000_ms_force_master:
+                       phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+                       break;
+               case e1000_ms_force_slave:
+                       phy_data |= CR_1000T_MS_ENABLE;
+                       phy_data &= ~(CR_1000T_MS_VALUE);
+                       break;
+               case e1000_ms_auto:
+                       phy_data &= ~CR_1000T_MS_ENABLE;
+               default:
+                       break;
+               }
+               ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+               if (ret_val)
+                       return ret_val;
+       }
+
+       return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * This function checks the mode of the firmware.
+ *
+ * returns  - TRUE when the mode is IAMT or FALSE.
+ ****************************************************************************/
+boolean_t
+e1000_check_mng_mode(struct e1000_hw *hw)
+{
+       uint32_t fwsm;
+       DEBUGFUNC();
+
+       fwsm = E1000_READ_REG(hw, FWSM);
+
+       if (hw->mac_type == e1000_ich8lan) {
+               if ((fwsm & E1000_FWSM_MODE_MASK) ==
+                   (E1000_MNG_ICH_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+                       return TRUE;
+       } else if ((fwsm & E1000_FWSM_MODE_MASK) ==
+                      (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+                       return TRUE;
+
+       return FALSE;
+}
+
+static int32_t
+e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data)
+{
+       uint16_t swfw = E1000_SWFW_PHY0_SM;
+       uint32_t reg_val;
+       DEBUGFUNC();
+
+       if (e1000_is_second_port(hw))
+               swfw = E1000_SWFW_PHY1_SM;
+
+       if (e1000_swfw_sync_acquire(hw, swfw))
+               return -E1000_ERR_SWFW_SYNC;
+
+       reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT)
+                       & E1000_KUMCTRLSTA_OFFSET) | data;
+       E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
+       udelay(2);
+
+       return E1000_SUCCESS;
+}
+
+static int32_t
+e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data)
+{
+       uint16_t swfw = E1000_SWFW_PHY0_SM;
+       uint32_t reg_val;
+       DEBUGFUNC();
+
+       if (e1000_is_second_port(hw))
+               swfw = E1000_SWFW_PHY1_SM;
+
+       if (e1000_swfw_sync_acquire(hw, swfw))
+               return -E1000_ERR_SWFW_SYNC;
+
+       /* Write register address */
+       reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) &
+                       E1000_KUMCTRLSTA_OFFSET) | E1000_KUMCTRLSTA_REN;
+       E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
+       udelay(2);
+
+       /* Read the data returned */
+       reg_val = E1000_READ_REG(hw, KUMCTRLSTA);
+       *data = (uint16_t)reg_val;
+
+       return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Copper link setup for e1000_phy_gg82563 series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_ggp_setup(struct e1000_hw *hw)
+{
+       int32_t ret_val;
+       uint16_t phy_data;
+       uint32_t reg_data;
+
+       DEBUGFUNC();
+
+       if (!hw->phy_reset_disable) {
+               /* Enable CRS on TX for half-duplex operation. */
+               ret_val = e1000_read_phy_reg(hw,
+                               GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+               /* Use 25MHz for both link down and 1000BASE-T for Tx clock */
+               phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
+
+               ret_val = e1000_write_phy_reg(hw,
+                               GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               /* Options:
+                *   MDI/MDI-X = 0 (default)
+                *   0 - Auto for all speeds
+                *   1 - MDI mode
+                *   2 - MDI-X mode
+                *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+                */
+               ret_val = e1000_read_phy_reg(hw,
+                               GG82563_PHY_SPEC_CTRL, &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+               switch (hw->mdix) {
+               case 1:
+                       phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+                       break;
+               case 2:
+                       phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+                       break;
+               case 0:
+               default:
+                       phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+                       break;
+               }
+
+               /* Options:
+                *   disable_polarity_correction = 0 (default)
+                *       Automatic Correction for Reversed Cable Polarity
+                *   0 - Disabled
+                *   1 - Enabled
+                */
+               phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+               ret_val = e1000_write_phy_reg(hw,
+                               GG82563_PHY_SPEC_CTRL, phy_data);
+
+               if (ret_val)
+                       return ret_val;
+
+               /* SW Reset the PHY so all changes take effect */
+               ret_val = e1000_phy_reset(hw);
+               if (ret_val) {
+                       DEBUGOUT("Error Resetting the PHY\n");
+                       return ret_val;
+               }
+       } /* phy_reset_disable */
+
+       if (hw->mac_type == e1000_80003es2lan) {
+               /* Bypass RX and TX FIFO's */
+               ret_val = e1000_write_kmrn_reg(hw,
+                               E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL,
+                               E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS
+                               | E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS);
+               if (ret_val)
+                       return ret_val;
+
+               ret_val = e1000_read_phy_reg(hw,
+                               GG82563_PHY_SPEC_CTRL_2, &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+               ret_val = e1000_write_phy_reg(hw,
+                               GG82563_PHY_SPEC_CTRL_2, phy_data);
+
+               if (ret_val)
+                       return ret_val;
+
+               reg_data = E1000_READ_REG(hw, CTRL_EXT);
+               reg_data &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+               E1000_WRITE_REG(hw, CTRL_EXT, reg_data);
+
+               ret_val = e1000_read_phy_reg(hw,
+                               GG82563_PHY_PWR_MGMT_CTRL, &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+       /* Do not init these registers when the HW is in IAMT mode, since the
+        * firmware will have already initialized them.  We only initialize
+        * them if the HW is not in IAMT mode.
+        */
+               if (e1000_check_mng_mode(hw) == FALSE) {
+                       /* Enable Electrical Idle on the PHY */
+                       phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       GG82563_PHY_PWR_MGMT_CTRL, phy_data);
+                       if (ret_val)
+                               return ret_val;
+
+                       ret_val = e1000_read_phy_reg(hw,
+                                       GG82563_PHY_KMRN_MODE_CTRL, &phy_data);
+                       if (ret_val)
+                               return ret_val;
+
+                       phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       GG82563_PHY_KMRN_MODE_CTRL, phy_data);
+
+                       if (ret_val)
+                               return ret_val;
+               }
+
+               /* Workaround: Disable padding in Kumeran interface in the MAC
+                * and in the PHY to avoid CRC errors.
+                */
+               ret_val = e1000_read_phy_reg(hw,
+                               GG82563_PHY_INBAND_CTRL, &phy_data);
+               if (ret_val)
+                       return ret_val;
+               phy_data |= GG82563_ICR_DIS_PADDING;
+               ret_val = e1000_write_phy_reg(hw,
+                               GG82563_PHY_INBAND_CTRL, phy_data);
+               if (ret_val)
+                       return ret_val;
        }
        }
+       return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Copper link setup for e1000_phy_m88 series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_mgp_setup(struct e1000_hw *hw)
+{
+       int32_t ret_val;
+       uint16_t phy_data;
+
+       DEBUGFUNC();
+
+       if (hw->phy_reset_disable)
+               return E1000_SUCCESS;
+
+       /* Enable CRS on TX. This must be set for half-duplex operation. */
+       ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+       if (ret_val)
+               return ret_val;
+
        phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
 
        phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
 
-#if 0
        /* Options:
         *   MDI/MDI-X = 0 (default)
         *   0 - Auto for all speeds
        /* Options:
         *   MDI/MDI-X = 0 (default)
         *   0 - Auto for all speeds
@@ -1207,6 +2743,7 @@ e1000_setup_copper_link(struct eth_device *nic)
         *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
         */
        phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
         *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
         */
        phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
        switch (hw->mdix) {
        case 1:
                phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
        switch (hw->mdix) {
        case 1:
                phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
@@ -1222,11 +2759,7 @@ e1000_setup_copper_link(struct eth_device *nic)
                phy_data |= M88E1000_PSCR_AUTO_X_MODE;
                break;
        }
                phy_data |= M88E1000_PSCR_AUTO_X_MODE;
                break;
        }
-#else
-       phy_data |= M88E1000_PSCR_AUTO_X_MODE;
-#endif
 
 
-#if 0
        /* Options:
         *   disable_polarity_correction = 0 (default)
         *       Automatic Correction for Reversed Cable Polarity
        /* Options:
         *   disable_polarity_correction = 0 (default)
         *       Automatic Correction for Reversed Cable Polarity
@@ -1234,154 +2767,264 @@ e1000_setup_copper_link(struct eth_device *nic)
         *   1 - Enabled
         */
        phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
         *   1 - Enabled
         */
        phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-       if (hw->disable_polarity_correction == 1)
-               phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-#else
-       phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-#endif
-       if (e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
-               DEBUGOUT("PHY Write Error\n");
-               return -E1000_ERR_PHY;
-       }
+       ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+       if (ret_val)
+               return ret_val;
 
 
-       /* Force TX_CLK in the Extended PHY Specific Control Register
-        * to 25MHz clock.
-        */
-       if (e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
-               DEBUGOUT("PHY Read Error\n");
-               return -E1000_ERR_PHY;
-       }
-       phy_data |= M88E1000_EPSCR_TX_CLK_25;
-       /* Configure Master and Slave downshift values */
-       phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
-                     M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
-       phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
-                    M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
-       if (e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
-               DEBUGOUT("PHY Write Error\n");
-               return -E1000_ERR_PHY;
+       if (hw->phy_revision < M88E1011_I_REV_4) {
+               /* Force TX_CLK in the Extended PHY Specific Control Register
+                * to 25MHz clock.
+                */
+               ret_val = e1000_read_phy_reg(hw,
+                               M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+               if ((hw->phy_revision == E1000_REVISION_2) &&
+                       (hw->phy_id == M88E1111_I_PHY_ID)) {
+                       /* Vidalia Phy, set the downshift counter to 5x */
+                       phy_data &= ~(M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK);
+                       phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+                       ret_val = e1000_write_phy_reg(hw,
+                                       M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+                       if (ret_val)
+                               return ret_val;
+               } else {
+                       /* Configure Master and Slave downshift values */
+                       phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK
+                                       | M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+                       phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X
+                                       | M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+                       ret_val = e1000_write_phy_reg(hw,
+                                       M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+                       if (ret_val)
+                               return ret_val;
+               }
        }
 
        /* SW Reset the PHY so all changes take effect */
        ret_val = e1000_phy_reset(hw);
        }
 
        /* SW Reset the PHY so all changes take effect */
        ret_val = e1000_phy_reset(hw);
-       if (ret_val < 0) {
+       if (ret_val) {
                DEBUGOUT("Error Resetting the PHY\n");
                return ret_val;
        }
 
                DEBUGOUT("Error Resetting the PHY\n");
                return ret_val;
        }
 
-       /* Options:
-        *   autoneg = 1 (default)
-        *      PHY will advertise value(s) parsed from
-        *      autoneg_advertised and fc
-        *   autoneg = 0
-        *      PHY will be set to 10H, 10F, 100H, or 100F
-        *      depending on value parsed from forced_speed_duplex.
-        */
+       return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Setup auto-negotiation and flow control advertisements,
+* and then perform auto-negotiation.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+       int32_t ret_val;
+       uint16_t phy_data;
+
+       DEBUGFUNC();
 
 
-       /* Is autoneg enabled?  This is enabled by default or by software override.
-        * If so, call e1000_phy_setup_autoneg routine to parse the
-        * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
-        * user should have provided a speed/duplex override.  If so, then call
-        * e1000_phy_force_speed_duplex to parse and set this up.
-        */
        /* Perform some bounds checking on the hw->autoneg_advertised
         * parameter.  If this variable is zero, then set it to the default.
         */
        hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
 
        /* Perform some bounds checking on the hw->autoneg_advertised
         * parameter.  If this variable is zero, then set it to the default.
         */
        hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
 
-       /* If autoneg_advertised is zero, we assume it was not defaulted
-        * by the calling code so we set to advertise full capability.
-        */
-       if (hw->autoneg_advertised == 0)
-               hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+       /* If autoneg_advertised is zero, we assume it was not defaulted
+        * by the calling code so we set to advertise full capability.
+        */
+       if (hw->autoneg_advertised == 0)
+               hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+       /* IFE phy only supports 10/100 */
+       if (hw->phy_type == e1000_phy_ife)
+               hw->autoneg_advertised &= AUTONEG_ADVERTISE_10_100_ALL;
+
+       DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+       ret_val = e1000_phy_setup_autoneg(hw);
+       if (ret_val) {
+               DEBUGOUT("Error Setting up Auto-Negotiation\n");
+               return ret_val;
+       }
+       DEBUGOUT("Restarting Auto-Neg\n");
+
+       /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+        * the Auto Neg Restart bit in the PHY control register.
+        */
+       ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+       if (ret_val)
+               return ret_val;
+
+       phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+       ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+       if (ret_val)
+               return ret_val;
+
+       /* Does the user want to wait for Auto-Neg to complete here, or
+        * check at a later time (for example, callback routine).
+        */
+       /* If we do not wait for autonegtation to complete I
+        * do not see a valid link status.
+        * wait_autoneg_complete = 1 .
+        */
+       if (hw->wait_autoneg_complete) {
+               ret_val = e1000_wait_autoneg(hw);
+               if (ret_val) {
+                       DEBUGOUT("Error while waiting for autoneg"
+                                       "to complete\n");
+                       return ret_val;
+               }
+       }
+
+       hw->get_link_status = TRUE;
+
+       return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Config the MAC and the PHY after link is up.
+*   1) Set up the MAC to the current PHY speed/duplex
+*      if we are on 82543.  If we
+*      are on newer silicon, we only need to configure
+*      collision distance in the Transmit Control Register.
+*   2) Set up flow control on the MAC to that established with
+*      the link partner.
+*   3) Config DSP to improve Gigabit link quality for some PHY revisions.
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_copper_link_postconfig(struct e1000_hw *hw)
+{
+       int32_t ret_val;
+       DEBUGFUNC();
+
+       if (hw->mac_type >= e1000_82544) {
+               e1000_config_collision_dist(hw);
+       } else {
+               ret_val = e1000_config_mac_to_phy(hw);
+               if (ret_val) {
+                       DEBUGOUT("Error configuring MAC to PHY settings\n");
+                       return ret_val;
+               }
+       }
+       ret_val = e1000_config_fc_after_link_up(hw);
+       if (ret_val) {
+               DEBUGOUT("Error Configuring Flow Control\n");
+               return ret_val;
+       }
+       return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Detects which PHY is present and setup the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int
+e1000_setup_copper_link(struct eth_device *nic)
+{
+       struct e1000_hw *hw = nic->priv;
+       int32_t ret_val;
+       uint16_t i;
+       uint16_t phy_data;
+       uint16_t reg_data;
+
+       DEBUGFUNC();
 
 
-       DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
-       ret_val = e1000_phy_setup_autoneg(hw);
-       if (ret_val < 0) {
-               DEBUGOUT("Error Setting up Auto-Negotiation\n");
-               return ret_val;
+       switch (hw->mac_type) {
+       case e1000_80003es2lan:
+       case e1000_ich8lan:
+               /* 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 = e1000_write_kmrn_reg(hw,
+                               GG82563_REG(0x34, 4), 0xFFFF);
+               if (ret_val)
+                       return ret_val;
+               ret_val = e1000_read_kmrn_reg(hw,
+                               GG82563_REG(0x34, 9), &reg_data);
+               if (ret_val)
+                       return ret_val;
+               reg_data |= 0x3F;
+               ret_val = e1000_write_kmrn_reg(hw,
+                               GG82563_REG(0x34, 9), reg_data);
+               if (ret_val)
+                       return ret_val;
+       default:
+               break;
        }
        }
-       DEBUGOUT("Restarting Auto-Neg\n");
 
 
-       /* Restart auto-negotiation by setting the Auto Neg Enable bit and
-        * the Auto Neg Restart bit in the PHY control register.
-        */
-       if (e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
-               DEBUGOUT("PHY Read Error\n");
-               return -E1000_ERR_PHY;
-       }
-       phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-       if (e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
-               DEBUGOUT("PHY Write Error\n");
-               return -E1000_ERR_PHY;
+       /* Check if it is a valid PHY and set PHY mode if necessary. */
+       ret_val = e1000_copper_link_preconfig(hw);
+       if (ret_val)
+               return ret_val;
+       switch (hw->mac_type) {
+       case e1000_80003es2lan:
+               /* Kumeran registers are written-only */
+               reg_data =
+               E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT;
+               reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING;
+               ret_val = e1000_write_kmrn_reg(hw,
+                               E1000_KUMCTRLSTA_OFFSET_INB_CTRL, reg_data);
+               if (ret_val)
+                       return ret_val;
+               break;
+       default:
+               break;
        }
        }
-#if 0
-       /* Does the user want to wait for Auto-Neg to complete here, or
-        * check at a later time (for example, callback routine).
-        */
-       if (hw->wait_autoneg_complete) {
-               ret_val = e1000_wait_autoneg(hw);
-               if (ret_val < 0) {
-                       DEBUGOUT
-                           ("Error while waiting for autoneg to complete\n");
+
+       if (hw->phy_type == e1000_phy_igp ||
+               hw->phy_type == e1000_phy_igp_3 ||
+               hw->phy_type == e1000_phy_igp_2) {
+               ret_val = e1000_copper_link_igp_setup(hw);
+               if (ret_val)
+                       return ret_val;
+       } else if (hw->phy_type == e1000_phy_m88) {
+               ret_val = e1000_copper_link_mgp_setup(hw);
+               if (ret_val)
+                       return ret_val;
+       } else if (hw->phy_type == e1000_phy_gg82563) {
+               ret_val = e1000_copper_link_ggp_setup(hw);
+               if (ret_val)
                        return ret_val;
                        return ret_val;
-               }
        }
        }
-#else
-       /* If we do not wait for autonegtation to complete I
-        * do not see a valid link status.
-        */
-       ret_val = e1000_wait_autoneg(hw);
-       if (ret_val < 0) {
-               DEBUGOUT("Error while waiting for autoneg to complete\n");
+
+       /* always auto */
+       /* Setup autoneg and flow control advertisement
+         * and perform autonegotiation */
+       ret_val = e1000_copper_link_autoneg(hw);
+       if (ret_val)
                return ret_val;
                return ret_val;
-       }
-#endif
 
        /* Check link status. Wait up to 100 microseconds for link to become
         * valid.
         */
        for (i = 0; i < 10; i++) {
 
        /* Check link status. Wait up to 100 microseconds for link to become
         * valid.
         */
        for (i = 0; i < 10; i++) {
-               if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
-                       DEBUGOUT("PHY Read Error\n");
-                       return -E1000_ERR_PHY;
-               }
-               if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
-                       DEBUGOUT("PHY Read Error\n");
-                       return -E1000_ERR_PHY;
-               }
+               ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+               if (ret_val)
+                       return ret_val;
+               ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+               if (ret_val)
+                       return ret_val;
+
                if (phy_data & MII_SR_LINK_STATUS) {
                if (phy_data & MII_SR_LINK_STATUS) {
-                       /* We have link, so we need to finish the config process:
-                        *   1) Set up the MAC to the current PHY speed/duplex
-                        *      if we are on 82543.  If we
-                        *      are on newer silicon, we only need to configure
-                        *      collision distance in the Transmit Control Register.
-                        *   2) Set up flow control on the MAC to that established with
-                        *      the link partner.
-                        */
-                       if (hw->mac_type >= e1000_82544) {
-                               e1000_config_collision_dist(hw);
-                       } else {
-                               ret_val = e1000_config_mac_to_phy(hw);
-                               if (ret_val < 0) {
-                                       DEBUGOUT
-                                           ("Error configuring MAC to PHY settings\n");
-                                       return ret_val;
-                               }
-                       }
-                       ret_val = e1000_config_fc_after_link_up(hw);
-                       if (ret_val < 0) {
-                               DEBUGOUT("Error Configuring Flow Control\n");
+                       /* Config the MAC and PHY after link is up */
+                       ret_val = e1000_copper_link_postconfig(hw);
+                       if (ret_val)
                                return ret_val;
                                return ret_val;
-                       }
+
                        DEBUGOUT("Valid link established!!!\n");
                        DEBUGOUT("Valid link established!!!\n");
-                       return 0;
+                       return E1000_SUCCESS;
                }
                udelay(10);
        }
 
        DEBUGOUT("Unable to establish link!!!\n");
                }
                udelay(10);
        }
 
        DEBUGOUT("Unable to establish link!!!\n");
-       return -E1000_ERR_NOLINK;
+       return E1000_SUCCESS;
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
@@ -1389,25 +3032,28 @@ e1000_setup_copper_link(struct eth_device *nic)
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
-static int
+int32_t
 e1000_phy_setup_autoneg(struct e1000_hw *hw)
 {
 e1000_phy_setup_autoneg(struct e1000_hw *hw)
 {
+       int32_t ret_val;
        uint16_t mii_autoneg_adv_reg;
        uint16_t mii_1000t_ctrl_reg;
 
        DEBUGFUNC();
 
        /* Read the MII Auto-Neg Advertisement Register (Address 4). */
        uint16_t mii_autoneg_adv_reg;
        uint16_t mii_1000t_ctrl_reg;
 
        DEBUGFUNC();
 
        /* Read the MII Auto-Neg Advertisement Register (Address 4). */
-       if (e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg) < 0) {
-               DEBUGOUT("PHY Read Error\n");
-               return -E1000_ERR_PHY;
-       }
+       ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+       if (ret_val)
+               return ret_val;
 
 
-       /* Read the MII 1000Base-T Control Register (Address 9). */
-       if (e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg) < 0) {
-               DEBUGOUT("PHY Read Error\n");
-               return -E1000_ERR_PHY;
-       }
+       if (hw->phy_type != e1000_phy_ife) {
+               /* Read the MII 1000Base-T Control Register (Address 9). */
+               ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
+                               &mii_1000t_ctrl_reg);
+               if (ret_val)
+                       return ret_val;
+       } else
+               mii_1000t_ctrl_reg = 0;
 
        /* Need to parse both autoneg_advertised and fc and set up
         * the appropriate PHY registers.  First we will parse for
 
        /* Need to parse both autoneg_advertised and fc and set up
         * the appropriate PHY registers.  First we will parse for
@@ -1468,14 +3114,14 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
         * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
         *
         * The possible values of the "fc" parameter are:
         * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
         *
         * The possible values of the "fc" parameter are:
-        *      0:  Flow control is completely disabled
-        *      1:  Rx flow control is enabled (we can receive pause frames
-        *          but not send pause frames).
-        *      2:  Tx flow control is enabled (we can send pause frames
-        *          but we do not support receiving pause frames).
-        *      3:  Both Rx and TX flow control (symmetric) are enabled.
+        *      0:  Flow control is completely disabled
+        *      1:  Rx flow control is enabled (we can receive pause frames
+        *          but not send pause frames).
+        *      2:  Tx flow control is enabled (we can send pause frames
+        *          but we do not support receiving pause frames).
+        *      3:  Both Rx and TX flow control (symmetric) are enabled.
         *  other:  No software override.  The flow control configuration
         *  other:  No software override.  The flow control configuration
-        *          in the EEPROM is used.
+        *          in the EEPROM is used.
         */
        switch (hw->fc) {
        case e1000_fc_none:     /* 0 */
         */
        switch (hw->fc) {
        case e1000_fc_none:     /* 0 */
@@ -1514,18 +3160,20 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
                return -E1000_ERR_CONFIG;
        }
 
                return -E1000_ERR_CONFIG;
        }
 
-       if (e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg) < 0) {
-               DEBUGOUT("PHY Write Error\n");
-               return -E1000_ERR_PHY;
-       }
+       ret_val = e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+       if (ret_val)
+               return ret_val;
 
        DEBUGOUT("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
 
 
        DEBUGOUT("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
 
-       if (e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg) < 0) {
-               DEBUGOUT("PHY Write Error\n");
-               return -E1000_ERR_PHY;
+       if (hw->phy_type != e1000_phy_ife) {
+               ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
+                               mii_1000t_ctrl_reg);
+               if (ret_val)
+                       return ret_val;
        }
        }
-       return 0;
+
+       return E1000_SUCCESS;
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
@@ -1539,12 +3187,19 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
 static void
 e1000_config_collision_dist(struct e1000_hw *hw)
 {
 static void
 e1000_config_collision_dist(struct e1000_hw *hw)
 {
-       uint32_t tctl;
+       uint32_t tctl, coll_dist;
+
+       DEBUGFUNC();
+
+       if (hw->mac_type < e1000_82543)
+               coll_dist = E1000_COLLISION_DISTANCE_82542;
+       else
+               coll_dist = E1000_COLLISION_DISTANCE;
 
        tctl = E1000_READ_REG(hw, TCTL);
 
        tctl &= ~E1000_TCTL_COLD;
 
        tctl = E1000_READ_REG(hw, TCTL);
 
        tctl &= ~E1000_TCTL_COLD;
-       tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+       tctl |= coll_dist << E1000_COLD_SHIFT;
 
        E1000_WRITE_REG(hw, TCTL, tctl);
        E1000_WRITE_FLUSH(hw);
 
        E1000_WRITE_REG(hw, TCTL, tctl);
        E1000_WRITE_FLUSH(hw);
@@ -1630,12 +3285,12 @@ e1000_force_mac_fc(struct e1000_hw *hw)
         * according to the "hw->fc" parameter.
         *
         * The possible values of the "fc" parameter are:
         * according to the "hw->fc" parameter.
         *
         * The possible values of the "fc" parameter are:
-        *      0:  Flow control is completely disabled
-        *      1:  Rx flow control is enabled (we can receive pause
-        *          frames but not send pause frames).
-        *      2:  Tx flow control is enabled (we can send pause frames
-        *          frames but we do not receive pause frames).
-        *      3:  Both Rx and TX flow control (symmetric) is enabled.
+        *      0:  Flow control is completely disabled
+        *      1:  Rx flow control is enabled (we can receive pause
+        *          frames but not send pause frames).
+        *      2:  Tx flow control is enabled (we can send pause frames
+        *          frames but we do not receive pause frames).
+        *      3:  Both Rx and TX flow control (symmetric) is enabled.
         *  other:  No other values should be possible at this point.
         */
 
         *  other:  No other values should be possible at this point.
         */
 
@@ -1678,7 +3333,7 @@ e1000_force_mac_fc(struct e1000_hw *hw)
  * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
  * and RFCE bits will be automaticaly set to the negotiated flow control mode.
  *****************************************************************************/
  * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
  * and RFCE bits will be automaticaly set to the negotiated flow control mode.
  *****************************************************************************/
-static int
+static int32_t
 e1000_config_fc_after_link_up(struct e1000_hw *hw)
 {
        int32_t ret_val;
 e1000_config_fc_after_link_up(struct e1000_hw *hw)
 {
        int32_t ret_val;
@@ -1694,7 +3349,11 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
         * so we had to force link.  In this case, we need to force the
         * configuration of the MAC to match the "fc" parameter.
         */
         * so we had to force link.  In this case, we need to force the
         * configuration of the MAC to match the "fc" parameter.
         */
-       if ((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) {
+       if (((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed))
+               || ((hw->media_type == e1000_media_type_internal_serdes)
+               && (hw->autoneg_failed))
+               || ((hw->media_type == e1000_media_type_copper)
+               && (!hw->autoneg))) {
                ret_val = e1000_force_mac_fc(hw);
                if (ret_val < 0) {
                        DEBUGOUT("Error forcing flow control settings\n");
                ret_val = e1000_force_mac_fc(hw);
                if (ret_val < 0) {
                        DEBUGOUT("Error forcing flow control settings\n");
@@ -1752,14 +3411,14 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
                         *   LOCAL DEVICE  |   LINK PARTNER
                         * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
                         *-------|---------|-------|---------|--------------------
                         *   LOCAL DEVICE  |   LINK PARTNER
                         * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
                         *-------|---------|-------|---------|--------------------
-                        *   0   |    0    |  DC   |   DC    | e1000_fc_none
-                        *   0   |    1    |   0   |   DC    | e1000_fc_none
-                        *   0   |    1    |   1   |    0    | e1000_fc_none
-                        *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-                        *   1   |    0    |   0   |   DC    | e1000_fc_none
-                        *   1   |   DC    |   1   |   DC    | e1000_fc_full
-                        *   1   |    1    |   0   |    0    | e1000_fc_none
-                        *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+                        *   0   |    0    |  DC   |   DC    | e1000_fc_none
+                        *   0   |    1    |   0   |   DC    | e1000_fc_none
+                        *   0   |    1    |   1   |    0    | e1000_fc_none
+                        *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+                        *   1   |    0    |   0   |   DC    | e1000_fc_none
+                        *   1   |   DC    |   1   |   DC    | e1000_fc_full
+                        *   1   |    1    |   0   |    0    | e1000_fc_none
+                        *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
                         *
                         */
                        /* Are both PAUSE bits set to 1?  If so, this implies
                         *
                         */
                        /* Are both PAUSE bits set to 1?  If so, this implies
@@ -1771,7 +3430,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
                         *   LOCAL DEVICE  |   LINK PARTNER
                         * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
                         *-------|---------|-------|---------|--------------------
                         *   LOCAL DEVICE  |   LINK PARTNER
                         * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
                         *-------|---------|-------|---------|--------------------
-                        *   1   |   DC    |   1   |   DC    | e1000_fc_full
+                        *   1   |   DC    |   1   |   DC    | e1000_fc_full
                         *
                         */
                        if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
                         *
                         */
                        if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
@@ -1796,7 +3455,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
                         *   LOCAL DEVICE  |   LINK PARTNER
                         * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
                         *-------|---------|-------|---------|--------------------
                         *   LOCAL DEVICE  |   LINK PARTNER
                         * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
                         *-------|---------|-------|---------|--------------------
-                        *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+                        *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
                         *
                         */
                        else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
                         *
                         */
                        else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
@@ -1813,7 +3472,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
                         *   LOCAL DEVICE  |   LINK PARTNER
                         * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
                         *-------|---------|-------|---------|--------------------
                         *   LOCAL DEVICE  |   LINK PARTNER
                         * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
                         *-------|---------|-------|---------|--------------------
-                        *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+                        *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
                         *
                         */
                        else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
                         *
                         */
                        else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
@@ -1855,7 +3514,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
                                    ("Flow Control = RX PAUSE frames only.\r\n");
                        }
 
                                    ("Flow Control = RX PAUSE frames only.\r\n");
                        }
 
-                       /* Now we need to do one last check...  If we auto-
+                       /* Now we need to do one last check...  If we auto-
                         * negotiated to HALF DUPLEX, flow control should not be
                         * enabled per IEEE 802.3 spec.
                         */
                         * negotiated to HALF DUPLEX, flow control should not be
                         * enabled per IEEE 802.3 spec.
                         */
@@ -1878,7 +3537,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
                            ("Copper PHY and Auto Neg has not completed.\r\n");
                }
        }
                            ("Copper PHY and Auto Neg has not completed.\r\n");
                }
        }
-       return 0;
+       return E1000_SUCCESS;
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
@@ -1919,7 +3578,7 @@ e1000_check_for_link(struct eth_device *nic)
 
        /* If we have a copper PHY then we only want to go out to the PHY
         * registers to see if Auto-Neg has completed and/or if our link
 
        /* If we have a copper PHY then 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 will be set if we
+        * status has changed.  The get_link_status flag will be set if we
         * receive a Link Status Change interrupt or we have Rx Sequence
         * Errors.
         */
         * receive a Link Status Change interrupt or we have Rx Sequence
         * Errors.
         */
@@ -1976,7 +3635,7 @@ e1000_check_for_link(struct eth_device *nic)
 
                /* At this point we know that we are on copper and we have
                 * auto-negotiated link.  These are conditions for checking the link
 
                /* At this point we know that we are on copper and we have
                 * auto-negotiated link.  These are conditions for checking the link
-                * parter capability register.  We use the link partner capability to
+                * parter capability register.  We use the link partner capability to
                 * determine if TBI Compatibility needs to be turned on or off.  If
                 * the link partner advertises any speed in addition to Gigabit, then
                 * we assume that they are GMII-based, and TBI compatibility is not
                 * determine if TBI Compatibility needs to be turned on or off.  If
                 * the link partner advertises any speed in addition to Gigabit, then
                 * we assume that they are GMII-based, and TBI compatibility is not
@@ -2066,6 +3725,79 @@ e1000_check_for_link(struct eth_device *nic)
        return 0;
 }
 
        return 0;
 }
 
+/******************************************************************************
+* Configure the MAC-to-PHY interface for 10/100Mbps
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, uint16_t duplex)
+{
+       int32_t ret_val = E1000_SUCCESS;
+       uint32_t tipg;
+       uint16_t reg_data;
+
+       DEBUGFUNC();
+
+       reg_data = E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT;
+       ret_val = e1000_write_kmrn_reg(hw,
+                       E1000_KUMCTRLSTA_OFFSET_HD_CTRL, reg_data);
+       if (ret_val)
+               return ret_val;
+
+       /* Configure Transmit Inter-Packet Gap */
+       tipg = E1000_READ_REG(hw, TIPG);
+       tipg &= ~E1000_TIPG_IPGT_MASK;
+       tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100;
+       E1000_WRITE_REG(hw, TIPG, tipg);
+
+       ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+       if (ret_val)
+               return ret_val;
+
+       if (duplex == HALF_DUPLEX)
+               reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+       else
+               reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+       ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+       return ret_val;
+}
+
+static int32_t
+e1000_configure_kmrn_for_1000(struct e1000_hw *hw)
+{
+       int32_t ret_val = E1000_SUCCESS;
+       uint16_t reg_data;
+       uint32_t tipg;
+
+       DEBUGFUNC();
+
+       reg_data = E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT;
+       ret_val = e1000_write_kmrn_reg(hw,
+                       E1000_KUMCTRLSTA_OFFSET_HD_CTRL, reg_data);
+       if (ret_val)
+               return ret_val;
+
+       /* Configure Transmit Inter-Packet Gap */
+       tipg = E1000_READ_REG(hw, TIPG);
+       tipg &= ~E1000_TIPG_IPGT_MASK;
+       tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
+       E1000_WRITE_REG(hw, TIPG, tipg);
+
+       ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+       if (ret_val)
+               return ret_val;
+
+       reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+       ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+       return ret_val;
+}
+
 /******************************************************************************
  * Detects the current speed and duplex settings of the hardware.
  *
 /******************************************************************************
  * Detects the current speed and duplex settings of the hardware.
  *
@@ -2073,11 +3805,13 @@ e1000_check_for_link(struct eth_device *nic)
  * speed - Speed of the connection
  * duplex - Duplex setting of the connection
  *****************************************************************************/
  * speed - Speed of the connection
  * duplex - Duplex setting of the connection
  *****************************************************************************/
-static void
-e1000_get_speed_and_duplex(struct e1000_hw *hw,
-                          uint16_t * speed, uint16_t * duplex)
+static int
+e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t *speed,
+               uint16_t *duplex)
 {
        uint32_t status;
 {
        uint32_t status;
+       int32_t ret_val;
+       uint16_t phy_data;
 
        DEBUGFUNC();
 
 
        DEBUGFUNC();
 
@@ -2106,6 +3840,41 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw,
                *speed = SPEED_1000;
                *duplex = FULL_DUPLEX;
        }
                *speed = SPEED_1000;
                *duplex = FULL_DUPLEX;
        }
+
+       /* IGP01 PHY may advertise full duplex operation after speed downgrade
+        * even if it is operating at half duplex.  Here we set the duplex
+        * settings to match the duplex in the link partner's capabilities.
+        */
+       if (hw->phy_type == e1000_phy_igp && hw->speed_downgraded) {
+               ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               if (!(phy_data & NWAY_ER_LP_NWAY_CAPS))
+                       *duplex = HALF_DUPLEX;
+               else {
+                       ret_val = e1000_read_phy_reg(hw,
+                                       PHY_LP_ABILITY, &phy_data);
+                       if (ret_val)
+                               return ret_val;
+                       if ((*speed == SPEED_100 &&
+                               !(phy_data & NWAY_LPAR_100TX_FD_CAPS))
+                               || (*speed == SPEED_10
+                               && !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
+                               *duplex = HALF_DUPLEX;
+               }
+       }
+
+       if ((hw->mac_type == e1000_80003es2lan) &&
+               (hw->media_type == e1000_media_type_copper)) {
+               if (*speed == SPEED_1000)
+                       ret_val = e1000_configure_kmrn_for_1000(hw);
+               else
+                       ret_val = e1000_configure_kmrn_for_10_100(hw, *duplex);
+               if (ret_val)
+                       return ret_val;
+       }
+       return E1000_SUCCESS;
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
@@ -2425,46 +4194,270 @@ e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t phy_data)
        return 0;
 }
 
        return 0;
 }
 
+/******************************************************************************
+ * Checks if PHY reset is blocked due to SOL/IDER session, for example.
+ * Returning E1000_BLK_PHY_RESET isn't necessarily an error.  But it's up to
+ * the caller to figure out how to deal with it.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_BLK_PHY_RESET
+ *            E1000_SUCCESS
+ *
+ *****************************************************************************/
+int32_t
+e1000_check_phy_reset_block(struct e1000_hw *hw)
+{
+       uint32_t manc = 0;
+       uint32_t fwsm = 0;
+
+       if (hw->mac_type == e1000_ich8lan) {
+               fwsm = E1000_READ_REG(hw, FWSM);
+               return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS
+                                               : E1000_BLK_PHY_RESET;
+       }
+
+       if (hw->mac_type > e1000_82547_rev_2)
+               manc = E1000_READ_REG(hw, MANC);
+       return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+               E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * Checks if the PHY configuration is done
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ *            E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+static int32_t
+e1000_get_phy_cfg_done(struct e1000_hw *hw)
+{
+       int32_t timeout = PHY_CFG_TIMEOUT;
+       uint32_t cfg_mask = E1000_EEPROM_CFG_DONE;
+
+       DEBUGFUNC();
+
+       switch (hw->mac_type) {
+       default:
+               mdelay(10);
+               break;
+
+       case e1000_80003es2lan:
+               /* Separate *_CFG_DONE_* bit for each port */
+               if (e1000_is_second_port(hw))
+                       cfg_mask = E1000_EEPROM_CFG_DONE_PORT_1;
+               /* Fall Through */
+
+       case e1000_82571:
+       case e1000_82572:
+               while (timeout) {
+                       if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask)
+                               break;
+                       else
+                               mdelay(1);
+                       timeout--;
+               }
+               if (!timeout) {
+                       DEBUGOUT("MNG configuration cycle has not "
+                                       "completed.\n");
+                       return -E1000_ERR_RESET;
+               }
+               break;
+       }
+
+       return E1000_SUCCESS;
+}
+
 /******************************************************************************
 * Returns the PHY to the power-on reset state
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
 /******************************************************************************
 * Returns the PHY to the power-on reset state
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
-static void
+int32_t
 e1000_phy_hw_reset(struct e1000_hw *hw)
 {
 e1000_phy_hw_reset(struct e1000_hw *hw)
 {
-       uint32_t ctrl;
-       uint32_t ctrl_ext;
+       uint16_t swfw = E1000_SWFW_PHY0_SM;
+       uint32_t ctrl, ctrl_ext;
+       uint32_t led_ctrl;
+       int32_t ret_val;
+
+       DEBUGFUNC();
+
+       /* In the case of the phy reset being blocked, it's not an error, we
+        * simply return success without performing the reset. */
+       ret_val = e1000_check_phy_reset_block(hw);
+       if (ret_val)
+               return E1000_SUCCESS;
+
+       DEBUGOUT("Resetting Phy...\n");
+
+       if (hw->mac_type > e1000_82543) {
+               if (e1000_is_second_port(hw))
+                       swfw = E1000_SWFW_PHY1_SM;
+
+               if (e1000_swfw_sync_acquire(hw, swfw)) {
+                       DEBUGOUT("Unable to acquire swfw sync\n");
+                       return -E1000_ERR_SWFW_SYNC;
+               }
+
+               /* Read the device control register and assert the E1000_CTRL_PHY_RST
+                * bit. Then, take it out of reset.
+                */
+               ctrl = E1000_READ_REG(hw, CTRL);
+               E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+               E1000_WRITE_FLUSH(hw);
+
+               if (hw->mac_type < e1000_82571)
+                       udelay(10);
+               else
+                       udelay(100);
+
+               E1000_WRITE_REG(hw, CTRL, ctrl);
+               E1000_WRITE_FLUSH(hw);
+
+               if (hw->mac_type >= e1000_82571)
+                       mdelay(10);
+
+       } else {
+               /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+                * bit to put the PHY into reset. Then, take it out of reset.
+                */
+               ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+               ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+               ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+               E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+               E1000_WRITE_FLUSH(hw);
+               mdelay(10);
+               ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+               E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+               E1000_WRITE_FLUSH(hw);
+       }
+       udelay(150);
+
+       if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+               /* Configure activity LED after PHY reset */
+               led_ctrl = E1000_READ_REG(hw, LEDCTL);
+               led_ctrl &= IGP_ACTIVITY_LED_MASK;
+               led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+               E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+       }
+
+       /* Wait for FW to finish PHY configuration. */
+       ret_val = e1000_get_phy_cfg_done(hw);
+       if (ret_val != E1000_SUCCESS)
+               return ret_val;
+
+       return ret_val;
+}
+
+/******************************************************************************
+ * IGP phy init script - initializes the GbE PHY
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_phy_init_script(struct e1000_hw *hw)
+{
+       uint32_t ret_val;
+       uint16_t phy_saved_data;
+       DEBUGFUNC();
+
+       if (hw->phy_init_script) {
+               mdelay(20);
+
+               /* Save off the current value of register 0x2F5B to be
+                * restored at the end of this routine. */
+               ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+               /* Disabled the PHY transmitter */
+               e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+               mdelay(20);
+
+               e1000_write_phy_reg(hw, 0x0000, 0x0140);
+
+               mdelay(5);
+
+               switch (hw->mac_type) {
+               case e1000_82541:
+               case e1000_82547:
+                       e1000_write_phy_reg(hw, 0x1F95, 0x0001);
+
+                       e1000_write_phy_reg(hw, 0x1F71, 0xBD21);
 
 
-       DEBUGFUNC();
+                       e1000_write_phy_reg(hw, 0x1F79, 0x0018);
 
 
-       DEBUGOUT("Resetting Phy...\n");
+                       e1000_write_phy_reg(hw, 0x1F30, 0x1600);
 
 
-       if (hw->mac_type > e1000_82543) {
-               /* Read the device control register and assert the E1000_CTRL_PHY_RST
-                * bit. Then, take it out of reset.
-                */
-               ctrl = E1000_READ_REG(hw, CTRL);
-               E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
-               E1000_WRITE_FLUSH(hw);
-               mdelay(10);
-               E1000_WRITE_REG(hw, CTRL, ctrl);
-               E1000_WRITE_FLUSH(hw);
-       } else {
-               /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
-                * bit to put the PHY into reset. Then, take it out of reset.
-                */
-               ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
-               ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
-               ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
-               E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
-               E1000_WRITE_FLUSH(hw);
-               mdelay(10);
-               ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
-               E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
-               E1000_WRITE_FLUSH(hw);
+                       e1000_write_phy_reg(hw, 0x1F31, 0x0014);
+
+                       e1000_write_phy_reg(hw, 0x1F32, 0x161C);
+
+                       e1000_write_phy_reg(hw, 0x1F94, 0x0003);
+
+                       e1000_write_phy_reg(hw, 0x1F96, 0x003F);
+
+                       e1000_write_phy_reg(hw, 0x2010, 0x0008);
+                       break;
+
+               case e1000_82541_rev_2:
+               case e1000_82547_rev_2:
+                       e1000_write_phy_reg(hw, 0x1F73, 0x0099);
+                       break;
+               default:
+                       break;
+               }
+
+               e1000_write_phy_reg(hw, 0x0000, 0x3300);
+
+               mdelay(20);
+
+               /* Now enable the transmitter */
+               if (!ret_val)
+                       e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+               if (hw->mac_type == e1000_82547) {
+                       uint16_t fused, fine, coarse;
+
+                       /* Move to analog registers page */
+                       e1000_read_phy_reg(hw,
+                               IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused);
+
+                       if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
+                               e1000_read_phy_reg(hw,
+                                       IGP01E1000_ANALOG_FUSE_STATUS, &fused);
+
+                               fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
+                               coarse = fused
+                                       & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
+
+                               if (coarse >
+                                       IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
+                                       coarse -=
+                                       IGP01E1000_ANALOG_FUSE_COARSE_10;
+                                       fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
+                               } else if (coarse
+                                       == IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
+                                       fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
+
+                               fused = (fused
+                                       & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
+                                       (fine
+                                       & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
+                                       (coarse
+                                       & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
+
+                               e1000_write_phy_reg(hw,
+                                       IGP01E1000_ANALOG_FUSE_CONTROL, fused);
+                               e1000_write_phy_reg(hw,
+                                       IGP01E1000_ANALOG_FUSE_BYPASS,
+                               IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
+                       }
+               }
        }
        }
-       udelay(150);
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
@@ -2472,56 +4465,98 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
 *
 * hw - Struct containing variables accessed by shared code
 *
 *
 * hw - Struct containing variables accessed by shared code
 *
-* Sets bit 15 of the MII Control regiser
+* Sets bit 15 of the MII Control register
 ******************************************************************************/
 ******************************************************************************/
-static int
+int32_t
 e1000_phy_reset(struct e1000_hw *hw)
 {
 e1000_phy_reset(struct e1000_hw *hw)
 {
+       int32_t ret_val;
        uint16_t phy_data;
 
        DEBUGFUNC();
 
        uint16_t phy_data;
 
        DEBUGFUNC();
 
-       if (e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
-               DEBUGOUT("PHY Read Error\n");
-               return -E1000_ERR_PHY;
-       }
-       phy_data |= MII_CR_RESET;
-       if (e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
-               DEBUGOUT("PHY Write Error\n");
-               return -E1000_ERR_PHY;
+       /* In the case of the phy reset being blocked, it's not an error, we
+        * simply return success without performing the reset. */
+       ret_val = e1000_check_phy_reset_block(hw);
+       if (ret_val)
+               return E1000_SUCCESS;
+
+       switch (hw->phy_type) {
+       case e1000_phy_igp:
+       case e1000_phy_igp_2:
+       case e1000_phy_igp_3:
+       case e1000_phy_ife:
+               ret_val = e1000_phy_hw_reset(hw);
+               if (ret_val)
+                       return ret_val;
+               break;
+       default:
+               ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               phy_data |= MII_CR_RESET;
+               ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               udelay(1);
+               break;
        }
        }
-       udelay(1);
-       return 0;
+
+       if (hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2)
+               e1000_phy_init_script(hw);
+
+       return E1000_SUCCESS;
 }
 
 }
 
-static int
-e1000_set_phy_type(struct e1000_hw *hw)
-{
-    DEBUGFUNC();
-
-    if(hw->mac_type == e1000_undefined)
-        return -E1000_ERR_PHY_TYPE;
-
-    switch(hw->phy_id) {
-    case M88E1000_E_PHY_ID:
-    case M88E1000_I_PHY_ID:
-    case M88E1011_I_PHY_ID:
-        hw->phy_type = e1000_phy_m88;
-        break;
-    case IGP01E1000_I_PHY_ID:
-        if(hw->mac_type == e1000_82541 ||
-           hw->mac_type == e1000_82541_rev_2) {
-            hw->phy_type = e1000_phy_igp;
-            break;
-        }
-        /* Fall Through */
-    default:
-        /* Should never have loaded on this device */
-        hw->phy_type = e1000_phy_undefined;
-        return -E1000_ERR_PHY_TYPE;
-    }
-
-    return E1000_SUCCESS;
+static int e1000_set_phy_type (struct e1000_hw *hw)
+{
+       DEBUGFUNC ();
+
+       if (hw->mac_type == e1000_undefined)
+               return -E1000_ERR_PHY_TYPE;
+
+       switch (hw->phy_id) {
+       case M88E1000_E_PHY_ID:
+       case M88E1000_I_PHY_ID:
+       case M88E1011_I_PHY_ID:
+       case M88E1111_I_PHY_ID:
+               hw->phy_type = e1000_phy_m88;
+               break;
+       case IGP01E1000_I_PHY_ID:
+               if (hw->mac_type == e1000_82541 ||
+                       hw->mac_type == e1000_82541_rev_2 ||
+                       hw->mac_type == e1000_82547 ||
+                       hw->mac_type == e1000_82547_rev_2) {
+                       hw->phy_type = e1000_phy_igp;
+                       hw->phy_type = e1000_phy_igp;
+                       break;
+               }
+       case IGP03E1000_E_PHY_ID:
+               hw->phy_type = e1000_phy_igp_3;
+               break;
+       case IFE_E_PHY_ID:
+       case IFE_PLUS_E_PHY_ID:
+       case IFE_C_E_PHY_ID:
+               hw->phy_type = e1000_phy_ife;
+               break;
+       case GG82563_E_PHY_ID:
+               if (hw->mac_type == e1000_80003es2lan) {
+                       hw->phy_type = e1000_phy_gg82563;
+                       break;
+               }
+       case BME1000_E_PHY_ID:
+               hw->phy_type = e1000_phy_bm;
+               break;
+               /* Fall Through */
+       default:
+               /* Should never have loaded on this device */
+               hw->phy_type = e1000_phy_undefined;
+               return -E1000_ERR_PHY_TYPE;
+       }
+
+       return E1000_SUCCESS;
 }
 
 /******************************************************************************
 }
 
 /******************************************************************************
@@ -2529,27 +4564,47 @@ e1000_set_phy_type(struct e1000_hw *hw)
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
-static int
+static int32_t
 e1000_detect_gig_phy(struct e1000_hw *hw)
 {
 e1000_detect_gig_phy(struct e1000_hw *hw)
 {
-       int32_t phy_init_status;
+       int32_t phy_init_status, ret_val;
        uint16_t phy_id_high, phy_id_low;
        uint16_t phy_id_high, phy_id_low;
-       int match = FALSE;
+       boolean_t match = FALSE;
 
        DEBUGFUNC();
 
 
        DEBUGFUNC();
 
-       /* Read the PHY ID Registers to identify which PHY is onboard. */
-       if (e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high) < 0) {
-               DEBUGOUT("PHY Read Error\n");
-               return -E1000_ERR_PHY;
+       /* The 82571 firmware may still be configuring the PHY.  In this
+        * case, we cannot access the PHY until the configuration is done.  So
+        * we explicitly set the PHY values. */
+       if (hw->mac_type == e1000_82571 ||
+               hw->mac_type == e1000_82572) {
+               hw->phy_id = IGP01E1000_I_PHY_ID;
+               hw->phy_type = e1000_phy_igp_2;
+               return E1000_SUCCESS;
        }
        }
+
+       /* ESB-2 PHY reads require e1000_phy_gg82563 to be set because of a
+        * work- around that forces PHY page 0 to be set or the reads fail.
+        * The rest of the code in this routine uses e1000_read_phy_reg to
+        * read the PHY ID.  So for ESB-2 we need to have this set so our
+        * reads won't fail.  If the attached PHY is not a e1000_phy_gg82563,
+        * the routines below will figure this out as well. */
+       if (hw->mac_type == e1000_80003es2lan)
+               hw->phy_type = e1000_phy_gg82563;
+
+       /* Read the PHY ID Registers to identify which PHY is onboard. */
+       ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high);
+       if (ret_val)
+               return ret_val;
+
        hw->phy_id = (uint32_t) (phy_id_high << 16);
        hw->phy_id = (uint32_t) (phy_id_high << 16);
-       udelay(2);
-       if (e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
-               DEBUGOUT("PHY Read Error\n");
-               return -E1000_ERR_PHY;
-       }
+       udelay(20);
+       ret_val = e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low);
+       if (ret_val)
+               return ret_val;
+
        hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
        hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+       hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
 
        switch (hw->mac_type) {
        case e1000_82543:
 
        switch (hw->mac_type) {
        case e1000_82543:
@@ -2562,15 +4617,42 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
                break;
        case e1000_82540:
        case e1000_82545:
                break;
        case e1000_82540:
        case e1000_82545:
+       case e1000_82545_rev_3:
        case e1000_82546:
        case e1000_82546:
+       case e1000_82546_rev_3:
                if (hw->phy_id == M88E1011_I_PHY_ID)
                        match = TRUE;
                break;
                if (hw->phy_id == M88E1011_I_PHY_ID)
                        match = TRUE;
                break;
+       case e1000_82541:
        case e1000_82541_rev_2:
        case e1000_82541_rev_2:
+       case e1000_82547:
+       case e1000_82547_rev_2:
                if(hw->phy_id == IGP01E1000_I_PHY_ID)
                        match = TRUE;
 
                break;
                if(hw->phy_id == IGP01E1000_I_PHY_ID)
                        match = TRUE;
 
                break;
+       case e1000_82573:
+               if (hw->phy_id == M88E1111_I_PHY_ID)
+                       match = TRUE;
+               break;
+       case e1000_82574:
+               if (hw->phy_id == BME1000_E_PHY_ID)
+                       match = TRUE;
+               break;
+       case e1000_80003es2lan:
+               if (hw->phy_id == GG82563_E_PHY_ID)
+                       match = TRUE;
+               break;
+       case e1000_ich8lan:
+               if (hw->phy_id == IGP03E1000_E_PHY_ID)
+                       match = TRUE;
+               if (hw->phy_id == IFE_E_PHY_ID)
+                       match = TRUE;
+               if (hw->phy_id == IFE_PLUS_E_PHY_ID)
+                       match = TRUE;
+               if (hw->phy_id == IFE_C_E_PHY_ID)
+                       match = TRUE;
+               break;
        default:
                DEBUGOUT("Invalid MAC type %d\n", hw->mac_type);
                return -E1000_ERR_CONFIG;
        default:
                DEBUGOUT("Invalid MAC type %d\n", hw->mac_type);
                return -E1000_ERR_CONFIG;
@@ -2586,6 +4668,61 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
        return -E1000_ERR_PHY;
 }
 
        return -E1000_ERR_PHY;
 }
 
+/*****************************************************************************
+ * Set media type and TBI compatibility.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * **************************************************************************/
+void
+e1000_set_media_type(struct e1000_hw *hw)
+{
+       uint32_t status;
+
+       DEBUGFUNC();
+
+       if (hw->mac_type != e1000_82543) {
+               /* tbi_compatibility is only valid on 82543 */
+               hw->tbi_compatibility_en = FALSE;
+       }
+
+       switch (hw->device_id) {
+       case E1000_DEV_ID_82545GM_SERDES:
+       case E1000_DEV_ID_82546GB_SERDES:
+       case E1000_DEV_ID_82571EB_SERDES:
+       case E1000_DEV_ID_82571EB_SERDES_DUAL:
+       case E1000_DEV_ID_82571EB_SERDES_QUAD:
+       case E1000_DEV_ID_82572EI_SERDES:
+       case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+               hw->media_type = e1000_media_type_internal_serdes;
+               break;
+       default:
+               switch (hw->mac_type) {
+               case e1000_82542_rev2_0:
+               case e1000_82542_rev2_1:
+                       hw->media_type = e1000_media_type_fiber;
+                       break;
+               case e1000_ich8lan:
+               case e1000_82573:
+               case e1000_82574:
+                       /* The STATUS_TBIMODE bit is reserved or reused
+                        * for the this device.
+                        */
+                       hw->media_type = e1000_media_type_copper;
+                       break;
+               default:
+                       status = E1000_READ_REG(hw, STATUS);
+                       if (status & E1000_STATUS_TBIMODE) {
+                               hw->media_type = e1000_media_type_fiber;
+                               /* tbi_compatibility not valid on fiber */
+                               hw->tbi_compatibility_en = FALSE;
+                       } else {
+                               hw->media_type = e1000_media_type_copper;
+                       }
+                       break;
+               }
+       }
+}
+
 /**
  * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
  *
 /**
  * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
  *
@@ -2595,7 +4732,7 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
  **/
 
 static int
  **/
 
 static int
-e1000_sw_init(struct eth_device *nic, int cardnum)
+e1000_sw_init(struct eth_device *nic)
 {
        struct e1000_hw *hw = (typeof(hw)) nic->priv;
        int result;
 {
        struct e1000_hw *hw = (typeof(hw)) nic->priv;
        int result;
@@ -2613,17 +4750,20 @@ e1000_sw_init(struct eth_device *nic, int cardnum)
        /* identify the MAC */
        result = e1000_set_mac_type(hw);
        if (result) {
        /* identify the MAC */
        result = e1000_set_mac_type(hw);
        if (result) {
-               E1000_ERR("Unknown MAC Type\n");
+               E1000_ERR(hw->nic, "Unknown MAC Type\n");
                return result;
        }
 
                return result;
        }
 
-       /* lan a vs. lan b settings */
-       if (hw->mac_type == e1000_82546)
-               /*this also works w/ multiple 82546 cards */
-               /*but not if they're intermingled /w other e1000s */
-               hw->lan_loc = (cardnum % 2) ? e1000_lan_b : e1000_lan_a;
-       else
-               hw->lan_loc = e1000_lan_a;
+       switch (hw->mac_type) {
+       default:
+               break;
+       case e1000_82541:
+       case e1000_82547:
+       case e1000_82541_rev_2:
+       case e1000_82547_rev_2:
+               hw->phy_init_script = 1;
+               break;
+       }
 
        /* flow control settings */
        hw->fc_high_water = E1000_FC_HIGH_THRESH;
 
        /* flow control settings */
        hw->fc_high_water = E1000_FC_HIGH_THRESH;
@@ -2632,6 +4772,7 @@ e1000_sw_init(struct eth_device *nic, int cardnum)
        hw->fc_send_xon = 1;
 
        /* Media type - copper or fiber */
        hw->fc_send_xon = 1;
 
        /* Media type - copper or fiber */
+       e1000_set_media_type(hw);
 
        if (hw->mac_type >= e1000_82543) {
                uint32_t status = E1000_READ_REG(hw, STATUS);
 
        if (hw->mac_type >= e1000_82543) {
                uint32_t status = E1000_READ_REG(hw, STATUS);
@@ -2647,22 +4788,13 @@ e1000_sw_init(struct eth_device *nic, int cardnum)
                hw->media_type = e1000_media_type_fiber;
        }
 
                hw->media_type = e1000_media_type_fiber;
        }
 
+       hw->tbi_compatibility_en = TRUE;
+       hw->wait_autoneg_complete = TRUE;
        if (hw->mac_type < e1000_82543)
                hw->report_tx_early = 0;
        else
                hw->report_tx_early = 1;
 
        if (hw->mac_type < e1000_82543)
                hw->report_tx_early = 0;
        else
                hw->report_tx_early = 1;
 
-       hw->tbi_compatibility_en = TRUE;
-#if 0
-       hw->wait_autoneg_complete = FALSE;
-       hw->adaptive_ifs = TRUE;
-
-       /* Copper options */
-       if (hw->media_type == e1000_media_type_copper) {
-               hw->mdix = AUTO_ALL_MODES;
-               hw->disable_polarity_correction = FALSE;
-       }
-#endif
        return E1000_SUCCESS;
 }
 
        return E1000_SUCCESS;
 }
 
@@ -2691,7 +4823,8 @@ e1000_configure_tx(struct e1000_hw *hw)
 {
        unsigned long ptr;
        unsigned long tctl;
 {
        unsigned long ptr;
        unsigned long tctl;
-       unsigned long tipg;
+       unsigned long tipg, tarc;
+       uint32_t ipgr1, ipgr2;
 
        ptr = (u32) tx_pool;
        if (ptr & 0xf)
 
        ptr = (u32) tx_pool;
        if (ptr & 0xf)
@@ -2709,46 +4842,65 @@ e1000_configure_tx(struct e1000_hw *hw)
        E1000_WRITE_REG(hw, TDT, 0);
        tx_tail = 0;
 
        E1000_WRITE_REG(hw, TDT, 0);
        tx_tail = 0;
 
+       /* Set the default values for the Tx Inter Packet Gap timer */
+       if (hw->mac_type <= e1000_82547_rev_2 &&
+           (hw->media_type == e1000_media_type_fiber ||
+            hw->media_type == e1000_media_type_internal_serdes))
+               tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
+       else
+               tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
+
        /* Set the default values for the Tx Inter Packet Gap timer */
        switch (hw->mac_type) {
        case e1000_82542_rev2_0:
        case e1000_82542_rev2_1:
                tipg = DEFAULT_82542_TIPG_IPGT;
        /* Set the default values for the Tx Inter Packet Gap timer */
        switch (hw->mac_type) {
        case e1000_82542_rev2_0:
        case e1000_82542_rev2_1:
                tipg = DEFAULT_82542_TIPG_IPGT;
-               tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
-               tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+               ipgr1 = DEFAULT_82542_TIPG_IPGR1;
+               ipgr2 = DEFAULT_82542_TIPG_IPGR2;
+               break;
+       case e1000_80003es2lan:
+               ipgr1 = DEFAULT_82543_TIPG_IPGR1;
+               ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2;
                break;
        default:
                break;
        default:
-               if (hw->media_type == e1000_media_type_fiber)
-                       tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
-               else
-                       tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
-               tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
-               tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+               ipgr1 = DEFAULT_82543_TIPG_IPGR1;
+               ipgr2 = DEFAULT_82543_TIPG_IPGR2;
+               break;
        }
        }
+       tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT;
+       tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT;
        E1000_WRITE_REG(hw, TIPG, tipg);
        E1000_WRITE_REG(hw, TIPG, tipg);
-#if 0
-       /* Set the Tx Interrupt Delay register */
-       E1000_WRITE_REG(hw, TIDV, adapter->tx_int_delay);
-       if (hw->mac_type >= e1000_82540)
-               E1000_WRITE_REG(hw, TADV, adapter->tx_abs_int_delay);
-#endif
        /* Program the Transmit Control Register */
        tctl = E1000_READ_REG(hw, TCTL);
        tctl &= ~E1000_TCTL_CT;
        tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
            (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
        /* Program the Transmit Control Register */
        tctl = E1000_READ_REG(hw, TCTL);
        tctl &= ~E1000_TCTL_CT;
        tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
            (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
-       E1000_WRITE_REG(hw, TCTL, tctl);
+
+       if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) {
+               tarc = E1000_READ_REG(hw, TARC0);
+               /* set the speed mode bit, we'll clear it if we're not at
+                * gigabit link later */
+               /* git bit can be set to 1*/
+       } else if (hw->mac_type == e1000_80003es2lan) {
+               tarc = E1000_READ_REG(hw, TARC0);
+               tarc |= 1;
+               E1000_WRITE_REG(hw, TARC0, tarc);
+               tarc = E1000_READ_REG(hw, TARC1);
+               tarc |= 1;
+               E1000_WRITE_REG(hw, TARC1, tarc);
+       }
+
 
        e1000_config_collision_dist(hw);
 
        e1000_config_collision_dist(hw);
-#if 0
-       /* Setup Transmit Descriptor Settings for this adapter */
-       adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
+       /* Setup Transmit Descriptor Settings for eop descriptor */
+       hw->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
 
 
-       if (adapter->hw.report_tx_early == 1)
-               adapter->txd_cmd |= E1000_TXD_CMD_RS;
+       /* Need to set up RS bit */
+       if (hw->mac_type < e1000_82543)
+               hw->txd_cmd |= E1000_TXD_CMD_RPS;
        else
        else
-               adapter->txd_cmd |= E1000_TXD_CMD_RPS;
-#endif
+               hw->txd_cmd |= E1000_TXD_CMD_RS;
+       E1000_WRITE_REG(hw, TCTL, tctl);
 }
 
 /**
 }
 
 /**
@@ -2764,8 +4916,9 @@ e1000_setup_rctl(struct e1000_hw *hw)
 
        rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
 
 
        rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
 
-       rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF;     /* |
-                                                                                                  (hw.mc_filter_type << E1000_RCTL_MO_SHIFT); */
+       rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO
+               | E1000_RCTL_RDMTS_HALF;        /* |
+                       (hw.mc_filter_type << E1000_RCTL_MO_SHIFT); */
 
        if (hw->tbi_compatibility_on == 1)
                rctl |= E1000_RCTL_SBP;
 
        if (hw->tbi_compatibility_on == 1)
                rctl |= E1000_RCTL_SBP;
@@ -2773,26 +4926,8 @@ e1000_setup_rctl(struct e1000_hw *hw)
                rctl &= ~E1000_RCTL_SBP;
 
        rctl &= ~(E1000_RCTL_SZ_4096);
                rctl &= ~E1000_RCTL_SBP;
 
        rctl &= ~(E1000_RCTL_SZ_4096);
-#if 0
-       switch (adapter->rx_buffer_len) {
-       case E1000_RXBUFFER_2048:
-       default:
-#endif
                rctl |= E1000_RCTL_SZ_2048;
                rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
                rctl |= E1000_RCTL_SZ_2048;
                rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
-#if 0
-               break;
-       case E1000_RXBUFFER_4096:
-               rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
-               break;
-       case E1000_RXBUFFER_8192:
-               rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
-               break;
-       case E1000_RXBUFFER_16384:
-               rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
-               break;
-       }
-#endif
        E1000_WRITE_REG(hw, RCTL, rctl);
 }
 
        E1000_WRITE_REG(hw, RCTL, rctl);
 }
 
@@ -2806,30 +4941,26 @@ static void
 e1000_configure_rx(struct e1000_hw *hw)
 {
        unsigned long ptr;
 e1000_configure_rx(struct e1000_hw *hw)
 {
        unsigned long ptr;
-       unsigned long rctl;
-#if 0
-       unsigned long rxcsum;
-#endif
+       unsigned long rctl, ctrl_ext;
        rx_tail = 0;
        /* make sure receives are disabled while setting up the descriptors */
        rctl = E1000_READ_REG(hw, RCTL);
        E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
        rx_tail = 0;
        /* make sure receives are disabled while setting up the descriptors */
        rctl = E1000_READ_REG(hw, RCTL);
        E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
-#if 0
-       /* set the Receive Delay Timer Register */
-
-       E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay);
-#endif
        if (hw->mac_type >= e1000_82540) {
        if (hw->mac_type >= e1000_82540) {
-#if 0
-               E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay);
-#endif
                /* Set the interrupt throttling rate.  Value is calculated
                 * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
                /* Set the interrupt throttling rate.  Value is calculated
                 * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
-#define MAX_INTS_PER_SEC        8000
-#define DEFAULT_ITR             1000000000/(MAX_INTS_PER_SEC * 256)
+#define MAX_INTS_PER_SEC       8000
+#define DEFAULT_ITR            1000000000/(MAX_INTS_PER_SEC * 256)
                E1000_WRITE_REG(hw, ITR, DEFAULT_ITR);
        }
 
                E1000_WRITE_REG(hw, ITR, DEFAULT_ITR);
        }
 
+       if (hw->mac_type >= e1000_82571) {
+               ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+               /* Reset delay timers after every interrupt */
+               ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR;
+               E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+               E1000_WRITE_FLUSH(hw);
+       }
        /* Setup the Base and Length of the Rx Descriptor Ring */
        ptr = (u32) rx_pool;
        if (ptr & 0xf)
        /* Setup the Base and Length of the Rx Descriptor Ring */
        ptr = (u32) rx_pool;
        if (ptr & 0xf)
@@ -2843,14 +4974,6 @@ e1000_configure_rx(struct e1000_hw *hw)
        /* Setup the HW Rx Head and Tail Descriptor Pointers */
        E1000_WRITE_REG(hw, RDH, 0);
        E1000_WRITE_REG(hw, RDT, 0);
        /* Setup the HW Rx Head and Tail Descriptor Pointers */
        E1000_WRITE_REG(hw, RDH, 0);
        E1000_WRITE_REG(hw, RDT, 0);
-#if 0
-       /* Enable 82543 Receive Checksum Offload for TCP and UDP */
-       if ((adapter->hw.mac_type >= e1000_82543) && (adapter->rx_csum == TRUE)) {
-               rxcsum = E1000_READ_REG(hw, RXCSUM);
-               rxcsum |= E1000_RXCSUM_TUOFL;
-               E1000_WRITE_REG(hw, RXCSUM, rxcsum);
-       }
-#endif
        /* Enable Receives */
 
        E1000_WRITE_REG(hw, RCTL, rctl);
        /* Enable Receives */
 
        E1000_WRITE_REG(hw, RCTL, rctl);
@@ -2878,9 +5001,9 @@ e1000_poll(struct eth_device *nic)
 /**************************************************************************
 TRANSMIT - Transmit a frame
 ***************************************************************************/
 /**************************************************************************
 TRANSMIT - Transmit a frame
 ***************************************************************************/
-static int
-e1000_transmit(struct eth_device *nic, volatile void *packet, int length)
+static int e1000_transmit(struct eth_device *nic, void *packet, int length)
 {
 {
+       void *nv_packet = (void *)packet;
        struct e1000_hw *hw = nic->priv;
        struct e1000_tx_desc *txp;
        int i = 0;
        struct e1000_hw *hw = nic->priv;
        struct e1000_tx_desc *txp;
        int i = 0;
@@ -2888,12 +5011,12 @@ e1000_transmit(struct eth_device *nic, volatile void *packet, int length)
        txp = tx_base + tx_tail;
        tx_tail = (tx_tail + 1) % 8;
 
        txp = tx_base + tx_tail;
        tx_tail = (tx_tail + 1) % 8;
 
-       txp->buffer_addr = cpu_to_le64(virt_to_bus(packet));
-       txp->lower.data = cpu_to_le32(E1000_TXD_CMD_RPS | E1000_TXD_CMD_EOP |
-                                     E1000_TXD_CMD_IFCS | length);
+       txp->buffer_addr = cpu_to_le64(virt_to_bus(hw->pdev, nv_packet));
+       txp->lower.data = cpu_to_le32(hw->txd_cmd | length);
        txp->upper.data = 0;
        E1000_WRITE_REG(hw, TDT, tx_tail);
 
        txp->upper.data = 0;
        E1000_WRITE_REG(hw, TDT, tx_tail);
 
+       E1000_WRITE_FLUSH(hw);
        while (!(le32_to_cpu(txp->upper.data) & E1000_TXD_STAT_DD)) {
                if (i++ > TOUT_LOOP) {
                        DEBUGOUT("e1000: tx timeout\n");
        while (!(le32_to_cpu(txp->upper.data) & E1000_TXD_STAT_DD)) {
                if (i++ > TOUT_LOOP) {
                        DEBUGOUT("e1000: tx timeout\n");
@@ -2958,9 +5081,9 @@ e1000_init(struct eth_device *nic, bd_t * bis)
        if (ret_val < 0) {
                if ((ret_val == -E1000_ERR_NOLINK) ||
                    (ret_val == -E1000_ERR_TIMEOUT)) {
        if (ret_val < 0) {
                if ((ret_val == -E1000_ERR_NOLINK) ||
                    (ret_val == -E1000_ERR_TIMEOUT)) {
-                       E1000_ERR("Valid Link not detected\n");
+                       E1000_ERR(hw->nic, "Valid Link not detected\n");
                } else {
                } else {
-                       E1000_ERR("Hardware Initialization Failed\n");
+                       E1000_ERR(hw->nic, "Hardware Initialization Failed\n");
                }
                return 0;
        }
                }
                return 0;
        }
@@ -2970,6 +5093,41 @@ e1000_init(struct eth_device *nic, bd_t * bis)
        return 1;
 }
 
        return 1;
 }
 
+/******************************************************************************
+ * Gets the current PCI bus type of hardware
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void e1000_get_bus_type(struct e1000_hw *hw)
+{
+       uint32_t status;
+
+       switch (hw->mac_type) {
+       case e1000_82542_rev2_0:
+       case e1000_82542_rev2_1:
+               hw->bus_type = e1000_bus_type_pci;
+               break;
+       case e1000_82571:
+       case e1000_82572:
+       case e1000_82573:
+       case e1000_82574:
+       case e1000_80003es2lan:
+               hw->bus_type = e1000_bus_type_pci_express;
+               break;
+       case e1000_ich8lan:
+               hw->bus_type = e1000_bus_type_pci_express;
+               break;
+       default:
+               status = E1000_READ_REG(hw, STATUS);
+               hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+                               e1000_bus_type_pcix : e1000_bus_type_pci;
+               break;
+       }
+}
+
+/* A list of all registered e1000 devices */
+static LIST_HEAD(e1000_hw_list);
+
 /**************************************************************************
 PROBE - Look for an adapter, this routine's visible to the outside
 You should omit the last argument struct pci_device * for a non-PCI NIC
 /**************************************************************************
 PROBE - Look for an adapter, this routine's visible to the outside
 You should omit the last argument struct pci_device * for a non-PCI NIC
@@ -2977,88 +5135,165 @@ You should omit the last argument struct pci_device * for a non-PCI NIC
 int
 e1000_initialize(bd_t * bis)
 {
 int
 e1000_initialize(bd_t * bis)
 {
+       unsigned int i;
        pci_dev_t devno;
        pci_dev_t devno;
-       int card_number = 0;
-       struct eth_device *nic = NULL;
-       struct e1000_hw *hw = NULL;
-       u32 iobase;
-       int idx = 0;
-       u32 PciCommandWord;
-
-       while (1) {             /* Find PCI device(s) */
-               if ((devno = pci_find_devices(supported, idx++)) < 0) {
-                       break;
-               }
 
 
-               pci_read_config_dword(devno, PCI_BASE_ADDRESS_0, &iobase);
-               iobase &= ~0xf; /* Mask the bits that say "this is an io addr" */
-               DEBUGOUT("e1000#%d: iobase 0x%08x\n", card_number, iobase);
+       DEBUGFUNC();
+
+       /* Find and probe all the matching PCI devices */
+       for (i = 0; (devno = pci_find_devices(e1000_supported, i)) >= 0; i++) {
+               u32 val;
 
 
-               pci_write_config_dword(devno, PCI_COMMAND,
-                                      PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-               /* Check if I/O accesses and Bus Mastering are enabled. */
-               pci_read_config_dword(devno, PCI_COMMAND, &PciCommandWord);
-               if (!(PciCommandWord & PCI_COMMAND_MEMORY)) {
-                       printf("Error: Can not enable MEM access.\n");
-                       continue;
-               } else if (!(PciCommandWord & PCI_COMMAND_MASTER)) {
-                       printf("Error: Can not enable Bus Mastering.\n");
+               /*
+                * These will never get freed due to errors, this allows us to
+                * perform SPI EEPROM programming from U-boot, for example.
+                */
+               struct eth_device *nic = malloc(sizeof(*nic));
+               struct e1000_hw *hw = malloc(sizeof(*hw));
+               if (!nic || !hw) {
+                       printf("e1000#%u: Out of Memory!\n", i);
+                       free(nic);
+                       free(hw);
                        continue;
                }
 
                        continue;
                }
 
-               nic = (struct eth_device *) malloc(sizeof (*nic));
-               hw = (struct e1000_hw *) malloc(sizeof (*hw));
+               /* Make sure all of the fields are initially zeroed */
+               memset(nic, 0, sizeof(*nic));
+               memset(hw, 0, sizeof(*hw));
+
+               /* Assign the passed-in values */
+               hw->cardnum = i;
                hw->pdev = devno;
                hw->pdev = devno;
+               hw->nic = nic;
                nic->priv = hw;
                nic->priv = hw;
-               nic->iobase = bus_to_phys(devno, iobase);
 
 
-               sprintf(nic->name, "e1000#%d", card_number);
+               /* Generate a card name */
+               sprintf(nic->name, "e1000#%u", hw->cardnum);
+
+               /* Print a debug message with the IO base address */
+               pci_read_config_dword(devno, PCI_BASE_ADDRESS_0, &val);
+               E1000_DBG(nic, "iobase 0x%08x\n", val & 0xfffffff0);
+
+               /* Try to enable I/O accesses and bus-mastering */
+               val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+               pci_write_config_dword(devno, PCI_COMMAND, val);
+
+               /* Make sure it worked */
+               pci_read_config_dword(devno, PCI_COMMAND, &val);
+               if (!(val & PCI_COMMAND_MEMORY)) {
+                       E1000_ERR(nic, "Can't enable I/O memory\n");
+                       continue;
+               }
+               if (!(val & PCI_COMMAND_MASTER)) {
+                       E1000_ERR(nic, "Can't enable bus-mastering\n");
+                       continue;
+               }
 
                /* Are these variables needed? */
 
                /* Are these variables needed? */
-#if 0
-               hw->fc = e1000_fc_none;
-               hw->original_fc = e1000_fc_none;
-#else
                hw->fc = e1000_fc_default;
                hw->original_fc = e1000_fc_default;
                hw->fc = e1000_fc_default;
                hw->original_fc = e1000_fc_default;
-#endif
                hw->autoneg_failed = 0;
                hw->autoneg_failed = 0;
+               hw->autoneg = 1;
                hw->get_link_status = TRUE;
                hw->get_link_status = TRUE;
-               hw->hw_addr = (typeof(hw->hw_addr)) iobase;
+               hw->hw_addr = pci_map_bar(devno,        PCI_BASE_ADDRESS_0,
+                                                       PCI_REGION_MEM);
                hw->mac_type = e1000_undefined;
 
                /* MAC and Phy settings */
                hw->mac_type = e1000_undefined;
 
                /* MAC and Phy settings */
-               if (e1000_sw_init(nic, card_number) < 0) {
-                       free(hw);
-                       free(nic);
-                       return 0;
+               if (e1000_sw_init(nic) < 0) {
+                       E1000_ERR(nic, "Software init failed\n");
+                       continue;
                }
                }
-#if !(defined(CONFIG_AP1000) || defined(CONFIG_MVBC_1G))
-               if (e1000_validate_eeprom_checksum(nic) < 0) {
-                       printf("The EEPROM Checksum Is Not Valid\n");
-                       free(hw);
-                       free(nic);
-                       return 0;
+               if (e1000_check_phy_reset_block(hw))
+                       E1000_ERR(nic, "PHY Reset is blocked!\n");
+
+               /* Basic init was OK, reset the hardware and allow SPI access */
+               e1000_reset_hw(hw);
+               list_add_tail(&hw->list_node, &e1000_hw_list);
+
+               /* Validate the EEPROM and get chipset information */
+#if !defined(CONFIG_MVBC_1G)
+               if (e1000_init_eeprom_params(hw)) {
+                       E1000_ERR(nic, "EEPROM is invalid!\n");
+                       continue;
                }
                }
+               if (e1000_validate_eeprom_checksum(hw))
+                       continue;
 #endif
                e1000_read_mac_addr(nic);
 #endif
                e1000_read_mac_addr(nic);
+               e1000_get_bus_type(hw);
 
 
-               E1000_WRITE_REG(hw, PBA, E1000_DEFAULT_PBA);
-
-               printf("e1000: %02x:%02x:%02x:%02x:%02x:%02x\n",
+               printf("e1000: %02x:%02x:%02x:%02x:%02x:%02x\n       ",
                       nic->enetaddr[0], nic->enetaddr[1], nic->enetaddr[2],
                       nic->enetaddr[3], nic->enetaddr[4], nic->enetaddr[5]);
 
                       nic->enetaddr[0], nic->enetaddr[1], nic->enetaddr[2],
                       nic->enetaddr[3], nic->enetaddr[4], nic->enetaddr[5]);
 
+               /* Set up the function pointers and register the device */
                nic->init = e1000_init;
                nic->recv = e1000_poll;
                nic->send = e1000_transmit;
                nic->halt = e1000_disable;
                nic->init = e1000_init;
                nic->recv = e1000_poll;
                nic->send = e1000_transmit;
                nic->halt = e1000_disable;
-
                eth_register(nic);
                eth_register(nic);
+       }
+
+       return i;
+}
+
+struct e1000_hw *e1000_find_card(unsigned int cardnum)
+{
+       struct e1000_hw *hw;
+
+       list_for_each_entry(hw, &e1000_hw_list, list_node)
+               if (hw->cardnum == cardnum)
+                       return hw;
+
+       return NULL;
+}
+
+#ifdef CONFIG_CMD_E1000
+static int do_e1000(cmd_tbl_t *cmdtp, int flag,
+               int argc, char * const argv[])
+{
+       struct e1000_hw *hw;
 
 
-               card_number++;
+       if (argc < 3) {
+               cmd_usage(cmdtp);
+               return 1;
        }
        }
+
+       /* Make sure we can find the requested e1000 card */
+       hw = e1000_find_card(simple_strtoul(argv[1], NULL, 10));
+       if (!hw) {
+               printf("e1000: ERROR: No such device: e1000#%s\n", argv[1]);
+               return 1;
+       }
+
+       if (!strcmp(argv[2], "print-mac-address")) {
+               unsigned char *mac = hw->nic->enetaddr;
+               printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+               return 0;
+       }
+
+#ifdef CONFIG_E1000_SPI
+       /* Handle the "SPI" subcommand */
+       if (!strcmp(argv[2], "spi"))
+               return do_e1000_spi(cmdtp, hw, argc - 3, argv + 3);
+#endif
+
+       cmd_usage(cmdtp);
        return 1;
 }
 
        return 1;
 }
 
+U_BOOT_CMD(
+       e1000, 7, 0, do_e1000,
+       "Intel e1000 controller management",
+       /*  */"<card#> print-mac-address\n"
+#ifdef CONFIG_E1000_SPI
+       "e1000 <card#> spi show [<offset> [<length>]]\n"
+       "e1000 <card#> spi dump <addr> <offset> <length>\n"
+       "e1000 <card#> spi program <addr> <offset> <length>\n"
+       "e1000 <card#> spi checksum [update]\n"
 #endif
 #endif
+       "       - Manage the Intel E1000 PCI device"
+);
+#endif /* not CONFIG_CMD_E1000 */