patch-2.4.23 linux-2.4.23/drivers/net/e1000/e1000_hw.c

Next file: linux-2.4.23/drivers/net/e1000/e1000_hw.h
Previous file: linux-2.4.23/drivers/net/e1000/e1000_ethtool.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/net/e1000/e1000_hw.c linux-2.4.23/drivers/net/e1000/e1000_hw.c
@@ -34,14 +34,15 @@
 
 static int32_t e1000_set_phy_type(struct e1000_hw *hw);
 static void e1000_phy_init_script(struct e1000_hw *hw);
-static int32_t e1000_setup_fiber_link(struct e1000_hw *hw);
 static int32_t e1000_setup_copper_link(struct e1000_hw *hw);
+static int32_t e1000_setup_fiber_serdes_link(struct e1000_hw *hw);
+static int32_t e1000_adjust_serdes_amplitude(struct e1000_hw *hw);
 static int32_t e1000_phy_force_speed_duplex(struct e1000_hw *hw);
 static int32_t e1000_config_mac_to_phy(struct e1000_hw *hw);
-static int32_t e1000_force_mac_fc(struct e1000_hw *hw);
 static void e1000_raise_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
 static void e1000_lower_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
-static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count);
+static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data,
+                                     uint16_t count);
 static uint16_t e1000_shift_in_mdi_bits(struct e1000_hw *hw);
 static int32_t e1000_phy_reset_dsp(struct e1000_hw *hw);
 static int32_t e1000_write_eeprom_spi(struct e1000_hw *hw, uint16_t offset,
@@ -52,13 +53,30 @@
 static int32_t e1000_spi_eeprom_ready(struct e1000_hw *hw);
 static void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
 static void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
-static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count);
+static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data,
+                                    uint16_t count);
+static int32_t e1000_write_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr,
+                                      uint16_t phy_data);
+static int32_t e1000_read_phy_reg_ex(struct e1000_hw *hw,uint32_t reg_addr,
+                                     uint16_t *phy_data);
 static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count);
 static int32_t e1000_acquire_eeprom(struct e1000_hw *hw);
 static void e1000_release_eeprom(struct e1000_hw *hw);
 static void e1000_standby_eeprom(struct e1000_hw *hw);
 static int32_t e1000_id_led_init(struct e1000_hw * hw);
+static int32_t e1000_set_vco_speed(struct e1000_hw *hw);
 
+/* IGP cable length table */
+static const
+uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
+    { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
+      25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
+      90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+      100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+      110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
 
 
 /******************************************************************************
@@ -100,50 +118,41 @@
     DEBUGFUNC("e1000_phy_init_script");
 
     if(hw->phy_init_script) {
-        msec_delay(10);
+        msec_delay(20);
 
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000);
         e1000_write_phy_reg(hw,0x0000,0x0140);
 
         msec_delay(5);
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F95);
-        e1000_write_phy_reg(hw,0x0015,0x0001);
 
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F71);
-        e1000_write_phy_reg(hw,0x0011,0xBD21);
+        if(hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547) {
+            e1000_write_phy_reg(hw, 0x1F95, 0x0001);
+
+            e1000_write_phy_reg(hw, 0x1F71, 0xBD21);
 
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F79);
-        e1000_write_phy_reg(hw,0x0019,0x0018);
+            e1000_write_phy_reg(hw, 0x1F79, 0x0018);
 
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F30);
-        e1000_write_phy_reg(hw,0x0010,0x1600);
+            e1000_write_phy_reg(hw, 0x1F30, 0x1600);
 
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F31);
-        e1000_write_phy_reg(hw,0x0011,0x0014);
+            e1000_write_phy_reg(hw, 0x1F31, 0x0014);
 
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F32);
-        e1000_write_phy_reg(hw,0x0012,0x161C);
+            e1000_write_phy_reg(hw, 0x1F32, 0x161C);
 
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F94);
-        e1000_write_phy_reg(hw,0x0014,0x0003);
+            e1000_write_phy_reg(hw, 0x1F94, 0x0003);
 
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F96);
-        e1000_write_phy_reg(hw,0x0016,0x003F);
+            e1000_write_phy_reg(hw, 0x1F96, 0x003F);
 
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x2010);
-        e1000_write_phy_reg(hw,0x0010,0x0008);
+            e1000_write_phy_reg(hw, 0x2010, 0x0008);
+        } else {
+            e1000_write_phy_reg(hw, 0x1F73, 0x0099);
+        }
 
-        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000);
-        e1000_write_phy_reg(hw,0x0000,0x3300);
+        e1000_write_phy_reg(hw, 0x0000, 0x3300);
 
 
         if(hw->mac_type == e1000_82547) {
             uint16_t fused, fine, coarse;
 
             /* Move to analog registers page */
-            e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 
-                                IGP01E1000_ANALOG_REGS_PAGE);
-
             e1000_read_phy_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused);
 
             if(!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
@@ -158,17 +167,14 @@
                 } 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) | 
+                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, 
+                e1000_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_BYPASS,
                                     IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
             }
-            /* Return to first page of registers */
-            e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
-                                IGP01E1000_IEEE_REGS_PAGE);
         }
     }
 }
@@ -218,32 +224,89 @@
     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_QUAD_COPPER:
         hw->mac_type = e1000_82546;
         break;
+    case E1000_DEV_ID_82546GB_COPPER:
+    case E1000_DEV_ID_82546GB_FIBER:
+    case E1000_DEV_ID_82546GB_SERDES:
+        hw->mac_type = e1000_82546_rev_3;
+        break;
     case E1000_DEV_ID_82541EI:
-    case E1000_DEV_ID_82541EP:
+    case E1000_DEV_ID_82541EI_MOBILE:
         hw->mac_type = e1000_82541;
         break;
+    case E1000_DEV_ID_82541ER:
+    case E1000_DEV_ID_82541GI:
+    case E1000_DEV_ID_82541GI_MOBILE:
+        hw->mac_type = e1000_82541_rev_2;
+        break;
     case E1000_DEV_ID_82547EI:
         hw->mac_type = e1000_82547;
         break;
+    case E1000_DEV_ID_82547GI:
+        hw->mac_type = e1000_82547_rev_2;
+        break;
     default:
         /* Should never have loaded on this device */
         return -E1000_ERR_MAC_TYPE;
     }
 
-
     return E1000_SUCCESS;
 }
+
+/*****************************************************************************
+ * 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("e1000_set_media_type");
+
+    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:
+        hw->media_type = e1000_media_type_internal_serdes;
+        break;
+    default:
+        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;
+        }
+    }
+}
+
 /******************************************************************************
  * Reset the transmit and receive units; mask and clear all interrupts.
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
-void
+int32_t
 e1000_reset_hw(struct e1000_hw *hw)
 {
     uint32_t ctrl;
@@ -280,49 +343,75 @@
      */
     msec_delay(10);
 
-    /* Issue a global reset to the MAC.  This will reset the chip's
-     * transmit, receive, DMA, and link units.  It will not effect
-     * the current PCI configuration.  The global reset bit is self-
-     * clearing, and should clear within a microsecond.
-     */
-    DEBUGOUT("Issuing a global reset to MAC\n");
     ctrl = E1000_READ_REG(hw, CTRL);
 
     /* Must reset the PHY before resetting the MAC */
     if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
         E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
-	msec_delay(5);
+        msec_delay(5);
     }
 
+    /* Issue a global reset to the MAC.  This will reset the chip's
+     * transmit, receive, DMA, and link units.  It will not effect
+     * the current PCI configuration.  The global reset bit is self-
+     * clearing, and should clear within a microsecond.
+     */
+    DEBUGOUT("Issuing a global reset to MAC\n");
+
     switch(hw->mac_type) {
         case e1000_82544:
         case e1000_82540:
         case e1000_82545:
         case e1000_82546:
         case e1000_82541:
+        case e1000_82541_rev_2:
             /* These controllers can't ack the 64-bit write when issuing the
              * reset, so use IO-mapping as a workaround to issue the reset */
             E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
             break;
+        case e1000_82545_rev_3:
+        case e1000_82546_rev_3:
+            /* Reset is performed on a shadow of the control register */
+            E1000_WRITE_REG(hw, CTRL_DUP, (ctrl | E1000_CTRL_RST));
+            break;
         default:
             E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
             break;
     }
 
-    /* Force a reload from the EEPROM if necessary */
-    if(hw->mac_type < e1000_82540) {
-        /* Wait for reset to complete */
-        udelay(10);
-        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
-        ctrl_ext |= E1000_CTRL_EXT_EE_RST;
-        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
-        E1000_WRITE_FLUSH(hw);
-        /* Wait for EEPROM reload */
-        msec_delay(2);
-    } else {
-        /* Wait for EEPROM reload (it happens automatically) */
-        msec_delay(5);
-        /* Dissable HW ARPs on ASF enabled adapters */
+    /* After MAC reset, force reload of EEPROM to restore power-on settings to
+     * device.  Later controllers reload the EEPROM automatically, so just wait
+     * for reload to complete.
+     */
+    switch(hw->mac_type) {
+        case e1000_82542_rev2_0:
+        case e1000_82542_rev2_1:
+        case e1000_82543:
+        case e1000_82544:
+            /* Wait for reset to complete */
+            udelay(10);
+            ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+            ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+            E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+            E1000_WRITE_FLUSH(hw);
+            /* Wait for EEPROM reload */
+            msec_delay(2);
+            break;
+        case e1000_82541:
+        case e1000_82541_rev_2:
+        case e1000_82547:
+        case e1000_82547_rev_2:
+            /* Wait for EEPROM reload */
+            msec_delay(20);
+            break;
+        default:
+            /* Wait for EEPROM reload (it happens automatically) */
+            msec_delay(5);
+            break;
+    }
+
+    /* Disable HW ARPs on ASF enabled adapters */
+    if(hw->mac_type >= e1000_82540) {
         manc = E1000_READ_REG(hw, MANC);
         manc &= ~(E1000_MANC_ARP_EN);
         E1000_WRITE_REG(hw, MANC, manc);
@@ -350,6 +439,8 @@
         if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
             e1000_pci_set_mwi(hw);
     }
+
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -366,7 +457,7 @@
 int32_t
 e1000_init_hw(struct e1000_hw *hw)
 {
-    uint32_t ctrl, status;
+    uint32_t ctrl;
     uint32_t i;
     int32_t ret_val;
     uint16_t pcix_cmd_word;
@@ -377,31 +468,13 @@
     DEBUGFUNC("e1000_init_hw");
 
     /* Initialize Identification LED */
-    ret_val = e1000_id_led_init(hw);
-    if(ret_val < 0) {
+    if((ret_val = e1000_id_led_init(hw))) {
         DEBUGOUT("Error Initializing Identification LED\n");
         return ret_val;
     }
 
-    /* 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;
-    }
-
-    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);
 
     /* Disabling VLAN filtering. */
     DEBUGOUT("Initializing the IEEE VLAN\n");
@@ -446,21 +519,30 @@
         E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
     }
 
-    /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
-    if(hw->bus_type == e1000_bus_type_pcix) {
-        e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
-        e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word);
-        cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
-            PCIX_COMMAND_MMRBC_SHIFT;
-        stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
-            PCIX_STATUS_HI_MMRBC_SHIFT;
-        if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
-            stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
-        if(cmd_mmrbc > stat_mmrbc) {
-            pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
-            pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
-            e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+    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. */
+        if(hw->bus_type == e1000_bus_type_pcix) {
+            e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+            e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI,
+                &pcix_stat_hi_word);
+            cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
+                PCIX_COMMAND_MMRBC_SHIFT;
+            stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+                PCIX_STATUS_HI_MMRBC_SHIFT;
+            if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+                stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+            if(cmd_mmrbc > stat_mmrbc) {
+                pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
+                pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+                e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER,
+                    &pcix_cmd_word);
+            }
         }
+        break;
     }
 
     /* Call a subroutine to configure the link and setup flow control. */
@@ -484,6 +566,46 @@
 }
 
 /******************************************************************************
+ * Adjust SERDES output amplitude based on EEPROM setting.
+ *
+ * hw - Struct containing variables accessed by shared code.
+ *****************************************************************************/
+static int32_t
+e1000_adjust_serdes_amplitude(struct e1000_hw *hw)
+{
+    uint16_t eeprom_data;
+    int32_t  ret_val;
+
+    DEBUGFUNC("e1000_adjust_serdes_amplitude");
+
+    if(hw->media_type != e1000_media_type_internal_serdes)
+        return E1000_SUCCESS;
+
+    switch(hw->mac_type) {
+    case e1000_82545_rev_3:
+    case e1000_82546_rev_3:
+        break;
+    default:
+        return E1000_SUCCESS;
+    }
+
+    if ((ret_val = e1000_read_eeprom(hw, EEPROM_SERDES_AMPLITUDE, 1,
+                                     &eeprom_data))) {
+        return ret_val;
+    }
+
+    if(eeprom_data != EEPROM_RESERVED_WORD) {
+        /* Adjust SERDES output amplitude only. */
+        eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK; 
+        if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL,
+                                          eeprom_data)))
+            return ret_val;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
  * Configures flow control and link settings.
  *
  * hw - Struct containing variables accessed by shared code
@@ -554,9 +676,9 @@
     }
 
     /* Call the necessary subroutine to configure the link. */
-    ret_val = (hw->media_type == e1000_media_type_fiber) ?
-              e1000_setup_fiber_link(hw) :
-              e1000_setup_copper_link(hw);
+    ret_val = (hw->media_type == e1000_media_type_copper) ?
+              e1000_setup_copper_link(hw) :
+              e1000_setup_fiber_serdes_link(hw);
 
     /* Initialize the flow control address, type, and PAUSE timer
      * registers to their default values.  This is done even if flow
@@ -595,7 +717,7 @@
 }
 
 /******************************************************************************
- * Sets up link for a fiber based adapter
+ * Sets up link for a fiber based or serdes based adapter
  *
  * hw - Struct containing variables accessed by shared code
  *
@@ -604,28 +726,37 @@
  * and receiver are not enabled.
  *****************************************************************************/
 static int32_t
-e1000_setup_fiber_link(struct e1000_hw *hw)
+e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
 {
     uint32_t ctrl;
     uint32_t status;
     uint32_t txcw = 0;
     uint32_t i;
-    uint32_t signal;
+    uint32_t signal = 0;
     int32_t ret_val;
 
-    DEBUGFUNC("e1000_setup_fiber_link");
+    DEBUGFUNC("e1000_setup_fiber_serdes_link");
 
-    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+    /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
      * set when the optics detect a signal. On older adapters, it will be
-     * cleared when there is a signal
+     * cleared when there is a signal.  This applies to fiber media only.
+     * If we're on serdes media, adjust the output amplitude to value set in
+     * the EEPROM.
      */
     ctrl = E1000_READ_REG(hw, CTRL);
-    if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
-    else signal = 0;
+    if(hw->media_type == e1000_media_type_fiber)
+        signal = (hw->mac_type > e1000_82544) ? E1000_CTRL_SWDPIN1 : 0;
+
+    if((ret_val = e1000_adjust_serdes_amplitude(hw)))
+        return ret_val;
 
     /* Take the link out of reset */
     ctrl &= ~(E1000_CTRL_LRST);
 
+    /* Adjust VCO speed to improve BER performance */
+    if((ret_val = e1000_set_vco_speed(hw)))
+        return ret_val;
+
     e1000_config_collision_dist(hw);
 
     /* Check for a software override of the flow control settings, and setup
@@ -692,8 +823,10 @@
      * indication in the Device Status Register.  Time-out if a link isn't
      * seen in 500 milliseconds seconds (Auto-negotiation should complete in
      * less than 500 milliseconds even if the other end is doing it in SW).
+     * For internal serdes, we just assume a signal is present, then poll.
      */
-    if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+    if(hw->media_type == e1000_media_type_internal_serdes ||
+       (E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
         DEBUGOUT("Looking for Link\n");
         for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
             msec_delay(10);
@@ -701,15 +834,14 @@
             if(status & E1000_STATUS_LU) break;
         }
         if(i == (LINK_UP_TIMEOUT / 10)) {
+            DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+            hw->autoneg_failed = 1;
             /* AutoNeg failed to achieve a link, so we'll call
-             * e1000_check_for_link. This routine will force the link up if we
-             * detect a signal. This will allow us to communicate with
+             * e1000_check_for_link. This routine will force the link up if
+             * we detect a signal. This will allow us to communicate with
              * non-autonegotiating link partners.
              */
-            DEBUGOUT("Never got a valid link from auto-neg!!!\n");
-            hw->autoneg_failed = 1;
-            ret_val = e1000_check_for_link(hw);
-            if(ret_val < 0) {
+            if((ret_val = e1000_check_for_link(hw))) {
                 DEBUGOUT("Error while checking for link\n");
                 return ret_val;
             }
@@ -721,7 +853,7 @@
     } else {
         DEBUGOUT("No Signal Detected\n");
     }
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -756,233 +888,281 @@
     }
 
     /* Make sure we have a valid PHY */
-    ret_val = e1000_detect_gig_phy(hw);
-    if(ret_val < 0) {
+    if((ret_val = e1000_detect_gig_phy(hw))) {
         DEBUGOUT("Error, did not detect valid phy.\n");
         return ret_val;
     }
     DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
 
-    if (hw->phy_type == e1000_phy_igp) {
-
-        ret_val = e1000_phy_reset(hw);
-        if(ret_val < 0) {
-            DEBUGOUT("Error Resetting the PHY\n");
-            return ret_val;
-        }
+    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;
 
-        /* Wait 10ms for MAC to configure PHY from eeprom settings */
-        msec_delay(15);
+    if(!hw->phy_reset_disable) {
+        if (hw->phy_type == e1000_phy_igp) {
 
-        if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) {
-            DEBUGOUT("PHY Write Error\n");
-            return -E1000_ERR_PHY;
-        }
+            if((ret_val = e1000_phy_reset(hw))) {
+                DEBUGOUT("Error Resetting the PHY\n");
+                return ret_val;
+            }
 
-        /* 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 10ms for MAC to configure PHY from eeprom settings */
+            msec_delay(15);
 
-        if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
-            /* Disable SmartSpeed */
-            if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                  &phy_data) < 0) {
-                DEBUGOUT("PHY Read Error\n");
-                return -E1000_ERR_PHY;
-            }
-            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-            if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                   phy_data) < 0) {
-                DEBUGOUT("PHY Write Error\n");
-                return -E1000_ERR_PHY;
-            }
-            /* Set auto Master/Slave resolution process */
-            if(e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data) < 0) {
-                DEBUGOUT("PHY Read Error\n");
-                return -E1000_ERR_PHY;
+            /* 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);
+
+            /* disable lplu d3 during driver init */
+            if((ret_val = e1000_set_d3_lplu_state(hw, FALSE))) {
+                DEBUGOUT("Error Disabling LPLU D3\n");
+                return ret_val;
             }
-            phy_data &= ~CR_1000T_MS_ENABLE;
-            if(e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data) < 0) {
-                DEBUGOUT("PHY Write Error\n");
-                return -E1000_ERR_PHY;
+
+            /* Configure mdi-mdix settings */
+            if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
+                                             &phy_data)))
+                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 IGP B-0 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;
+                }
             }
-        }
+            if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
+                                              phy_data)))
+                return ret_val;
 
-        if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) {
-            DEBUGOUT("PHY Read Error\n");
-            return -E1000_ERR_PHY;
-        }
+            /* 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 */
+                    if((ret_val = e1000_read_phy_reg(hw,
+                                                    IGP01E1000_PHY_PORT_CONFIG,
+                                                    &phy_data)))
+                        return ret_val;
+                    phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+                    if((ret_val = e1000_write_phy_reg(hw,
+                                                     IGP01E1000_PHY_PORT_CONFIG,
+                                                     phy_data)))
+                        return ret_val;
+                    /* Set auto Master/Slave resolution process */
+                    if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
+                                                     &phy_data)))
+                        return ret_val;
+                    phy_data &= ~CR_1000T_MS_ENABLE;
+                    if((ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
+                                                      phy_data)))
+                        return ret_val;
+                }
 
-        /* Force MDI for IGP PHY */
-        phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX |
-                      IGP01E1000_PSCR_FORCE_MDI_MDIX);
+                if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
+                                                 &phy_data)))
+                    return ret_val;
 
-        hw->mdix = 1;
+                /* 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;
+                }
+                if((ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
+                                                  phy_data)))
+                    return ret_val;
+            }
+        } else {
+            /* Enable CRS on TX. This must be set for half-duplex operation. */
+            if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                             &phy_data)))
+                return ret_val;
 
-        if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) {
-            DEBUGOUT("PHY Write Error\n");
-            return -E1000_ERR_PHY;
-        }
+            phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
 
-    } else {
-        /* 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;
-        }
-        phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+            /* 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)
+             */
+            phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
 
-        /* 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)
-         */
-        phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+            switch (hw->mdix) {
+            case 1:
+                phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+                break;
+            case 2:
+                phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+                break;
+            case 3:
+                phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+                break;
+            case 0:
+            default:
+                phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+                break;
+            }
 
-        switch (hw->mdix) {
-        case 1:
-            phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
-            break;
-        case 2:
-            phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
-            break;
-        case 3:
-            phy_data |= M88E1000_PSCR_AUTO_X_1000T;
-            break;
-        case 0:
-        default:
-            phy_data |= M88E1000_PSCR_AUTO_X_MODE;
-            break;
-        }
+            /* Options:
+             *   disable_polarity_correction = 0 (default)
+             *       Automatic Correction for Reversed Cable Polarity
+             *   0 - Disabled
+             *   1 - Enabled
+             */
+            phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+            if(hw->disable_polarity_correction == 1)
+                phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+            if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                              phy_data)))
+                return ret_val;
 
-        /* Options:
-         *   disable_polarity_correction = 0 (default)
-         *       Automatic Correction for Reversed Cable Polarity
-         *   0 - Disabled
-         *   1 - Enabled
-         */
-        phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-        if(hw->disable_polarity_correction == 1)
-            phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-        if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
-            DEBUGOUT("PHY Write Error\n");
-            return -E1000_ERR_PHY;
-        }
+            /* Force TX_CLK in the Extended PHY Specific Control Register
+             * to 25MHz clock.
+             */
+            if((ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                             &phy_data)))
+                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;
+            phy_data |= M88E1000_EPSCR_TX_CLK_25;
 
-        if (hw->phy_revision < M88E1011_I_REV_4) {
-            /* 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) {
+                /* 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((ret_val = e1000_write_phy_reg(hw,
+                                                  M88E1000_EXT_PHY_SPEC_CTRL,
+                                                  phy_data)))
+                    return ret_val;
             }
-        }
 
-        /* SW Reset the PHY so all changes take effect */
-        ret_val = e1000_phy_reset(hw);
-        if(ret_val < 0) {
-            DEBUGOUT("Error Resetting the PHY\n");
-            return ret_val;
+            /* SW Reset the PHY so all changes take effect */
+            if((ret_val = e1000_phy_reset(hw))) {
+                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.
-     */
+        /* 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.
+         */
+
+        /* 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.
+         */
+        if(hw->autoneg) {
+            /* 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;
 
-    /* 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.
-     */
-    if(hw->autoneg) {
-        /* 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;
+            DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+            if((ret_val = e1000_phy_setup_autoneg(hw))) {
+                DEBUGOUT("Error Setting up Auto-Negotiation\n");
+                return ret_val;
+            }
+            DEBUGOUT("Restarting Auto-Neg\n");
 
-        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;
-        }
-        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((ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data)))
+                return ret_val;
 
-        /* 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;
-        }
+            phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+            if((ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data)))
+                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(hw->wait_autoneg_complete) {
-            ret_val = e1000_wait_autoneg(hw);
-            if(ret_val < 0) {
-                DEBUGOUT("Error while waiting for autoneg to complete\n");
+            /* 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) {
+                if((ret_val = e1000_wait_autoneg(hw))) {
+                    DEBUGOUT("Error while waiting for autoneg to complete\n");
+                    return ret_val;
+                }
+            }
+            hw->get_link_status = TRUE;
+        } else {
+            DEBUGOUT("Forcing speed and duplex\n");
+            if((ret_val = e1000_phy_force_speed_duplex(hw))) {
+                DEBUGOUT("Error Forcing Speed and Duplex\n");
                 return ret_val;
             }
         }
-        hw->get_link_status = TRUE;
-    } else {
-        DEBUGOUT("Forcing speed and duplex\n");
-        ret_val = e1000_phy_force_speed_duplex(hw);
-        if(ret_val < 0) {
-            DEBUGOUT("Error Forcing Speed and Duplex\n");
-            return ret_val;
-        }
-    }
+    } /* !hw->phy_reset_disable */
 
     /* 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;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+            return ret_val;
+        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+            return ret_val;
+
         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
@@ -995,25 +1175,31 @@
             if(hw->mac_type >= e1000_82544) {
                 e1000_config_collision_dist(hw);
             } else {
-                ret_val = e1000_config_mac_to_phy(hw);
-                if(ret_val < 0) {
+                if((ret_val = e1000_config_mac_to_phy(hw))) {
                     DEBUGOUT("Error configuring MAC to PHY settings\n");
                     return ret_val;
-                  }
+                }
             }
-            ret_val = e1000_config_fc_after_link_up(hw);
-            if(ret_val < 0) {
+            if((ret_val = e1000_config_fc_after_link_up(hw))) {
                 DEBUGOUT("Error Configuring Flow Control\n");
                 return ret_val;
             }
             DEBUGOUT("Valid link established!!!\n");
-            return 0;
+
+            if(hw->phy_type == e1000_phy_igp) {
+                if((ret_val = e1000_config_dsp_after_link_change(hw, TRUE))) {
+                    DEBUGOUT("Error Configuring DSP after link up\n");
+                    return ret_val;
+                }
+            }
+            DEBUGOUT("Valid link established!!!\n");
+            return E1000_SUCCESS;
         }
         udelay(10);
     }
 
     DEBUGOUT("Unable to establish link!!!\n");
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -1024,22 +1210,20 @@
 int32_t
 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("e1000_phy_setup_autoneg");
 
     /* 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;
-    }
+    if((ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV,
+                                     &mii_autoneg_adv_reg)))
+        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((ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg)))
+        return ret_val;
 
     /* Need to parse both autoneg_advertised and fc and set up
      * the appropriate PHY registers.  First we will parse for
@@ -1145,18 +1329,16 @@
         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;
-    }
+    if((ret_val = e1000_write_phy_reg(hw, PHY_AUTONEG_ADV,
+                                      mii_autoneg_adv_reg)))
+        return ret_val;
 
     DEBUGOUT1("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;
-    }
-    return 0;
+    if((ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg)))
+        return ret_val;
+
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -1192,10 +1374,8 @@
     ctrl &= ~E1000_CTRL_ASDE;
 
     /* Read the MII Control Register. */
-    if(e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
+    if((ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg)))
+        return ret_val;
 
     /* We need to disable autoneg in order to force link and duplex. */
 
@@ -1241,19 +1421,18 @@
     E1000_WRITE_REG(hw, CTRL, ctrl);
 
     if (hw->phy_type == e1000_phy_m88) {
-        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
-            DEBUGOUT("PHY Read Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                         &phy_data)))
+            return ret_val;
 
         /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
          * forced whenever speed are duplex are forced.
          */
         phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-        if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
-            DEBUGOUT("PHY Write Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                          phy_data)))
+            return ret_val;
+
         DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
 
         /* Need to reset the PHY or these changes will be ignored */
@@ -1262,25 +1441,22 @@
         /* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
          * forced whenever speed or duplex are forced.
          */
-        if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) {
-            DEBUGOUT("PHY Read Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
+                                         &phy_data)))
+            return ret_val;
 
         phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
         phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
 
-        if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) {
-            DEBUGOUT("PHY Write Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
+                                          phy_data)))
+            return ret_val;
     }
 
     /* Write back the modified PHY MII control register. */
-    if(e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
-    }
+    if((ret_val = e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg)))
+        return ret_val;
+
     udelay(1);
 
     /* The wait_autoneg_complete flag may be a little misleading here.
@@ -1300,22 +1476,18 @@
             /* Read the MII Status Register and wait for Auto-Neg Complete bit
              * to be set.
              */
-            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
-                DEBUGOUT("PHY Read Error\n");
-                return -E1000_ERR_PHY;
-            }
-            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
-                DEBUGOUT("PHY Read Error\n");
-                return -E1000_ERR_PHY;
-            }
+            if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+                return ret_val;
+
+            if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+                return ret_val;
+
             if(mii_status_reg & MII_SR_LINK_STATUS) break;
             msec_delay(100);
         }
         if(i == 0) { /* We didn't get link */
             /* Reset the DSP and wait again for link. */
-
-            ret_val = e1000_phy_reset_dsp(hw);
-            if(ret_val < 0) {
+            if((ret_val = e1000_phy_reset_dsp(hw))) {
                 DEBUGOUT("Error Resetting PHY DSP\n");
                 return ret_val;
             }
@@ -1327,14 +1499,11 @@
             /* Read the MII Status Register and wait for Auto-Neg Complete bit
              * to be set.
              */
-            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
-                DEBUGOUT("PHY Read Error\n");
-                return -E1000_ERR_PHY;
-            }
-            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
-                DEBUGOUT("PHY Read Error\n");
-                return -E1000_ERR_PHY;
-            }
+            if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+                return ret_val;
+
+            if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+                return ret_val;
         }
     }
 
@@ -1343,30 +1512,29 @@
          * Extended PHY Specific Control Register to 25MHz clock.  This value
          * defaults back to a 2.5MHz clock when the PHY is reset.
          */
-        if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
-            DEBUGOUT("PHY Read Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                         &phy_data)))
+            return ret_val;
+
         phy_data |= M88E1000_EPSCR_TX_CLK_25;
-        if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
-            DEBUGOUT("PHY Write Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                          phy_data)))
+            return ret_val;
 
         /* In addition, because of the s/w reset above, we need to enable CRS on
          * TX.  This must be set for both full and 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;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                         &phy_data)))
+            return ret_val;
+
         phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-        if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
-            DEBUGOUT("PHY Write Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                          phy_data)))
+            return ret_val;
+
     }
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -1406,6 +1574,7 @@
 e1000_config_mac_to_phy(struct e1000_hw *hw)
 {
     uint32_t ctrl;
+    int32_t ret_val;
     uint16_t phy_data;
 
     DEBUGFUNC("e1000_config_mac_to_phy");
@@ -1421,10 +1590,10 @@
      * registers depending on negotiated values.
      */
     if (hw->phy_type == e1000_phy_igp) {
-        if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) {
-            DEBUGOUT("PHY Read Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+                                         &phy_data)))
+            return ret_val;
+
         if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD;
         else ctrl &= ~E1000_CTRL_FD;
 
@@ -1440,10 +1609,10 @@
                 IGP01E1000_PSSR_SPEED_100MBPS)
             ctrl |= E1000_CTRL_SPD_100;
     } else {
-        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
-            DEBUGOUT("PHY Read Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                         &phy_data)))
+            return ret_val;
+
         if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
         else ctrl &= ~E1000_CTRL_FD;
 
@@ -1459,7 +1628,7 @@
     }
     /* Write the configured values back to the Device Control Reg. */
     E1000_WRITE_REG(hw, CTRL, ctrl);
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -1473,7 +1642,7 @@
  * by the PHY rather than the MAC. Software must also configure these
  * bits when link is forced on a fiber connection.
  *****************************************************************************/
-static int32_t
+int32_t
 e1000_force_mac_fc(struct e1000_hw *hw)
 {
     uint32_t ctrl;
@@ -1526,7 +1695,7 @@
         ctrl &= (~E1000_CTRL_TFCE);
 
     E1000_WRITE_REG(hw, CTRL, ctrl);
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -1557,9 +1726,9 @@
      * configuration of the MAC to match the "fc" parameter.
      */
     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) {
+        if((ret_val = e1000_force_mac_fc(hw))) {
             DEBUGOUT("Error forcing flow control settings\n");
             return ret_val;
         }
@@ -1575,14 +1744,10 @@
          * has completed.  We read this twice because this reg has
          * some "sticky" (latched) bits.
          */
-        if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
-            DEBUGOUT("PHY Read Error \n");
-            return -E1000_ERR_PHY;
-        }
-        if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
-            DEBUGOUT("PHY Read Error \n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+            return ret_val;
+        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+            return ret_val;
 
         if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
             /* The AutoNeg process has completed, so we now need to
@@ -1591,14 +1756,12 @@
              * Register (Address 5) to determine how flow control was
              * negotiated.
              */
-            if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg) < 0) {
-                DEBUGOUT("PHY Read Error\n");
-                return -E1000_ERR_PHY;
-            }
-            if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg) < 0) {
-                DEBUGOUT("PHY Read Error\n");
-                return -E1000_ERR_PHY;
-            }
+            if((ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV,
+                                             &mii_nway_adv_reg)))
+                return ret_val;
+            if((ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY,
+                                             &mii_nway_lp_ability_reg)))
+                return ret_val;
 
             /* Two bits in the Auto Negotiation Advertisement Register
              * (Address 4) and two bits in the Auto Negotiation Base
@@ -1700,8 +1863,9 @@
              * be asked to delay transmission of packets than asking
              * our link partner to pause transmission of frames.
              */
-            else if(hw->original_fc == e1000_fc_none ||
-                    hw->original_fc == e1000_fc_tx_pause) {
+            else if((hw->original_fc == e1000_fc_none ||
+                     hw->original_fc == e1000_fc_tx_pause) ||
+                    hw->fc_strict_ieee) {
                 hw->fc = e1000_fc_none;
                 DEBUGOUT("Flow Control = NONE.\r\n");
             } else {
@@ -1713,7 +1877,10 @@
              * negotiated to HALF DUPLEX, flow control should not be
              * enabled per IEEE 802.3 spec.
              */
-            e1000_get_speed_and_duplex(hw, &speed, &duplex);
+            if((ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex))) {
+                DEBUGOUT("Error getting link speed and duplex\n");
+                return ret_val;
+            }
 
             if(duplex == HALF_DUPLEX)
                 hw->fc = e1000_fc_none;
@@ -1721,16 +1888,15 @@
             /* Now we call a subroutine to actually force the MAC
              * controller to use the correct flow control settings.
              */
-            ret_val = e1000_force_mac_fc(hw);
-            if(ret_val < 0) {
+            if((ret_val = e1000_force_mac_fc(hw))) {
                 DEBUGOUT("Error forcing flow control settings\n");
                 return ret_val;
-             }
+            }
         } else {
             DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
         }
     }
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -1747,19 +1913,19 @@
     uint32_t ctrl;
     uint32_t status;
     uint32_t rctl;
-    uint32_t signal;
+    uint32_t signal = 0;
     int32_t ret_val;
     uint16_t phy_data;
     uint16_t lp_capability;
 
     DEBUGFUNC("e1000_check_for_link");
 
-    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+    /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
      * set when the optics detect a signal. On older adapters, it will be
-     * cleared when there is a signal
+     * cleared when there is a signal.  This applies to fiber media only.
      */
-    if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
-    else signal = 0;
+    if(hw->media_type == e1000_media_type_fiber)
+        signal = (hw->mac_type > e1000_82544) ? E1000_CTRL_SWDPIN1 : 0;
 
     ctrl = E1000_READ_REG(hw, CTRL);
     status = E1000_READ_REG(hw, STATUS);
@@ -1777,14 +1943,10 @@
          * of the PHY.
          * Read the register twice since the link bit is sticky.
          */
-        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;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+            return ret_val;
+        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+            return ret_val;
 
         if(phy_data & MII_SR_LINK_STATUS) {
             hw->get_link_status = FALSE;
@@ -1794,6 +1956,7 @@
 
         } else {
             /* No link detected */
+            e1000_config_dsp_after_link_change(hw, FALSE);
             return 0;
         }
 
@@ -1802,6 +1965,9 @@
          */
         if(!hw->autoneg) return -E1000_ERR_CONFIG;
 
+        /* optimize the dsp settings for the igp phy */
+        e1000_config_dsp_after_link_change(hw, TRUE);
+
         /* We have a M88E1000 PHY and Auto-Neg is enabled.  If we
          * have Si on board that is 82544 or newer, Auto
          * Speed Detection takes care of MAC speed/duplex
@@ -1813,8 +1979,7 @@
         if(hw->mac_type >= e1000_82544)
             e1000_config_collision_dist(hw);
         else {
-            ret_val = e1000_config_mac_to_phy(hw);
-            if(ret_val < 0) {
+            if((ret_val = e1000_config_mac_to_phy(hw))) {
                 DEBUGOUT("Error configuring MAC to PHY settings\n");
                 return ret_val;
             }
@@ -1824,8 +1989,7 @@
          * need to restore the desired flow control settings because we may
          * have had to re-autoneg with a different link partner.
          */
-        ret_val = e1000_config_fc_after_link_up(hw);
-        if(ret_val < 0) {
+        if((ret_val = e1000_config_fc_after_link_up(hw))) {
             DEBUGOUT("Error configuring flow control\n");
             return ret_val;
         }
@@ -1840,10 +2004,9 @@
          * partner is TBI-based, and we turn on TBI Compatibility.
          */
         if(hw->tbi_compatibility_en) {
-            if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &lp_capability) < 0) {
-                DEBUGOUT("PHY Read Error\n");
-                return -E1000_ERR_PHY;
-            }
+            if((ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY,
+                                             &lp_capability)))
+                return ret_val;
             if(lp_capability & (NWAY_LPAR_10T_HD_CAPS |
                                 NWAY_LPAR_10T_FD_CAPS |
                                 NWAY_LPAR_100TX_HD_CAPS |
@@ -1881,9 +2044,10 @@
      * auto-negotiation time to complete, in case the cable was just plugged
      * in. The autoneg_failed flag does this.
      */
-    else if((hw->media_type == e1000_media_type_fiber) &&
+    else if((((hw->media_type == e1000_media_type_fiber) &&
+            ((ctrl & E1000_CTRL_SWDPIN1) == signal)) ||
+            (hw->media_type == e1000_media_type_internal_serdes)) &&
             (!(status & E1000_STATUS_LU)) &&
-            ((ctrl & E1000_CTRL_SWDPIN1) == signal) &&
             (!(rxcw & E1000_RXCW_C))) {
         if(hw->autoneg_failed == 0) {
             hw->autoneg_failed = 1;
@@ -1900,8 +2064,7 @@
         E1000_WRITE_REG(hw, CTRL, ctrl);
 
         /* Configure Flow Control after forcing link up. */
-        ret_val = e1000_config_fc_after_link_up(hw);
-        if(ret_val < 0) {
+        if((ret_val = e1000_config_fc_after_link_up(hw))) {
             DEBUGOUT("Error configuring flow control\n");
             return ret_val;
         }
@@ -1911,14 +2074,15 @@
      * Device Control register in an attempt to auto-negotiate with our link
      * partner.
      */
-    else if((hw->media_type == e1000_media_type_fiber) &&
+    else if(((hw->media_type == e1000_media_type_fiber) ||
+             (hw->media_type == e1000_media_type_internal_serdes)) &&
               (ctrl & E1000_CTRL_SLU) &&
               (rxcw & E1000_RXCW_C)) {
         DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
         E1000_WRITE_REG(hw, TXCW, hw->txcw);
         E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
     }
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -1928,12 +2092,14 @@
  * speed - Speed of the connection
  * duplex - Duplex setting of the connection
  *****************************************************************************/
-void
+int32_t
 e1000_get_speed_and_duplex(struct e1000_hw *hw,
                            uint16_t *speed,
                            uint16_t *duplex)
 {
     uint32_t status;
+    int32_t ret_val;
+    uint16_t phy_data;
 
     DEBUGFUNC("e1000_get_speed_and_duplex");
 
@@ -1962,6 +2128,27 @@
         *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) {
+        if((ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data)))
+            return ret_val;
+
+        if(!(phy_data & NWAY_ER_LP_NWAY_CAPS))
+            *duplex = HALF_DUPLEX;
+        else {
+            if((ret_val == e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data)))
+                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;
+        }
+    }
+
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -1972,6 +2159,7 @@
 int32_t
 e1000_wait_autoneg(struct e1000_hw *hw)
 {
+    int32_t ret_val;
     uint16_t i;
     uint16_t phy_data;
 
@@ -1983,20 +2171,16 @@
         /* Read the MII Status Register and wait for Auto-Neg
          * Complete bit to be set.
          */
-        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;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+            return ret_val;
+        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+            return ret_val;
         if(phy_data & MII_SR_AUTONEG_COMPLETE) {
-            return 0;
+            return E1000_SUCCESS;
         }
         msec_delay(100);
     }
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -2010,11 +2194,11 @@
                     uint32_t *ctrl)
 {
     /* Raise the clock input to the Management Data Clock (by setting the MDC
-     * bit), and then delay 2 microseconds.
+     * bit), and then delay 10 microseconds.
      */
     E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
     E1000_WRITE_FLUSH(hw);
-    udelay(2);
+    udelay(10);
 }
 
 /******************************************************************************
@@ -2028,11 +2212,11 @@
                     uint32_t *ctrl)
 {
     /* Lower the clock input to the Management Data Clock (by clearing the MDC
-     * bit), and then delay 2 microseconds.
+     * bit), and then delay 10 microseconds.
      */
     E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
     E1000_WRITE_FLUSH(hw);
-    udelay(2);
+    udelay(10);
 }
 
 /******************************************************************************
@@ -2076,7 +2260,7 @@
         E1000_WRITE_REG(hw, CTRL, ctrl);
         E1000_WRITE_FLUSH(hw);
 
-        udelay(2);
+        udelay(10);
 
         e1000_raise_mdi_clk(hw, &ctrl);
         e1000_lower_mdi_clk(hw, &ctrl);
@@ -2138,8 +2322,8 @@
 }
 
 /*****************************************************************************
-* Reads the value from a PHY register
-*
+* Reads the value from a PHY register, if the value is on a specific non zero
+* page, sets the page first.
 * hw - Struct containing variables accessed by shared code
 * reg_addr - address of the PHY register to read
 ******************************************************************************/
@@ -2148,11 +2332,33 @@
                    uint32_t reg_addr,
                    uint16_t *phy_data)
 {
+    uint32_t ret_val;
+
+    DEBUGFUNC("e1000_read_phy_reg");
+
+    if(hw->phy_type == e1000_phy_igp &&
+       (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
+        if((ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                             (uint16_t)reg_addr)))
+            return ret_val;
+    }
+
+    ret_val = e1000_read_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
+                                    phy_data);
+
+    return ret_val;
+}
+
+int32_t
+e1000_read_phy_reg_ex(struct e1000_hw *hw,
+                      uint32_t reg_addr,
+                      uint16_t *phy_data)
+{
     uint32_t i;
     uint32_t mdic = 0;
     const uint32_t phy_addr = 1;
 
-    DEBUGFUNC("e1000_read_phy_reg");
+    DEBUGFUNC("e1000_read_phy_reg_ex");
 
     if(reg_addr > MAX_PHY_REG_ADDRESS) {
         DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
@@ -2172,7 +2378,7 @@
 
         /* Poll the ready bit to see if the MDI read completed */
         for(i = 0; i < 64; i++) {
-            udelay(10);
+            udelay(50);
             mdic = E1000_READ_REG(hw, MDIC);
             if(mdic & E1000_MDIC_READY) break;
         }
@@ -2214,7 +2420,7 @@
          */
         *phy_data = e1000_shift_in_mdi_bits(hw);
     }
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -2229,11 +2435,33 @@
                     uint32_t reg_addr,
                     uint16_t phy_data)
 {
+    uint32_t ret_val;
+
+    DEBUGFUNC("e1000_write_phy_reg");
+
+    if(hw->phy_type == e1000_phy_igp &&
+       (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
+        if((ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                             (uint16_t)reg_addr)))
+            return ret_val;
+    }
+
+    ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
+                                     phy_data);
+
+    return ret_val;
+}
+
+int32_t
+e1000_write_phy_reg_ex(struct e1000_hw *hw,
+                    uint32_t reg_addr,
+                    uint16_t phy_data)
+{
     uint32_t i;
     uint32_t mdic = 0;
     const uint32_t phy_addr = 1;
 
-    DEBUGFUNC("e1000_write_phy_reg");
+    DEBUGFUNC("e1000_write_phy_reg_ex");
 
     if(reg_addr > MAX_PHY_REG_ADDRESS) {
         DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
@@ -2253,8 +2481,8 @@
         E1000_WRITE_REG(hw, MDIC, mdic);
 
         /* Poll the ready bit to see if the MDI read completed */
-        for(i = 0; i < 64; i++) {
-            udelay(10);
+        for(i = 0; i < 640; i++) {
+            udelay(5);
             mdic = E1000_READ_REG(hw, MDIC);
             if(mdic & E1000_MDIC_READY) break;
         }
@@ -2284,7 +2512,7 @@
         e1000_shift_out_mdi_bits(hw, mdic, 32);
     }
 
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -2329,11 +2557,6 @@
     udelay(150);
 
     if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
-        if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) {
-            DEBUGOUT("PHY Write Error\n");
-            return;
-        }
-
         /* Configure activity LED after PHY reset */
         led_ctrl = E1000_READ_REG(hw, LEDCTL);
         led_ctrl &= IGP_ACTIVITY_LED_MASK;
@@ -2352,24 +2575,26 @@
 int32_t
 e1000_phy_reset(struct e1000_hw *hw)
 {
+    int32_t ret_val;
     uint16_t phy_data;
 
     DEBUGFUNC("e1000_phy_reset");
 
-    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;
-    }
-    udelay(1);
-    if (hw->phy_type == e1000_phy_igp) {
+    if(hw->mac_type != e1000_82541_rev_2) {
+        if((ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data)))
+            return ret_val;
+
+        phy_data |= MII_CR_RESET;
+        if((ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data)))
+            return ret_val;
+
+        udelay(1);
+    } else e1000_phy_hw_reset(hw);
+
+    if(hw->phy_type == e1000_phy_igp)
         e1000_phy_init_script(hw);
-    }
-    return 0;
+
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -2380,23 +2605,21 @@
 int32_t
 e1000_detect_gig_phy(struct e1000_hw *hw)
 {
+    int32_t phy_init_status, ret_val;
     uint16_t phy_id_high, phy_id_low;
     boolean_t match = FALSE;
-    int32_t phy_init_status;
 
     DEBUGFUNC("e1000_detect_gig_phy");
 
     /* 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;
-    }
+    if((ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high)))
+        return ret_val;
+
     hw->phy_id = (uint32_t) (phy_id_high << 16);
     udelay(20);
-    if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
+    if((ret_val = e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low)))
+        return ret_val;
+
     hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
     hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
 
@@ -2409,11 +2632,15 @@
         break;
     case e1000_82540:
     case e1000_82545:
+    case e1000_82545_rev_3:
     case e1000_82546:
+    case e1000_82546_rev_3:
         if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
         break;
     case e1000_82541:
+    case e1000_82541_rev_2:
     case e1000_82547:
+    case e1000_82547_rev_2:
         if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
         break;
     default:
@@ -2424,7 +2651,7 @@
 
     if ((match) && (phy_init_status == E1000_SUCCESS)) {
         DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
-        return 0;
+        return E1000_SUCCESS;
     }
     DEBUGOUT1("Invalid PHY ID 0x%X\n", hw->phy_id);
     return -E1000_ERR_PHY;
@@ -2438,17 +2665,16 @@
 static int32_t
 e1000_phy_reset_dsp(struct e1000_hw *hw)
 {
-    int32_t ret_val = -E1000_ERR_PHY;
+    int32_t ret_val;
     DEBUGFUNC("e1000_phy_reset_dsp");
 
     do {
-        if(e1000_write_phy_reg(hw, 29, 0x001d) < 0) break;
-        if(e1000_write_phy_reg(hw, 30, 0x00c1) < 0) break;
-        if(e1000_write_phy_reg(hw, 30, 0x0000) < 0) break;
-        ret_val = 0;
+        if((ret_val = e1000_write_phy_reg(hw, 29, 0x001d))) break;
+        if((ret_val = e1000_write_phy_reg(hw, 30, 0x00c1))) break;
+        if((ret_val = e1000_write_phy_reg(hw, 30, 0x0000))) break;
+        ret_val = E1000_SUCCESS;
     } while(0);
 
-    if(ret_val < 0) DEBUGOUT("PHY Write Error\n");
     return ret_val;
 }
 
@@ -2459,8 +2685,10 @@
 * phy_info - PHY information structure
 ******************************************************************************/
 int32_t
-e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
+e1000_phy_igp_get_info(struct e1000_hw *hw,
+                       struct e1000_phy_info *phy_info)
 {
+    int32_t ret_val;
     uint16_t phy_data, polarity, min_length, max_length, average;
 
     DEBUGFUNC("e1000_phy_igp_get_info");
@@ -2476,13 +2704,14 @@
     phy_info->polarity_correction = e1000_polarity_reversal_enabled;
 
     /* Check polarity status */
-    if(e1000_check_polarity(hw, &polarity) < 0)
-        return -E1000_ERR_PHY;
+    if((ret_val = e1000_check_polarity(hw, &polarity)))
+        return ret_val;
 
     phy_info->cable_polarity = polarity;
 
-    if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0)
-        return -E1000_ERR_PHY;
+    if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+                                     &phy_data)))
+        return ret_val;
 
     phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
                           IGP01E1000_PSSR_MDIX_SHIFT;
@@ -2490,8 +2719,8 @@
     if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
        IGP01E1000_PSSR_SPEED_1000MBPS) {
         /* Local/Remote Receiver Information are only valid at 1000 Mbps */
-        if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0)
-            return -E1000_ERR_PHY;
+        if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data)))
+            return ret_val;
 
         phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
                              SR_1000T_LOCAL_RX_STATUS_SHIFT;
@@ -2499,8 +2728,8 @@
                               SR_1000T_REMOTE_RX_STATUS_SHIFT;
 
         /* Get cable length */
-        if(e1000_get_cable_length(hw, &min_length, &max_length) < 0)
-            return -E1000_ERR_PHY;
+        if((ret_val = e1000_get_cable_length(hw, &min_length, &max_length)))
+            return ret_val;
 
         /* transalte to old method */
         average = (max_length + min_length) / 2;
@@ -2527,8 +2756,10 @@
 * phy_info - PHY information structure
 ******************************************************************************/
 int32_t
-e1000_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
+e1000_phy_m88_get_info(struct e1000_hw *hw,
+                       struct e1000_phy_info *phy_info)
 {
+    int32_t ret_val;
     uint16_t phy_data, polarity;
 
     DEBUGFUNC("e1000_phy_m88_get_info");
@@ -2537,8 +2768,8 @@
      * and it stored in the hw->speed_downgraded parameter. */
     phy_info->downshift = hw->speed_downgraded;
 
-    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
-        return -E1000_ERR_PHY;
+    if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data)))
+        return ret_val;
 
     phy_info->extended_10bt_distance =
         (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
@@ -2548,13 +2779,13 @@
         M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
 
     /* Check polarity status */
-    if(e1000_check_polarity(hw, &polarity) < 0)
-        return -E1000_ERR_PHY;
+    if((ret_val = e1000_check_polarity(hw, &polarity)))
+        return ret_val;
 
     phy_info->cable_polarity = polarity;
 
-    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
-        return -E1000_ERR_PHY;
+    if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data)))
+        return ret_val;
 
     phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
                           M88E1000_PSSR_MDIX_SHIFT;
@@ -2566,8 +2797,8 @@
         phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
                                   M88E1000_PSSR_CABLE_LENGTH_SHIFT);
 
-        if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0)
-            return -E1000_ERR_PHY;
+        if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data)))
+            return ret_val;
 
         phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
                              SR_1000T_LOCAL_RX_STATUS_SHIFT;
@@ -2589,6 +2820,7 @@
 e1000_phy_get_info(struct e1000_hw *hw,
                    struct e1000_phy_info *phy_info)
 {
+    int32_t ret_val;
     uint16_t phy_data;
 
     DEBUGFUNC("e1000_phy_get_info");
@@ -2607,20 +2839,18 @@
         return -E1000_ERR_CONFIG;
     }
 
-    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;
-    }
+    if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        return ret_val;
+
+    if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        return ret_val;
+
     if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
         DEBUGOUT("PHY info is only valid if link is up\n");
         return -E1000_ERR_CONFIG;
     }
 
-    if (hw->phy_type == e1000_phy_igp)
+    if(hw->phy_type == e1000_phy_igp)
         return e1000_phy_igp_get_info(hw, phy_info);
     else
         return e1000_phy_m88_get_info(hw, phy_info);
@@ -2636,7 +2866,7 @@
         hw->mdix = 1;
         return -E1000_ERR_CONFIG;
     }
-    return 0;
+    return E1000_SUCCESS;
 }
 
 
@@ -2668,7 +2898,9 @@
         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;
@@ -2681,8 +2913,9 @@
         }
         break;
     case e1000_82541:
+    case e1000_82541_rev_2:
     case e1000_82547:
-    default:
+    case e1000_82547_rev_2:
         if (eecd & E1000_EECD_TYPE) {
             eeprom->type = e1000_eeprom_spi;
             eeprom->opcode_bits = 8;
@@ -2707,6 +2940,18 @@
             }
         }
         break;
+    default:
+        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;
+        }
+        break;
     }
 
     if (eeprom->type == e1000_eeprom_spi) {
@@ -2715,28 +2960,28 @@
             eeprom_size &= EEPROM_SIZE_MASK;
 
             switch (eeprom_size) {
-                case EEPROM_SIZE_16KB:
-                    eeprom->word_size = 8192;
-                    break;
-                case EEPROM_SIZE_8KB:
-                    eeprom->word_size = 4096;
-                    break;
-                case EEPROM_SIZE_4KB:
-                    eeprom->word_size = 2048;
-                    break;
-                case EEPROM_SIZE_2KB:
-                    eeprom->word_size = 1024;
-                    break;
-                case EEPROM_SIZE_1KB:
-                    eeprom->word_size = 512;
-                    break;
-                case EEPROM_SIZE_512B:
-                    eeprom->word_size = 256;
-                    break;
-                case EEPROM_SIZE_128B:
-                default:
-                    eeprom->word_size = 64;
-                    break;
+            case EEPROM_SIZE_16KB:
+                eeprom->word_size = 8192;
+                break;
+            case EEPROM_SIZE_8KB:
+                eeprom->word_size = 4096;
+                break;
+            case EEPROM_SIZE_4KB:
+                eeprom->word_size = 2048;
+                break;
+            case EEPROM_SIZE_2KB:
+                eeprom->word_size = 1024;
+                break;
+            case EEPROM_SIZE_1KB:
+                eeprom->word_size = 512;
+                break;
+            case EEPROM_SIZE_512B:
+                eeprom->word_size = 256;
+                break;
+            case EEPROM_SIZE_128B:
+            default:
+                eeprom->word_size = 64;
+                break;
             }
         }
     }
@@ -2841,7 +3086,8 @@
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
 static uint16_t
-e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count)
+e1000_shift_in_ee_bits(struct e1000_hw *hw,
+                       uint16_t count)
 {
     uint32_t eecd;
     uint32_t i;
@@ -3101,13 +3347,17 @@
     }
 
     /* Prepare the EEPROM for reading  */
-    if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+    if(e1000_acquire_eeprom(hw) != E1000_SUCCESS)
         return -E1000_ERR_EEPROM;
 
     if(eeprom->type == e1000_eeprom_spi) {
+        uint16_t word_in;
         uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
 
-        if(e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
+        if(e1000_spi_eeprom_ready(hw)) {
+            e1000_release_eeprom(hw);
+            return -E1000_ERR_EEPROM;
+        }
 
         e1000_standby_eeprom(hw);
 
@@ -3118,30 +3368,35 @@
         /* 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);
-    }
-    else if(eeprom->type == e1000_eeprom_microwire) {
-        /* 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, offset, eeprom->address_bits);
-    }
 
-    /* Read the data.  The address of the eeprom internally increments with
-     * each word (microwire) or 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++) {
-        uint16_t word_in = e1000_shift_in_ee_bits(hw, 16);
-        if (eeprom->type == e1000_eeprom_spi)
-            word_in = (word_in >> 8) | (word_in << 8);
-        data[i] = word_in;
+        /* 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 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -3169,9 +3424,9 @@
         checksum += eeprom_data;
     }
 
-    if(checksum == (uint16_t) EEPROM_SUM) {
-        return 0;
-    } else {
+    if(checksum == (uint16_t) EEPROM_SUM)
+        return E1000_SUCCESS;
+    else {
         DEBUGOUT("EEPROM Checksum Invalid\n");
         return -E1000_ERR_EEPROM;
     }
@@ -3205,7 +3460,7 @@
         DEBUGOUT("EEPROM Write Error\n");
         return -E1000_ERR_EEPROM;
     }
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -3243,10 +3498,12 @@
     if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
         return -E1000_ERR_EEPROM;
 
-    if(eeprom->type == e1000_eeprom_microwire)
+    if(eeprom->type == e1000_eeprom_microwire) {
         status = e1000_write_eeprom_microwire(hw, offset, words, data);
-    else
+    } else {
         status = e1000_write_eeprom_spi(hw, offset, words, data);
+        msec_delay(10);
+    }
 
     /* Done with writing */
     e1000_release_eeprom(hw);
@@ -3403,7 +3660,7 @@
 
     e1000_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
 
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -3437,7 +3694,7 @@
     /* Save word 1 in lower half of part_num */
     *part_num |= eeprom_data;
 
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -3463,16 +3720,13 @@
         hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
         hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
     }
-    if((hw->mac_type == e1000_82546) &&
-       (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
-        if(hw->perm_mac_addr[5] & 0x01)
-            hw->perm_mac_addr[5] &= ~(0x01);
-        else
-            hw->perm_mac_addr[5] |= 0x01;
-    }
+    if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) &&
+       (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1))
+            hw->perm_mac_addr[5] ^= 0x01;
+
     for(i = 0; i < NODE_ADDRESS_SIZE; i++)
         hw->mac_addr[i] = hw->perm_mac_addr[i];
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -3748,7 +4002,7 @@
 
     if(hw->mac_type < e1000_82540) {
         /* Nothing to do */
-        return 0;
+        return E1000_SUCCESS;
     }
 
     ledctl = E1000_READ_REG(hw, LEDCTL);
@@ -3799,7 +4053,7 @@
             break;
         }
     }
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -3811,49 +4065,48 @@
 e1000_setup_led(struct e1000_hw *hw)
 {
     uint32_t ledctl;
+    int32_t ret_val = E1000_SUCCESS;
 
     DEBUGFUNC("e1000_setup_led");
 
-    switch(hw->device_id) {
-    case E1000_DEV_ID_82542:
-    case E1000_DEV_ID_82543GC_FIBER:
-    case E1000_DEV_ID_82543GC_COPPER:
-    case E1000_DEV_ID_82544EI_COPPER:
-    case E1000_DEV_ID_82544EI_FIBER:
-    case E1000_DEV_ID_82544GC_COPPER:
-    case E1000_DEV_ID_82544GC_LOM:
+    switch(hw->mac_type) {
+    case e1000_82542_rev2_0:
+    case e1000_82542_rev2_1:
+    case e1000_82543:
+    case e1000_82544:
         /* No setup necessary */
         break;
-    case E1000_DEV_ID_82545EM_FIBER:
-    case E1000_DEV_ID_82546EB_FIBER:
-        ledctl = E1000_READ_REG(hw, LEDCTL);
-        /* Save current LEDCTL settings */
-        hw->ledctl_default = ledctl;
-        /* Turn off LED0 */
-        ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
-                    E1000_LEDCTL_LED0_BLINK |
-                    E1000_LEDCTL_LED0_MODE_MASK);
-        ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT);
-        E1000_WRITE_REG(hw, LEDCTL, ledctl);
-        break;
-    case E1000_DEV_ID_82540EP:
-    case E1000_DEV_ID_82540EP_LOM:
-    case E1000_DEV_ID_82540EP_LP:
-    case E1000_DEV_ID_82540EM:
-    case E1000_DEV_ID_82540EM_LOM:
-    case E1000_DEV_ID_82545EM_COPPER:
-    case E1000_DEV_ID_82546EB_COPPER:
-    case E1000_DEV_ID_82546EB_QUAD_COPPER:
-    case E1000_DEV_ID_82541EI:
-    case E1000_DEV_ID_82541EP:
-    case E1000_DEV_ID_82547EI:
-        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
-        break;
+    case e1000_82541:
+    case e1000_82547:
+    case e1000_82541_rev_2:
+    case e1000_82547_rev_2:
+        /* Turn off PHY Smart Power Down (if enabled) */
+        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                         &hw->phy_spd_default)))
+            return ret_val;
+        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                          (uint16_t)(hw->phy_spd_default &
+                                          ~IGP01E1000_GMII_SPD))))
+            return ret_val;
+        /* Fall Through */
     default:
-        DEBUGOUT("Invalid device ID\n");
-        return -E1000_ERR_CONFIG;
+        if(hw->media_type == e1000_media_type_fiber) {
+            ledctl = E1000_READ_REG(hw, LEDCTL);
+            /* Save current LEDCTL settings */
+            hw->ledctl_default = ledctl;
+            /* Turn off LED0 */
+            ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+                        E1000_LEDCTL_LED0_BLINK |
+                        E1000_LEDCTL_LED0_MODE_MASK);
+            ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+                       E1000_LEDCTL_LED0_MODE_SHIFT);
+            E1000_WRITE_REG(hw, LEDCTL, ledctl);
+        } else if(hw->media_type == e1000_media_type_copper)
+            E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+        break;
     }
-    return 0;
+
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -3864,39 +4117,33 @@
 int32_t
 e1000_cleanup_led(struct e1000_hw *hw)
 {
+    int32_t ret_val = E1000_SUCCESS;
+
     DEBUGFUNC("e1000_cleanup_led");
 
-    switch(hw->device_id) {
-    case E1000_DEV_ID_82542:
-    case E1000_DEV_ID_82543GC_FIBER:
-    case E1000_DEV_ID_82543GC_COPPER:
-    case E1000_DEV_ID_82544EI_COPPER:
-    case E1000_DEV_ID_82544EI_FIBER:
-    case E1000_DEV_ID_82544GC_COPPER:
-    case E1000_DEV_ID_82544GC_LOM:
+    switch(hw->mac_type) {
+    case e1000_82542_rev2_0:
+    case e1000_82542_rev2_1:
+    case e1000_82543:
+    case e1000_82544:
         /* No cleanup necessary */
         break;
-    case E1000_DEV_ID_82540EP:
-    case E1000_DEV_ID_82540EP_LOM:
-    case E1000_DEV_ID_82540EP_LP:
-    case E1000_DEV_ID_82540EM:
-    case E1000_DEV_ID_82540EM_LOM:
-    case E1000_DEV_ID_82545EM_COPPER:
-    case E1000_DEV_ID_82545EM_FIBER:
-    case E1000_DEV_ID_82546EB_COPPER:
-    case E1000_DEV_ID_82546EB_FIBER:
-    case E1000_DEV_ID_82546EB_QUAD_COPPER:
-    case E1000_DEV_ID_82541EI:
-    case E1000_DEV_ID_82541EP:
-    case E1000_DEV_ID_82547EI:
+    case e1000_82541:
+    case e1000_82547:
+    case e1000_82541_rev_2:
+    case e1000_82547_rev_2:
+        /* Turn on PHY Smart Power Down (if previously enabled) */
+        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                          hw->phy_spd_default)))
+            return ret_val;
+        /* Fall Through */
+    default:
         /* Restore LEDCTL settings */
         E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
         break;
-    default:
-        DEBUGOUT("Invalid device ID\n");
-        return -E1000_ERR_CONFIG;
     }
-    return 0;
+
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -3907,50 +4154,44 @@
 int32_t
 e1000_led_on(struct e1000_hw *hw)
 {
-    uint32_t ctrl;
+    uint32_t ctrl = E1000_READ_REG(hw, CTRL);
 
     DEBUGFUNC("e1000_led_on");
 
-    switch(hw->device_id) {
-    case E1000_DEV_ID_82542:
-    case E1000_DEV_ID_82543GC_FIBER:
-    case E1000_DEV_ID_82543GC_COPPER:
-    case E1000_DEV_ID_82544EI_FIBER:
-        ctrl = E1000_READ_REG(hw, CTRL);
+    switch(hw->mac_type) {
+    case e1000_82542_rev2_0:
+    case e1000_82542_rev2_1:
+    case e1000_82543:
         /* Set SW Defineable Pin 0 to turn on the LED */
         ctrl |= E1000_CTRL_SWDPIN0;
         ctrl |= E1000_CTRL_SWDPIO0;
-        E1000_WRITE_REG(hw, CTRL, ctrl);
-        break;
-    case E1000_DEV_ID_82544EI_COPPER:
-    case E1000_DEV_ID_82544GC_COPPER:
-    case E1000_DEV_ID_82544GC_LOM:
-    case E1000_DEV_ID_82545EM_FIBER:
-    case E1000_DEV_ID_82546EB_FIBER:
-        ctrl = E1000_READ_REG(hw, CTRL);
-        /* Clear SW Defineable Pin 0 to turn on the LED */
-        ctrl &= ~E1000_CTRL_SWDPIN0;
-        ctrl |= E1000_CTRL_SWDPIO0;
-        E1000_WRITE_REG(hw, CTRL, ctrl);
         break;
-    case E1000_DEV_ID_82540EP:
-    case E1000_DEV_ID_82540EP_LOM:
-    case E1000_DEV_ID_82540EP_LP:
-    case E1000_DEV_ID_82540EM:
-    case E1000_DEV_ID_82540EM_LOM:
-    case E1000_DEV_ID_82545EM_COPPER:
-    case E1000_DEV_ID_82546EB_COPPER:
-    case E1000_DEV_ID_82546EB_QUAD_COPPER:
-    case E1000_DEV_ID_82541EI:
-    case E1000_DEV_ID_82541EP:
-    case E1000_DEV_ID_82547EI:
-        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
+    case e1000_82544:
+        if(hw->media_type == e1000_media_type_fiber) {
+            /* Set SW Defineable Pin 0 to turn on the LED */
+            ctrl |= E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        } else {
+            /* Clear SW Defineable Pin 0 to turn on the LED */
+            ctrl &= ~E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        }
         break;
     default:
-        DEBUGOUT("Invalid device ID\n");
-        return -E1000_ERR_CONFIG;
+        if(hw->media_type == e1000_media_type_fiber) {
+            /* Clear SW Defineable Pin 0 to turn on the LED */
+            ctrl &= ~E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        } else if(hw->media_type == e1000_media_type_copper) {
+            E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
+            return E1000_SUCCESS;
+        }
+        break;
     }
-    return 0;
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -3961,50 +4202,44 @@
 int32_t
 e1000_led_off(struct e1000_hw *hw)
 {
-    uint32_t ctrl;
+    uint32_t ctrl = E1000_READ_REG(hw, CTRL);
 
     DEBUGFUNC("e1000_led_off");
 
-    switch(hw->device_id) {
-    case E1000_DEV_ID_82542:
-    case E1000_DEV_ID_82543GC_FIBER:
-    case E1000_DEV_ID_82543GC_COPPER:
-    case E1000_DEV_ID_82544EI_FIBER:
-        ctrl = E1000_READ_REG(hw, CTRL);
+    switch(hw->mac_type) {
+    case e1000_82542_rev2_0:
+    case e1000_82542_rev2_1:
+    case e1000_82543:
         /* Clear SW Defineable Pin 0 to turn off the LED */
         ctrl &= ~E1000_CTRL_SWDPIN0;
         ctrl |= E1000_CTRL_SWDPIO0;
-        E1000_WRITE_REG(hw, CTRL, ctrl);
-        break;
-    case E1000_DEV_ID_82544EI_COPPER:
-    case E1000_DEV_ID_82544GC_COPPER:
-    case E1000_DEV_ID_82544GC_LOM:
-    case E1000_DEV_ID_82545EM_FIBER:
-    case E1000_DEV_ID_82546EB_FIBER:
-        ctrl = E1000_READ_REG(hw, CTRL);
-        /* Set SW Defineable Pin 0 to turn off the LED */
-        ctrl |= E1000_CTRL_SWDPIN0;
-        ctrl |= E1000_CTRL_SWDPIO0;
-        E1000_WRITE_REG(hw, CTRL, ctrl);
         break;
-    case E1000_DEV_ID_82540EP:
-    case E1000_DEV_ID_82540EP_LOM:
-    case E1000_DEV_ID_82540EP_LP:
-    case E1000_DEV_ID_82540EM:
-    case E1000_DEV_ID_82540EM_LOM:
-    case E1000_DEV_ID_82545EM_COPPER:
-    case E1000_DEV_ID_82546EB_COPPER:
-    case E1000_DEV_ID_82546EB_QUAD_COPPER:
-    case E1000_DEV_ID_82541EI:
-    case E1000_DEV_ID_82541EP:
-    case E1000_DEV_ID_82547EI:
-        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+    case e1000_82544:
+        if(hw->media_type == e1000_media_type_fiber) {
+            /* Clear SW Defineable Pin 0 to turn off the LED */
+            ctrl &= ~E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        } else {
+            /* Set SW Defineable Pin 0 to turn off the LED */
+            ctrl |= E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        }
         break;
     default:
-        DEBUGOUT("Invalid device ID\n");
-        return -E1000_ERR_CONFIG;
+        if(hw->media_type == e1000_media_type_fiber) {
+            /* Set SW Defineable Pin 0 to turn off the LED */
+            ctrl |= E1000_CTRL_SWDPIN0;
+            ctrl |= E1000_CTRL_SWDPIO0;
+        } else if(hw->media_type == e1000_media_type_copper) {
+            E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+            return E1000_SUCCESS;
+        }
+        break;
     }
-    return 0;
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -4127,8 +4362,7 @@
     DEBUGFUNC("e1000_update_adaptive");
 
     if(hw->adaptive_ifs) {
-        if((hw->collision_delta * hw->ifs_ratio) >
-           hw->tx_packet_delta) {
+        if((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) {
             if(hw->tx_packet_delta > MIN_NUM_XMITS) {
                 hw->in_ifs_mode = TRUE;
                 if(hw->current_ifs_val < hw->ifs_max_val) {
@@ -4140,8 +4374,7 @@
                 }
             }
         } else {
-            if((hw->in_ifs_mode == TRUE) &&
-               (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+            if(hw->in_ifs_mode && (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
                 hw->current_ifs_val = 0;
                 hw->in_ifs_mode = FALSE;
                 E1000_WRITE_REG(hw, AIT, 0);
@@ -4324,7 +4557,8 @@
  * min_length - The estimated minimum length
  * max_length - The estimated maximum length
  *
- * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ * returns: - E1000_ERR_XXX
+ *            E1000_SUCCESS
  *
  * This function always returns a ranged length (minimum & maximum).
  * So for M88 phy's, this function interprets the one value returned from the
@@ -4332,9 +4566,11 @@
  * For IGP phy's, the function calculates the range by the AGC registers.
  *****************************************************************************/
 int32_t
-e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length,
+e1000_get_cable_length(struct e1000_hw *hw,
+                       uint16_t *min_length,
                        uint16_t *max_length)
 {
+    int32_t ret_val;
     uint16_t agc_value = 0;
     uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
     uint16_t i, phy_data;
@@ -4345,8 +4581,9 @@
 
     /* Use old method for Phy older than IGP */
     if(hw->phy_type == e1000_phy_m88) {
-        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
-            return -E1000_ERR_PHY;
+        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                         &phy_data)))
+            return ret_val;
 
         /* Convert the enum value to ranged values */
         switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
@@ -4376,19 +4613,16 @@
             break;
         }
     } else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
-        uint16_t agc_reg_array[IGP01E1000_PHY_AGC_NUM] = {IGP01E1000_PHY_AGC_A,
+        uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
+                                                         {IGP01E1000_PHY_AGC_A,
                                                           IGP01E1000_PHY_AGC_B,
                                                           IGP01E1000_PHY_AGC_C,
                                                           IGP01E1000_PHY_AGC_D};
         /* Read the AGC registers for all channels */
-        for(i = 0; i < IGP01E1000_PHY_AGC_NUM; i++) {
-            if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
-                                   agc_reg_array[i]) != E1000_SUCCESS)
-                return -E1000_ERR_PHY;
-            if(e1000_read_phy_reg(hw, agc_reg_array[i] &
-                                  IGP01E1000_PHY_PAGE_SELECT, &phy_data) !=
-                                  E1000_SUCCESS)
-                return -E1000_ERR_PHY;
+        for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+
+            if((ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data)))
+                return ret_val;
 
             cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
 
@@ -4404,20 +4638,15 @@
                 min_agc = cur_agc;
         }
 
-        /* Return to page 0 */
-        if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) !=
-           E1000_SUCCESS)
-            return -E1000_ERR_PHY;
-
         /* Remove the minimal AGC result for length < 50m */
-        if(agc_value < IGP01E1000_PHY_AGC_NUM * e1000_igp_cable_length_50) {
+        if(agc_value < IGP01E1000_PHY_CHANNEL_NUM * e1000_igp_cable_length_50) {
             agc_value -= min_agc;
 
             /* Get the average length of the remaining 3 channels */
-            agc_value /= (IGP01E1000_PHY_AGC_NUM - 1);
+            agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
         } else {
             /* Get the average length of all the 4 channels. */
-            agc_value /= IGP01E1000_PHY_AGC_NUM;
+            agc_value /= IGP01E1000_PHY_CHANNEL_NUM;
         }
 
         /* Set the range of the calculated length. */
@@ -4439,7 +4668,8 @@
  * polarity - output parameter : 0 - Polarity is not reversed
  *                               1 - Polarity is reversed.
  *
- * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ * returns: - E1000_ERR_XXX
+ *            E1000_SUCCESS
  *
  * For phy's older then IGP, this function simply reads the polarity bit in the
  * Phy Status register.  For IGP phy's, this bit is valid only if link speed is
@@ -4448,22 +4678,26 @@
  * IGP01E1000_PHY_PCS_INIT_REG.
  *****************************************************************************/
 int32_t
-e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity)
+e1000_check_polarity(struct e1000_hw *hw,
+                     uint16_t *polarity)
 {
+    int32_t ret_val;
     uint16_t phy_data;
 
     DEBUGFUNC("e1000_check_polarity");
 
     if(hw->phy_type == e1000_phy_m88) {
         /* return the Polarity bit in the Status register. */
-        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
-            return -E1000_ERR_PHY;
+        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                         &phy_data)))
+            return ret_val;
         *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
                     M88E1000_PSSR_REV_POLARITY_SHIFT;
     } else if(hw->phy_type == e1000_phy_igp) {
         /* Read the Status register to check the speed */
-        if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0)
-            return -E1000_ERR_PHY;
+        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+                                         &phy_data)))
+            return ret_val;
 
         /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
          * find the polarity status */
@@ -4471,18 +4705,9 @@
            IGP01E1000_PSSR_SPEED_1000MBPS) {
 
             /* Read the GIG initialization PCS register (0x00B4) */
-            if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
-                                   IGP01E1000_PHY_PCS_INIT_REG) < 0)
-                return -E1000_ERR_PHY;
-
-            if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG &
-                                  IGP01E1000_PHY_PAGE_SELECT, &phy_data) < 0)
-                return -E1000_ERR_PHY;
-
-            /* Return to page 0 */
-            if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) !=
-               E1000_SUCCESS)
-                return -E1000_ERR_PHY;
+            if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG,
+                                             &phy_data)))
+                return ret_val;
 
             /* Check the polarity bits */
             *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0;
@@ -4502,7 +4727,8 @@
  * downshift - output parameter : 0 - No Downshift ocured.
  *                                1 - Downshift ocured.
  *
- * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ * returns: - E1000_ERR_XXX
+ *            E1000_SUCCESS 
  *
  * For phy's older then IGP, this function reads the Downshift bit in the Phy
  * Specific Status register.  For IGP phy's, it reads the Downgrade bit in the
@@ -4512,25 +4738,287 @@
 int32_t
 e1000_check_downshift(struct e1000_hw *hw)
 {
+    int32_t ret_val;
     uint16_t phy_data;
 
     DEBUGFUNC("e1000_check_downshift");
 
     if(hw->phy_type == e1000_phy_igp) {
-        if(e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data) < 0) {
-            DEBUGOUT("PHY Read Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
+                                         &phy_data)))
+            return ret_val;
+
         hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
     }
     else if(hw->phy_type == e1000_phy_m88) {
-        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
-            DEBUGOUT("PHY Read Error\n");
-            return -E1000_ERR_PHY;
-        }
+        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                         &phy_data)))
+            return ret_val;
+
         hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
-                                M88E1000_PSSR_DOWNSHIFT_SHIFT;
+                               M88E1000_PSSR_DOWNSHIFT_SHIFT;
+    }
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * 82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
+ * gigabit link is achieved to improve link quality.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ *            E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+int32_t
+e1000_config_dsp_after_link_change(struct e1000_hw *hw,
+                                   boolean_t link_up)
+{
+    int32_t ret_val;
+    uint16_t phy_data, speed, duplex, i;
+    uint16_t dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
+                                        {IGP01E1000_PHY_AGC_PARAM_A,
+                                        IGP01E1000_PHY_AGC_PARAM_B,
+                                        IGP01E1000_PHY_AGC_PARAM_C,
+                                        IGP01E1000_PHY_AGC_PARAM_D};
+    uint16_t min_length, max_length;
+
+    DEBUGFUNC("e1000_config_dsp_after_link_change");
+
+    if(hw->phy_type != e1000_phy_igp)
+        return E1000_SUCCESS;
+
+    if(link_up) {
+        if((ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex))) {
+            DEBUGOUT("Error getting link speed and duplex\n");
+            return ret_val;
+        }
+
+        if(speed == SPEED_1000) {
+
+            e1000_get_cable_length(hw, &min_length, &max_length);
+
+            if((hw->dsp_config_state == e1000_dsp_config_enabled) &&
+                min_length >= e1000_igp_cable_length_50) {
+
+                for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+                    if((ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i],
+                                                     &phy_data)))
+                        return ret_val;
+
+                    phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+
+                    if((ret_val = e1000_write_phy_reg(hw, dsp_reg_array[i],
+                                                      phy_data)))
+                        return ret_val;
+                }
+                hw->dsp_config_state = e1000_dsp_config_activated;
+            }
+
+            if((hw->ffe_config_state == e1000_ffe_config_enabled) &&
+               (min_length < e1000_igp_cable_length_50)) {
+
+                uint16_t ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
+                uint32_t idle_errs = 0;
+
+                /* clear previous idle error counts */
+                if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
+                                                 &phy_data)))
+                    return ret_val;
+
+                for(i = 0; i < ffe_idle_err_timeout; i++) {
+                    udelay(1000);
+                    if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
+                                                     &phy_data)))
+                        return ret_val;
+
+                    idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
+                    if(idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
+                        hw->ffe_config_state = e1000_ffe_config_active;
+
+                        if((ret_val = e1000_write_phy_reg(hw,
+                                    IGP01E1000_PHY_DSP_FFE,
+                                    IGP01E1000_PHY_DSP_FFE_CM_CP)))
+                            return ret_val;
+                        break;
+                    }
+
+                    if(idle_errs)
+                        ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_100;
+                }
+            }
+        }
+    } else {
+        if(hw->dsp_config_state == e1000_dsp_config_activated) {
+            if((ret_val = e1000_write_phy_reg(hw, 0x0000,
+                IGP01E1000_IEEE_FORCE_GIGA)))
+                return ret_val;
+            for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+                if((ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i],
+                                                 &phy_data)))
+                    return ret_val;
+
+                phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+                phy_data |=  IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
+
+                if((ret_val = e1000_write_phy_reg(hw,dsp_reg_array[i],
+                                                  phy_data)))
+                    return ret_val;
+            }
+
+            if((ret_val = e1000_write_phy_reg(hw, 0x0000,
+                                              IGP01E1000_IEEE_RESTART_AUTONEG)))
+                return ret_val;
+
+            hw->dsp_config_state = e1000_dsp_config_enabled;
+        }
+
+        if(hw->ffe_config_state == e1000_ffe_config_active) {
+            if((ret_val = e1000_write_phy_reg(hw, 0x0000,
+                                              IGP01E1000_IEEE_FORCE_GIGA)))
+                return ret_val;
+            if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE,
+                                              IGP01E1000_PHY_DSP_FFE_DEFAULT)))
+                return ret_val;
+
+            if((ret_val = e1000_write_phy_reg(hw, 0x0000,
+                                              IGP01E1000_IEEE_RESTART_AUTONEG)))
+                return ret_val;
+        hw->ffe_config_state = e1000_ffe_config_enabled;
+        }
     }
     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.
+ *
+ ****************************************************************************/
+
+int32_t
+e1000_set_d3_lplu_state(struct e1000_hw *hw,
+                        boolean_t active)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+    DEBUGFUNC("e1000_set_d3_lplu_state");
+
+    if(!((hw->mac_type == e1000_82541_rev_2) ||
+         (hw->mac_type == e1000_82547_rev_2)))
+        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((ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data)))
+        return ret_val;
+
+    if(!active) {
+        phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
+        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data)))
+            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((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data)))
+            return ret_val;
+
+        phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data)))
+            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)) {
+
+        phy_data |= IGP01E1000_GMII_FLEX_SPD;
+        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data)))
+            return ret_val;
+
+        /* When LPLU is enabled we should disable SmartSpeed */
+        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data)))
+            return ret_val;
+
+        phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data)))
+            return ret_val;
+
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Change VCO speed register to improve Bit Error Rate performance of SERDES.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t
+e1000_set_vco_speed(struct e1000_hw *hw)
+{
+    int32_t  ret_val;
+    uint16_t default_page = 0;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_set_vco_speed");
+
+    switch(hw->mac_type) {
+    case e1000_82545_rev_3:
+    case e1000_82546_rev_3:
+       break;
+    default:
+        return E1000_SUCCESS;
+    }
+
+    /* Set PHY register 30, page 5, bit 8 to 0 */
+
+    if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT,
+                                     &default_page)))
+        return ret_val;
+
+    if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005)))
+        return ret_val;
+
+    if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data)))
+        return ret_val;
+
+    phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
+    if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data)))
+        return ret_val;
+
+    /* Set PHY register 30, page 4, bit 11 to 1 */
+
+    if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004)))
+        return ret_val;
+
+    if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data)))
+        return ret_val;
+
+    phy_data |= M88E1000_PHY_VCO_REG_BIT11;
+    if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data)))
+        return ret_val;
+
+    if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT,
+                                      default_page)))
+        return ret_val;
+
+    return E1000_SUCCESS;
+}
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)