Sync with Intel's em(4) driver version 3.2.15
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 8 Nov 2005 12:48:18 +0000 (12:48 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 8 Nov 2005 12:48:18 +0000 (12:48 +0000)
- Add support for 82571EB, 82572EI and 82573E adapters
- Nuke DBG_STATS related code and struct adapter's fields
- Flow control water marks are now calculated from hardware's register value
  instead of using hardwired values(FC_DEFAULT_{LOW, HIGH}_THRESH)
- Flow control pause time is bumped to 512us (old value is 131us) (*)
- In em_detach(), call bus_teardown_intr() if adapter.int_handler_tag != NULL
- Update Intel's LICENSE and README
- Update README to reflect recent changes to device polling
- Minor style changes

(*) Original code misuses 0x1000 (should be 1000) as em_hw.fc_pause_time

sys/dev/netif/em/LICENSE
sys/dev/netif/em/README
sys/dev/netif/em/if_em.c
sys/dev/netif/em/if_em.h
sys/dev/netif/em/if_em_hw.c
sys/dev/netif/em/if_em_hw.h
sys/dev/netif/em/if_em_osdep.h

index fca1b9b..0868a73 100644 (file)
@@ -1,6 +1,5 @@
-$FreeBSD: src/sys/dev/em/LICENSE,v 1.1.2.2 2003/04/04 18:39:28 pdeuskar Exp $
-$DragonFly: src/sys/dev/netif/em/LICENSE,v 1.3 2004/03/17 04:59:41 dillon Exp $
-Copyright (c) 2001-2003, Intel Corporation 
+$DragonFly: src/sys/dev/netif/em/LICENSE,v 1.4 2005/11/08 12:48:18 sephe Exp $
+Copyright (c) 2001-2005, Intel Corporation 
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without 
index 35b64fa..9245f4f 100644 (file)
@@ -1,16 +1,15 @@
-$FreeBSD: src/sys/dev/em/README,v 1.1.2.7 2003/06/09 21:43:41 pdeuskar Exp $
-$DragonFly: src/sys/dev/netif/em/README,v 1.3 2004/03/17 04:59:41 dillon Exp $
+$DragonFly: src/sys/dev/netif/em/README,v 1.4 2005/11/08 12:48:18 sephe Exp $
 FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters
 ============================================================
 
-July 24, 2003
+July 6, 2005
 
 
 Contents
 ========
 
 - Overview
-- Supported Adapters
+- Identifying Your Adapter
 - Building and Installation
 - Speed and Duplex Configuration
 - Additional Configurations
@@ -22,82 +21,43 @@ Contents
 Overview
 ========
 
-This file describes the FreeBSD* driver, version 1.7.x, for the Intel(R)
-PRO/1000 Family of Adapters. This driver has been developed for use with 
-FreeBSD, version 4.7. 
+This file describes the FreeBSD* driver, version 3.1.x, for the Intel
+PRO/1000 Family of Adapters. This driver has been developed for use with
+FreeBSD, Release 4.10 and greater and Release 5.4.
 
-For questions related to hardware requirements, refer to the documentation 
-supplied with your Intel PRO/1000 adapter. All hardware requirements listed 
+For questions related to hardware requirements, refer to the documentation
+supplied with your Intel PRO/1000 adapter. All hardware requirements listed
 apply to use with FreeBSD.
 
 
-Supported Adapters
-==================
+Identifying Your Adapter
+========================
 
-The following Intel network adapters are compatible with the drivers in this 
-release:
-
-   Controller  Adapter Name                         Board IDs
-   ----------  ------------                         ---------
-
-   82542       PRO/1000 Gigabit Server Adapter      700262-xxx, 717037-xxx
-
-   82543       PRO/1000 F Server Adapter            738640-xxx, A38888-xxx,
-                                                    A06512-xxx
-
-   82543       PRO/1000 T Server Adapter            A19845-xxx, A33948-xxx
-
-   82544       PRO/1000 XT Server Adapter           A51580-xxx
-
-   82544       PRO/1000 XF Server Adapter           A50484-xxx
-
-   82544       PRO/1000 T Desktop Adapter           A62947-xxx
-
-   82540       PRO/1000 MT Desktop Adapter          A78408-xxx
-
-   82541       PRO/1000 MT Desktop Adapter          C91016-xxx
-
-   82545       PRO/1000 MT Server Adapter           A92165-xxx
-
-   82545       PRO/1000 MF Server Adapter           A91622-xxx
-
-   82545       PRO/1000 MF Server Adapter(LX)       A91624-xxx
-
-   82546       PRO/1000 MT Dual Port Server Adapter A92111-xxx
-
-   82546       PRO/1000 MF Dual Port Server Adapter A91620-xxx
-
-   82546EB     PRO/1000 MT Quad Port Server Adapter C11227-xxx 
-
-   82547       PRO/1000 CT Network Connection
+For information on how to identify your adapter, go to the Adapter &
+Driver ID Guide at:
 
+http://support.intel.com/support/network/adapter/pro100/21397.htm
 
-To verify your Intel adapter is supported, find the board ID number on the
-adapter. Look for a label that has a barcode and a number in the format of
-123456-001 (six digits hyphen three digits). Match this to the list of 
-numbers above.
 
-For more information on how to identify your adapter, go to the Adapter &
-Driver ID Guide at:
+For the latest Intel network drivers for FreeBSD, see:
 
-    http://support.intel.com/support/network/adapter/pro100/21397.htm
+http://downloadfinder.intel.com/scripts-df-external/support_intel.aspx
 
-For the latest Intel network drivers for FreeBSD, see:
 
-    http://appsr.intel.com/scripts-df/support_intel.asp
+NOTE: Mobile adapters are not fully supported.
 
 
 Building and Installation
 =========================
 
-NOTE: The driver can be installed as a dynamic loadable kernel module or 
-      compiled into the kernel. You must have kernel sources installed in 
+NOTE: The driver can be installed as a dynamic loadable kernel module or
+      compiled into the kernel. You must have kernel sources installed in
       order to compile the driver module.
 
-In the instructions below, x.x.x is the driver version as indicated in the 
+In the instructions below, x.x.x is the driver version as indicated in the
 name of the driver tar file.
 
-1. Move the base driver tar file to the directory of your choice. For 
+1. Move the base driver tar file to the directory of your choice. For
    example, use /home/username/em or /usr/local/src/em.
 
 2. Untar/unzip the archive:
@@ -106,24 +66,23 @@ name of the driver tar file.
 
    This will create an em-x.x.x directory.
 
-3. To create a loadable module, perform the following steps. 
+3. To create a loadable module, perform the following steps.
    NOTE: To compile the driver into the kernel, go directly to step 4.
 
-       a. To compile the module
+        a. To compile the module
 
-                 cd em-x.x.x
-                 make
+                  cd em-x.x.x
+                  make
 
-       b. To install the compiled module in system directory:
-        
-                 make install
-               
-       c. If you want the driver to load automatically when the system is booted:
+        b. To install the compiled module in system directory:
 
-             1. Follow steps a, and b above to compile and install the module
-             2. Edit /boot/loader.conf, and add the following line:
+                  make install
 
-                 if_em_load="YES"
+        c. If you want the driver to load automatically when the system is booted:
+
+              1. Edit /boot/loader.conf, and add the following line:
+
+                  if_em_load="YES"
 
 4. To compile the driver into the kernel:
 
@@ -133,25 +92,26 @@ name of the driver tar file.
 
         cp Makefile.kernel /usr/src/sys/modules/em/Makefile
 
-   Edit the /usr/src/sys/conf/files.i386 file, and add the following lines:
+   Edit the /usr/src/sys/conf/files.i386 file, and add the following lines only if
+   they don't already exist:
 
         dev/em/if_em.c optional em
 
-        dev/em/if_em_hw.c optional em 
+        dev/em/if_em_hw.c optional em
 
-   Remove the following lines from the /usr/src/sys/conf/files.i386 file, 
+   Remove the following lines from the /usr/src/sys/conf/files.i386 file,
    if they exist:
 
         dev/em/if_em_fxhw.c optional em
         dev/em/if_em_phy.c optional em
 
-   Edit the kernel configuration file (i.e., GENERIC or MYKERNEL) in 
+   Edit the kernel configuration file (i.e., GENERIC or MYKERNEL) in
    /usr/src/sys/i386/conf, and ensure the following line is present:
 
         device em
 
    Compile and install the kernel. The system must be rebooted for the kernel
-   updates to take effect. For additional information on compiling the 
+   updates to take effect. For additional information on compiling the
    kernel, consult the FreeBSD operating system documentation.
 
 5. To assign an IP address to the interface, enter the following:
@@ -164,8 +124,8 @@ name of the driver tar file.
 
         ping <IP_address>
 
-7. To configure the IP address to remain after reboot, edit /etc/rc.conf, 
-   and create the appropriate ifconfig_em<interface_num> entry:
+7. To configure the IP address to remain after reboot, edit /etc/rc.conf,
+   and create the appropriate ifconfig_em<interface_num>entry:
 
         ifconfig_em<interface_num>="<ifconfig_settings>"
 
@@ -179,15 +139,15 @@ name of the driver tar file.
 Speed and Duplex Configuration
 ==============================
 
-By default, the adapter auto-negotiates the speed and duplex of the 
-connection. If there is a specific need, the ifconfig utility can be used to 
+By default, the adapter auto-negotiates the speed and duplex of the
+connection. If there is a specific need, the ifconfig utility can be used to
 configure the speed and duplex settings on the adapter. Example usage:
 
-        ifconfig em<interface_num> <IP_address> media 100baseTX mediaopt 
+        ifconfig em<interface_num> <IP_address> media 100baseTX mediaopt
             full-duplex
 
-   NOTE: Only use mediaopt to set the driver to full-duplex. If mediaopt is 
-         not specified and you are not running at gigabit speed, the driver 
+   NOTE: Only use mediaopt to set the driver to full-duplex. If mediaopt is
+         not specified and you are not running at gigabit speed, the driver
          defaults to half-duplex.
 
 
@@ -195,7 +155,7 @@ This driver supports the following media type options:
 
    autoselect      -  Enables auto-negotiation for speed and duplex.
 
-   10baseT/UTP     -  Sets speed to 10 Mbps. Use the ifconfig mediaopt 
+   10baseT/UTP     -  Sets speed to 10 Mbps. Use the ifconfig mediaopt
                       option to select full-duplex mode.
 
    100baseTX       -  Sets speed to 100 Mbps. Use the ifconfig mediaopt
@@ -213,117 +173,160 @@ For more information on the ifconfig utility, see the ifconfig man page.
 Additional Configurations
 =========================
 
-The driver supports Transmit/Receive Checksum Offload and Jumbo Frames on 
-all but the 82542-based adapters. For specific adapters, refer to the 
-Supported Adapters section.
+The driver supports Transmit/Receive Checksum Offload and Jumbo Frames on
+all but the 82542-based adapters. For specific adapters, refer to the
+Identifying Your Adapter section.
 
   Jumbo Frames
   ------------
-  To enable Jumbo Frames, use the ifconfig utility to increase the MTU 
-  beyond 1500 bytes. 
-
-  NOTES: Only enable Jumbo Frames if your network infrastructure supports 
-         them.
-   
-         The Jumbo Frames setting on the switch must be set to at least 
-         22 bytes larger than that of the adapter.
+  To enable Jumbo Frames, use the ifconfig utility to set the Maximum
+  Transport Unit (MTU) frame size above its default of 1500 bytes.
 
-  The Jumbo Frames MTU range for Intel Adapters is 1500 to 16114. The default 
-  MTU range is 1500. To modify the setting, enter the following:
+  The Jumbo Frames MTU range for Intel Adapters is 1500 to 16110. To modify
+  the setting, enter the following:
 
         ifconfig em<interface_num> <hostname or IP address> mtu 9000
 
-  To confirm an interface's MTU value, use the ifconfig command. To confirm
-  the MTU used between two specific devices, use:
+  To confirm the MTU used between two specific devices, use:
 
         route get <destination_IP_address>
 
+  Notes:
+
+  - Only enable Jumbo Frames if your network infrastructure supports them.
+
+  - The Jumbo Frames setting on the switch must be set to at least 22 bytes
+    larger than that of the MTU.
+
+  - The maximum MTU setting is 16110, with a corresponding maximum Jumbo
+    Frames size of 16128.
+
+  - Some Intel gigabit adapters that support Jumbo Frames have a frame size limit
+    of 9238 bytes, with a corresponding MTU size limit of 9216 bytes. The adapters
+    with this limitation are based on the Intel 82571EB and 82572EI controllers,
+    which correspond to these product names:
+     Intel PRO/1000 PT Dual Port Server Adapter
+     Intel PRO/1000 PF Dual Port Server Adapter
+     Intel PRO/1000 PT Server Adapter
+     Intel PRO/1000 PT Desktop Adapter
+     Intel PRO/1000 PF Server Adapter
+
+  - Using Jumbo Frames at 10 or 100 Mbps may result in poor performance or loss
+    of link.
+
+  - The Intel PRO/1000 PM Network Connection does not support jumbo frames.
+
+
   VLANs
   -----
-  To create a new VLAN pseudo-interface:
+  To create a new VLAN interface:
 
         ifconfig <vlan_name> create
 
-  To associate the VLAN pseudo-interface with a physical interface and 
+  To associate the VLAN interface with a physical interface and
   assign a VLAN ID, IP address, and netmask:
 
-        ifconfig <vlan_name> <ip_address> netmask <subnet_mask> vlan 
+        ifconfig <vlan_name> <ip_address> netmask <subnet_mask> vlan
            <vlan_id> vlandev <physical_interface>
 
   Example:
 
         ifconfig vlan10 10.0.0.1 netmask 255.255.255.0 vlan10 vlandev em0
 
-  In this example, all packets will be marked on egress with  802.1Q VLAN 
+  In this example, all packets will be marked on egress with  802.1Q VLAN
   tags, specifying a VLAN ID of 10.
 
-  To remove a VLAN pseudo-interface:
+  To remove a VLAN interface:
 
         ifconfig <vlan_name> destroy
 
   Polling
   -------
-  To enable polling in the driver, add the following options to the kernel 
+  NOTES: DEVICE POLLING is only valid for non-SMP kernels.
+
+        The driver has to be compiled into the kernel for DEVICE POLLING to be
+        enabled in the driver.
+
+  To enable polling in the driver, add the following options to the kernel
   configuration, and then recompile the kernel:
 
         options DEVICE_POLLING
-        options HZ=1000
-
-  At runtime, use the following command to turn on polling mode. Similarly,
-  turn off polling mode by setting the variable to 0:
 
+  At runtime use:
         sysctl kern.polling.enable=1
+       ifconfig <interface_num> polling
+  to turn polling on
 
+  Use:
+        sysctl kern.polling.enable=0
+  or
+       ifconfig <interface_num> -polling
+  to turn polling off
 
-  NOTES: DEVICE POLLING is only valid for non-SMP kernels.
+  Checksum Offload
+  ----------------
+  Checksum offloading is not supported on 82542 Gigabit adapters.
 
-         The driver has to be built into the kernel for DEVICE POLLING to be
-         enabled in the driver.
+  Checksum offloading supports both TCP and UDP packets and is
+  supported for both transmit and receive.
 
+  Checksum offloading can be enabled or disabled using ifconfig.
+  Both transmit and receive offloading will be either enabled or
+  disabled together. You cannot enable/disable one without the other.
 
-Known Limitations
-=================
-  There are known performance issues with this driver when running UDP traffic
-  with Jumbo Frames. Intel recommends not using Jumbo Frames for UDP traffic.
+  To enable checksum offloading:
 
+         ifconfig <interface_num> rxcsum
 
-  82541/82547 can't link or is slow to link with some link partners
-  -----------------------------------------------------------------
+  To disable checksum offloading:
 
-  There is a known compatibility issue with 82541/82547 and some switches 
-  where link will not be established, or will be slow to establish.  In 
-  particular, these switches are known to be incompatible with 82541/82547:
+         ifconfig <interface_num> -rxcsum
 
+  To confirm the current setting:
+
+         ifconfig <interface_num>
+
+  Look for the presence or absence of the following line:
+
+         options=3 <RXCSUM,TXCSUM>
+
+  See the ifconfig man page for further information.
+
+Known Limitations
+=================
+
+  There are known performance issues with this driver when running UDP traffic
+  with Jumbo Frames.
+
+  There is a known compatibility issue where time to link is slow or link is not
+  established between 82541/82547 controllers and some switches.  Known switches
+  include:
         Planex FXG-08TE
         I-O Data ETG-SH8
 
-  To workaround the issue, the driver can be compiled with an override of the 
-  PHY's master/slave setting.  Forcing master or forcing slave mode will 
-  improve time-to-link.
+  The driver can be compiled with the following changes:
 
-  Edit ./em.x.x.x/src/if_em.h to remove the #define EM_MASTER_SLAVE 
-  from within the comments.  
+  Edit ./em.x.x.x/src/if_em.h to uncomment the #define EM_MASTER_SLAVE
+  from within the comments.  For example, change from:
 
       /* #define EM_MASTER_SLAVE  2 */
-      #define EM_MASTER_SLAVE  2 
+  to:
+      #define EM_MASTER_SLAVE  2
 
-  Use one of the following options.
-      0 = Hardware default
+  Use one of the following options:
       1 = Master mode
       2 = Slave mode
       3 = Auto master/slave
+  Setting 2 is recommended.
 
-  Recompile the module (refer to step 3 above)
-  a. To compile the module
-
-          cd em-x.x.x
-          make clean
-          make
+  Recompile the module:
+          a. To compile the module
+                cd em-x.x.x
+                make clean
+                make
 
    b. To install the compiled module in system directory:
-          make install
+                make install
 
 
 Support
@@ -333,20 +336,18 @@ For general information and support, go to the Intel support website at:
 
         http://support.intel.com
 
-If an issue is identified with the released source code on the supported
-kernel with a supported adapter, email the specific information related to 
-the issue to freebsdnic@mailbox.intel.com.
-
+If an issue is identified, support is through email only at:
+freebsdnic@mailbox.intel.com
 
 License
 =======
 
-This software program is released under the terms of a license agreement 
-between you ('Licensee') and Intel. Do not use or load this software or any 
-associated materials (collectively, the 'Software') until you have carefully 
-read the full terms and conditions of the LICENSE located in this software 
-package. By loading or using the Software, you agree to the terms of this 
-Agreement. If you do not agree with the terms of this Agreement, do not 
+This software program is released under the terms of a license agreement
+between you ('Licensee') and Intel. Do not use or load this software or any
+associated materials (collectively, the 'Software') until you have carefully
+read the full terms and conditions of the LICENSE located in this software
+package. By loading or using the Software, you agree to the terms of this
+Agreement. If you do not agree with the terms of this Agreement, do not
 install or use the Software.
 
 * Other names and brands may be claimed as the property of others.
index 5cad7ac..bd0b219 100644 (file)
@@ -2,7 +2,7 @@
 
 Copyright (c) 2004 Joerg Sonnenberger <joerg@bec.de>.  All rights reserved.
 
-Copyright (c) 2001-2003, Intel Corporation
+Copyright (c) 2001-2005, Intel Corporation
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
 ***************************************************************************/
 
 /*$FreeBSD: src/sys/dev/em/if_em.c,v 1.2.2.15 2003/06/09 22:10:15 pdeuskar Exp $*/
-/*$DragonFly: src/sys/dev/netif/em/if_em.c,v 1.41 2005/10/24 08:06:15 sephe Exp $*/
+/*$DragonFly: src/sys/dev/netif/em/if_em.c,v 1.42 2005/11/08 12:48:18 sephe Exp $*/
 
 #include "opt_polling.h"
 
@@ -50,7 +50,7 @@ int             em_display_debug_stats = 0;
  *  Driver version
  *********************************************************************/
 
-char em_driver_version[] = "1.7.35";
+char em_driver_version[] = "3.2.15";
 
 
 /*********************************************************************
@@ -66,40 +66,63 @@ char em_driver_version[] = "1.7.35";
 static em_vendor_info_t em_vendor_info_array[] =
 {
        /* Intel(R) PRO/1000 Network Connection */
-       { 0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1018, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82540EM,         PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82540EM_LOM,     PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82540EP,         PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82540EP_LOM,     PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82540EP_LP,      PCI_ANY_ID, PCI_ANY_ID, 0},
+
+       { 0x8086, E1000_DEV_ID_82541EI,         PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82541ER,         PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82541EI_MOBILE,  PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82541GI,         PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82541GI_LF,      PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82541GI_MOBILE,  PCI_ANY_ID, PCI_ANY_ID, 0},
+
+       { 0x8086, E1000_DEV_ID_82542,           PCI_ANY_ID, PCI_ANY_ID, 0},
+
+       { 0x8086, E1000_DEV_ID_82543GC_FIBER,   PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82543GC_COPPER,  PCI_ANY_ID, PCI_ANY_ID, 0},
+
+       { 0x8086, E1000_DEV_ID_82544EI_COPPER,  PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82544EI_FIBER,   PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82544GC_COPPER,  PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82544GC_LOM,     PCI_ANY_ID, PCI_ANY_ID, 0},
+
+       { 0x8086, E1000_DEV_ID_82545EM_COPPER,  PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82545EM_FIBER,   PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82545GM_COPPER,  PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82545GM_FIBER,   PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82545GM_SERDES,  PCI_ANY_ID, PCI_ANY_ID, 0},
+
+       { 0x8086, E1000_DEV_ID_82546EB_COPPER,  PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82546EB_FIBER,   PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82546EB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82546GB_COPPER,  PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82546GB_FIBER,   PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82546GB_SERDES,  PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82546GB_PCIE,    PCI_ANY_ID, PCI_ANY_ID, 0},
+#ifdef KINGSPORT_PROJECT
+       { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+#endif /* KINGSPORT_PROJECT */
+
+       { 0x8086, E1000_DEV_ID_82547EI,         PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82547GI,         PCI_ANY_ID, PCI_ANY_ID, 0},
+
+       { 0x8086, E1000_DEV_ID_82571EB_COPPER,  PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82571EB_FIBER,   PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82571EB_SERDES,  PCI_ANY_ID, PCI_ANY_ID, 0},
+
+       { 0x8086, E1000_DEV_ID_82572EI_COPPER,  PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82572EI_FIBER,   PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82572EI_SERDES,  PCI_ANY_ID, PCI_ANY_ID, 0},
+
+       { 0x8086, E1000_DEV_ID_82573E,          PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82573E_IAMT,     PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82573L,          PCI_ANY_ID, PCI_ANY_ID, 0},
+
        { 0x8086, 0x101A, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1026, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1027, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1028, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1075, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1076, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1077, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1078, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x107C, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x108A, PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0},
        /* required last entry */
        { 0, 0, 0, 0, 0}
 };
@@ -358,7 +381,7 @@ em_attach(device_t dev)
                        OID_AUTO, "int_throttle_ceil", CTLTYPE_INT|CTLFLAG_RW,
                        adapter, 0, em_sysctl_int_throttle, "I", NULL);
        }
-     
+
        /* Parameters (to be read from user) */   
        adapter->num_tx_desc = EM_MAX_TXD;
        adapter->num_rx_desc = EM_MAX_RXD;
@@ -368,16 +391,6 @@ em_attach(device_t dev)
        adapter->hw.tbi_compatibility_en = TRUE;
        adapter->rx_buffer_len = EM_RXBUFFER_2048;
 
-       /*
-        * These parameters control the automatic generation(Tx) and
-        * response(Rx) to Ethernet PAUSE frames.
-        */
-       adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH;
-       adapter->hw.fc_low_water  = FC_DEFAULT_LO_THRESH;
-       adapter->hw.fc_pause_time = FC_DEFAULT_TX_TIMER;
-       adapter->hw.fc_send_xon   = TRUE;
-       adapter->hw.fc = em_fc_full;
-
        adapter->hw.phy_init_script = 1;
        adapter->hw.phy_reset_disable = FALSE;
 
@@ -451,10 +464,10 @@ em_attach(device_t dev)
 
        adapter->hw.back = &adapter->osdep;
 
-       /* Initialize eeprom parameters */
        em_init_eeprom_params(&adapter->hw);
 
-       tsize = adapter->num_tx_desc * sizeof(struct em_tx_desc);
+       tsize = EM_ROUNDUP(adapter->num_tx_desc *
+                          sizeof(struct em_tx_desc), 4096);
 
        /* Allocate Transmit Descriptor ring */
        if (em_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_WAITOK)) {
@@ -464,7 +477,8 @@ em_attach(device_t dev)
        }
        adapter->tx_desc_base = (struct em_tx_desc *) adapter->txdma.dma_vaddr;
 
-       rsize = adapter->num_rx_desc * sizeof(struct em_rx_desc);
+       rsize = EM_ROUNDUP(adapter->num_rx_desc *
+                          sizeof(struct em_rx_desc), 4096);
 
        /* Allocate Receive Descriptor ring */
        if (em_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_WAITOK)) {
@@ -565,9 +579,11 @@ em_detach(device_t dev)
        }
        bus_generic_detach(dev);
 
-       if (adapter->res_interrupt != NULL) {
+       if (adapter->int_handler_tag != NULL) {
                bus_teardown_intr(dev, adapter->res_interrupt, 
                                  adapter->int_handler_tag);
+       }
+       if (adapter->res_interrupt != NULL) {
                bus_release_resource(dev, SYS_RES_IRQ, 0, 
                                     adapter->res_interrupt);
        }
@@ -674,7 +690,7 @@ em_start_serialized(struct ifnet *ifp)
 static int
 em_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
 {
-       int mask, error = 0;
+       int max_frame_size, mask, error = 0;
        struct ifreq *ifr = (struct ifreq *) data;
        struct adapter *adapter = ifp->if_softc;
 
@@ -693,7 +709,21 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
                break;
        case SIOCSIFMTU:
                IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)");
-               if (ifr->ifr_mtu > MAX_JUMBO_FRAME_SIZE - ETHER_HDR_LEN) {
+               switch (adapter->hw.mac_type) {
+               case em_82571:
+               case em_82572:
+                       max_frame_size = 10500;
+                       break;
+               case em_82573:
+                       /* 82573 does not support jumbo frames */
+                       max_frame_size = ETHER_MAX_LEN;
+                       break;
+               default:
+                       max_frame_size = MAX_JUMBO_FRAME_SIZE;
+                       break;
+               }
+               if (ifr->ifr_mtu >
+                       max_frame_size - ETHER_HDR_LEN - ETHER_CRC_LEN) {
                        error = EINVAL;
                } else {
                        ifp->if_mtu = ifr->ifr_mtu;
@@ -819,31 +849,36 @@ em_init_serialized(void *arg)
         * Packet Buffer Allocation (PBA)
         * Writing PBA sets the receive portion of the buffer
         * the remainder is used for the transmit buffer.
-        *
-        * Devices before the 82547 had a Packet Buffer of 64K.
-        *   Default allocation: PBA=48K for Rx, leaving 16K for Tx.
-        * After the 82547 the buffer was reduced to 40K.
-        *   Default allocation: PBA=30K for Rx, leaving 10K for Tx.
-        *   Note: default does not leave enough room for Jumbo Frame >10k.
         */
-       if(adapter->hw.mac_type < em_82547) {
-               /* Total FIFO is 64K */
-               if(adapter->rx_buffer_len > EM_RXBUFFER_8192)
-                       pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */
-               else
-                       pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */
-       } else {
-               /* Total FIFO is 40K */
-               if(adapter->hw.max_frame_size > EM_RXBUFFER_8192) {
+       switch (adapter->hw.mac_type) {
+       case em_82547: 
+       case em_82547_rev_2: /* 82547: Total Packet Buffer is 40K */
+               if (adapter->hw.max_frame_size > EM_RXBUFFER_8192)
                        pba = E1000_PBA_22K; /* 22K for Rx, 18K for Tx */
-               } else {
-                       pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */
-               }
+               else
+                       pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */
+
                adapter->tx_fifo_head = 0;
                adapter->tx_head_addr = pba << EM_TX_HEAD_ADDR_SHIFT;
                adapter->tx_fifo_size =
                        (E1000_PBA_40K - pba) << EM_PBA_BYTES_SHIFT;
+               break;
+       case em_82571: /* 82571: Total Packet Buffer is 48K */
+       case em_82572: /* 82572: Total Packet Buffer is 48K */
+               pba = E1000_PBA_32K; /* 32K for Rx, 16K for Tx */
+               break;
+       case em_82573: /* 82573: Total Packet Buffer is 32K */
+               /* Jumbo frames not supported */
+               pba = E1000_PBA_12K; /* 12K for Rx, 20K for Tx */
+               break;
+       default:
+               /* Devices before 82547 had a Packet Buffer of 64K.   */
+               if(adapter->hw.max_frame_size > EM_RXBUFFER_8192)
+                       pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */
+               else
+                       pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */
        }
+
        INIT_DEBUGOUT1("em_init: pba=%dK",pba);
        E1000_WRITE_REG(&adapter->hw, PBA, pba);
 
@@ -877,7 +912,7 @@ em_init_serialized(void *arg)
                return;
        }
        em_initialize_receive_unit(adapter);
-       
+
        /* Don't loose promiscuous settings */
        em_set_promisc(adapter);
 
@@ -1181,9 +1216,9 @@ em_encap(struct adapter *adapter, struct mbuf *m_head)
        if (ifp->if_hwassist > 0) {
                em_transmit_checksum_setup(adapter,  m_head,
                                           &txd_upper, &txd_lower);
-       }
-       else 
+       } else {
                txd_upper = txd_lower = 0;
+       }
 
        /* Find out if we are in vlan mode */
        if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
@@ -1295,7 +1330,7 @@ em_encap(struct adapter *adapter, struct mbuf *m_head)
  * 82547 workaround to avoid controller hang in half-duplex environment.
  * The workaround is to avoid queuing a large packet that would span   
  * the internal Tx FIFO ring boundary. We need to reset the FIFO pointers
- * in this case. We do that only when FIFO is quiescent.
+ * in this case. We do that only when FIFO is queiced.
  *
  **********************************************************************/
 static void
@@ -1376,7 +1411,7 @@ em_82547_update_fifo_head(struct adapter *adapter, int len)
 
 static int
 em_82547_tx_fifo_reset(struct adapter *adapter)
-{      
+{
        uint32_t tctl;
 
        if ( (E1000_READ_REG(&adapter->hw, TDT) ==
@@ -1444,8 +1479,8 @@ em_disable_promisc(struct adapter *adapter)
 
        reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
 
-       reg_rctl &=  (~E1000_RCTL_UPE);
-       reg_rctl &=  (~E1000_RCTL_MPE);
+       reg_rctl &= (~E1000_RCTL_UPE);
+       reg_rctl &= (~E1000_RCTL_MPE);
        E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
 
        em_enable_vlans(adapter);
@@ -1494,8 +1529,9 @@ em_set_multi(struct adapter *adapter)
                reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
                reg_rctl |= E1000_RCTL_MPE;
                E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
-       } else
+       } else {
                em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0, 1);
+       }
 
        if (adapter->hw.mac_type == em_82542_rev2_0) {
                reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
@@ -1636,6 +1672,8 @@ em_identify_hardware(struct adapter * adapter)
 static int
 em_hardware_init(struct adapter *adapter)
 {
+       uint16_t        rx_buffer_size;
+
        INIT_DEBUGOUT("em_hardware_init: begin");
        /* Issue a global reset */
        em_reset_hw(&adapter->hw);
@@ -1645,15 +1683,40 @@ em_hardware_init(struct adapter *adapter)
 
        /* Make sure we have a good EEPROM before we read from it */
        if (em_validate_eeprom_checksum(&adapter->hw) < 0) {
-               device_printf(adapter->dev, "The EEPROM Checksum Is Not Valid\n");
+               device_printf(adapter->dev,
+                             "The EEPROM Checksum Is Not Valid\n");
                return(EIO);
        }
 
        if (em_read_part_num(&adapter->hw, &(adapter->part_num)) < 0) {
-               device_printf(adapter->dev, "EEPROM read error while reading part number\n");
+               device_printf(adapter->dev,
+                             "EEPROM read error while reading part number\n");
                return(EIO);
        }
 
+       /*
+        * These parameters control the automatic generation (Tx) and 
+        * response(Rx) to Ethernet PAUSE frames.
+        * - High water mark should allow for at least two frames to be
+        *   received after sending an XOFF.
+        * - Low water mark works best when it is very near the high water mark.
+        *   This allows the receiver to restart by sending XON when it has
+        *   drained a bit.  Here we use an arbitary value of 1500 which will
+        *   restart after one full frame is pulled from the buffer.  There
+        *   could be several smaller frames in the buffer and if so they will
+        *   not trigger the XON until their total number reduces the buffer
+        *   by 1500.
+        * - The pause time is fairly large at 1000 x 512ns = 512 usec.
+        */
+       rx_buffer_size = ((E1000_READ_REG(&adapter->hw, PBA) & 0xffff) << 10);
+
+       adapter->hw.fc_high_water =
+           rx_buffer_size - EM_ROUNDUP(1 * adapter->hw.max_frame_size, 1024); 
+       adapter->hw.fc_low_water = adapter->hw.fc_high_water - 1500;
+       adapter->hw.fc_pause_time = 1000;
+       adapter->hw.fc_send_xon = TRUE;
+       adapter->hw.fc = em_fc_full;
+
        if (em_init_hw(&adapter->hw) < 0) {
                device_printf(adapter->dev, "Hardware Initialization Failed");
                return(EIO);
@@ -1998,6 +2061,8 @@ em_initialize_transmit_unit(struct adapter * adapter)
        /* Program the Transmit Control Register */
        reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
                   (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+       if (adapter->hw.mac_type >= em_82571)
+               reg_tctl |= E1000_TCTL_MULR;
        if (adapter->link_duplex == 1)
                reg_tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
        else
@@ -2146,9 +2211,6 @@ em_clean_transmit_interrupts(struct adapter *adapter)
        if (adapter->num_tx_desc_avail == adapter->num_tx_desc)
                return;
 
-#ifdef DBG_STATS
-       adapter->clean_tx_interrupts++;
-#endif
        num_avail = adapter->num_tx_desc_avail; 
        i = adapter->oldest_used_tx_desc;
 
@@ -2424,7 +2486,7 @@ em_initialize_receive_unit(struct adapter *adapter)
        }
 
        /* Enable Receives */
-       E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);  
+       E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
 }
 
 /*********************************************************************
@@ -2492,12 +2554,9 @@ em_process_receive_interrupts(struct adapter *adapter, int count)
        bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
                        BUS_DMASYNC_POSTREAD);
 
-       if (!((current_desc->status) & E1000_RXD_STAT_DD)) {
-#ifdef DBG_STATS
-               adapter->no_pkts_avail++;
-#endif
+       if (!((current_desc->status) & E1000_RXD_STAT_DD))
                return;
-       }
+
        while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) {
                mp = adapter->rx_buffer_area[i].m_head;
                bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map,
@@ -2512,8 +2571,7 @@ em_process_receive_interrupts(struct adapter *adapter, int count)
                        if (desc_len < ETHER_CRC_LEN) {
                                len = 0;
                                prev_len_adj = ETHER_CRC_LEN - desc_len;
-                       }
-                       else {
+                       } else {
                                len = desc_len - ETHER_CRC_LEN;
                        }
                } else {
@@ -2539,8 +2597,7 @@ em_process_receive_interrupts(struct adapter *adapter, int count)
                                                    adapter->hw.mac_addr);
                                if (len > 0)
                                        len--;
-                       }
-                       else {
+                       } else {
                                accept_frame = 0;
                        }
                }
@@ -2584,12 +2641,15 @@ em_process_receive_interrupts(struct adapter *adapter, int count)
 
                                em_receive_checksum(adapter, current_desc,
                                                    adapter->fmp);
-                               if (current_desc->status & E1000_RXD_STAT_VP)
+                               if (current_desc->status & E1000_RXD_STAT_VP) {
                                        VLAN_INPUT_TAG(adapter->fmp,
                                                       (current_desc->special & 
                                                        E1000_RXD_SPC_VLAN_MASK));
-                               else
+                               } else {
+                                       /* lwkt_serialize_exit() */
                                        (*ifp->if_input)(ifp, adapter->fmp);
+                                       /* lwkt_serialize_enter() */
+                               }
                                adapter->fmp = NULL;
                                adapter->lmp = NULL;
                        }
@@ -2612,8 +2672,9 @@ em_process_receive_interrupts(struct adapter *adapter, int count)
                if (++i == adapter->num_rx_desc) {
                        i = 0;
                        current_desc = adapter->rx_desc_base;
-               } else
+               } else {
                        current_desc++;
+               }
        }
 
        bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
@@ -2936,17 +2997,17 @@ em_print_debug_info(struct adapter *adapter)
                      E1000_READ_REG(&adapter->hw, CTRL)); 
        device_printf(dev, "RCTL  = 0x%x PS=(0x8402)\n",
                      E1000_READ_REG(&adapter->hw, RCTL)); 
+       device_printf(dev, "Packet buffer = Tx=%dk Rx=%dk\n",
+                     ((E1000_READ_REG(&adapter->hw, PBA) & 0xffff0000) >> 16),
+                     (E1000_READ_REG(&adapter->hw, PBA) & 0xffff));
+       device_printf(dev, "Flow control watermarks high = %d low = %d\n",
+                     adapter->hw.fc_high_water, adapter->hw.fc_low_water);
        device_printf(dev, "tx_int_delay = %d, tx_abs_int_delay = %d\n",
                      E1000_READ_REG(&adapter->hw, TIDV),
                      E1000_READ_REG(&adapter->hw, TADV));
        device_printf(dev, "rx_int_delay = %d, rx_abs_int_delay = %d\n",
                      E1000_READ_REG(&adapter->hw, RDTR),
                      E1000_READ_REG(&adapter->hw, RADV));
-#ifdef DBG_STATS
-       device_printf(dev, "Packets not Avail = %ld\n", adapter->no_pkts_avail);
-       device_printf(dev, "CleanTxInterrupts = %ld\n",
-                     adapter->clean_tx_interrupts);
-#endif
        device_printf(dev, "fifo workaround = %lld, fifo_reset = %lld\n",
                      (long long)adapter->tx_fifo_wrk_cnt,
                      (long long)adapter->tx_fifo_reset_cnt);
index 78f0e0b..6e20881 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
 
-Copyright (c) 2001-2003, Intel Corporation
+Copyright (c) 2001-2005, Intel Corporation
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
 ***************************************************************************/
 
 /*$FreeBSD: src/sys/dev/em/if_em.h,v 1.1.2.13 2003/06/09 21:43:41 pdeuskar Exp $*/
-/*$DragonFly: src/sys/dev/netif/em/if_em.h,v 1.11 2005/10/17 06:18:36 sephe Exp $*/
+/*$DragonFly: src/sys/dev/netif/em/if_em.h,v 1.12 2005/11/08 12:48:18 sephe Exp $*/
 
 #ifndef _EM_H_DEFINED_
 #define _EM_H_DEFINED_
@@ -428,10 +428,6 @@ struct adapter {
        boolean_t pcix_82544;
        boolean_t in_detach;
 
-#ifdef DBG_STATS
-       unsigned long   no_pkts_avail;
-       unsigned long   clean_tx_interrupts;
-#endif
        struct em_hw_stats stats;
 };
 
index 8195f97..77b3b3e 100644 (file)
@@ -1,6 +1,6 @@
 /*******************************************************************************
 
-  Copyright (c) 2001-2003, Intel Corporation 
+  Copyright (c) 2001-2005, Intel Corporation 
   All rights reserved.
   
   Redistribution and use in source and binary forms, with or without 
@@ -32,7 +32,7 @@
 *******************************************************************************/
 
 /*$FreeBSD: src/sys/dev/em/if_em_hw.c,v 1.1.2.8 2003/06/09 21:43:41 pdeuskar Exp $*/
-/*$DragonFly: src/sys/dev/netif/em/if_em_hw.c,v 1.7 2005/10/17 06:18:36 sephe Exp $*/
+/*$DragonFly: src/sys/dev/netif/em/if_em_hw.c,v 1.8 2005/11/08 12:48:18 sephe Exp $*/
 /* if_em_hw.c
  * Shared functions for accessing and configuring the MAC
  */
@@ -70,9 +70,11 @@ static uint16_t em_shift_in_ee_bits(struct em_hw *hw, uint16_t count);
 static int32_t em_acquire_eeprom(struct em_hw *hw);
 static void em_release_eeprom(struct em_hw *hw);
 static void em_standby_eeprom(struct em_hw *hw);
-static int32_t em_id_led_init(struct em_hw * hw);
 static int32_t em_set_vco_speed(struct em_hw *hw);
+static int32_t em_polarity_reversal_workaround(struct em_hw *hw);
 static int32_t em_set_phy_mode(struct em_hw *hw);
+static int32_t em_host_if_read_cookie(struct em_hw *hw, uint8_t *buffer);
+static uint8_t em_calculate_mng_checksum(char *buffer, uint32_t length);
 
 /* IGP cable length table */
 static const
@@ -86,6 +88,17 @@ uint16_t em_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
       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};
 
+static const
+uint16_t em_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] =
+    { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+      0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+      6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+      21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+      40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+      60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+      83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+      104, 109, 114, 118, 121, 124};
+
 
 /******************************************************************************
  * Set the phy type member in the hw struct.
@@ -97,10 +110,14 @@ em_set_phy_type(struct em_hw *hw)
 {
     DEBUGFUNC("em_set_phy_type");
 
+    if(hw->mac_type == em_undefined)
+        return -E1000_ERR_PHY_TYPE;
+
     switch(hw->phy_id) {
     case M88E1000_E_PHY_ID:
     case M88E1000_I_PHY_ID:
     case M88E1011_I_PHY_ID:
+    case M88E1111_I_PHY_ID:
         hw->phy_type = em_phy_m88;
         break;
     case IGP01E1000_I_PHY_ID:
@@ -129,16 +146,30 @@ em_set_phy_type(struct em_hw *hw)
 static void
 em_phy_init_script(struct em_hw *hw)
 {
+    uint32_t ret_val;
+    uint16_t phy_saved_data;
+
     DEBUGFUNC("em_phy_init_script");
 
     if(hw->phy_init_script) {
         msec_delay(20);
 
+        /* Save off the current value of register 0x2F5B to be restored at
+         * the end of this routine. */
+        ret_val = em_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+        /* Disabled the PHY transmitter */
+        em_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+        msec_delay(20);
+
         em_write_phy_reg(hw,0x0000,0x0140);
 
         msec_delay(5);
 
-        if(hw->mac_type == em_82541 || hw->mac_type == em_82547) {
+        switch(hw->mac_type) {
+        case em_82541:
+        case em_82547:
             em_write_phy_reg(hw, 0x1F95, 0x0001);
 
             em_write_phy_reg(hw, 0x1F71, 0xBD21);
@@ -156,12 +187,23 @@ em_phy_init_script(struct em_hw *hw)
             em_write_phy_reg(hw, 0x1F96, 0x003F);
 
             em_write_phy_reg(hw, 0x2010, 0x0008);
-        } else {
+            break;
+
+        case em_82541_rev_2:
+        case em_82547_rev_2:
             em_write_phy_reg(hw, 0x1F73, 0x0099);
+            break;
+        default:
+            break;
         }
 
         em_write_phy_reg(hw, 0x0000, 0x3300);
 
+        msec_delay(20);
+
+        /* Now enable the transmitter */
+        em_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
         if(hw->mac_type == em_82547) {
             uint16_t fused, fine, coarse;
 
@@ -250,6 +292,7 @@ em_set_mac_type(struct em_hw *hw)
     case E1000_DEV_ID_82546GB_COPPER:
     case E1000_DEV_ID_82546GB_FIBER:
     case E1000_DEV_ID_82546GB_SERDES:
+    case E1000_DEV_ID_82546GB_PCIE:
         hw->mac_type = em_82546_rev_3;
         break;
     case E1000_DEV_ID_82541EI:
@@ -268,11 +311,42 @@ em_set_mac_type(struct em_hw *hw)
     case E1000_DEV_ID_82547GI:
         hw->mac_type = em_82547_rev_2;
         break;
+    case E1000_DEV_ID_82571EB_COPPER:
+    case E1000_DEV_ID_82571EB_FIBER:
+    case E1000_DEV_ID_82571EB_SERDES:
+            hw->mac_type = em_82571;
+        break;
+    case E1000_DEV_ID_82572EI_COPPER:
+    case E1000_DEV_ID_82572EI_FIBER:
+    case E1000_DEV_ID_82572EI_SERDES:
+        hw->mac_type = em_82572;
+        break;
+    case E1000_DEV_ID_82573E:
+    case E1000_DEV_ID_82573E_IAMT:
+    case E1000_DEV_ID_82573L:
+        hw->mac_type = em_82573;
+        break;
     default:
         /* Should never have loaded on this device */
         return -E1000_ERR_MAC_TYPE;
     }
 
+    switch(hw->mac_type) {
+    case em_82571:
+    case em_82572:
+    case em_82573:
+        hw->eeprom_semaphore_present = TRUE;
+        /* fall through */
+    case em_82541:
+    case em_82547:
+    case em_82541_rev_2:
+    case em_82547_rev_2:
+        hw->asf_firmware_present = TRUE;
+        break;
+    default:
+        break;
+    }
+
     return E1000_SUCCESS;
 }
 
@@ -296,21 +370,32 @@ em_set_media_type(struct em_hw *hw)
     switch (hw->device_id) {
     case E1000_DEV_ID_82545GM_SERDES:
     case E1000_DEV_ID_82546GB_SERDES:
+    case E1000_DEV_ID_82571EB_SERDES:
+    case E1000_DEV_ID_82572EI_SERDES:
         hw->media_type = em_media_type_internal_serdes;
         break;
     default:
-        if(hw->mac_type >= em_82543) {
+        switch (hw->mac_type) {
+        case em_82542_rev2_0:
+        case em_82542_rev2_1:
+            hw->media_type = em_media_type_fiber;
+            break;
+        case em_82573:
+            /* The STATUS_TBIMODE bit is reserved or reused for the this
+             * device.
+             */
+            hw->media_type = em_media_type_copper;
+            break;
+        default:
             status = E1000_READ_REG(hw, STATUS);
-            if(status & E1000_STATUS_TBIMODE) {
+            if (status & E1000_STATUS_TBIMODE) {
                 hw->media_type = em_media_type_fiber;
                 /* tbi_compatibility not valid on fiber */
                 hw->tbi_compatibility_en = FALSE;
             } else {
                 hw->media_type = em_media_type_copper;
             }
-        } else {
-            /* This is an 82542 (fiber only) */
-            hw->media_type = em_media_type_fiber;
+            break;
         }
     }
 }
@@ -328,6 +413,9 @@ em_reset_hw(struct em_hw *hw)
     uint32_t icr;
     uint32_t manc;
     uint32_t led_ctrl;
+    uint32_t timeout;
+    uint32_t extcnf_ctrl;
+    int32_t ret_val;
 
     DEBUGFUNC("em_reset_hw");
 
@@ -337,6 +425,15 @@ em_reset_hw(struct em_hw *hw)
         em_pci_clear_mwi(hw);
     }
 
+    if(hw->bus_type == em_bus_type_pci_express) {
+        /* Prevent the PCI-E bus from sticking if there is no TLP connection
+         * on the last TLP read/write transaction when MAC is reset.
+         */
+        if(em_disable_pciex_master(hw) != E1000_SUCCESS) {
+            DEBUGOUT("PCI-E Master disable polling has failed.\n");
+        }
+    }
+
     /* Clear interrupt mask to stop board from generating interrupts */
     DEBUGOUT("Masking off all interrupts\n");
     E1000_WRITE_REG(hw, IMC, 0xffffffff);
@@ -361,10 +458,32 @@ em_reset_hw(struct em_hw *hw)
 
     /* Must reset the PHY before resetting the MAC */
     if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
-        E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
+        E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
         msec_delay(5);
     }
 
+    /* Must acquire the MDIO ownership before MAC reset.
+     * Ownership defaults to firmware after a reset. */
+    if(hw->mac_type == em_82573) {
+        timeout = 10;
+
+        extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+        extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+        do {
+            E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+            extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+
+            if(extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+                break;
+            else
+                extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+            msec_delay(2);
+            timeout--;
+        } while(timeout);
+    }
+
     /* 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-
@@ -418,6 +537,20 @@ em_reset_hw(struct em_hw *hw)
             /* Wait for EEPROM reload */
             msec_delay(20);
             break;
+        case em_82573:
+            usec_delay(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);
+            /* fall through */
+        case em_82571:
+        case em_82572:
+            ret_val = em_get_auto_rd_done(hw);
+            if(ret_val)
+                /* We don't want to continue accessing MAC registers. */
+                return ret_val;
+            break;
         default:
             /* Wait for EEPROM reload (it happens automatically) */
             msec_delay(5);
@@ -425,7 +558,7 @@ em_reset_hw(struct em_hw *hw)
     }
 
     /* Disable HW ARPs on ASF enabled adapters */
-    if(hw->mac_type >= em_82540) {
+    if(hw->mac_type >= em_82540 && hw->mac_type <= em_82547_rev_2) {
         manc = E1000_READ_REG(hw, MANC);
         manc &= ~(E1000_MANC_ARP_EN);
         E1000_WRITE_REG(hw, MANC, manc);
@@ -478,11 +611,13 @@ em_init_hw(struct em_hw *hw)
     uint16_t pcix_stat_hi_word;
     uint16_t cmd_mmrbc;
     uint16_t stat_mmrbc;
+    uint32_t mta_size;
 
     DEBUGFUNC("em_init_hw");
 
     /* Initialize Identification LED */
-    if((ret_val = em_id_led_init(hw))) {
+    ret_val = em_id_led_init(hw);
+    if(ret_val) {
         DEBUGOUT("Error Initializing Identification LED\n");
         return ret_val;
     }
@@ -492,8 +627,8 @@ em_init_hw(struct em_hw *hw)
 
     /* Disabling VLAN filtering. */
     DEBUGOUT("Initializing the IEEE VLAN\n");
-    E1000_WRITE_REG(hw, VET, 0);
-
+    if (hw->mac_type < em_82545_rev_3)
+        E1000_WRITE_REG(hw, VET, 0);
     em_clear_vfta(hw);
 
     /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
@@ -521,14 +656,16 @@ em_init_hw(struct em_hw *hw)
 
     /* Zero out the Multicast HASH table */
     DEBUGOUT("Zeroing the MTA\n");
-    for(i = 0; i < E1000_MC_TBL_SIZE; i++)
+    mta_size = E1000_MC_TBL_SIZE;
+    for(i = 0; i < mta_size; i++)
         E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
 
     /* Set the PCI priority bit correctly in the CTRL register.  This
      * determines if the adapter gives priority to receives, or if it
-     * gives equal priority to transmits and receives.
+     * gives equal priority to transmits and receives.  Valid only on
+     * 82542 and 82543 silicon.
      */
-    if(hw->dma_fairness) {
+    if(hw->dma_fairness && hw->mac_type <= em_82543) {
         ctrl = E1000_READ_REG(hw, CTRL);
         E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
     }
@@ -566,9 +703,44 @@ em_init_hw(struct em_hw *hw)
     if(hw->mac_type > em_82544) {
         ctrl = E1000_READ_REG(hw, TXDCTL);
         ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+        switch (hw->mac_type) {
+        default:
+            break;
+        case em_82571:
+        case em_82572:
+            ctrl |= (1 << 22);
+        case em_82573:
+            ctrl |= E1000_TXDCTL_COUNT_DESC;
+            break;
+        }
         E1000_WRITE_REG(hw, TXDCTL, ctrl);
     }
 
+    if (hw->mac_type == em_82573) {
+        em_enable_tx_pkt_filtering(hw); 
+    }
+
+    switch (hw->mac_type) {
+    default:
+        break;
+    case em_82571:
+    case em_82572:
+        ctrl = E1000_READ_REG(hw, TXDCTL1);
+        ctrl &= ~E1000_TXDCTL_WTHRESH;
+        ctrl |= E1000_TXDCTL_COUNT_DESC | E1000_TXDCTL_FULL_TX_DESC_WB;
+        ctrl |= (1 << 22);
+        E1000_WRITE_REG(hw, TXDCTL1, ctrl);
+        break;
+    }
+
+
+
+    if (hw->mac_type == em_82573) {
+        uint32_t gcr = E1000_READ_REG(hw, GCR);
+        gcr |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+        E1000_WRITE_REG(hw, GCR, gcr);
+    }
+
     /* Clear all of the statistics registers (clear on read).  It is
      * important that we do this after we have tried to establish link
      * because the symbol error count will increment wildly if there
@@ -603,16 +775,16 @@ em_adjust_serdes_amplitude(struct em_hw *hw)
         return E1000_SUCCESS;
     }
 
-    if ((ret_val = em_read_eeprom(hw, EEPROM_SERDES_AMPLITUDE, 1,
-                                     &eeprom_data))) {
+    ret_val = em_read_eeprom(hw, EEPROM_SERDES_AMPLITUDE, 1, &eeprom_data);
+    if (ret_val) {
         return ret_val;
     }
 
     if(eeprom_data != EEPROM_RESERVED_WORD) {
         /* Adjust SERDES output amplitude only. */
         eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK; 
-        if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL,
-                                          eeprom_data)))
+        ret_val = em_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL, eeprom_data);
+        if(ret_val)
             return ret_val;
     }
 
@@ -647,7 +819,7 @@ em_setup_link(struct em_hw *hw)
      * control setting, then the variable hw->fc will
      * be initialized based on a value in the EEPROM.
      */
-    if(em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data) < 0) {
+    if(em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data)) {
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
@@ -704,6 +876,7 @@ em_setup_link(struct em_hw *hw)
     E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
     E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
     E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+
     E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
 
     /* Set the flow control receive threshold registers.  Normally,
@@ -751,6 +924,14 @@ em_setup_fiber_serdes_link(struct em_hw *hw)
 
     DEBUGFUNC("em_setup_fiber_serdes_link");
 
+    /* On 82571 and 82572 Fiber connections, SerDes loopback mode persists
+     * until explicitly turned off or a power cycle is performed.  A read to
+     * the register does not indicate its status.  Therefore, we ensure
+     * loopback mode is disabled during initialization.
+     */
+    if (hw->mac_type == em_82571 || hw->mac_type == em_82572)
+        E1000_WRITE_REG(hw, SCTL, E1000_DISABLE_SERDES_LOOPBACK);
+
     /* 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.  This applies to fiber media only.
@@ -761,14 +942,16 @@ em_setup_fiber_serdes_link(struct em_hw *hw)
     if(hw->media_type == em_media_type_fiber)
         signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0;
 
-    if((ret_val = em_adjust_serdes_amplitude(hw)))
+    ret_val = em_adjust_serdes_amplitude(hw);
+    if(ret_val)
         return ret_val;
 
     /* Take the link out of reset */
     ctrl &= ~(E1000_CTRL_LRST);
 
     /* Adjust VCO speed to improve BER performance */
-    if((ret_val = em_set_vco_speed(hw)))
+    ret_val = em_set_vco_speed(hw);
+    if(ret_val)
         return ret_val;
 
     em_config_collision_dist(hw);
@@ -855,7 +1038,8 @@ em_setup_fiber_serdes_link(struct em_hw *hw)
              * we detect a signal. This will allow us to communicate with
              * non-autonegotiating link partners.
              */
-            if((ret_val = em_check_for_link(hw))) {
+            ret_val = em_check_for_link(hw);
+            if(ret_val) {
                 DEBUGOUT("Error while checking for link\n");
                 return ret_val;
             }
@@ -871,20 +1055,18 @@ em_setup_fiber_serdes_link(struct em_hw *hw)
 }
 
 /******************************************************************************
-* Detects which PHY is present and the speed and duplex
+* Make sure we have a valid PHY and change PHY mode before link setup.
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
 static int32_t
-em_setup_copper_link(struct em_hw *hw)
+em_copper_link_preconfig(struct em_hw *hw)
 {
     uint32_t ctrl;
-    uint32_t led_ctrl;
     int32_t ret_val;
-    uint16_t i;
     uint16_t phy_data;
 
-    DEBUGFUNC("em_setup_copper_link");
+    DEBUGFUNC("em_copper_link_preconfig");
 
     ctrl = E1000_READ_REG(hw, CTRL);
     /* With 82543, we need to force speed and duplex on the MAC equal to what
@@ -898,31 +1080,29 @@ em_setup_copper_link(struct em_hw *hw)
     } else {
         ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
         E1000_WRITE_REG(hw, CTRL, ctrl);
-        em_phy_hw_reset(hw);
+        ret_val = em_phy_hw_reset(hw);
+        if(ret_val)
+            return ret_val;
     }
 
     /* Make sure we have a valid PHY */
-    if((ret_val = em_detect_gig_phy(hw))) {
+    ret_val = em_detect_gig_phy(hw);
+    if(ret_val) {
         DEBUGOUT("Error, did not detect valid phy.\n");
         return ret_val;
     }
     DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
 
     /* Set PHY to class A mode (if necessary) */
-    if ((ret_val = em_set_phy_mode(hw)))
+    ret_val = em_set_phy_mode(hw);
+    if(ret_val)
         return ret_val;
 
     if((hw->mac_type == em_82545_rev_3) ||
        (hw->mac_type == em_82546_rev_3)) {
         ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-        if (ret_val)
-            return ret_val;
-
         phy_data |= 0x00000008;
-
         ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-        if (ret_val)
-            return ret_val;
     }
 
     if(hw->mac_type <= em_82543 ||
@@ -930,347 +1110,465 @@ em_setup_copper_link(struct em_hw *hw)
        hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2)
         hw->phy_reset_disable = FALSE;
 
-    if(!hw->phy_reset_disable) {
-        if (hw->phy_type == em_phy_igp) {
-
-            if((ret_val = em_phy_reset(hw))) {
-                DEBUGOUT("Error Resetting the PHY\n");
-                return ret_val;
-            }
-
-            /* Wait 10ms for MAC to configure PHY from eeprom settings */
-            msec_delay(15);
-
-            /* 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 = em_set_d3_lplu_state(hw, FALSE))) {
-                DEBUGOUT("Error Disabling LPLU D3\n");
-                return ret_val;
-            }
-
-            /* Configure mdi-mdix settings */
-            if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
-                                             &phy_data)))
-                return ret_val;
-
-            if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
-                hw->dsp_config_state = em_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 = em_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 = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
-                                              phy_data)))
-                return ret_val;
-
-            /* set auto-master slave resolution settings */
-            if(hw->autoneg) {
-                em_ms_type phy_ms_setting = hw->master_slave;
-
-                if(hw->ffe_config_state == em_ffe_config_active)
-                    hw->ffe_config_state = em_ffe_config_enabled;
-
-                if(hw->dsp_config_state == em_dsp_config_activated)
-                    hw->dsp_config_state = em_dsp_config_enabled;
+   return E1000_SUCCESS;
+}
 
-                /* 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 = em_read_phy_reg(hw,
-                                                    IGP01E1000_PHY_PORT_CONFIG,
-                                                    &phy_data)))
-                        return ret_val;
-                    phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-                    if((ret_val = em_write_phy_reg(hw,
-                                                     IGP01E1000_PHY_PORT_CONFIG,
-                                                     phy_data)))
-                        return ret_val;
-                    /* Set auto Master/Slave resolution process */
-                    if((ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL,
-                                                     &phy_data)))
-                        return ret_val;
-                    phy_data &= ~CR_1000T_MS_ENABLE;
-                    if((ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL,
-                                                      phy_data)))
-                        return ret_val;
-                }
 
-                if((ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL,
-                                                 &phy_data)))
-                    return ret_val;
+/********************************************************************
+* Copper link setup for em_phy_igp series.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+em_copper_link_igp_setup(struct em_hw *hw)
+{
+    uint32_t led_ctrl;
+    int32_t ret_val;
+    uint16_t phy_data;
 
-                /* load defaults for future use */
-                hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ?
-                                            ((phy_data & CR_1000T_MS_VALUE) ?
-                                             em_ms_force_master :
-                                             em_ms_force_slave) :
-                                             em_ms_auto;
-
-                switch (phy_ms_setting) {
-                case em_ms_force_master:
-                    phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
-                    break;
-                case em_ms_force_slave:
-                    phy_data |= CR_1000T_MS_ENABLE;
-                    phy_data &= ~(CR_1000T_MS_VALUE);
-                    break;
-                case em_ms_auto:
-                    phy_data &= ~CR_1000T_MS_ENABLE;
-                default:
-                    break;
-                }
-                if((ret_val = em_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 = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                             &phy_data)))
-                return ret_val;
+    DEBUGFUNC("em_copper_link_igp_setup");
 
-            phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+    if (hw->phy_reset_disable)
+        return E1000_SUCCESS;
+    
+    ret_val = em_phy_reset(hw);
+    if (ret_val) {
+        DEBUGOUT("Error Resetting the PHY\n");
+        return ret_val;
+    }
 
-            /* Options:
-             *   MDI/MDI-X = 0 (default)
-             *   0 - Auto for all speeds
-             *   1 - MDI mode
-             *   2 - MDI-X mode
-             *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
-             */
-            phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+    /* Wait 10ms for MAC to configure PHY from eeprom settings */
+    msec_delay(15);
 
-            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;
-            }
+    /* 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);
 
-            /* 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 = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                              phy_data)))
-                return ret_val;
+    /* disable lplu d3 during driver init */
+    ret_val = em_set_d3_lplu_state(hw, FALSE);
+    if (ret_val) {
+        DEBUGOUT("Error Disabling LPLU D3\n");
+        return ret_val;
+    }
 
-            /* Force TX_CLK in the Extended PHY Specific Control Register
-             * to 25MHz clock.
-             */
-            if((ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-                                             &phy_data)))
-                return ret_val;
+    /* disable lplu d0 during driver init */
+    ret_val = em_set_d0_lplu_state(hw, FALSE);
+    if (ret_val) {
+        DEBUGOUT("Error Disabling LPLU D0\n");
+        return ret_val;
+    }
+    /* Configure mdi-mdix settings */
+    ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+    if (ret_val)
+        return ret_val;
 
-            phy_data |= M88E1000_EPSCR_TX_CLK_25;
+    if ((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
+        hw->dsp_config_state = em_dsp_config_disabled;
+        /* Force MDI for earlier revs of the IGP PHY */
+        phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | IGP01E1000_PSCR_FORCE_MDI_MDIX);
+        hw->mdix = 1;
 
-            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 = em_write_phy_reg(hw,
-                                                  M88E1000_EXT_PHY_SPEC_CTRL,
-                                                  phy_data)))
-                    return ret_val;
-            }
+    } else {
+        hw->dsp_config_state = em_dsp_config_enabled;
+        phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
 
-            /* SW Reset the PHY so all changes take effect */
-            if((ret_val = em_phy_reset(hw))) {
-                DEBUGOUT("Error Resetting the PHY\n");
-                return ret_val;
-            }
+        switch (hw->mdix) {
+        case 1:
+            phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+            break;
+        case 2:
+            phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+            break;
+        case 0:
+        default:
+            phy_data |= IGP01E1000_PSCR_AUTO_MDIX;
+            break;
         }
+    }
+    ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+    if(ret_val)
+        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.
-         */
+    /* set auto-master slave resolution settings */
+    if(hw->autoneg) {
+        em_ms_type phy_ms_setting = hw->master_slave;
 
-        /* Is autoneg enabled?  This is enabled by default or by software
-         * override.  If so, call em_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 em_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(hw->ffe_config_state == em_ffe_config_active)
+            hw->ffe_config_state = em_ffe_config_enabled;
 
-            /* 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(hw->dsp_config_state == em_dsp_config_activated)
+            hw->dsp_config_state = em_dsp_config_enabled;
 
-            DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
-            if((ret_val = em_phy_setup_autoneg(hw))) {
-                DEBUGOUT("Error Setting up Auto-Negotiation\n");
+        /* when autonegotiation advertisment is only 1000Mbps then we
+          * should disable SmartSpeed and enable Auto MasterSlave
+          * resolution as hardware default. */
+        if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+            /* Disable SmartSpeed */
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+            if(ret_val)
                 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 = em_read_phy_reg(hw, PHY_CTRL, &phy_data)))
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = em_write_phy_reg(hw,
+                                                  IGP01E1000_PHY_PORT_CONFIG,
+                                                  phy_data);
+            if(ret_val)
                 return ret_val;
-
-            phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-            if((ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data)))
+            /* Set auto Master/Slave resolution process */
+            ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+            if(ret_val)
                 return ret_val;
-
-            /* Does the user want to wait for Auto-Neg to complete here, or
-             * check at a later time (for example, callback routine).
-             */
-            if(hw->wait_autoneg_complete) {
-                if((ret_val = em_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 = em_phy_force_speed_duplex(hw))) {
-                DEBUGOUT("Error Forcing Speed and Duplex\n");
+            phy_data &= ~CR_1000T_MS_ENABLE;
+            ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+            if(ret_val)
                 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((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data)))
-            return ret_val;
-        if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+        if(ret_val)
             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
-             *      if we are on 82543.  If we
-             *      are on newer silicon, we only need to configure
-             *      collision distance in the Transmit Control Register.
-             *   2) Set up flow control on the MAC to that established with
-             *      the link partner.
-             */
-            if(hw->mac_type >= em_82544) {
-                em_config_collision_dist(hw);
-            } else {
-                if((ret_val = em_config_mac_to_phy(hw))) {
-                    DEBUGOUT("Error configuring MAC to PHY settings\n");
-                    return ret_val;
-                }
-            }
-            if((ret_val = em_config_fc_after_link_up(hw))) {
-                DEBUGOUT("Error Configuring Flow Control\n");
-                return ret_val;
-            }
-            DEBUGOUT("Valid link established!!!\n");
+        /* load defaults for future use */
+        hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ?
+                                        ((phy_data & CR_1000T_MS_VALUE) ?
+                                         em_ms_force_master :
+                                         em_ms_force_slave) :
+                                         em_ms_auto;
 
-            if(hw->phy_type == em_phy_igp) {
-                if((ret_val = em_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;
+        switch (phy_ms_setting) {
+        case em_ms_force_master:
+            phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+            break;
+        case em_ms_force_slave:
+            phy_data |= CR_1000T_MS_ENABLE;
+            phy_data &= ~(CR_1000T_MS_VALUE);
+            break;
+        case em_ms_auto:
+            phy_data &= ~CR_1000T_MS_ENABLE;
+            default:
+            break;
         }
-        usec_delay(10);
+        ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
     }
 
-    DEBUGOUT("Unable to establish link!!!\n");
     return E1000_SUCCESS;
 }
 
-/******************************************************************************
-* Configures PHY autoneg and flow control advertisement settings
+
+/********************************************************************
+* Copper link setup for em_phy_m88 series.
 *
 * hw - Struct containing variables accessed by shared code
-******************************************************************************/
-int32_t
-em_phy_setup_autoneg(struct em_hw *hw)
+*********************************************************************/
+static int32_t
+em_copper_link_mgp_setup(struct em_hw *hw)
 {
     int32_t ret_val;
-    uint16_t mii_autoneg_adv_reg;
-    uint16_t mii_1000t_ctrl_reg;
-
-    DEBUGFUNC("em_phy_setup_autoneg");
+    uint16_t phy_data;
 
-    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
-    if((ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV,
-                                     &mii_autoneg_adv_reg)))
-        return ret_val;
+    DEBUGFUNC("em_copper_link_mgp_setup");
 
-    /* Read the MII 1000Base-T Control Register (Address 9). */
-    if((ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg)))
+    if(hw->phy_reset_disable)
+        return E1000_SUCCESS;
+    
+    /* Enable CRS on TX. This must be set for half-duplex operation. */
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+    if(ret_val)
         return ret_val;
 
-    /* Need to parse both autoneg_advertised and fc and set up
-     * the appropriate PHY registers.  First we will parse for
-     * autoneg_advertised software override.  Since we can advertise
-     * a plethora of combinations, we need to check each bit
-     * individually.
-     */
+    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
 
-    /* First we clear all the 10/100 mb speed bits in the Auto-Neg
-     * Advertisement Register (Address 4) and the 1000 mb speed bits in
-     * the  1000Base-T Control Register (Address 9).
+    /* 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)
      */
-    mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
-    mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
 
-    DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
+    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;
+        ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
+
+    /* Force TX_CLK in the Extended PHY Specific Control Register
+     * to 25MHz clock.
+     */
+    ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+    if (hw->phy_revision < 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);
+        ret_val = em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
+            return ret_val;
+    }
+
+    /* SW Reset the PHY so all changes take effect */
+    ret_val = em_phy_reset(hw);
+    if(ret_val) {
+        DEBUGOUT("Error Resetting the PHY\n");
+        return ret_val;
+    }
+
+   return E1000_SUCCESS;
+}
+
+/********************************************************************
+* Setup auto-negotiation and flow control advertisements,
+* and then perform auto-negotiation.
+*
+* hw - Struct containing variables accessed by shared code
+*********************************************************************/
+static int32_t
+em_copper_link_autoneg(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_copper_link_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;
+
+    DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+    ret_val = em_phy_setup_autoneg(hw);
+    if(ret_val) {
+        DEBUGOUT("Error Setting up Auto-Negotiation\n");
+        return ret_val;
+    }
+    DEBUGOUT("Restarting Auto-Neg\n");
+
+    /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+     * the Auto Neg Restart bit in the PHY control register.
+     */
+    ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data);
+    if(ret_val)
+        return ret_val;
+
+    phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+    ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data);
+    if(ret_val)
+        return ret_val;
+
+    /* Does the user want to wait for Auto-Neg to complete here, or
+     * check at a later time (for example, callback routine).
+     */
+    if(hw->wait_autoneg_complete) {
+        ret_val = em_wait_autoneg(hw);
+        if(ret_val) {
+            DEBUGOUT("Error while waiting for autoneg to complete\n");
+            return ret_val;
+        }
+    }
+
+    hw->get_link_status = TRUE;
+
+    return E1000_SUCCESS;
+}
+
+
+/******************************************************************************
+* Config the MAC and the PHY after link is up.
+*   1) Set up the MAC to the current PHY speed/duplex
+*      if we are on 82543.  If we
+*      are on newer silicon, we only need to configure
+*      collision distance in the Transmit Control Register.
+*   2) Set up flow control on the MAC to that established with
+*      the link partner.
+*   3) Config DSP to improve Gigabit link quality for some PHY revisions.    
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_copper_link_postconfig(struct em_hw *hw)
+{
+    int32_t ret_val;
+    DEBUGFUNC("em_copper_link_postconfig");
+    
+    if(hw->mac_type >= em_82544) {
+        em_config_collision_dist(hw);
+    } else {
+        ret_val = em_config_mac_to_phy(hw);
+        if(ret_val) {
+            DEBUGOUT("Error configuring MAC to PHY settings\n");
+            return ret_val;
+        }
+    }
+    ret_val = em_config_fc_after_link_up(hw);
+    if(ret_val) {
+        DEBUGOUT("Error Configuring Flow Control\n");
+        return ret_val;
+    }
+
+    /* Config DSP to improve Giga link quality */
+    if(hw->phy_type == em_phy_igp) {
+        ret_val = em_config_dsp_after_link_change(hw, TRUE);
+        if(ret_val) {
+            DEBUGOUT("Error Configuring DSP after link up\n");
+            return ret_val;
+        }
+    }
+                
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Detects which PHY is present and setup the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+em_setup_copper_link(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t i;
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_setup_copper_link");
+
+    /* Check if it is a valid PHY and set PHY mode if necessary. */
+    ret_val = em_copper_link_preconfig(hw);
+    if(ret_val)
+        return ret_val;
+
+    if (hw->phy_type == em_phy_igp ||
+        hw->phy_type == em_phy_igp_2) {
+        ret_val = em_copper_link_igp_setup(hw);
+        if(ret_val)
+            return ret_val;
+    } else if (hw->phy_type == em_phy_m88) {
+        ret_val = em_copper_link_mgp_setup(hw);
+        if(ret_val)
+            return ret_val;
+    }
+
+    if(hw->autoneg) {
+        /* Setup autoneg and flow control advertisement 
+          * and perform autonegotiation */   
+        ret_val = em_copper_link_autoneg(hw);
+        if(ret_val)
+            return ret_val;           
+    } else {
+        /* PHY will be set to 10H, 10F, 100H,or 100F
+          * depending on value from forced_speed_duplex. */
+        DEBUGOUT("Forcing speed and duplex\n");
+        ret_val = em_phy_force_speed_duplex(hw);
+        if(ret_val) {
+            DEBUGOUT("Error Forcing Speed and Duplex\n");
+            return ret_val;
+        }
+    }
+
+    /* Check link status. Wait up to 100 microseconds for link to become
+     * valid.
+     */
+    for(i = 0; i < 10; i++) {
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        if(phy_data & MII_SR_LINK_STATUS) {
+            /* Config the MAC and PHY after link is up */
+            ret_val = em_copper_link_postconfig(hw);
+            if(ret_val)
+                return ret_val;
+            
+            DEBUGOUT("Valid link established!!!\n");
+            return E1000_SUCCESS;
+        }
+        usec_delay(10);
+    }
+
+    DEBUGOUT("Unable to establish link!!!\n");
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Configures PHY autoneg and flow control advertisement settings
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+em_phy_setup_autoneg(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t mii_autoneg_adv_reg;
+    uint16_t mii_1000t_ctrl_reg;
+
+    DEBUGFUNC("em_phy_setup_autoneg");
+
+    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+    ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+    if(ret_val)
+        return ret_val;
+
+        /* Read the MII 1000Base-T Control Register (Address 9). */
+        ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+        if(ret_val)
+            return ret_val;
+
+    /* Need to parse both autoneg_advertised and fc and set up
+     * the appropriate PHY registers.  First we will parse for
+     * autoneg_advertised software override.  Since we can advertise
+     * a plethora of combinations, we need to check each bit
+     * individually.
+     */
+
+    /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+     * Advertisement Register (Address 4) and the 1000 mb speed bits in
+     * the  1000Base-T Control Register (Address 9).
+     */
+    mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
+    mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+
+    DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
 
     /* Do we want to advertise 10 Mb Half Duplex? */
     if(hw->autoneg_advertised & ADVERTISE_10_HALF) {
@@ -1360,13 +1658,14 @@ em_phy_setup_autoneg(struct em_hw *hw)
         return -E1000_ERR_CONFIG;
     }
 
-    if((ret_val = em_write_phy_reg(hw, PHY_AUTONEG_ADV,
-                                      mii_autoneg_adv_reg)))
+    ret_val = em_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+    if(ret_val)
         return ret_val;
 
     DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
 
-    if((ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg)))
+    ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);    
+    if(ret_val)
         return ret_val;
 
     return E1000_SUCCESS;
@@ -1405,7 +1704,8 @@ em_phy_force_speed_duplex(struct em_hw *hw)
     ctrl &= ~E1000_CTRL_ASDE;
 
     /* Read the MII Control Register. */
-    if((ret_val = em_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg)))
+    ret_val = em_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg);
+    if(ret_val)
         return ret_val;
 
     /* We need to disable autoneg in order to force link and duplex. */
@@ -1452,16 +1752,16 @@ em_phy_force_speed_duplex(struct em_hw *hw)
     E1000_WRITE_REG(hw, CTRL, ctrl);
 
     if (hw->phy_type == em_phy_m88) {
-        if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                         &phy_data)))
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+        if(ret_val)
             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((ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                          phy_data)))
+        ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
             return ret_val;
 
         DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
@@ -1472,20 +1772,21 @@ em_phy_force_speed_duplex(struct em_hw *hw)
         /* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
          * forced whenever speed or duplex are forced.
          */
-        if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
-                                         &phy_data)))
+        ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
         phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
 
-        if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
-                                          phy_data)))
+        ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+        if(ret_val)
             return ret_val;
     }
 
     /* Write back the modified PHY MII control register. */
-    if((ret_val = em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg)))
+    ret_val = em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg);
+    if(ret_val)
         return ret_val;
 
     usec_delay(1);
@@ -1507,18 +1808,22 @@ em_phy_force_speed_duplex(struct em_hw *hw)
             /* Read the MII Status Register and wait for Auto-Neg Complete bit
              * to be set.
              */
-            if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+            ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
                 return ret_val;
 
-            if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+            ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
                 return ret_val;
 
             if(mii_status_reg & MII_SR_LINK_STATUS) break;
             msec_delay(100);
         }
-        if((i == 0) && (hw->phy_type == em_phy_m88)) {
+        if((i == 0) &&
+           (hw->phy_type == em_phy_m88)) {
             /* We didn't get link.  Reset the DSP and wait again for link. */
-            if((ret_val = em_phy_reset_dsp(hw))) {
+            ret_val = em_phy_reset_dsp(hw);
+            if(ret_val) {
                 DEBUGOUT("Error Resetting PHY DSP\n");
                 return ret_val;
             }
@@ -1530,10 +1835,12 @@ em_phy_force_speed_duplex(struct em_hw *hw)
             /* Read the MII Status Register and wait for Auto-Neg Complete bit
              * to be set.
              */
-            if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+            ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
                 return ret_val;
 
-            if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+            ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
                 return ret_val;
         }
     }
@@ -1543,26 +1850,35 @@ em_phy_force_speed_duplex(struct em_hw *hw)
          * Extended PHY Specific Control Register to 25MHz clock.  This value
          * defaults back to a 2.5MHz clock when the PHY is reset.
          */
-        if((ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-                                         &phy_data)))
+        ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data |= M88E1000_EPSCR_TX_CLK_25;
-        if((ret_val = em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-                                          phy_data)))
+        ret_val = em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
             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((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                         &phy_data)))
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-        if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                          phy_data)))
+        ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
             return ret_val;
+
+        if((hw->mac_type == em_82544 || hw->mac_type == em_82543) &&
+           (!hw->autoneg) &&
+           (hw->forced_speed_duplex == em_10_full ||
+            hw->forced_speed_duplex == em_10_half)) {
+            ret_val = em_polarity_reversal_workaround(hw);
+            if(ret_val)
+                return ret_val;
+        }
     }
     return E1000_SUCCESS;
 }
@@ -1609,6 +1925,11 @@ em_config_mac_to_phy(struct em_hw *hw)
 
     DEBUGFUNC("em_config_mac_to_phy");
 
+    /* 82544 or newer MAC, Auto Speed Detection takes care of 
+    * MAC speed/duplex configuration.*/
+    if (hw->mac_type >= em_82544)
+        return E1000_SUCCESS;
+
     /* Read the Device Control Register and set the bits to Force Speed
      * and Duplex.
      */
@@ -1619,43 +1940,25 @@ em_config_mac_to_phy(struct em_hw *hw)
     /* Set up duplex in the Device Control and Transmit Control
      * registers depending on negotiated values.
      */
-    if (hw->phy_type == em_phy_igp) {
-        if((ret_val = em_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;
-
-        em_config_collision_dist(hw);
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+    if(ret_val)
+        return ret_val;
 
-        /* Set up speed in the Device Control register depending on
-         * negotiated values.
-         */
-        if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
-           IGP01E1000_PSSR_SPEED_1000MBPS)
-            ctrl |= E1000_CTRL_SPD_1000;
-        else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
-                IGP01E1000_PSSR_SPEED_100MBPS)
-            ctrl |= E1000_CTRL_SPD_100;
-    } else {
-        if((ret_val = em_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;
 
-        if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
-        else ctrl &= ~E1000_CTRL_FD;
+    em_config_collision_dist(hw);
 
-        em_config_collision_dist(hw);
+    /* Set up speed in the Device Control register depending on
+     * negotiated values.
+     */
+    if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+        ctrl |= E1000_CTRL_SPD_1000;
+    else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+        ctrl |= E1000_CTRL_SPD_100;
 
-        /* Set up speed in the Device Control register depending on
-         * negotiated values.
-         */
-        if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
-            ctrl |= E1000_CTRL_SPD_1000;
-        else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
-            ctrl |= E1000_CTRL_SPD_100;
-    }
     /* Write the configured values back to the Device Control Reg. */
     E1000_WRITE_REG(hw, CTRL, ctrl);
     return E1000_SUCCESS;
@@ -1758,7 +2061,8 @@ em_config_fc_after_link_up(struct em_hw *hw)
     if(((hw->media_type == em_media_type_fiber) && (hw->autoneg_failed)) ||
        ((hw->media_type == em_media_type_internal_serdes) && (hw->autoneg_failed)) ||
        ((hw->media_type == em_media_type_copper) && (!hw->autoneg))) {
-        if((ret_val = em_force_mac_fc(hw))) {
+        ret_val = em_force_mac_fc(hw);
+        if(ret_val) {
             DEBUGOUT("Error forcing flow control settings\n");
             return ret_val;
         }
@@ -1774,9 +2078,11 @@ em_config_fc_after_link_up(struct em_hw *hw)
          * has completed.  We read this twice because this reg has
          * some "sticky" (latched) bits.
          */
-        if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
             return ret_val;
-        if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
             return ret_val;
 
         if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
@@ -1786,11 +2092,13 @@ em_config_fc_after_link_up(struct em_hw *hw)
              * Register (Address 5) to determine how flow control was
              * negotiated.
              */
-            if((ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV,
-                                             &mii_nway_adv_reg)))
+            ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV,
+                                         &mii_nway_adv_reg);
+            if(ret_val)
                 return ret_val;
-            if((ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY,
-                                             &mii_nway_lp_ability_reg)))
+            ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY,
+                                         &mii_nway_lp_ability_reg);
+            if(ret_val)
                 return ret_val;
 
             /* Two bits in the Auto Negotiation Advertisement Register
@@ -1907,7 +2215,8 @@ em_config_fc_after_link_up(struct em_hw *hw)
              * negotiated to HALF DUPLEX, flow control should not be
              * enabled per IEEE 802.3 spec.
              */
-            if((ret_val = em_get_speed_and_duplex(hw, &speed, &duplex))) {
+            ret_val = em_get_speed_and_duplex(hw, &speed, &duplex);
+            if(ret_val) {
                 DEBUGOUT("Error getting link speed and duplex\n");
                 return ret_val;
             }
@@ -1918,7 +2227,8 @@ em_config_fc_after_link_up(struct em_hw *hw)
             /* Now we call a subroutine to actually force the MAC
              * controller to use the correct flow control settings.
              */
-            if((ret_val = em_force_mac_fc(hw))) {
+            ret_val = em_force_mac_fc(hw);
+            if(ret_val) {
                 DEBUGOUT("Error forcing flow control settings\n");
                 return ret_val;
             }
@@ -1943,6 +2253,7 @@ em_check_for_link(struct em_hw *hw)
     uint32_t ctrl;
     uint32_t status;
     uint32_t rctl;
+    uint32_t icr;
     uint32_t signal = 0;
     int32_t ret_val;
     uint16_t phy_data;
@@ -1979,9 +2290,11 @@ em_check_for_link(struct em_hw *hw)
          * of the PHY.
          * Read the register twice since the link bit is sticky.
          */
-        if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
-        if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
 
         if(phy_data & MII_SR_LINK_STATUS) {
@@ -1990,6 +2303,25 @@ em_check_for_link(struct em_hw *hw)
              * link-up */
             em_check_downshift(hw);
 
+            /* If we are on 82544 or 82543 silicon and speed/duplex
+             * are forced to 10H or 10F, then we will implement the polarity
+             * reversal workaround.  We disable interrupts first, and upon
+             * returning, place the devices interrupt state to its previous
+             * value except for the link status change interrupt which will
+             * happen due to the execution of this workaround.
+             */
+
+            if((hw->mac_type == em_82544 || hw->mac_type == em_82543) &&
+               (!hw->autoneg) &&
+               (hw->forced_speed_duplex == em_10_full ||
+                hw->forced_speed_duplex == em_10_half)) {
+                E1000_WRITE_REG(hw, IMC, 0xffffffff);
+                ret_val = em_polarity_reversal_workaround(hw);
+                icr = E1000_READ_REG(hw, ICR);
+                E1000_WRITE_REG(hw, ICS, (icr & ~E1000_ICS_LSC));
+                E1000_WRITE_REG(hw, IMS, IMS_ENABLE_MASK);
+            }
+
         } else {
             /* No link detected */
             em_config_dsp_after_link_change(hw, FALSE);
@@ -2015,7 +2347,8 @@ em_check_for_link(struct em_hw *hw)
         if(hw->mac_type >= em_82544)
             em_config_collision_dist(hw);
         else {
-            if((ret_val = em_config_mac_to_phy(hw))) {
+            ret_val = em_config_mac_to_phy(hw);
+            if(ret_val) {
                 DEBUGOUT("Error configuring MAC to PHY settings\n");
                 return ret_val;
             }
@@ -2025,7 +2358,8 @@ em_check_for_link(struct em_hw *hw)
          * need to restore the desired flow control settings because we may
          * have had to re-autoneg with a different link partner.
          */
-        if((ret_val = em_config_fc_after_link_up(hw))) {
+        ret_val = em_config_fc_after_link_up(hw);
+        if(ret_val) {
             DEBUGOUT("Error configuring flow control\n");
             return ret_val;
         }
@@ -2037,7 +2371,7 @@ em_check_for_link(struct em_hw *hw)
          * at gigabit speed, then TBI compatibility is not needed.  If we are
          * at gigabit speed, we turn on TBI compatibility.
          */
-       if(hw->tbi_compatibility_en) {
+        if(hw->tbi_compatibility_en) {
             uint16_t speed, duplex;
             em_get_speed_and_duplex(hw, &speed, &duplex);
             if(speed != SPEED_1000) {
@@ -2074,8 +2408,8 @@ em_check_for_link(struct em_hw *hw)
      * in. The autoneg_failed flag does this.
      */
     else if((((hw->media_type == em_media_type_fiber) &&
-            ((ctrl & E1000_CTRL_SWDPIN1) == signal)) ||
-            (hw->media_type == em_media_type_internal_serdes)) &&
+              ((ctrl & E1000_CTRL_SWDPIN1) == signal)) ||
+             (hw->media_type == em_media_type_internal_serdes)) &&
             (!(status & E1000_STATUS_LU)) &&
             (!(rxcw & E1000_RXCW_C))) {
         if(hw->autoneg_failed == 0) {
@@ -2093,7 +2427,8 @@ em_check_for_link(struct em_hw *hw)
         E1000_WRITE_REG(hw, CTRL, ctrl);
 
         /* Configure Flow Control after forcing link up. */
-        if((ret_val = em_config_fc_after_link_up(hw))) {
+        ret_val = em_config_fc_after_link_up(hw);
+        if(ret_val) {
             DEBUGOUT("Error configuring flow control\n");
             return ret_val;
         }
@@ -2105,8 +2440,7 @@ em_check_for_link(struct em_hw *hw)
      */
     else if(((hw->media_type == em_media_type_fiber) ||
              (hw->media_type == em_media_type_internal_serdes)) &&
-              (ctrl & E1000_CTRL_SLU) &&
-              (rxcw & E1000_RXCW_C)) {
+            (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));
@@ -2186,13 +2520,15 @@ em_get_speed_and_duplex(struct em_hw *hw,
      * match the duplex in the link partner's capabilities.
      */
     if(hw->phy_type == em_phy_igp && hw->speed_downgraded) {
-        if((ret_val = em_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data)))
+        ret_val = em_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
+        if(ret_val)
             return ret_val;
 
         if(!(phy_data & NWAY_ER_LP_NWAY_CAPS))
             *duplex = HALF_DUPLEX;
         else {
-            if((ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data)))
+            ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data);
+            if(ret_val)
                 return ret_val;
             if((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) ||
                (*speed == SPEED_10 && !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
@@ -2223,9 +2559,11 @@ em_wait_autoneg(struct em_hw *hw)
         /* Read the MII Status Register and wait for Auto-Neg
          * Complete bit to be set.
          */
-        if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
-        if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
         if(phy_data & MII_SR_AUTONEG_COMPLETE) {
             return E1000_SUCCESS;
@@ -2388,14 +2726,17 @@ em_read_phy_reg(struct em_hw *hw,
 
     DEBUGFUNC("em_read_phy_reg");
 
-    if(hw->phy_type == em_phy_igp &&
+    if((hw->phy_type == em_phy_igp || 
+        hw->phy_type == em_phy_igp_2) &&
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
-        if((ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
-                                             (uint16_t)reg_addr)))
+        ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                         (uint16_t)reg_addr);
+        if(ret_val) {
             return ret_val;
+        }
     }
 
-    ret_val = em_read_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
+    ret_val = em_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
                                     phy_data);
 
     return ret_val;
@@ -2491,14 +2832,17 @@ em_write_phy_reg(struct em_hw *hw,
 
     DEBUGFUNC("em_write_phy_reg");
 
-    if(hw->phy_type == em_phy_igp &&
+    if((hw->phy_type == em_phy_igp || 
+        hw->phy_type == em_phy_igp_2) &&
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
-        if((ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
-                                             (uint16_t)reg_addr)))
+        ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                         (uint16_t)reg_addr);
+        if(ret_val) {
             return ret_val;
+        }
     }
 
-    ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
+    ret_val = em_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
                                      phy_data);
 
     return ret_val;
@@ -2567,19 +2911,27 @@ em_write_phy_reg_ex(struct em_hw *hw,
     return E1000_SUCCESS;
 }
 
+
 /******************************************************************************
 * Returns the PHY to the power-on reset state
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
-void
+int32_t
 em_phy_hw_reset(struct em_hw *hw)
 {
     uint32_t ctrl, ctrl_ext;
     uint32_t led_ctrl;
+    int32_t ret_val;
 
     DEBUGFUNC("em_phy_hw_reset");
 
+    /* In the case of the phy reset being blocked, it's not an error, we
+     * simply return success without performing the reset. */
+    ret_val = em_check_phy_reset_block(hw);
+    if (ret_val)
+        return E1000_SUCCESS;
+
     DEBUGOUT("Resetting Phy...\n");
 
     if(hw->mac_type > em_82543) {
@@ -2615,6 +2967,11 @@ em_phy_hw_reset(struct em_hw *hw)
         led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
         E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
     }
+
+    /* Wait for FW to finish PHY configuration. */
+    ret_val = em_get_phy_cfg_done(hw);
+
+    return ret_val;
 }
 
 /******************************************************************************
@@ -2632,18 +2989,35 @@ em_phy_reset(struct em_hw *hw)
 
     DEBUGFUNC("em_phy_reset");
 
-    if(hw->mac_type != em_82541_rev_2) {
-        if((ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data)))
+    /* In the case of the phy reset being blocked, it's not an error, we
+     * simply return success without performing the reset. */
+    ret_val = em_check_phy_reset_block(hw);
+    if (ret_val)
+        return E1000_SUCCESS;
+
+    switch (hw->mac_type) {
+    case em_82541_rev_2:
+    case em_82571:
+    case em_82572:
+        ret_val = em_phy_hw_reset(hw);
+        if(ret_val)
+            return ret_val;
+        break;
+    default:
+        ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data |= MII_CR_RESET;
-        if((ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data)))
+        ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data);
+        if(ret_val)
             return ret_val;
 
         usec_delay(1);
-    } else em_phy_hw_reset(hw);
+        break;
+    }
 
-    if(hw->phy_type == em_phy_igp)
+    if(hw->phy_type == em_phy_igp || hw->phy_type == em_phy_igp_2)
         em_phy_init_script(hw);
 
     return E1000_SUCCESS;
@@ -2663,13 +3037,25 @@ em_detect_gig_phy(struct em_hw *hw)
 
     DEBUGFUNC("em_detect_gig_phy");
 
+    /* The 82571 firmware may still be configuring the PHY.  In this
+     * case, we cannot access the PHY until the configuration is done.  So
+     * we explicitly set the PHY values. */
+    if(hw->mac_type == em_82571 ||
+       hw->mac_type == em_82572) {
+        hw->phy_id = IGP01E1000_I_PHY_ID;
+        hw->phy_type = em_phy_igp_2;
+        return E1000_SUCCESS;
+    }
+
     /* Read the PHY ID Registers to identify which PHY is onboard. */
-    if((ret_val = em_read_phy_reg(hw, PHY_ID1, &phy_id_high)))
+    ret_val = em_read_phy_reg(hw, PHY_ID1, &phy_id_high);
+    if(ret_val)
         return ret_val;
 
     hw->phy_id = (uint32_t) (phy_id_high << 16);
     usec_delay(20);
-    if((ret_val = em_read_phy_reg(hw, PHY_ID2, &phy_id_low)))
+    ret_val = em_read_phy_reg(hw, PHY_ID2, &phy_id_low);
+    if(ret_val)
         return ret_val;
 
     hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
@@ -2695,6 +3081,9 @@ em_detect_gig_phy(struct em_hw *hw)
     case em_82547_rev_2:
         if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
         break;
+    case em_82573:
+        if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE;
+        break;
     default:
         DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
         return -E1000_ERR_CONFIG;
@@ -2721,9 +3110,12 @@ em_phy_reset_dsp(struct em_hw *hw)
     DEBUGFUNC("em_phy_reset_dsp");
 
     do {
-        if((ret_val = em_write_phy_reg(hw, 29, 0x001d))) break;
-        if((ret_val = em_write_phy_reg(hw, 30, 0x00c1))) break;
-        if((ret_val = em_write_phy_reg(hw, 30, 0x0000))) break;
+        ret_val = em_write_phy_reg(hw, 29, 0x001d);
+        if(ret_val) break;
+        ret_val = em_write_phy_reg(hw, 30, 0x00c1);
+        if(ret_val) break;
+        ret_val = em_write_phy_reg(hw, 30, 0x0000);
+        if(ret_val) break;
         ret_val = E1000_SUCCESS;
     } while(0);
 
@@ -2747,7 +3139,7 @@ em_phy_igp_get_info(struct em_hw *hw,
 
     /* The downshift status is checked only once, after link is established,
      * and it stored in the hw->speed_downgraded parameter. */
-    phy_info->downshift = hw->speed_downgraded;
+    phy_info->downshift = (em_downshift)hw->speed_downgraded;
 
     /* IGP01E1000 does not need to support it. */
     phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_normal;
@@ -2756,13 +3148,14 @@ em_phy_igp_get_info(struct em_hw *hw,
     phy_info->polarity_correction = em_polarity_reversal_enabled;
 
     /* Check polarity status */
-    if((ret_val = em_check_polarity(hw, &polarity)))
+    ret_val = em_check_polarity(hw, &polarity);
+    if(ret_val)
         return ret_val;
 
     phy_info->cable_polarity = polarity;
 
-    if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
-                                     &phy_data)))
+    ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data);
+    if(ret_val)
         return ret_val;
 
     phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
@@ -2771,7 +3164,8 @@ em_phy_igp_get_info(struct em_hw *hw,
     if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
        IGP01E1000_PSSR_SPEED_1000MBPS) {
         /* Local/Remote Receiver Information are only valid at 1000 Mbps */
-        if((ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data)))
+        ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
@@ -2780,10 +3174,11 @@ em_phy_igp_get_info(struct em_hw *hw,
                               SR_1000T_REMOTE_RX_STATUS_SHIFT;
 
         /* Get cable length */
-        if((ret_val = em_get_cable_length(hw, &min_length, &max_length)))
+        ret_val = em_get_cable_length(hw, &min_length, &max_length);
+        if(ret_val)
             return ret_val;
 
-        /* transalte to old method */
+        /* Translate to old method */
         average = (max_length + min_length) / 2;
 
         if(average <= em_igp_cable_length_50)
@@ -2818,9 +3213,10 @@ em_phy_m88_get_info(struct em_hw *hw,
 
     /* The downshift status is checked only once, after link is established,
      * and it stored in the hw->speed_downgraded parameter. */
-    phy_info->downshift = hw->speed_downgraded;
+    phy_info->downshift = (em_downshift)hw->speed_downgraded;
 
-    if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data)))
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+    if(ret_val)
         return ret_val;
 
     phy_info->extended_10bt_distance =
@@ -2831,25 +3227,27 @@ em_phy_m88_get_info(struct em_hw *hw,
         M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
 
     /* Check polarity status */
-    if((ret_val = em_check_polarity(hw, &polarity)))
-        return ret_val;
-
+    ret_val = em_check_polarity(hw, &polarity);
+    if(ret_val)
+        return ret_val; 
     phy_info->cable_polarity = polarity;
 
-    if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data)))
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+    if(ret_val)
         return ret_val;
 
     phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
                           M88E1000_PSSR_MDIX_SHIFT;
 
-    if(phy_data & M88E1000_PSSR_1000MBS) {
-        /* Cable Length Estimation and Local/Remote Receiver Informatoion
-         * are only valid at 1000 Mbps
+    if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+        /* Cable Length Estimation and Local/Remote Receiver Information
+         * are only valid at 1000 Mbps.
          */
         phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
                                   M88E1000_PSSR_CABLE_LENGTH_SHIFT);
 
-        if((ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data)))
+        ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
@@ -2891,10 +3289,12 @@ em_phy_get_info(struct em_hw *hw,
         return -E1000_ERR_CONFIG;
     }
 
-    if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+    ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+    if(ret_val)
         return ret_val;
 
-    if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+    ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data);
+    if(ret_val)
         return ret_val;
 
     if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
@@ -2902,7 +3302,8 @@ em_phy_get_info(struct em_hw *hw,
         return -E1000_ERR_CONFIG;
     }
 
-    if(hw->phy_type == em_phy_igp)
+    if(hw->phy_type == em_phy_igp ||
+        hw->phy_type == em_phy_igp_2)
         return em_phy_igp_get_info(hw, phy_info);
     else
         return em_phy_m88_get_info(hw, phy_info);
@@ -2913,12 +3314,6 @@ em_validate_mdi_setting(struct em_hw *hw)
 {
     DEBUGFUNC("em_validate_mdi_settings");
 
-#ifdef RK_SV
-    /* Don't disable MDI-X for 82570/1 */
-    if(hw->phy_type == em_phy_igp_2)
-        return E1000_SUCCESS;
-#endif
-
     if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
         DEBUGOUT("Invalid MDI setting detected\n");
         hw->mdix = 1;
@@ -2934,11 +3329,12 @@ em_validate_mdi_setting(struct em_hw *hw)
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
-void
+int32_t
 em_init_eeprom_params(struct em_hw *hw)
 {
     struct em_eeprom_info *eeprom = &hw->eeprom;
     uint32_t eecd = E1000_READ_REG(hw, EECD);
+    int32_t ret_val = E1000_SUCCESS;
     uint16_t eeprom_size;
 
     DEBUGFUNC("em_init_eeprom_params");
@@ -2953,6 +3349,8 @@ em_init_eeprom_params(struct em_hw *hw)
         eeprom->opcode_bits = 3;
         eeprom->address_bits = 6;
         eeprom->delay_usec = 50;
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
         break;
     case em_82540:
     case em_82545:
@@ -2969,6 +3367,8 @@ em_init_eeprom_params(struct em_hw *hw)
             eeprom->word_size = 64;
             eeprom->address_bits = 6;
         }
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
         break;
     case em_82541:
     case em_82541_rev_2:
@@ -2997,8 +3397,11 @@ em_init_eeprom_params(struct em_hw *hw)
                 eeprom->address_bits = 6;
             }
         }
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
         break;
-    default:
+    case em_82571:
+    case em_82572:
         eeprom->type = em_eeprom_spi;
         eeprom->opcode_bits = 8;
         eeprom->delay_usec = 1;
@@ -3009,40 +3412,60 @@ em_init_eeprom_params(struct em_hw *hw)
             eeprom->page_size = 8;
             eeprom->address_bits = 8;
         }
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
         break;
-    }
-
-    if (eeprom->type == em_eeprom_spi) {
-        eeprom->word_size = 64;
-        if (em_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size) == 0) {
-            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 em_82573:
+        eeprom->type = em_eeprom_spi;
+        eeprom->opcode_bits = 8;
+        eeprom->delay_usec = 1;
+        if (eecd & E1000_EECD_ADDR_BITS) {
+            eeprom->page_size = 32;
+            eeprom->address_bits = 16;
+        } else {
+            eeprom->page_size = 8;
+            eeprom->address_bits = 8;
+        }
+        eeprom->use_eerd = TRUE;
+        eeprom->use_eewr = TRUE;
+        if(em_is_onboard_nvm_eeprom(hw) == FALSE) {
+            eeprom->type = em_eeprom_flash;
+            eeprom->word_size = 2048;
+
+            /* Ensure that the Autonomous FLASH update bit is cleared due to
+             * Flash update issue on parts which use a FLASH for NVM. */
+            eecd &= ~E1000_EECD_AUPDEN;
+            E1000_WRITE_REG(hw, EECD, eecd);
+        }
+        break;
+    default:
+        break;
+    }
+
+    if (eeprom->type == em_eeprom_spi) {
+        /* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to
+         * 32KB (incremented by powers of 2).
+         */
+        if(hw->mac_type <= em_82547_rev_2) {
+            /* Set to default value for initial eeprom read. */
+            eeprom->word_size = 64;
+            ret_val = em_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size);
+            if(ret_val)
+                return ret_val;
+            eeprom_size = (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT;
+            /* 256B eeprom size was not supported in earlier hardware, so we
+             * bump eeprom_size up one to ensure that "1" (which maps to 256B)
+             * is never the result used in the shifting logic below. */
+            if(eeprom_size)
+                eeprom_size++;
+        } else {
+            eeprom_size = (uint16_t)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+                          E1000_EECD_SIZE_EX_SHIFT);
         }
+
+        eeprom->word_size = 1 << (eeprom_size + EEPROM_WORD_SIZE_SHIFT);
     }
+    return ret_val;
 }
 
 /******************************************************************************
@@ -3195,24 +3618,30 @@ em_acquire_eeprom(struct em_hw *hw)
 
     DEBUGFUNC("em_acquire_eeprom");
 
+    if(em_get_hw_eeprom_semaphore(hw))
+        return -E1000_ERR_EEPROM;
+
     eecd = E1000_READ_REG(hw, EECD);
 
-    /* Request EEPROM Access */
-    if(hw->mac_type > em_82544) {
-        eecd |= E1000_EECD_REQ;
-        E1000_WRITE_REG(hw, EECD, eecd);
-        eecd = E1000_READ_REG(hw, EECD);
-        while((!(eecd & E1000_EECD_GNT)) &&
-              (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
-            i++;
-            usec_delay(5);
-            eecd = E1000_READ_REG(hw, EECD);
-        }
-        if(!(eecd & E1000_EECD_GNT)) {
-            eecd &= ~E1000_EECD_REQ;
+    if (hw->mac_type != em_82573) {
+        /* Request EEPROM Access */
+        if(hw->mac_type > em_82544) {
+            eecd |= E1000_EECD_REQ;
             E1000_WRITE_REG(hw, EECD, eecd);
-            DEBUGOUT("Could not acquire EEPROM grant\n");
-            return -E1000_ERR_EEPROM;
+            eecd = E1000_READ_REG(hw, EECD);
+            while((!(eecd & E1000_EECD_GNT)) &&
+                  (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+                i++;
+                usec_delay(5);
+                eecd = E1000_READ_REG(hw, EECD);
+            }
+            if(!(eecd & E1000_EECD_GNT)) {
+                eecd &= ~E1000_EECD_REQ;
+                E1000_WRITE_REG(hw, EECD, eecd);
+                DEBUGOUT("Could not acquire EEPROM grant\n");
+                em_put_hw_eeprom_semaphore(hw);
+                return -E1000_ERR_EEPROM;
+            }
         }
     }
 
@@ -3332,6 +3761,8 @@ em_release_eeprom(struct em_hw *hw)
         eecd &= ~E1000_EECD_REQ;
         E1000_WRITE_REG(hw, EECD, eecd);
     }
+
+    em_put_hw_eeprom_semaphore(hw);
 }
 
 /******************************************************************************
@@ -3393,21 +3824,36 @@ em_read_eeprom(struct em_hw *hw,
 {
     struct em_eeprom_info *eeprom = &hw->eeprom;
     uint32_t i = 0;
+    int32_t ret_val;
 
     DEBUGFUNC("em_read_eeprom");
 
     /* A check for invalid values:  offset too large, too many words, and not
      * enough words.
      */
-    if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+    if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
        (words == 0)) {
         DEBUGOUT("\"words\" parameter out of bounds\n");
         return -E1000_ERR_EEPROM;
     }
 
-    /* Prepare the EEPROM for reading  */
-    if(em_acquire_eeprom(hw) != E1000_SUCCESS)
-        return -E1000_ERR_EEPROM;
+    /* FLASH reads without acquiring the semaphore are safe in 82573-based
+     * controllers.
+     */
+    if ((em_is_onboard_nvm_eeprom(hw) == TRUE) ||
+        (hw->mac_type != em_82573)) {
+        /* Prepare the EEPROM for reading  */
+        if(em_acquire_eeprom(hw) != E1000_SUCCESS)
+            return -E1000_ERR_EEPROM;
+    }
+
+    if(eeprom->use_eerd == TRUE) {
+        ret_val = em_read_eeprom_eerd(hw, offset, words, data);
+        if ((em_is_onboard_nvm_eeprom(hw) == TRUE) ||
+            (hw->mac_type != em_82573))
+            em_release_eeprom(hw);
+        return ret_val;
+    }
 
     if(eeprom->type == em_eeprom_spi) {
         uint16_t word_in;
@@ -3458,6 +3904,132 @@ em_read_eeprom(struct em_hw *hw,
     return E1000_SUCCESS;
 }
 
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_read_eeprom_eerd(struct em_hw *hw,
+                  uint16_t offset,
+                  uint16_t words,
+                  uint16_t *data)
+{
+    uint32_t i, eerd = 0;
+    int32_t error = 0;
+
+    for (i = 0; i < words; i++) {
+        eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) +
+                         E1000_EEPROM_RW_REG_START;
+
+        E1000_WRITE_REG(hw, EERD, eerd);
+        error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
+        
+        if(error) {
+            break;
+        }
+        data[i] = (E1000_READ_REG(hw, EERD) >> E1000_EEPROM_RW_REG_DATA);
+      
+    }
+    
+    return error;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word from the EEPROM using the EEWR register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_write_eeprom_eewr(struct em_hw *hw,
+                   uint16_t offset,
+                   uint16_t words,
+                   uint16_t *data)
+{
+    uint32_t    register_value = 0;
+    uint32_t    i              = 0;
+    int32_t     error          = 0;
+
+    for (i = 0; i < words; i++) {
+        register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) | 
+                         ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) | 
+                         E1000_EEPROM_RW_REG_START;
+
+        error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
+        if(error) {
+            break;
+        }       
+
+        E1000_WRITE_REG(hw, EEWR, register_value);
+        
+        error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
+        
+        if(error) {
+            break;
+        }       
+    }
+    
+    return error;
+}
+
+/******************************************************************************
+ * Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_poll_eerd_eewr_done(struct em_hw *hw, int eerd)
+{
+    uint32_t attempts = 100000;
+    uint32_t i, reg = 0;
+    int32_t done = E1000_ERR_EEPROM;
+
+    for(i = 0; i < attempts; i++) {
+        if(eerd == E1000_EEPROM_POLL_READ)
+            reg = E1000_READ_REG(hw, EERD);
+        else 
+            reg = E1000_READ_REG(hw, EEWR);
+
+        if(reg & E1000_EEPROM_RW_REG_DONE) {
+            done = E1000_SUCCESS;
+            break;
+        }
+        usec_delay(5);
+    }
+
+    return done;
+}
+
+/***************************************************************************
+* Description:     Determines if the onboard NVM is FLASH or EEPROM.
+*
+* hw - Struct containing variables accessed by shared code
+****************************************************************************/
+boolean_t
+em_is_onboard_nvm_eeprom(struct em_hw *hw)
+{
+    uint32_t eecd = 0;
+
+    if(hw->mac_type == em_82573) {
+        eecd = E1000_READ_REG(hw, EECD);
+
+        /* Isolate bits 15 & 16 */
+        eecd = ((eecd >> 15) & 0x03);
+
+        /* If both bits are set, device is Flash type */
+        if(eecd == 0x03) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
 /******************************************************************************
  * Verifies that the EEPROM has a valid checksum
  *
@@ -3475,6 +4047,25 @@ em_validate_eeprom_checksum(struct em_hw *hw)
 
     DEBUGFUNC("em_validate_eeprom_checksum");
 
+    if ((hw->mac_type == em_82573) &&
+        (em_is_onboard_nvm_eeprom(hw) == FALSE)) {
+        /* Check bit 4 of word 10h.  If it is 0, firmware is done updating
+         * 10h-12h.  Checksum may need to be fixed. */
+        em_read_eeprom(hw, 0x10, 1, &eeprom_data);
+        if ((eeprom_data & 0x10) == 0) {
+            /* Read 0x23 and check bit 15.  This bit is a 1 when the checksum
+             * has already been fixed.  If the checksum is still wrong and this
+             * bit is a 1, we need to return bad checksum.  Otherwise, we need
+             * to set this bit to a 1 and update the checksum. */
+            em_read_eeprom(hw, 0x23, 1, &eeprom_data);
+            if ((eeprom_data & 0x8000) == 0) {
+                eeprom_data |= 0x8000;
+                em_write_eeprom(hw, 0x23, 1, &eeprom_data);
+                em_update_eeprom_checksum(hw);
+            }
+        }
+    }
+
     for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
         if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
             DEBUGOUT("EEPROM Read Error\n");
@@ -3518,6 +4109,8 @@ em_update_eeprom_checksum(struct em_hw *hw)
     if(em_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
         DEBUGOUT("EEPROM Write Error\n");
         return -E1000_ERR_EEPROM;
+    } else if (hw->eeprom.type == em_eeprom_flash) {
+        em_commit_shadow_ram(hw);
     }
     return E1000_SUCCESS;
 }
@@ -3547,12 +4140,16 @@ em_write_eeprom(struct em_hw *hw,
     /* A check for invalid values:  offset too large, too many words, and not
      * enough words.
      */
-    if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+    if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
        (words == 0)) {
         DEBUGOUT("\"words\" parameter out of bounds\n");
         return -E1000_ERR_EEPROM;
     }
 
+    /* 82573 writes only through eewr */
+    if(eeprom->use_eewr == TRUE)
+        return em_write_eeprom_eewr(hw, offset, words, data);
+
     /* Prepare the EEPROM for writing  */
     if (em_acquire_eeprom(hw) != E1000_SUCCESS)
         return -E1000_ERR_EEPROM;
@@ -3722,6 +4319,65 @@ em_write_eeprom_microwire(struct em_hw *hw,
     return E1000_SUCCESS;
 }
 
+/******************************************************************************
+ * Flushes the cached eeprom to NVM. This is done by saving the modified values
+ * in the eeprom cache and the non modified values in the currently active bank
+ * to the new bank.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+em_commit_shadow_ram(struct em_hw *hw)
+{
+    uint32_t attempts = 100000;
+    uint32_t eecd = 0;
+    uint32_t flop = 0;
+    uint32_t i = 0;
+    int32_t error = E1000_SUCCESS;
+
+    /* The flop register will be used to determine if flash type is STM */
+    flop = E1000_READ_REG(hw, FLOP);
+
+    if (hw->mac_type == em_82573) {
+        for (i=0; i < attempts; i++) {
+            eecd = E1000_READ_REG(hw, EECD);
+            if ((eecd & E1000_EECD_FLUPD) == 0) {
+                break;
+            }
+            usec_delay(5);
+        }
+
+        if (i == attempts) {
+            return -E1000_ERR_EEPROM;
+        }
+
+       /* If STM opcode located in bits 15:8 of flop, reset firmware */
+        if ((flop & 0xFF00) == E1000_STM_OPCODE) {
+            E1000_WRITE_REG(hw, HICR, E1000_HICR_FW_RESET);
+        }
+
+        /* Perform the flash update */
+        E1000_WRITE_REG(hw, EECD, eecd | E1000_EECD_FLUPD);
+
+       for (i=0; i < attempts; i++) {
+            eecd = E1000_READ_REG(hw, EECD);
+            if ((eecd & E1000_EECD_FLUPD) == 0) {
+                break;
+            }
+            usec_delay(5);
+        }
+
+        if (i == attempts) {
+            return -E1000_ERR_EEPROM;
+        }
+    }
+
+    return error;
+}
+
 /******************************************************************************
  * Reads the adapter's part number from the EEPROM
  *
@@ -3779,9 +4435,16 @@ em_read_mac_addr(struct em_hw * hw)
         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 == em_82546) || (hw->mac_type == em_82546_rev_3)) &&
-       (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1))
+    switch (hw->mac_type) {
+    default:
+        break;
+    case em_82546:
+    case em_82546_rev_3:
+    case em_82571:
+        if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
             hw->perm_mac_addr[5] ^= 0x01;
+        break;
+    }
 
     for(i = 0; i < NODE_ADDRESS_SIZE; i++)
         hw->mac_addr[i] = hw->perm_mac_addr[i];
@@ -3801,6 +4464,7 @@ void
 em_init_rx_addrs(struct em_hw *hw)
 {
     uint32_t i;
+    uint32_t rar_num;
 
     DEBUGFUNC("em_init_rx_addrs");
 
@@ -3809,9 +4473,16 @@ em_init_rx_addrs(struct em_hw *hw)
 
     em_rar_set(hw, hw->mac_addr, 0);
 
+    rar_num = E1000_RAR_ENTRIES;
+
+    /* Reserve a spot for the Locally Administered Address to work around
+     * an 82571 issue in which a reset on one port will reload the MAC on
+     * the other port. */
+    if ((hw->mac_type == em_82571) && (hw->laa_is_present == TRUE))
+        rar_num -= 1;
     /* Zero out the other 15 receive addresses. */
     DEBUGOUT("Clearing RAR[1-15]\n");
-    for(i = 1; i < E1000_RAR_ENTRIES; i++) {
+    for(i = 1; i < rar_num; i++) {
         E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
         E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
     }
@@ -3840,7 +4511,9 @@ em_mc_addr_list_update(struct em_hw *hw,
 {
     uint32_t hash_value;
     uint32_t i;
-
+    uint32_t num_rar_entry;
+    uint32_t num_mta_entry;
+    
     DEBUGFUNC("em_mc_addr_list_update");
 
     /* Set the new number of MC addresses that we are being requested to use. */
@@ -3848,14 +4521,22 @@ em_mc_addr_list_update(struct em_hw *hw,
 
     /* Clear RAR[1-15] */
     DEBUGOUT(" Clearing RAR[1-15]\n");
-    for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
+    num_rar_entry = E1000_RAR_ENTRIES;
+    /* Reserve a spot for the Locally Administered Address to work around
+     * an 82571 issue in which a reset on one port will reload the MAC on
+     * the other port. */
+    if ((hw->mac_type == em_82571) && (hw->laa_is_present == TRUE))
+        num_rar_entry -= 1;
+
+    for(i = rar_used_count; i < num_rar_entry; i++) {
         E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
         E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
     }
 
     /* Clear the MTA */
     DEBUGOUT(" Clearing MTA\n");
-    for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
+    num_mta_entry = E1000_NUM_MTA_REGISTERS;
+    for(i = 0; i < num_mta_entry; i++) {
         E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
     }
 
@@ -3879,7 +4560,7 @@ em_mc_addr_list_update(struct em_hw *hw,
         /* Place this multicast address in the RAR if there is room, *
          * else put it in the MTA
          */
-        if(rar_used_count < E1000_RAR_ENTRIES) {
+        if (rar_used_count < num_rar_entry) {
             em_rar_set(hw,
                           mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
                           rar_used_count);
@@ -3930,6 +4611,7 @@ em_hash_mc_addr(struct em_hw *hw,
     }
 
     hash_value &= 0xFFF;
+
     return hash_value;
 }
 
@@ -4034,12 +4716,33 @@ void
 em_clear_vfta(struct em_hw *hw)
 {
     uint32_t offset;
-
-    for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
-        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
+    uint32_t vfta_value = 0;
+    uint32_t vfta_offset = 0;
+    uint32_t vfta_bit_in_reg = 0;
+
+    if (hw->mac_type == em_82573) {
+        if (hw->mng_cookie.vlan_id != 0) {
+            /* The VFTA is a 4096b bit-field, each identifying a single VLAN
+             * ID.  The following operations determine which 32b entry
+             * (i.e. offset) into the array we want to set the VLAN ID
+             * (i.e. bit) of the manageability unit. */
+            vfta_offset = (hw->mng_cookie.vlan_id >>
+                           E1000_VFTA_ENTRY_SHIFT) &
+                          E1000_VFTA_ENTRY_MASK;
+            vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+                                    E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+        }
+    }
+    for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+        /* If the offset we want to clear is the same offset of the
+         * manageability VLAN ID, then clear all bits except that of the
+         * manageability unit */
+        vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value);
+    }
 }
 
-static int32_t
+int32_t
 em_id_led_init(struct em_hw * hw)
 {
     uint32_t ledctl;
@@ -4132,12 +4835,14 @@ em_setup_led(struct em_hw *hw)
     case em_82541_rev_2:
     case em_82547_rev_2:
         /* Turn off PHY Smart Power Down (if enabled) */
-        if((ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
-                                         &hw->phy_spd_default)))
+        ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                     &hw->phy_spd_default);
+        if(ret_val)
             return ret_val;
-        if((ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
-                                          (uint16_t)(hw->phy_spd_default &
-                                          ~IGP01E1000_GMII_SPD))))
+        ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                      (uint16_t)(hw->phy_spd_default &
+                                      ~IGP01E1000_GMII_SPD));
+        if(ret_val)
             return ret_val;
         /* Fall Through */
     default:
@@ -4184,8 +4889,9 @@ em_cleanup_led(struct em_hw *hw)
     case em_82541_rev_2:
     case em_82547_rev_2:
         /* Turn on PHY Smart Power Down (if previously enabled) */
-        if((ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
-                                          hw->phy_spd_default)))
+        ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                      hw->phy_spd_default);
+        if(ret_val)
             return ret_val;
         /* Fall Through */
     default:
@@ -4367,6 +5073,18 @@ em_clear_hw_cntrs(struct em_hw *hw)
     temp = E1000_READ_REG(hw, MGTPRC);
     temp = E1000_READ_REG(hw, MGTPDC);
     temp = E1000_READ_REG(hw, MGTPTC);
+
+    if(hw->mac_type <= em_82547_rev_2) return;
+
+    temp = E1000_READ_REG(hw, IAC);
+    temp = E1000_READ_REG(hw, ICRXOC);
+    temp = E1000_READ_REG(hw, ICRXPTC);
+    temp = E1000_READ_REG(hw, ICRXATC);
+    temp = E1000_READ_REG(hw, ICTXPTC);
+    temp = E1000_READ_REG(hw, ICTXATC);
+    temp = E1000_READ_REG(hw, ICTXQEC);
+    temp = E1000_READ_REG(hw, ICTXQMTC);
+    temp = E1000_READ_REG(hw, ICRXDMTC);
 }
 
 /******************************************************************************
@@ -4526,41 +5244,51 @@ em_get_bus_info(struct em_hw *hw)
 {
     uint32_t status;
 
-    if(hw->mac_type < em_82543) {
+    switch (hw->mac_type) {
+    case em_82542_rev2_0:
+    case em_82542_rev2_1:
         hw->bus_type = em_bus_type_unknown;
         hw->bus_speed = em_bus_speed_unknown;
         hw->bus_width = em_bus_width_unknown;
-        return;
-    }
-
-    status = E1000_READ_REG(hw, STATUS);
-    hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
-                   em_bus_type_pcix : em_bus_type_pci;
-
-    if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
-        hw->bus_speed = (hw->bus_type == em_bus_type_pci) ?
-                        em_bus_speed_66 : em_bus_speed_120;
-    } else if(hw->bus_type == em_bus_type_pci) {
-        hw->bus_speed = (status & E1000_STATUS_PCI66) ?
-                        em_bus_speed_66 : em_bus_speed_33;
-    } else {
-        switch (status & E1000_STATUS_PCIX_SPEED) {
-        case E1000_STATUS_PCIX_SPEED_66:
-            hw->bus_speed = em_bus_speed_66;
-            break;
-        case E1000_STATUS_PCIX_SPEED_100:
-            hw->bus_speed = em_bus_speed_100;
-            break;
-        case E1000_STATUS_PCIX_SPEED_133:
-            hw->bus_speed = em_bus_speed_133;
-            break;
-        default:
-            hw->bus_speed = em_bus_speed_reserved;
-            break;
+        break;
+    case em_82571:
+    case em_82572:
+    case em_82573:
+        hw->bus_type = em_bus_type_pci_express;
+        hw->bus_speed = em_bus_speed_2500;
+        hw->bus_width = em_bus_width_pciex_4;
+        break;
+    default:
+        status = E1000_READ_REG(hw, STATUS);
+        hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+                       em_bus_type_pcix : em_bus_type_pci;
+
+        if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
+            hw->bus_speed = (hw->bus_type == em_bus_type_pci) ?
+                            em_bus_speed_66 : em_bus_speed_120;
+        } else if(hw->bus_type == em_bus_type_pci) {
+            hw->bus_speed = (status & E1000_STATUS_PCI66) ?
+                            em_bus_speed_66 : em_bus_speed_33;
+        } else {
+            switch (status & E1000_STATUS_PCIX_SPEED) {
+            case E1000_STATUS_PCIX_SPEED_66:
+                hw->bus_speed = em_bus_speed_66;
+                break;
+            case E1000_STATUS_PCIX_SPEED_100:
+                hw->bus_speed = em_bus_speed_100;
+                break;
+            case E1000_STATUS_PCIX_SPEED_133:
+                hw->bus_speed = em_bus_speed_133;
+                break;
+            default:
+                hw->bus_speed = em_bus_speed_reserved;
+                break;
+            }
         }
+        hw->bus_width = (status & E1000_STATUS_BUS64) ?
+                        em_bus_width_64 : em_bus_width_32;
+        break;
     }
-    hw->bus_width = (status & E1000_STATUS_BUS64) ?
-                    em_bus_width_64 : em_bus_width_32;
 }
 
 /******************************************************************************
@@ -4586,7 +5314,9 @@ em_get_cable_length(struct em_hw *hw,
     int32_t ret_val;
     uint16_t agc_value = 0;
     uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+    uint16_t max_agc = 0;
     uint16_t i, phy_data;
+    uint16_t cable_length;
 
     DEBUGFUNC("em_get_cable_length");
 
@@ -4594,13 +5324,16 @@ em_get_cable_length(struct em_hw *hw,
 
     /* Use old method for Phy older than IGP */
     if(hw->phy_type == em_phy_m88) {
-        if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
-                                         &phy_data)))
+
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
+        cable_length = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+                       M88E1000_PSSR_CABLE_LENGTH_SHIFT;
 
         /* Convert the enum value to ranged values */
-        switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
-               M88E1000_PSSR_CABLE_LENGTH_SHIFT) {
+        switch (cable_length) {
         case em_cable_length_50:
             *min_length = 0;
             *max_length = em_igp_cable_length_50;
@@ -4634,7 +5367,8 @@ em_get_cable_length(struct em_hw *hw,
         /* Read the AGC registers for all channels */
         for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
 
-            if((ret_val = em_read_phy_reg(hw, agc_reg_array[i], &phy_data)))
+            ret_val = em_read_phy_reg(hw, agc_reg_array[i], &phy_data);
+            if(ret_val)
                 return ret_val;
 
             cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
@@ -4669,6 +5403,40 @@ em_get_cable_length(struct em_hw *hw,
                        IGP01E1000_AGC_RANGE) : 0;
         *max_length = em_igp_cable_length_table[agc_value] +
                       IGP01E1000_AGC_RANGE;
+    } else if (hw->phy_type == em_phy_igp_2) {
+        uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+                                                         {IGP02E1000_PHY_AGC_A,
+                                                          IGP02E1000_PHY_AGC_B,
+                                                          IGP02E1000_PHY_AGC_C,
+                                                          IGP02E1000_PHY_AGC_D};
+        /* Read the AGC registers for all channels */
+        for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+            ret_val = em_read_phy_reg(hw, agc_reg_array[i], &phy_data);
+            if (ret_val)
+                return ret_val;
+
+           /* Getting bits 15:9, which represent the combination of course and
+             * fine gain values.  The result is a number that can be put into
+             * the lookup table to obtain the approximate cable length. */
+            cur_agc = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+                      IGP02E1000_AGC_LENGTH_MASK;
+
+            /* Remove min & max AGC values from calculation. */
+            if (em_igp_2_cable_length_table[min_agc] > em_igp_2_cable_length_table[cur_agc])
+                min_agc = cur_agc;
+           if (em_igp_2_cable_length_table[max_agc] < em_igp_2_cable_length_table[cur_agc])
+                max_agc = cur_agc;
+
+            agc_value += em_igp_2_cable_length_table[cur_agc];
+        }
+
+        agc_value -= (em_igp_2_cable_length_table[min_agc] + em_igp_2_cable_length_table[max_agc]);
+        agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+        /* Calculate cable length with the error range of +/- 10 meters. */
+        *min_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+                       (agc_value - IGP02E1000_AGC_RANGE) : 0;
+        *max_length = agc_value + IGP02E1000_AGC_RANGE;
     }
 
     return E1000_SUCCESS;
@@ -4701,15 +5469,18 @@ em_check_polarity(struct em_hw *hw,
 
     if(hw->phy_type == em_phy_m88) {
         /* return the Polarity bit in the Status register. */
-        if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
-                                         &phy_data)))
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
         *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
                     M88E1000_PSSR_REV_POLARITY_SHIFT;
-    } else if(hw->phy_type == em_phy_igp) {
+    } else if(hw->phy_type == em_phy_igp ||
+              hw->phy_type == em_phy_igp_2) {
         /* Read the Status register to check the speed */
-        if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
-                                         &phy_data)))
+        ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
 
         /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
@@ -4718,8 +5489,9 @@ em_check_polarity(struct em_hw *hw,
            IGP01E1000_PSSR_SPEED_1000MBPS) {
 
             /* Read the GIG initialization PCS register (0x00B4) */
-            if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG,
-                                             &phy_data)))
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG,
+                                         &phy_data);
+            if(ret_val)
                 return ret_val;
 
             /* Check the polarity bits */
@@ -4756,21 +5528,24 @@ em_check_downshift(struct em_hw *hw)
 
     DEBUGFUNC("em_check_downshift");
 
-    if(hw->phy_type == em_phy_igp) {
-        if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
-                                         &phy_data)))
+    if(hw->phy_type == em_phy_igp || 
+        hw->phy_type == em_phy_igp_2) {
+        ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
 
         hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
-    }
-    else if(hw->phy_type == em_phy_m88) {
-        if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
-                                         &phy_data)))
+    } else if(hw->phy_type == em_phy_m88) {
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
 
         hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
                                M88E1000_PSSR_DOWNSHIFT_SHIFT;
     }
+
     return E1000_SUCCESS;
 }
 
@@ -4791,7 +5566,7 @@ em_config_dsp_after_link_change(struct em_hw *hw,
                                    boolean_t link_up)
 {
     int32_t ret_val;
-    uint16_t phy_data, speed, duplex, i;
+    uint16_t phy_data, phy_saved_data, speed, duplex, i;
     uint16_t dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
                                         {IGP01E1000_PHY_AGC_PARAM_A,
                                         IGP01E1000_PHY_AGC_PARAM_B,
@@ -4805,7 +5580,8 @@ em_config_dsp_after_link_change(struct em_hw *hw,
         return E1000_SUCCESS;
 
     if(link_up) {
-        if((ret_val = em_get_speed_and_duplex(hw, &speed, &duplex))) {
+        ret_val = em_get_speed_and_duplex(hw, &speed, &duplex);
+        if(ret_val) {
             DEBUGOUT("Error getting link speed and duplex\n");
             return ret_val;
         }
@@ -4818,14 +5594,16 @@ em_config_dsp_after_link_change(struct em_hw *hw,
                 min_length >= em_igp_cable_length_50) {
 
                 for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
-                    if((ret_val = em_read_phy_reg(hw, dsp_reg_array[i],
-                                                     &phy_data)))
+                    ret_val = em_read_phy_reg(hw, dsp_reg_array[i],
+                                                 &phy_data);
+                    if(ret_val)
                         return ret_val;
 
                     phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
 
-                    if((ret_val = em_write_phy_reg(hw, dsp_reg_array[i],
-                                                      phy_data)))
+                    ret_val = em_write_phy_reg(hw, dsp_reg_array[i],
+                                                  phy_data);
+                    if(ret_val)
                         return ret_val;
                 }
                 hw->dsp_config_state = em_dsp_config_activated;
@@ -4838,23 +5616,26 @@ em_config_dsp_after_link_change(struct em_hw *hw,
                 uint32_t idle_errs = 0;
 
                 /* clear previous idle error counts */
-                if((ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS,
-                                                 &phy_data)))
+                ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS,
+                                             &phy_data);
+                if(ret_val)
                     return ret_val;
 
                 for(i = 0; i < ffe_idle_err_timeout; i++) {
                     usec_delay(1000);
-                    if((ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS,
-                                                     &phy_data)))
+                    ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS,
+                                                 &phy_data);
+                    if(ret_val)
                         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 = em_ffe_config_active;
 
-                        if((ret_val = em_write_phy_reg(hw,
+                        ret_val = em_write_phy_reg(hw,
                                     IGP01E1000_PHY_DSP_FFE,
-                                    IGP01E1000_PHY_DSP_FFE_CM_CP)))
+                                    IGP01E1000_PHY_DSP_FFE_CM_CP);
+                        if(ret_val)
                             return ret_val;
                         break;
                     }
@@ -4866,50 +5647,102 @@ em_config_dsp_after_link_change(struct em_hw *hw,
         }
     } else {
         if(hw->dsp_config_state == em_dsp_config_activated) {
-            if((ret_val = em_write_phy_reg(hw, 0x0000,
-                IGP01E1000_IEEE_FORCE_GIGA)))
+            /* Save off the current value of register 0x2F5B to be restored at
+             * the end of the routines. */
+            ret_val = em_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
+            /* Disable the PHY transmitter */
+            ret_val = em_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+            if(ret_val)
+                return ret_val;
+
+            msec_delay_irq(20);
+
+            ret_val = em_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_FORCE_GIGA);
+            if(ret_val)
                 return ret_val;
             for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
-                if((ret_val = em_read_phy_reg(hw, dsp_reg_array[i],
-                                                 &phy_data)))
+                ret_val = em_read_phy_reg(hw, dsp_reg_array[i], &phy_data);
+                if(ret_val)
                     return ret_val;
 
                 phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
                 phy_data |=  IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
 
-                if((ret_val = em_write_phy_reg(hw,dsp_reg_array[i],
-                                                  phy_data)))
+                ret_val = em_write_phy_reg(hw,dsp_reg_array[i], phy_data);
+                if(ret_val)
                     return ret_val;
             }
 
-            if((ret_val = em_write_phy_reg(hw, 0x0000,
-                                              IGP01E1000_IEEE_RESTART_AUTONEG)))
+            ret_val = em_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_RESTART_AUTONEG);
+            if(ret_val)
+                return ret_val;
+
+            msec_delay_irq(20);
+
+            /* Now enable the transmitter */
+            ret_val = em_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+            if(ret_val)
                 return ret_val;
 
             hw->dsp_config_state = em_dsp_config_enabled;
         }
 
         if(hw->ffe_config_state == em_ffe_config_active) {
-            if((ret_val = em_write_phy_reg(hw, 0x0000,
-                                              IGP01E1000_IEEE_FORCE_GIGA)))
-                return ret_val;
-            if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE,
-                                              IGP01E1000_PHY_DSP_FFE_DEFAULT)))
+            /* Save off the current value of register 0x2F5B to be restored at
+             * the end of the routines. */
+            ret_val = em_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
+
+            if(ret_val)
                 return ret_val;
 
-            if((ret_val = em_write_phy_reg(hw, 0x0000,
-                                              IGP01E1000_IEEE_RESTART_AUTONEG)))
+            /* Disable the PHY transmitter */
+            ret_val = em_write_phy_reg(hw, 0x2F5B, 0x0003);
+
+            if(ret_val)
                 return ret_val;
-            hw->ffe_config_state = em_ffe_config_enabled;
-        }
-    }
-    return E1000_SUCCESS;
-}
 
- /*****************************************************************************
- * Set PHY to class A mode
- * Assumes the following operations will follow to enable the new class mode.
- *  1. Do a PHY soft reset
+            msec_delay_irq(20);
+
+            ret_val = em_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_FORCE_GIGA);
+            if(ret_val)
+                return ret_val;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE,
+                                          IGP01E1000_PHY_DSP_FFE_DEFAULT);
+            if(ret_val)
+                return ret_val;
+
+            ret_val = em_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_RESTART_AUTONEG);
+            if(ret_val)
+                return ret_val;
+
+            msec_delay_irq(20);
+
+            /* Now enable the transmitter */
+            ret_val = em_write_phy_reg(hw, 0x2F5B, phy_saved_data);
+
+            if(ret_val)
+                return ret_val;
+
+            hw->ffe_config_state = em_ffe_config_enabled;
+        }
+    }
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * Set PHY to class A mode
+ * Assumes the following operations will follow to enable the new class mode.
+ *  1. Do a PHY soft reset
  *  2. Restart auto-negotiation or force link.
  *
  * hw - Struct containing variables accessed by shared code
@@ -4925,15 +5758,15 @@ em_set_phy_mode(struct em_hw *hw)
     if((hw->mac_type == em_82545_rev_3) &&
        (hw->media_type == em_media_type_copper)) {
         ret_val = em_read_eeprom(hw, EEPROM_PHY_CLASS_WORD, 1, &eeprom_data);
-        if(ret_val)
+        if(ret_val) {
             return ret_val;
+        }
 
         if((eeprom_data != EEPROM_RESERVED_WORD) &&
            (eeprom_data & EEPROM_PHY_CLASS_A)) {
             ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x000B);
             if(ret_val)
                 return ret_val;
-
             ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x8104);
             if(ret_val)
                 return ret_val;
@@ -4941,6 +5774,7 @@ em_set_phy_mode(struct em_hw *hw)
             hw->phy_reset_disable = FALSE;
         }
     }
+
     return E1000_SUCCESS;
 }
 
@@ -4966,50 +5800,176 @@ em_set_d3_lplu_state(struct em_hw *hw,
     uint16_t phy_data;
     DEBUGFUNC("em_set_d3_lplu_state");
 
-    if(!((hw->mac_type == em_82541_rev_2) ||
-         (hw->mac_type == em_82547_rev_2)))
+    if(hw->phy_type != em_phy_igp && hw->phy_type != em_phy_igp_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 = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data)))
-        return ret_val;
+    if(hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2) {
+        ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data);
+        if(ret_val)
+            return ret_val;
+    } else {
+        ret_val = em_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+        if(ret_val)
+            return ret_val;
+    }
 
     if(!active) {
-        phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
-        if((ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data)))
-            return ret_val;
+        if(hw->mac_type == em_82541_rev_2 ||
+           hw->mac_type == em_82547_rev_2) {
+            phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+            if(ret_val)
+                return ret_val;
+        } else {
+                phy_data &= ~IGP02E1000_PM_D3_LPLU;
+                ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+                                              phy_data);
+                if (ret_val)
+                    return ret_val;
+        }
 
         /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
          * Dx states where the power conservation is most important.  During
          * driver activity we should enable SmartSpeed, so performance is
          * maintained. */
-        if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                         &phy_data)))
-            return ret_val;
+        if (hw->smart_speed == em_smart_speed_on) {
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+            if(ret_val)
+                return ret_val;
 
-        phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
-        if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                          phy_data)))
-            return ret_val;
+            phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        } else if (hw->smart_speed == em_smart_speed_off) {
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+           if (ret_val)
+                return ret_val;
+
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        }
 
     } else if((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
               (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) ||
               (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
 
-        phy_data |= IGP01E1000_GMII_FLEX_SPD;
-        if((ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data)))
+        if(hw->mac_type == em_82541_rev_2 ||
+           hw->mac_type == em_82547_rev_2) {
+            phy_data |= IGP01E1000_GMII_FLEX_SPD;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+            if(ret_val)
+                return ret_val;
+        } else {
+                phy_data |= IGP02E1000_PM_D3_LPLU;
+                ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+                                              phy_data);
+                if (ret_val)
+                    return ret_val;
+        }
+
+        /* When LPLU is enabled we should disable SmartSpeed */
+        ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+        phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+        ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+        if(ret_val)
             return ret_val;
 
+    }
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * This function sets the lplu d0 state according to the active flag.  When
+ * activating lplu this function also disables smart speed and vise versa.
+ * lplu will not be activated unless the device autonegotiation advertisment
+ * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * hw: Struct containing variables accessed by shared code
+ * active - true to enable lplu false to disable lplu.
+ *
+ * returns: - E1000_ERR_PHY if fail to read/write the PHY
+ *            E1000_SUCCESS at any other case.
+ *
+ ****************************************************************************/
+
+int32_t
+em_set_d0_lplu_state(struct em_hw *hw,
+                        boolean_t active)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+    DEBUGFUNC("em_set_d0_lplu_state");
+
+    if(hw->mac_type <= em_82547_rev_2)
+        return E1000_SUCCESS;
+
+        ret_val = em_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+        if(ret_val)
+            return ret_val;
+
+    if (!active) {
+            phy_data &= ~IGP02E1000_PM_D0_LPLU;
+            ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+            if (ret_val)
+                return ret_val;
+
+        /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
+         * Dx states where the power conservation is most important.  During
+         * driver activity we should enable SmartSpeed, so performance is
+         * maintained. */
+        if (hw->smart_speed == em_smart_speed_on) {
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+            if(ret_val)
+                return ret_val;
+
+            phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        } else if (hw->smart_speed == em_smart_speed_off) {
+            ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                         &phy_data);
+           if (ret_val)
+                return ret_val;
+
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                          phy_data);
+            if(ret_val)
+                return ret_val;
+        }
+
+
+    } else {
+            phy_data |= IGP02E1000_PM_D0_LPLU;   
+            ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+            if (ret_val)
+                return ret_val;
+
         /* When LPLU is enabled we should disable SmartSpeed */
-        if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                         &phy_data)))
+        ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-        if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                          phy_data)))
+        ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+        if(ret_val)
             return ret_val;
 
     }
@@ -5040,36 +6000,769 @@ em_set_vco_speed(struct em_hw *hw)
 
     /* Set PHY register 30, page 5, bit 8 to 0 */
 
-    if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT,
-                                     &default_page)))
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, &default_page);
+    if(ret_val)
         return ret_val;
 
-    if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005)))
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005);
+    if(ret_val)
         return ret_val;
 
-    if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data)))
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+    if(ret_val)
         return ret_val;
 
     phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
-    if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data)))
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+    if(ret_val)
         return ret_val;
 
     /* Set PHY register 30, page 4, bit 11 to 1 */
 
-    if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004)))
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004);
+    if(ret_val)
         return ret_val;
 
-    if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data)))
+    ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+    if(ret_val)
         return ret_val;
 
     phy_data |= M88E1000_PHY_VCO_REG_BIT11;
-    if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data)))
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+    if(ret_val)
         return ret_val;
 
-    if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT,
-                                      default_page)))
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, default_page);
+    if(ret_val)
         return ret_val;
 
     return E1000_SUCCESS;
 }
 
+
+/*****************************************************************************
+ * This function reads the cookie from ARC ram.
+ *
+ * returns: - E1000_SUCCESS .
+ ****************************************************************************/
+int32_t
+em_host_if_read_cookie(struct em_hw * hw, uint8_t *buffer)
+{
+    uint8_t i;
+    uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET; 
+    uint8_t length = E1000_MNG_DHCP_COOKIE_LENGTH;
+
+    length = (length >> 2);
+    offset = (offset >> 2);
+
+    for (i = 0; i < length; i++) {
+        *((uint32_t *) buffer + i) =
+            E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset + i);
+    }
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function checks whether the HOST IF is enabled for command operaton
+ * and also checks whether the previous command is completed.
+ * It busy waits in case of previous command is not completed.
+ *
+ * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or 
+ *            timeout
+ *          - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_enable_host_if(struct em_hw * hw)
+{
+    uint32_t hicr;
+    uint8_t i;
+
+    /* Check that the host interface is enabled. */
+    hicr = E1000_READ_REG(hw, HICR);
+    if ((hicr & E1000_HICR_EN) == 0) {
+        DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+        return -E1000_ERR_HOST_INTERFACE_COMMAND;
+    }
+    /* check the previous command is completed */
+    for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+        hicr = E1000_READ_REG(hw, HICR);
+        if (!(hicr & E1000_HICR_C))
+            break;
+        msec_delay_irq(1);
+    }
+
+    if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { 
+        DEBUGOUT("Previous command timeout failed .\n");
+        return -E1000_ERR_HOST_INTERFACE_COMMAND;
+    }
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient way.
+ * Also fills up the sum of the buffer in *buffer parameter.
+ *
+ * returns  - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_host_if_write(struct em_hw * hw, uint8_t *buffer,
+                        uint16_t length, uint16_t offset, uint8_t *sum)
+{
+    uint8_t *tmp;
+    uint8_t *bufptr = buffer;
+    uint32_t data;
+    uint16_t remaining, i, j, prev_bytes;
+
+    /* sum = only sum of the data and it is not checksum */
+
+    if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+        return -E1000_ERR_PARAM;
+    }
+
+    tmp = (uint8_t *)&data;
+    prev_bytes = offset & 0x3;
+    offset &= 0xFFFC;
+    offset >>= 2;
+
+    if (prev_bytes) {
+        data = E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset);
+        for (j = prev_bytes; j < sizeof(uint32_t); j++) {
+            *(tmp + j) = *bufptr++;
+            *sum += *(tmp + j);
+        }
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset, data);
+        length -= j - prev_bytes;
+        offset++;
+    }
+
+    remaining = length & 0x3;
+    length -= remaining;
+
+    /* Calculate length in DWORDs */
+    length >>= 2;
+
+    /* The device driver writes the relevant command block into the
+     * ram area. */
+    for (i = 0; i < length; i++) {
+        for (j = 0; j < sizeof(uint32_t); j++) {
+            *(tmp + j) = *bufptr++;
+            *sum += *(tmp + j);
+        }
+
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data);
+    }
+    if (remaining) {
+        for (j = 0; j < sizeof(uint32_t); j++) {
+            if (j < remaining)
+                *(tmp + j) = *bufptr++;
+            else
+                *(tmp + j) = 0;
+
+            *sum += *(tmp + j);
+        }
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data);
+    }
+
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function writes the command header after does the checksum calculation.
+ *
+ * returns  - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_write_cmd_header(struct em_hw * hw,
+                           struct em_host_mng_command_header * hdr)
+{
+    uint16_t i;
+    uint8_t sum;
+    uint8_t *buffer;
+
+    /* Write the whole command header structure which includes sum of
+     * the buffer */
+
+    uint16_t length = sizeof(struct em_host_mng_command_header);
+
+    sum = hdr->checksum;
+    hdr->checksum = 0;
+
+    buffer = (uint8_t *) hdr;
+    i = length;
+    while(i--)
+        sum += buffer[i];
+
+    hdr->checksum = 0 - sum;
+
+    length >>= 2;
+    /* The device driver writes the relevant command block into the ram area. */
+    for (i = 0; i < length; i++)
+        E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i));
+
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function indicates to ARC that a new command is pending which completes
+ * one write operation by the driver.
+ *
+ * returns  - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+em_mng_write_commit(
+    struct em_hw * hw)
+{
+    uint32_t hicr;
+
+    hicr = E1000_READ_REG(hw, HICR);
+    /* Setting this bit tells the ARC that a new command is pending. */
+    E1000_WRITE_REG(hw, HICR, hicr | E1000_HICR_C);
+
+    return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function checks the mode of the firmware.
+ *
+ * returns  - TRUE when the mode is IAMT or FALSE.
+ ****************************************************************************/
+boolean_t
+em_check_mng_mode(
+    struct em_hw *hw)
+{
+    uint32_t fwsm;
+
+    fwsm = E1000_READ_REG(hw, FWSM);
+
+    if((fwsm & E1000_FWSM_MODE_MASK) ==
+        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+        return TRUE;
+
+    return FALSE;
+}
+
+
+/*****************************************************************************
+ * This function writes the dhcp info .
+ ****************************************************************************/
+int32_t
+em_mng_write_dhcp_info(struct em_hw * hw, uint8_t *buffer,
+                         uint16_t length)
+{
+    int32_t ret_val;
+    struct em_host_mng_command_header hdr;
+
+    hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+    hdr.command_length = length;
+    hdr.reserved1 = 0;
+    hdr.reserved2 = 0;
+    hdr.checksum = 0;
+
+    ret_val = em_mng_enable_host_if(hw);
+    if (ret_val == E1000_SUCCESS) {
+        ret_val = em_mng_host_if_write(hw, buffer, length, sizeof(hdr),
+                                          &(hdr.checksum));
+        if (ret_val == E1000_SUCCESS) {
+            ret_val = em_mng_write_cmd_header(hw, &hdr);
+            if (ret_val == E1000_SUCCESS)
+                ret_val = em_mng_write_commit(hw);
+        }
+    }
+    return ret_val;
+}
+
+
+/*****************************************************************************
+ * This function calculates the checksum.
+ *
+ * returns  - checksum of buffer contents.
+ ****************************************************************************/
+uint8_t
+em_calculate_mng_checksum(char *buffer, uint32_t length)
+{
+    uint8_t sum = 0;
+    uint32_t i;
+
+    if (!buffer)
+        return 0;
+
+    for (i=0; i < length; i++)
+        sum += buffer[i];
+
+    return (uint8_t) (0 - sum);
+}
+
+/*****************************************************************************
+ * This function checks whether tx pkt filtering needs to be enabled or not.
+ *
+ * returns  - TRUE for packet filtering or FALSE.
+ ****************************************************************************/
+boolean_t
+em_enable_tx_pkt_filtering(struct em_hw *hw)
+{
+    /* called in init as well as watchdog timer functions */
+
+    int32_t ret_val, checksum;
+    boolean_t tx_filter = FALSE;
+    struct em_host_mng_dhcp_cookie *hdr = &(hw->mng_cookie);
+    uint8_t *buffer = (uint8_t *) &(hw->mng_cookie);
+
+    if (em_check_mng_mode(hw)) {
+        ret_val = em_mng_enable_host_if(hw);
+        if (ret_val == E1000_SUCCESS) {
+            ret_val = em_host_if_read_cookie(hw, buffer);
+            if (ret_val == E1000_SUCCESS) {
+                checksum = hdr->checksum;
+                hdr->checksum = 0;
+                if ((hdr->signature == E1000_IAMT_SIGNATURE) &&
+                    checksum == em_calculate_mng_checksum((char *)buffer,
+                                               E1000_MNG_DHCP_COOKIE_LENGTH)) {
+                    if (hdr->status &
+                        E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT)
+                        tx_filter = TRUE;
+                } else
+                    tx_filter = TRUE;
+            } else
+                tx_filter = TRUE;
+        }
+    }
+
+    hw->tx_pkt_filtering = tx_filter;
+    return tx_filter;
+}
+
+/******************************************************************************
+ * Verifies the hardware needs to allow ARPs to be processed by the host
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - TRUE/FALSE
+ *
+ *****************************************************************************/
+uint32_t
+em_enable_mng_pass_thru(struct em_hw *hw)
+{
+    uint32_t manc;
+    uint32_t fwsm, factps;
+
+    if (hw->asf_firmware_present) {
+        manc = E1000_READ_REG(hw, MANC);
+
+        if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+            !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+            return FALSE;
+        if (em_arc_subsystem_valid(hw) == TRUE) {
+            fwsm = E1000_READ_REG(hw, FWSM);
+            factps = E1000_READ_REG(hw, FACTPS);
+
+            if (((fwsm & E1000_FWSM_MODE_MASK) ==
+                (em_mng_mode_pt << E1000_FWSM_MODE_SHIFT)) &&
+                (factps & E1000_FACTPS_MNGCG))
+                return TRUE;
+        } else
+            if ((manc & E1000_MANC_SMBUS_EN) && !(manc & E1000_MANC_ASF_EN))
+                return TRUE;
+    }
+    return FALSE;
+}
+
+static int32_t
+em_polarity_reversal_workaround(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t mii_status_reg;
+    uint16_t i;
+
+    /* Polarity reversal workaround for forced 10F/10H links. */
+
+    /* Disable the transmitter on the PHY */
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+    if(ret_val)
+        return ret_val;
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+    if(ret_val)
+        return ret_val;
+
+    /* This loop will early-out if the NO link condition has been met. */
+    for(i = PHY_FORCE_TIME; i > 0; i--) {
+        /* Read the MII Status Register and wait for Link Status bit
+         * to be clear.
+         */
+
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        if((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break;
+        msec_delay_irq(100);
+    }
+
+    /* Recommended delay time after link has been lost */
+    msec_delay_irq(1000);
+
+    /* Now we will re-enable th transmitter on the PHY */
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+    if(ret_val)
+        return ret_val;
+    msec_delay_irq(50);
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
+    if(ret_val)
+        return ret_val;
+    msec_delay_irq(50);
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
+    if(ret_val)
+        return ret_val;
+    msec_delay_irq(50);
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+    if(ret_val)
+        return ret_val;
+
+    /* This loop will early-out if the link condition has been met. */
+    for(i = PHY_FORCE_TIME; i > 0; i--) {
+        /* Read the MII Status Register and wait for Link Status bit
+         * to be set.
+         */
+
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        if(mii_status_reg & MII_SR_LINK_STATUS) break;
+        msec_delay_irq(100);
+    }
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Disables PCI-Express master access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - none.
+ *
+ ***************************************************************************/
+void
+em_set_pci_express_master_disable(struct em_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("em_set_pci_express_master_disable");
+
+    if (hw->bus_type != em_bus_type_pci_express)
+        return;
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+}
+
+/***************************************************************************
+ *
+ * Enables PCI-Express master access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - none.
+ *
+ ***************************************************************************/
+void
+em_enable_pciex_master(struct em_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("em_enable_pciex_master");
+
+    if (hw->bus_type != em_bus_type_pci_express)
+        return;
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+}
+
+/*******************************************************************************
+ *
+ * Disables PCI-Express master access and verifies there are no pending requests
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_MASTER_REQUESTS_PENDING if master disable bit hasn't
+ *            caused the master requests to be disabled.
+ *            E1000_SUCCESS master requests disabled.
+ *
+ ******************************************************************************/
+int32_t
+em_disable_pciex_master(struct em_hw *hw)
+{
+    int32_t timeout = MASTER_DISABLE_TIMEOUT;   /* 80ms */
+
+    DEBUGFUNC("em_disable_pciex_master");
+
+    if (hw->bus_type != em_bus_type_pci_express)
+        return E1000_SUCCESS;
+
+    em_set_pci_express_master_disable(hw);
+
+    while(timeout) {
+        if(!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE))
+            break;
+        else
+            usec_delay(100);
+        timeout--;
+    }
+
+    if(!timeout) {
+        DEBUGOUT("Master requests are pending.\n");
+        return -E1000_ERR_MASTER_REQUESTS_PENDING;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Check for EEPROM Auto Read bit done.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ *            E1000_SUCCESS at any other case.
+ *
+ ******************************************************************************/
+int32_t
+em_get_auto_rd_done(struct em_hw *hw)
+{
+    int32_t timeout = AUTO_READ_DONE_TIMEOUT;
+
+    DEBUGFUNC("em_get_auto_rd_done");
+
+    switch (hw->mac_type) {
+    default:
+        msec_delay(5);
+        break;
+    case em_82571:
+    case em_82572:
+    case em_82573:
+        while(timeout) {
+            if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
+            else msec_delay(1);
+            timeout--;
+        }
+
+        if(!timeout) {
+            DEBUGOUT("Auto read by HW from EEPROM has not completed.\n");
+            return -E1000_ERR_RESET;
+        }
+        break;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * Checks if the PHY configuration is done
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ *            E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+em_get_phy_cfg_done(struct em_hw *hw)
+{
+    int32_t timeout = PHY_CFG_TIMEOUT;
+    uint32_t cfg_mask = E1000_EEPROM_CFG_DONE;
+
+    DEBUGFUNC("em_get_phy_cfg_done");
+
+    switch (hw->mac_type) {
+    default:
+        msec_delay(10);
+        break;
+    case em_82571:
+    case em_82572:
+        while (timeout) {
+            if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask)
+                break;
+            else
+                msec_delay(1);
+            timeout--;
+        }
+
+        if (!timeout) {
+            DEBUGOUT("MNG configuration cycle has not completed.\n");
+            return -E1000_ERR_RESET;
+        }
+        break;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Using the combination of SMBI and SWESMBI semaphore bits when resetting
+ * adapter or Eeprom access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_EEPROM if fail to access EEPROM.
+ *            E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+em_get_hw_eeprom_semaphore(struct em_hw *hw)
+{
+    int32_t timeout;
+    uint32_t swsm;
+
+    DEBUGFUNC("em_get_hw_eeprom_semaphore");
+
+    if(!hw->eeprom_semaphore_present)
+        return E1000_SUCCESS;
+
+
+    /* Get the FW semaphore. */
+    timeout = hw->eeprom.word_size + 1;
+    while(timeout) {
+        swsm = E1000_READ_REG(hw, SWSM);
+        swsm |= E1000_SWSM_SWESMBI;
+        E1000_WRITE_REG(hw, SWSM, swsm);
+        /* if we managed to set the bit we got the semaphore. */
+        swsm = E1000_READ_REG(hw, SWSM);
+        if(swsm & E1000_SWSM_SWESMBI)
+            break;
+
+        usec_delay(50);
+        timeout--;
+    }
+
+    if(!timeout) {
+        /* Release semaphores */
+        em_put_hw_eeprom_semaphore(hw);
+        DEBUGOUT("Driver can't access the Eeprom - SWESMBI bit is set.\n");
+        return -E1000_ERR_EEPROM;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * This function clears HW semaphore bits.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - None.
+ *
+ ***************************************************************************/
+void
+em_put_hw_eeprom_semaphore(struct em_hw *hw)
+{
+    uint32_t swsm;
+
+    DEBUGFUNC("em_put_hw_eeprom_semaphore");
+
+    if(!hw->eeprom_semaphore_present)
+        return;
+
+    swsm = E1000_READ_REG(hw, SWSM);
+        swsm &= ~(E1000_SWSM_SWESMBI);
+    E1000_WRITE_REG(hw, SWSM, swsm);
+}
+
+/******************************************************************************
+ * Checks if PHY reset is blocked due to SOL/IDER session, for example.
+ * Returning E1000_BLK_PHY_RESET isn't necessarily an error.  But it's up to
+ * the caller to figure out how to deal with it.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_BLK_PHY_RESET
+ *            E1000_SUCCESS
+ *
+ *****************************************************************************/
+int32_t
+em_check_phy_reset_block(struct em_hw *hw)
+{
+    uint32_t manc = 0;
+
+    if (hw->mac_type > em_82547_rev_2)
+        manc = E1000_READ_REG(hw, MANC);
+    return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+           E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+uint8_t
+em_arc_subsystem_valid(struct em_hw *hw)
+{
+    uint32_t fwsm;
+
+    /* On 8257x silicon, registers in the range of 0x8800 - 0x8FFC
+     * may not be provided a DMA clock when no manageability features are
+     * enabled.  We do not want to perform any reads/writes to these registers
+     * if this is the case.  We read FWSM to determine the manageability mode.
+     */
+    switch (hw->mac_type) {
+    case em_82571:
+    case em_82572:
+    case em_82573:
+        fwsm = E1000_READ_REG(hw, FWSM);
+        if((fwsm & E1000_FWSM_MODE_MASK) != 0)
+            return TRUE;
+        break;
+    default:
+        break;
+    }
+    return FALSE;
+}
+
+
+
+int32_t
+em_phy_misctst_get_info(struct em_hw *hw, uint16_t *enabled)
+{
+    int32_t ret_val;
+    uint16_t misctst_reg;
+
+    DEBUGFUNC("em_phy_misctst_get_info");
+
+    ret_val = em_read_phy_reg(hw, 0x0FF0, &misctst_reg);
+    if (ret_val)
+        return ret_val;
+
+    if (misctst_reg & 0x0002) {
+        DEBUGOUT("L1 ASPM disabled");
+        *enabled = FALSE;
+    } else {
+        DEBUGOUT("L1 ASPM enabled");
+        *enabled = TRUE;
+    }
+
+    return E1000_SUCCESS;
+}
+
index 67aebe2..97504ba 100644 (file)
@@ -1,6 +1,6 @@
 /*******************************************************************************
 
-  Copyright (c) 2001-2003, Intel Corporation 
+  Copyright (c) 2001-2005, Intel Corporation 
   All rights reserved.
   
   Redistribution and use in source and binary forms, with or without 
@@ -32,7 +32,7 @@
 *******************************************************************************/
 
 /*$FreeBSD: src/sys/dev/em/if_em_hw.h,v 1.1.2.8 2003/06/09 21:43:41 pdeuskar Exp $*/
-/*$DragonFly: src/sys/dev/netif/em/if_em_hw.h,v 1.8 2005/10/17 06:18:36 sephe Exp $*/
+/*$DragonFly: src/sys/dev/netif/em/if_em_hw.h,v 1.9 2005/11/08 12:48:18 sephe Exp $*/
 /* if_em_hw.h
  * Structures, enums, and macros for the MAC
  */
@@ -63,6 +63,9 @@ typedef enum {
     em_82541_rev_2,
     em_82547,
     em_82547_rev_2,
+    em_82571,
+    em_82572,
+    em_82573,
     em_num_macs
 } em_mac_type;
 
@@ -70,6 +73,8 @@ typedef enum {
     em_eeprom_uninitialized = 0,
     em_eeprom_spi,
     em_eeprom_microwire,
+    em_eeprom_flash,
+    em_eeprom_none, /* No NVM support */
     em_num_eeprom_types
 } em_eeprom_type;
 
@@ -102,6 +107,7 @@ typedef enum {
     em_bus_type_unknown = 0,
     em_bus_type_pci,
     em_bus_type_pcix,
+    em_bus_type_pci_express,
     em_bus_type_reserved
 } em_bus_type;
 
@@ -113,6 +119,7 @@ typedef enum {
     em_bus_speed_100,
     em_bus_speed_120,
     em_bus_speed_133,
+    em_bus_speed_2500,
     em_bus_speed_reserved
 } em_bus_speed;
 
@@ -121,6 +128,8 @@ typedef enum {
     em_bus_width_unknown = 0,
     em_bus_width_32,
     em_bus_width_64,
+    em_bus_width_pciex_1,
+    em_bus_width_pciex_4,
     em_bus_width_reserved
 } em_bus_width;
 
@@ -173,6 +182,12 @@ typedef enum {
     em_downshift_undefined = 0xFF
 } em_downshift;
 
+typedef enum {
+    em_smart_speed_default = 0,
+    em_smart_speed_on,
+    em_smart_speed_off
+} em_smart_speed;
+
 typedef enum {
     em_polarity_reversal_enabled = 0,
     em_polarity_reversal_disabled,
@@ -196,6 +211,7 @@ typedef enum {
 typedef enum {
     em_phy_m88 = 0,
     em_phy_igp,
+    em_phy_igp_2,
     em_phy_undefined = 0xFF
 } em_phy_type;
 
@@ -242,8 +258,19 @@ struct em_eeprom_info {
     uint16_t address_bits;
     uint16_t delay_usec;
     uint16_t page_size;
+    boolean_t use_eerd;
+    boolean_t use_eewr;
 };
 
+/* Flex ASF Information */
+#define E1000_HOST_IF_MAX_SIZE  2048
+
+typedef enum {
+    em_byte_align = 0,
+    em_word_align = 1,
+    em_dword_align = 2
+} em_align_type;
+
 
 
 /* Error Codes */
@@ -254,11 +281,16 @@ struct em_eeprom_info {
 #define E1000_ERR_PARAM    4
 #define E1000_ERR_MAC_TYPE 5
 #define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
 
 /* Function prototypes */
 /* Initialization */
 int32_t em_reset_hw(struct em_hw *hw);
 int32_t em_init_hw(struct em_hw *hw);
+int32_t em_id_led_init(struct em_hw * hw);
 int32_t em_set_mac_type(struct em_hw *hw);
 void em_set_media_type(struct em_hw *hw);
 
@@ -275,7 +307,7 @@ int32_t em_force_mac_fc(struct em_hw *hw);
 /* PHY */
 int32_t em_read_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *phy_data);
 int32_t em_write_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t data);
-void em_phy_hw_reset(struct em_hw *hw);
+int32_t em_phy_hw_reset(struct em_hw *hw);
 int32_t em_phy_reset(struct em_hw *hw);
 int32_t em_detect_gig_phy(struct em_hw *hw);
 int32_t em_phy_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
@@ -285,15 +317,89 @@ int32_t em_get_cable_length(struct em_hw *hw, uint16_t *min_length, uint16_t *ma
 int32_t em_check_polarity(struct em_hw *hw, uint16_t *polarity);
 int32_t em_check_downshift(struct em_hw *hw);
 int32_t em_validate_mdi_setting(struct em_hw *hw);
+int32_t em_phy_misctst_get_info(struct em_hw *hw, uint16_t *enabled);
 
 /* EEPROM Functions */
-void em_init_eeprom_params(struct em_hw *hw);
+int32_t em_init_eeprom_params(struct em_hw *hw);
+boolean_t em_is_onboard_nvm_eeprom(struct em_hw *hw);
+int32_t em_read_eeprom_eerd(struct em_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+int32_t em_write_eeprom_eewr(struct em_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+int32_t em_poll_eerd_eewr_done(struct em_hw *hw, int eerd);
+
+/* MNG HOST IF functions */
+uint32_t em_enable_mng_pass_thru(struct em_hw *hw);
+
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD   64
+#define E1000_HI_MAX_MNG_DATA_LENGTH    0x6F8   /* Host Interface data length */
+
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT  10      /* Time in ms to process MNG command */
+#define E1000_MNG_DHCP_COOKIE_OFFSET   0x6F0   /* Cookie offset */
+#define E1000_MNG_DHCP_COOKIE_LENGTH   0x10    /* Cookie length */
+#define E1000_MNG_IAMT_MODE            0x3
+#define E1000_IAMT_SIGNATURE            0x544D4149 /* Intel(R) Active Management Technology signature */
+
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT 0x1 /* DHCP parsing enabled */
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT    0x2 /* DHCP parsing enabled */
+#define E1000_VFTA_ENTRY_SHIFT                       0x5
+#define E1000_VFTA_ENTRY_MASK                        0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK              0x1F
+
+struct em_host_mng_command_header {
+    uint8_t command_id;
+    uint8_t checksum;
+    uint16_t reserved1;
+    uint16_t reserved2;
+    uint16_t command_length;
+};
+
+struct em_host_mng_command_info {
+    struct em_host_mng_command_header command_header;  /* Command Head/Command Result Head has 4 bytes */
+    uint8_t command_data[E1000_HI_MAX_MNG_DATA_LENGTH];   /* Command data can length 0..0x658*/
+};
+#ifdef __BIG_ENDIAN
+struct em_host_mng_dhcp_cookie{
+    uint32_t signature;
+    uint16_t vlan_id;
+    uint8_t reserved0;
+    uint8_t status;
+    uint32_t reserved1;
+    uint8_t checksum;
+    uint8_t reserved3;
+    uint16_t reserved2;
+};
+#else
+struct em_host_mng_dhcp_cookie{
+    uint32_t signature;
+    uint8_t status;
+    uint8_t reserved0;
+    uint16_t vlan_id;
+    uint32_t reserved1;
+    uint16_t reserved2;
+    uint8_t reserved3;
+    uint8_t checksum;
+};
+#endif
+
+int32_t em_mng_write_dhcp_info(struct em_hw *hw, uint8_t *buffer, 
+                                                       uint16_t length);
+boolean_t em_check_mng_mode(struct em_hw *hw);
+boolean_t em_enable_tx_pkt_filtering(struct em_hw *hw);
+int32_t em_mng_enable_host_if(struct em_hw *hw);
+int32_t em_mng_host_if_write(struct em_hw *hw, uint8_t *buffer,
+                            uint16_t length, uint16_t offset, uint8_t *sum);
+int32_t em_mng_write_cmd_header(struct em_hw* hw, 
+                                   struct em_host_mng_command_header* hdr);
+
+int32_t em_mng_write_commit(struct em_hw *hw);
+
 int32_t em_read_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
 int32_t em_validate_eeprom_checksum(struct em_hw *hw);
 int32_t em_update_eeprom_checksum(struct em_hw *hw);
 int32_t em_write_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
 int32_t em_read_part_num(struct em_hw *hw, uint32_t * part_num);
 int32_t em_read_mac_addr(struct em_hw * hw);
+int32_t em_swfw_sync_acquire(struct em_hw *hw, uint16_t mask);
+void em_swfw_sync_release(struct em_hw *hw, uint16_t mask);
 
 /* Filters (multicast, vlan, receive) */
 void em_init_rx_addrs(struct em_hw *hw);
@@ -322,17 +428,31 @@ void em_pci_set_mwi(struct em_hw *hw);
 void em_pci_clear_mwi(struct em_hw *hw);
 void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
 void em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
-int32_t em_config_dsp_after_link_change(struct em_hw *hw, boolean_t link_up);
-int32_t em_set_d3_lplu_state(struct em_hw *hw, boolean_t active);
-
-/* Port I/O is only supported on 82544 and newer (not numerical higher!) */
+/* Port I/O is only supported on 82544 and newer */
 uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset);
 void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
-
+int32_t em_config_dsp_after_link_change(struct em_hw *hw, boolean_t link_up);
+int32_t em_set_d3_lplu_state(struct em_hw *hw, boolean_t active);
+int32_t em_set_d0_lplu_state(struct em_hw *hw, boolean_t active);
+void em_set_pci_express_master_disable(struct em_hw *hw);
+void em_enable_pciex_master(struct em_hw *hw);
+int32_t em_disable_pciex_master(struct em_hw *hw);
+int32_t em_get_auto_rd_done(struct em_hw *hw);
+int32_t em_get_phy_cfg_done(struct em_hw *hw);
+int32_t em_get_software_semaphore(struct em_hw *hw);
+void em_release_software_semaphore(struct em_hw *hw);
+int32_t em_check_phy_reset_block(struct em_hw *hw);
+int32_t em_get_hw_eeprom_semaphore(struct em_hw *hw);
+void em_put_hw_eeprom_semaphore(struct em_hw *hw);
+int32_t em_commit_shadow_ram(struct em_hw *hw);
+uint8_t em_arc_subsystem_valid(struct em_hw *hw);
+
+#ifndef E1000_READ_REG_IO
 #define E1000_READ_REG_IO(a, reg) \
     em_read_reg_io((a), E1000_##reg)
 #define E1000_WRITE_REG_IO(a, reg, val) \
     em_write_reg_io((a), E1000_##reg, val)
+#endif
 
 /* PCI Device IDs */
 #define E1000_DEV_ID_82542               0x1000
@@ -360,12 +480,23 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
 #define E1000_DEV_ID_82541ER             0x1078
 #define E1000_DEV_ID_82547GI             0x1075
 #define E1000_DEV_ID_82541GI             0x1076
-#define E1000_DEV_ID_82541GI_LF          0x107C
 #define E1000_DEV_ID_82541GI_MOBILE      0x1077
+#define E1000_DEV_ID_82541GI_LF          0x107C
 #define E1000_DEV_ID_82546GB_COPPER      0x1079
 #define E1000_DEV_ID_82546GB_FIBER       0x107A
 #define E1000_DEV_ID_82546GB_SERDES      0x107B
+#define E1000_DEV_ID_82546GB_PCIE        0x108A
 #define E1000_DEV_ID_82547EI             0x1019
+#define E1000_DEV_ID_82571EB_COPPER      0x105E
+#define E1000_DEV_ID_82571EB_FIBER       0x105F
+#define E1000_DEV_ID_82571EB_SERDES      0x1060
+#define E1000_DEV_ID_82572EI_COPPER      0x107D
+#define E1000_DEV_ID_82572EI_FIBER       0x107E
+#define E1000_DEV_ID_82572EI_SERDES      0x107F
+#define E1000_DEV_ID_82573E              0x108B
+#define E1000_DEV_ID_82573E_IAMT         0x108C
+#define E1000_DEV_ID_82573L              0x109A
+
 
 #define NODE_ADDRESS_SIZE 6
 #define ETH_LENGTH_OF_ADDRESS 6
@@ -378,6 +509,7 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
 #define E1000_REVISION_0       0
 #define E1000_REVISION_1       1
 #define E1000_REVISION_2       2
+#define E1000_REVISION_3       3
 
 #define SPEED_10    10
 #define SPEED_100   100
@@ -434,6 +566,7 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
     E1000_IMS_RXSEQ  |    \
     E1000_IMS_LSC)
 
+
 /* Number of high/low register pairs in the RAR. The RAR (Receive Address
  * Registers) holds the directed and multicast addresses that we monitor. We
  * reserve one of these spots for our directed address, allowing us room for
@@ -454,14 +587,74 @@ struct em_rx_desc {
     uint16_t special;
 };
 
+/* Receive Descriptor - Extended */
+union em_rx_desc_extended {
+    struct {
+        uint64_t buffer_addr;
+        uint64_t reserved;
+    } read;
+    struct {
+        struct {
+            uint32_t mrq;              /* Multiple Rx Queues */
+            union {
+                uint32_t rss;          /* RSS Hash */
+                struct {
+                    uint16_t ip_id;    /* IP id */
+                    uint16_t csum;     /* Packet Checksum */
+                } csum_ip;
+            } hi_dword;
+        } lower;
+        struct {
+            uint32_t status_error;     /* ext status/error */
+            uint16_t length;
+            uint16_t vlan;             /* VLAN tag */
+        } upper;
+    } wb;  /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union em_rx_desc_packet_split {
+    struct {
+        /* one buffer for protocol header(s), three data buffers */
+        uint64_t buffer_addr[MAX_PS_BUFFERS];
+    } read;
+    struct {
+        struct {
+            uint32_t mrq;              /* Multiple Rx Queues */
+            union {
+                uint32_t rss;          /* RSS Hash */
+                struct {
+                    uint16_t ip_id;    /* IP id */
+                    uint16_t csum;     /* Packet Checksum */
+                } csum_ip;
+            } hi_dword;
+        } lower;
+        struct {
+            uint32_t status_error;     /* ext status/error */
+            uint16_t length0;          /* length of buffer 0 */
+            uint16_t vlan;             /* VLAN tag */
+        } middle;
+        struct {
+            uint16_t header_status;
+            uint16_t length[3];        /* length of buffers 1-3 */
+        } upper;
+        uint64_t reserved;
+    } wb; /* writeback */
+};
+
 /* Receive Decriptor bit definitions */
 #define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
 #define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
 #define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
 #define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
 #define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
 #define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
 #define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
 #define E1000_RXD_ERR_CE        0x01    /* CRC Error */
 #define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
 #define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
@@ -471,9 +664,20 @@ struct em_rx_desc {
 #define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
 #define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
 #define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
-#define E1000_RXD_SPC_PRI_SHIFT 0x000D  /* Priority is in upper 3 of 16 */
+#define E1000_RXD_SPC_PRI_SHIFT 13
 #define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
-#define E1000_RXD_SPC_CFI_SHIFT 0x000C  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP        0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK  0x000003FF
 
 /* mask to determine if packets should be dropped due to frame errors */
 #define E1000_RXD_ERR_FRAME_ERR_MASK ( \
@@ -483,6 +687,15 @@ struct em_rx_desc {
     E1000_RXD_ERR_CXE |                \
     E1000_RXD_ERR_RXE)
 
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
 /* Transmit Descriptor */
 struct em_tx_desc {
     uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
@@ -635,6 +848,8 @@ struct em_ffvt_entry {
 #define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
 #define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
 
+#define E1000_DISABLE_SERDES_LOOPBACK   0x0400
+
 /* Register Set. (82543, 82544)
  *
  * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
@@ -655,6 +870,7 @@ struct em_ffvt_entry {
 #define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
 #define E1000_FLA      0x0001C  /* Flash Access - RW */
 #define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_SCTL     0x00024  /* SerDes Control - RW */
 #define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
 #define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
 #define E1000_FCT      0x00030  /* Flow Control Type - RW */
@@ -664,7 +880,14 @@ struct em_ffvt_entry {
 #define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
 #define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
 #define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
 #define E1000_RCTL     0x00100  /* RX Control - RW */
+#define E1000_RDTR1    0x02820  /* RX Delay Timer (1) - RW */
+#define E1000_RDBAL1   0x02900  /* RX Descriptor Base Address Low (1) - RW */
+#define E1000_RDBAH1   0x02904  /* RX Descriptor Base Address High (1) - RW */
+#define E1000_RDLEN1   0x02908  /* RX Descriptor Length (1) - RW */
+#define E1000_RDH1     0x02910  /* RX Descriptor Head (1) - RW */
+#define E1000_RDT1     0x02918  /* RX Descriptor Tail (1) - RW */
 #define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
 #define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
 #define E1000_RXCW     0x00180  /* RX Configuration Word - RO */
@@ -673,18 +896,39 @@ struct em_ffvt_entry {
 #define E1000_TBT      0x00448  /* TX Burst Timer - RW */
 #define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
 #define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
 #define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_FLASH_UPDATES 1000
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL  0x01030  /* FLASH control register */
+#define E1000_FLSWDATA 0x01034  /* FLASH data register */
+#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
 #define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
 #define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
 #define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
 #define E1000_RDBAH    0x02804  /* RX Descriptor Base Address High - RW */
 #define E1000_RDLEN    0x02808  /* RX Descriptor Length - RW */
 #define E1000_RDH      0x02810  /* RX Descriptor Head - RW */
 #define E1000_RDT      0x02818  /* RX Descriptor Tail - RW */
 #define E1000_RDTR     0x02820  /* RX Delay Timer - RW */
+#define E1000_RDBAL0   E1000_RDBAL /* RX Desc Base Address Low (0) - RW */
+#define E1000_RDBAH0   E1000_RDBAH /* RX Desc Base Address High (0) - RW */
+#define E1000_RDLEN0   E1000_RDLEN /* RX Desc Length (0) - RW */
+#define E1000_RDH0     E1000_RDH   /* RX Desc Head (0) - RW */
+#define E1000_RDT0     E1000_RDT   /* RX Desc Tail (0) - RW */
+#define E1000_RDTR0    E1000_RDTR  /* RX Delay Timer (0) - RW */
 #define E1000_RXDCTL   0x02828  /* RX Descriptor Control - RW */
 #define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
 #define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
+#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
 #define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
 #define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
 #define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
@@ -700,6 +944,14 @@ struct em_ffvt_entry {
 #define E1000_TXDCTL   0x03828  /* TX Descriptor Control - RW */
 #define E1000_TADV     0x0382C  /* TX Interrupt Absolute Delay Val - RW */
 #define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_TARC0    0x03840 /* TX Arbitration Count (0) */
+#define E1000_TDBAL1   0x03900 /* TX Desc Base Address Low (1) - RW */
+#define E1000_TDBAH1   0x03904 /* TX Desc Base Address High (1) - RW */
+#define E1000_TDLEN1   0x03908 /* TX Desc Length (1) - RW */
+#define E1000_TDH1     0x03910 /* TX Desc Head (1) - RW */
+#define E1000_TDT1     0x03918 /* TX Desc Tail (1) - RW */
+#define E1000_TXDCTL1  0x03928 /* TX Descriptor Control (1) - RW */
+#define E1000_TARC1    0x03940 /* TX Arbitration Count (1) */
 #define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
 #define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
 #define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
@@ -758,7 +1010,17 @@ struct em_ffvt_entry {
 #define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
 #define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
 #define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
 #define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
 #define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
 #define E1000_RA       0x05400  /* Receive Address - RW Array */
 #define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
@@ -776,6 +1038,24 @@ struct em_ffvt_entry {
 #define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
 #define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
 
+#define E1000_GCR       0x05B00 /* PCI-Ex Control */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
+#define E1000_HICR      0x08F00 /* Host Inteface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_RETA      0x05C00 /* Redirection Table - RW Array */
+#define E1000_RSSRK     0x05C80 /* RSS Random Key - RW Array */
+#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
 /* Register Set (82542)
  *
  * Some of the 82542 registers are located at different offsets than they are
@@ -790,6 +1070,7 @@ struct em_ffvt_entry {
 #define E1000_82542_CTRL_EXT E1000_CTRL_EXT
 #define E1000_82542_FLA      E1000_FLA
 #define E1000_82542_MDIC     E1000_MDIC
+#define E1000_82542_SCTL     E1000_SCTL
 #define E1000_82542_FCAL     E1000_FCAL
 #define E1000_82542_FCAH     E1000_FCAH
 #define E1000_82542_FCT      E1000_FCT
@@ -807,6 +1088,18 @@ struct em_ffvt_entry {
 #define E1000_82542_RDLEN    0x00118
 #define E1000_82542_RDH      0x00120
 #define E1000_82542_RDT      0x00128
+#define E1000_82542_RDTR0    E1000_82542_RDTR
+#define E1000_82542_RDBAL0   E1000_82542_RDBAL
+#define E1000_82542_RDBAH0   E1000_82542_RDBAH
+#define E1000_82542_RDLEN0   E1000_82542_RDLEN
+#define E1000_82542_RDH0     E1000_82542_RDH
+#define E1000_82542_RDT0     E1000_82542_RDT
+#define E1000_82542_RDTR1    0x00130
+#define E1000_82542_RDBAL1   0x00138
+#define E1000_82542_RDBAH1   0x0013C
+#define E1000_82542_RDLEN1   0x00140
+#define E1000_82542_RDH1     0x00148
+#define E1000_82542_RDT1     0x00150
 #define E1000_82542_FCRTH    0x00160
 #define E1000_82542_FCRTL    0x00168
 #define E1000_82542_FCTTV    E1000_FCTTV
@@ -826,6 +1119,18 @@ struct em_ffvt_entry {
 #define E1000_82542_VFTA     0x00600
 #define E1000_82542_LEDCTL   E1000_LEDCTL
 #define E1000_82542_PBA      E1000_PBA
+#define E1000_82542_PBS      E1000_PBS
+#define E1000_82542_EEMNGCTL E1000_EEMNGCTL
+#define E1000_82542_EEARBC   E1000_EEARBC
+#define E1000_82542_FLASHT   E1000_FLASHT
+#define E1000_82542_EEWR     E1000_EEWR
+#define E1000_82542_FLSWCTL  E1000_FLSWCTL
+#define E1000_82542_FLSWDATA E1000_FLSWDATA
+#define E1000_82542_FLSWCNT  E1000_FLSWCNT
+#define E1000_82542_FLOP     E1000_FLOP
+#define E1000_82542_EXTCNF_CTRL  E1000_EXTCNF_CTRL
+#define E1000_82542_EXTCNF_SIZE  E1000_EXTCNF_SIZE
+#define E1000_82542_ERT      E1000_ERT
 #define E1000_82542_RXDCTL   E1000_RXDCTL
 #define E1000_82542_RADV     E1000_RADV
 #define E1000_82542_RSRPD    E1000_RSRPD
@@ -910,6 +1215,45 @@ struct em_ffvt_entry {
 #define E1000_82542_FFMT     E1000_FFMT
 #define E1000_82542_FFVT     E1000_FFVT
 #define E1000_82542_HOST_IF  E1000_HOST_IF
+#define E1000_82542_IAM         E1000_IAM
+#define E1000_82542_EEMNGCTL    E1000_EEMNGCTL
+#define E1000_82542_PSRCTL      E1000_PSRCTL
+#define E1000_82542_RAID        E1000_RAID
+#define E1000_82542_TARC0       E1000_TARC0
+#define E1000_82542_TDBAL1      E1000_TDBAL1
+#define E1000_82542_TDBAH1      E1000_TDBAH1
+#define E1000_82542_TDLEN1      E1000_TDLEN1
+#define E1000_82542_TDH1        E1000_TDH1
+#define E1000_82542_TDT1        E1000_TDT1
+#define E1000_82542_TXDCTL1     E1000_TXDCTL1
+#define E1000_82542_TARC1       E1000_TARC1
+#define E1000_82542_RFCTL       E1000_RFCTL
+#define E1000_82542_GCR         E1000_GCR
+#define E1000_82542_GSCL_1      E1000_GSCL_1
+#define E1000_82542_GSCL_2      E1000_GSCL_2
+#define E1000_82542_GSCL_3      E1000_GSCL_3
+#define E1000_82542_GSCL_4      E1000_GSCL_4
+#define E1000_82542_FACTPS      E1000_FACTPS
+#define E1000_82542_SWSM        E1000_SWSM
+#define E1000_82542_FWSM        E1000_FWSM
+#define E1000_82542_FFLT_DBG    E1000_FFLT_DBG
+#define E1000_82542_IAC         E1000_IAC
+#define E1000_82542_ICRXPTC     E1000_ICRXPTC
+#define E1000_82542_ICRXATC     E1000_ICRXATC
+#define E1000_82542_ICTXPTC     E1000_ICTXPTC
+#define E1000_82542_ICTXATC     E1000_ICTXATC
+#define E1000_82542_ICTXQEC     E1000_ICTXQEC
+#define E1000_82542_ICTXQMTC    E1000_ICTXQMTC
+#define E1000_82542_ICRXDMTC    E1000_ICRXDMTC
+#define E1000_82542_ICRXOC      E1000_ICRXOC
+#define E1000_82542_HICR        E1000_HICR
+
+#define E1000_82542_CPUVEC      E1000_CPUVEC
+#define E1000_82542_MRQC        E1000_MRQC
+#define E1000_82542_RETA        E1000_RETA
+#define E1000_82542_RSSRK       E1000_RSSRK
+#define E1000_82542_RSSIM       E1000_RSSIM
+#define E1000_82542_RSSIR       E1000_RSSIR
 
 /* Statistics counters collected by the MAC */
 struct em_hw_stats {
@@ -971,11 +1315,21 @@ struct em_hw_stats {
     uint64_t bptc;
     uint64_t tsctc;
     uint64_t tsctfc;
+    uint64_t iac;
+    uint64_t icrxptc;
+    uint64_t icrxatc;
+    uint64_t ictxptc;
+    uint64_t ictxatc;
+    uint64_t ictxqec;
+    uint64_t ictxqmtc;
+    uint64_t icrxdmtc;
+    uint64_t icrxoc;
 };
 
 /* Structure containing variables used by the shared code (em_hw.c) */
 struct em_hw {
     uint8_t *hw_addr;
+    uint8_t *flash_address;
     em_mac_type mac_type;
     em_phy_type phy_type;
     uint32_t phy_init_script;
@@ -989,6 +1343,8 @@ struct em_hw {
     em_ms_type master_slave;
     em_ms_type original_master_slave;
     em_ffe_config ffe_config_state;
+    uint32_t asf_firmware_present;
+    uint32_t eeprom_semaphore_present;
     bus_space_tag_t reg_io_tag;
     bus_space_tag_t reg_io_handle;
     uint32_t phy_id;
@@ -1006,6 +1362,8 @@ struct em_hw {
     uint32_t ledctl_default;
     uint32_t ledctl_mode1;
     uint32_t ledctl_mode2;
+    boolean_t tx_pkt_filtering;
+    struct em_host_mng_dhcp_cookie mng_cookie;
     uint16_t phy_spd_default;
     uint16_t autoneg_advertised;
     uint16_t pci_cmd_word;
@@ -1031,11 +1389,13 @@ struct em_hw {
     uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
     boolean_t disable_polarity_correction;
     boolean_t speed_downgraded;
+    em_smart_speed smart_speed;
     em_dsp_config dsp_config_state;
     boolean_t get_link_status;
     boolean_t serdes_link_down;
     boolean_t tbi_compatibility_en;
     boolean_t tbi_compatibility_on;
+    boolean_t laa_is_present;
     boolean_t phy_reset_disable;
     boolean_t fc_send_xon;
     boolean_t fc_strict_ieee;
@@ -1043,17 +1403,24 @@ struct em_hw {
     boolean_t adaptive_ifs;
     boolean_t ifs_params_forced;
     boolean_t in_ifs_mode;
+    boolean_t mng_reg_access_disabled;
 };
 
 
 #define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
 #define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
-
+#define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
+#define E1000_EEPROM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
+#define E1000_EEPROM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_EEPROM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_EEPROM_POLL_READ     0    /* Flag for polling for read complete */
 /* Register Bit Masks */
 /* Device Control */
 #define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
 #define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
 #define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
 #define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
 #define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
 #define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
@@ -1067,6 +1434,8 @@ struct em_hw {
 #define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
 #define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
 #define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
 #define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
 #define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
 #define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
@@ -1086,6 +1455,7 @@ struct em_hw {
 #define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
 #define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
 #define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
 #define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
 #define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
 #define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
@@ -1095,6 +1465,8 @@ struct em_hw {
 #define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
 #define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
 #define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state. Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
 #define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
 #define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
 #define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
@@ -1125,6 +1497,18 @@ struct em_hw {
 #ifndef E1000_EEPROM_GRANT_ATTEMPTS
 #define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
 #endif
+#define E1000_EECD_AUTO_RD          0x00000200  /* EEPROM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* EEprom Size */
+#define E1000_EECD_SIZE_EX_SHIFT    11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_STM_OPCODE     0xDB00
+#define E1000_HICR_FW_RESET  0xC0
 
 /* EEPROM Read */
 #define E1000_EERD_START      0x00000001 /* Start Read */
@@ -1168,6 +1552,10 @@ struct em_hw {
 #define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
 #define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
 #define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+#define E1000_CTRL_EXT_CANC           0x04000000  /* Interrupt delay cancellation */
+#define E1000_CTRL_EXT_DRV_LOAD       0x10000000  /* Driver loaded bit for FW */
+#define E1000_CTRL_EXT_IAME           0x08000000  /* Interrupt acknowledge Auto-mask */
+#define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000  /* Clear Interrupt timers after IMS clear */
 
 /* MDI Control */
 #define E1000_MDIC_DATA_MASK 0x0000FFFF
@@ -1184,18 +1572,22 @@ struct em_hw {
 /* LED Control */
 #define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
 #define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_BLINK_RATE      0x0000020
 #define E1000_LEDCTL_LED0_IVRT            0x00000040
 #define E1000_LEDCTL_LED0_BLINK           0x00000080
 #define E1000_LEDCTL_LED1_MODE_MASK       0x00000F00
 #define E1000_LEDCTL_LED1_MODE_SHIFT      8
+#define E1000_LEDCTL_LED1_BLINK_RATE      0x0002000
 #define E1000_LEDCTL_LED1_IVRT            0x00004000
 #define E1000_LEDCTL_LED1_BLINK           0x00008000
 #define E1000_LEDCTL_LED2_MODE_MASK       0x000F0000
 #define E1000_LEDCTL_LED2_MODE_SHIFT      16
+#define E1000_LEDCTL_LED2_BLINK_RATE      0x00200000
 #define E1000_LEDCTL_LED2_IVRT            0x00400000
 #define E1000_LEDCTL_LED2_BLINK           0x00800000
 #define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
 #define E1000_LEDCTL_LED3_MODE_SHIFT      24
+#define E1000_LEDCTL_LED3_BLINK_RATE      0x20000000
 #define E1000_LEDCTL_LED3_IVRT            0x40000000
 #define E1000_LEDCTL_LED3_BLINK           0x80000000
 
@@ -1235,6 +1627,10 @@ struct em_hw {
 #define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
 #define E1000_ICR_TXD_LOW       0x00008000
 #define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
 
 /* Interrupt Cause Set */
 #define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
@@ -1252,6 +1648,9 @@ struct em_hw {
 #define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
 #define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
 #define E1000_ICS_SRPD      E1000_ICR_SRPD
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
 
 /* Interrupt Mask Set */
 #define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
@@ -1269,6 +1668,9 @@ struct em_hw {
 #define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
 #define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
 #define E1000_IMS_SRPD      E1000_ICR_SRPD
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
 
 /* Interrupt Mask Clear */
 #define E1000_IMC_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
@@ -1286,6 +1688,9 @@ struct em_hw {
 #define E1000_IMC_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
 #define E1000_IMC_TXD_LOW   E1000_ICR_TXD_LOW
 #define E1000_IMC_SRPD      E1000_ICR_SRPD
+#define E1000_IMC_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMC_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMC_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
 
 /* Receive Control */
 #define E1000_RCTL_RST            0x00000001    /* Software reset */
@@ -1298,6 +1703,8 @@ struct em_hw {
 #define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
 #define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
 #define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
 #define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
 #define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min threshold size */
 #define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min threshold size */
@@ -1324,6 +1731,34 @@ struct em_hw {
 #define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
 #define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
 #define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+/* Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+    
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
 
 /* Receive Descriptor */
 #define E1000_RDT_DELAY 0x0000ffff      /* Delay timer (1=1024us) */
@@ -1338,6 +1773,23 @@ struct em_hw {
 #define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
 #define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
 
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS           0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
+#define E1000_RFCTL_NFSW_DIS            0x00000040
+#define E1000_RFCTL_NFSR_DIS            0x00000080
+#define E1000_RFCTL_NFS_VER_MASK        0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT       8
+#define E1000_RFCTL_IPV6_DIS            0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
+#define E1000_RFCTL_ACK_DIS             0x00001000
+#define E1000_RFCTL_ACKD_DIS            0x00002000
+#define E1000_RFCTL_IPFRSP_DIS          0x00004000
+#define E1000_RFCTL_EXTEN               0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
+
 /* Receive Descriptor Control */
 #define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */
 #define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
@@ -1351,6 +1803,8 @@ struct em_hw {
 #define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
 #define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
 #define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc.
+                                              still to be processed. */
 
 /* Transmit Configuration Word */
 #define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
@@ -1384,12 +1838,26 @@ struct em_hw {
 #define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
 #define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
 #define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
 
 /* Receive Checksum Control */
 #define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
 #define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
 #define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
 #define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
+
+/* Multiple Receive Queue Control */
+#define E1000_MRQC_ENABLE_MASK              0x00000003
+#define E1000_MRQC_ENABLE_RSS_2Q            0x00000001
+#define E1000_MRQC_ENABLE_RSS_INT           0x00000004
+#define E1000_MRQC_RSS_FIELD_MASK           0xFFFF0000
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP       0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4           0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP       0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_EX        0x00080000
+#define E1000_MRQC_RSS_FIELD_IPV6           0x00100000
 
 /* Definitions for power management and wakeup registers */
 /* Wake Up Control */
@@ -1408,6 +1876,7 @@ struct em_hw {
 #define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
 #define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
 #define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_IGNORE_TCO      0x00008000 /* Ignore WakeOn TCO packets */
 #define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
 #define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
 #define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
@@ -1443,13 +1912,19 @@ struct em_hw {
 #define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
 #define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery
                                              * Filtering */
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
 #define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
 #define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
 #define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
 #define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
                                                     * filtering */
 #define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
                                              * memory */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000 /* Enable IP address
+                                                    * filtering */
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
 #define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
 #define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
 #define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
@@ -1460,11 +1935,97 @@ struct em_hw {
 #define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
 #define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
 
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+/* FW Semaphore Register */
+#define E1000_FWSM_MODE_MASK    0x0000000E /* FW mode */
+#define E1000_FWSM_MODE_SHIFT            1
+#define E1000_FWSM_FW_VALID     0x00008000 /* FW established a valid mode */
+
+/* FFLT Debug Register */
+#define E1000_FFLT_DBG_INVC     0x00100000 /* Invalid /C/ code handling */
+
+typedef enum {
+    em_mng_mode_none     = 0,
+    em_mng_mode_asf,
+    em_mng_mode_pt,
+    em_mng_mode_ipmi,
+    em_mng_mode_host_interface_only
+} em_mng_mode;
+
+/* Host Inteface Control Register */
+#define E1000_HICR_EN           0x00000001  /* Enable Bit - RO */
+#define E1000_HICR_C            0x00000002  /* Driver sets this bit when done
+                                             * to put command in RAM */
+#define E1000_HICR_SV           0x00000004  /* Status Validity */
+#define E1000_HICR_FWR          0x00000080  /* FW reset. Set by the Host */
+
+/* Host Interface Command Interface - Address range 0x8800-0x8EFF */
+#define E1000_HI_MAX_DATA_LENGTH         252 /* Host Interface data length */
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH  1792 /* Number of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH  448 /* Number of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT         500 /* Time in ms to process HI command */
+
+struct em_host_command_header {
+    uint8_t command_id;
+    uint8_t command_length;
+    uint8_t command_options;   /* I/F bits for command, status for return */
+    uint8_t checksum;
+};
+struct em_host_command_info {
+    struct em_host_command_header command_header;  /* Command Head/Command Result Head has 4 bytes */
+    uint8_t command_data[E1000_HI_MAX_DATA_LENGTH];   /* Command data can length 0..252 */
+};
+
+/* Host SMB register #0 */
+#define E1000_HSMC0R_CLKIN      0x00000001  /* SMB Clock in */
+#define E1000_HSMC0R_DATAIN     0x00000002  /* SMB Data in */
+#define E1000_HSMC0R_DATAOUT    0x00000004  /* SMB Data out */
+#define E1000_HSMC0R_CLKOUT     0x00000008  /* SMB Clock out */
+
+/* Host SMB register #1 */
+#define E1000_HSMC1R_CLKIN      E1000_HSMC0R_CLKIN
+#define E1000_HSMC1R_DATAIN     E1000_HSMC0R_DATAIN
+#define E1000_HSMC1R_DATAOUT    E1000_HSMC0R_DATAOUT
+#define E1000_HSMC1R_CLKOUT     E1000_HSMC0R_CLKOUT
+
+/* FW Status Register */
+#define E1000_FWSTS_FWS_MASK    0x000000FF  /* FW Status */
+
 /* Wake Up Packet Length */
 #define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
 
 #define E1000_MDALIGN          4096
 
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+/* Function Active and Power State to MNG */
+#define E1000_FACTPS_FUNC0_POWER_STATE_MASK         0x00000003
+#define E1000_FACTPS_LAN0_VALID                     0x00000004
+#define E1000_FACTPS_FUNC0_AUX_EN                   0x00000008
+#define E1000_FACTPS_FUNC1_POWER_STATE_MASK         0x000000C0
+#define E1000_FACTPS_FUNC1_POWER_STATE_SHIFT        6
+#define E1000_FACTPS_LAN1_VALID                     0x00000100
+#define E1000_FACTPS_FUNC1_AUX_EN                   0x00000200
+#define E1000_FACTPS_FUNC2_POWER_STATE_MASK         0x00003000
+#define E1000_FACTPS_FUNC2_POWER_STATE_SHIFT        12
+#define E1000_FACTPS_IDE_ENABLE                     0x00004000
+#define E1000_FACTPS_FUNC2_AUX_EN                   0x00008000
+#define E1000_FACTPS_FUNC3_POWER_STATE_MASK         0x000C0000
+#define E1000_FACTPS_FUNC3_POWER_STATE_SHIFT        18
+#define E1000_FACTPS_SP_ENABLE                      0x00100000
+#define E1000_FACTPS_FUNC3_AUX_EN                   0x00200000
+#define E1000_FACTPS_FUNC4_POWER_STATE_MASK         0x03000000
+#define E1000_FACTPS_FUNC4_POWER_STATE_SHIFT        24
+#define E1000_FACTPS_IPMI_ENABLE                    0x04000000
+#define E1000_FACTPS_FUNC4_AUX_EN                   0x08000000
+#define E1000_FACTPS_MNGCG                          0x20000000
+#define E1000_FACTPS_LAN_FUNC_SEL                   0x40000000
+#define E1000_FACTPS_PM_STATE_CHANGED               0x80000000
+
 /* EEPROM Commands - Microwire */
 #define EEPROM_READ_OPCODE_MICROWIRE  0x6  /* EEPROM read opcode */
 #define EEPROM_WRITE_OPCODE_MICROWIRE 0x5  /* EEPROM write opcode */
@@ -1474,27 +2035,26 @@ struct em_hw {
 
 /* EEPROM Commands - SPI */
 #define EEPROM_MAX_RETRY_SPI    5000 /* Max wait of 5ms, for RDY signal */
-#define EEPROM_READ_OPCODE_SPI  0x3  /* EEPROM read opcode */
-#define EEPROM_WRITE_OPCODE_SPI 0x2  /* EEPROM write opcode */
-#define EEPROM_A8_OPCODE_SPI    0x8  /* opcode bit-3 = address bit-8 */
-#define EEPROM_WREN_OPCODE_SPI  0x6  /* EEPROM set Write Enable latch */
-#define EEPROM_WRDI_OPCODE_SPI  0x4  /* EEPROM reset Write Enable latch */
-#define EEPROM_RDSR_OPCODE_SPI  0x5  /* EEPROM read Status register */
-#define EEPROM_WRSR_OPCODE_SPI  0x1  /* EEPROM write Status register */
+#define EEPROM_READ_OPCODE_SPI      0x03  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_SPI     0x02  /* EEPROM write opcode */
+#define EEPROM_A8_OPCODE_SPI        0x08  /* opcode bit-3 = address bit-8 */
+#define EEPROM_WREN_OPCODE_SPI      0x06  /* EEPROM set Write Enable latch */
+#define EEPROM_WRDI_OPCODE_SPI      0x04  /* EEPROM reset Write Enable latch */
+#define EEPROM_RDSR_OPCODE_SPI      0x05  /* EEPROM read Status register */
+#define EEPROM_WRSR_OPCODE_SPI      0x01  /* EEPROM write Status register */
+#define EEPROM_ERASE4K_OPCODE_SPI   0x20  /* EEPROM ERASE 4KB */
+#define EEPROM_ERASE64K_OPCODE_SPI  0xD8  /* EEPROM ERASE 64KB */
+#define EEPROM_ERASE256_OPCODE_SPI  0xDB  /* EEPROM ERASE 256B */
 
 /* EEPROM Size definitions */
-#define EEPROM_SIZE_16KB        0x1800
-#define EEPROM_SIZE_8KB         0x1400
-#define EEPROM_SIZE_4KB         0x1000
-#define EEPROM_SIZE_2KB         0x0C00
-#define EEPROM_SIZE_1KB         0x0800
-#define EEPROM_SIZE_512B        0x0400
-#define EEPROM_SIZE_128B        0x0000
+#define EEPROM_WORD_SIZE_SHIFT  6
+#define EEPROM_SIZE_SHIFT       10
 #define EEPROM_SIZE_MASK        0x1C00
 
 /* EEPROM Word Offsets */
 #define EEPROM_COMPAT                 0x0003
 #define EEPROM_ID_LED_SETTINGS        0x0004
+#define EEPROM_VERSION                0x0005
 #define EEPROM_SERDES_AMPLITUDE       0x0006 /* For SERDES output amplitude adjustment. */
 #define EEPROM_PHY_CLASS_WORD         0x0007
 #define EEPROM_INIT_CONTROL1_REG      0x000A
@@ -1505,6 +2065,8 @@ struct em_hw {
 #define EEPROM_FLASH_VERSION          0x0032
 #define EEPROM_CHECKSUM_REG           0x003F
 
+#define E1000_EEPROM_CFG_DONE         0x00040000   /* MNG config cycle done */
+
 /* Word definitions for ID LED Settings */
 #define ID_LED_RESERVED_0000 0x0000
 #define ID_LED_RESERVED_FFFF 0xFFFF
@@ -1603,11 +2165,28 @@ struct em_hw {
 #define IFS_MIN                40
 #define IFS_RATIO              4
 
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_PCIE_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_PHY_WRITE_ENABLE  0x00000002
+#define E1000_EXTCNF_CTRL_D_UD_ENABLE       0x00000004
+#define E1000_EXTCNF_CTRL_D_UD_LATENCY      0x00000008
+#define E1000_EXTCNF_CTRL_D_UD_OWNER        0x00000010
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
+#define E1000_EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER   0x1FFF0000
+
+#define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH    0x000000FF
+#define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH   0x0000FF00
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH   0x00FF0000
+
 /* PBA constants */
+#define E1000_PBA_12K 0x000C    /* 12KB, default Rx allocation */
 #define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
 #define E1000_PBA_22K 0x0016
 #define E1000_PBA_24K 0x0018
 #define E1000_PBA_30K 0x001E
+#define E1000_PBA_32K 0x0020
+#define E1000_PBA_38K 0x0026
 #define E1000_PBA_40K 0x0028
 #define E1000_PBA_48K 0x0030    /* 48KB, default RX allocation */
 
@@ -1660,6 +2239,13 @@ struct em_hw {
 /* Number of milliseconds we wait for auto-negotiation to complete */
 #define LINK_UP_TIMEOUT             500
 
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for Eeprom auto read bit done after MAC reset */
+#define AUTO_READ_DONE_TIMEOUT      10
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             40
+
 #define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
 
 /* The carrier extension symbol, as received by the NIC. */
@@ -1732,6 +2318,9 @@ struct em_hw {
 #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
 #define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
 
+#define MAX_PHY_REG_ADDRESS        0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG     0xF   /* Registers equal on all pages */
+
 /* M88E1000 Specific Registers */
 #define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
 #define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
@@ -1757,6 +2346,7 @@ struct em_hw {
 #define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */
 #define IGP01E1000_GMII_FIFO       0x14 /* GMII FIFO Register */
 #define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */
+#define IGP02E1000_PHY_POWER_MGMT      0x19
 #define IGP01E1000_PHY_PAGE_SELECT     0x1F /* PHY Page Select Core Register */
 
 /* IGP01E1000 AGC Registers - stores the cable length values*/
@@ -1765,12 +2355,20 @@ struct em_hw {
 #define IGP01E1000_PHY_AGC_C        0x1472
 #define IGP01E1000_PHY_AGC_D        0x1872
 
+/* IGP02E1000 AGC Registers for cable length values */
+#define IGP02E1000_PHY_AGC_A        0x11B1
+#define IGP02E1000_PHY_AGC_B        0x12B1
+#define IGP02E1000_PHY_AGC_C        0x14B1
+#define IGP02E1000_PHY_AGC_D        0x18B1
+
 /* IGP01E1000 DSP Reset Register */
 #define IGP01E1000_PHY_DSP_RESET   0x1F33
 #define IGP01E1000_PHY_DSP_SET     0x1F71
 #define IGP01E1000_PHY_DSP_FFE     0x1F35
 
 #define IGP01E1000_PHY_CHANNEL_NUM    4
+#define IGP02E1000_PHY_CHANNEL_NUM    4
+
 #define IGP01E1000_PHY_AGC_PARAM_A    0x1171
 #define IGP01E1000_PHY_AGC_PARAM_B    0x1271
 #define IGP01E1000_PHY_AGC_PARAM_C    0x1471
@@ -1792,8 +2390,7 @@ struct em_hw {
 
 #define IGP01E1000_ANALOG_REGS_PAGE  0x20C0
 
-#define MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
-#define MAX_PHY_MULTI_PAGE_REG  0xF     /*Registers that are equal on all pages*/
+
 /* PHY Control Register */
 #define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
 #define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
@@ -2055,20 +2652,30 @@ struct em_hw {
 #define IGP01E1000_MSE_CHANNEL_B        0x0F00
 #define IGP01E1000_MSE_CHANNEL_A        0xF000
 
+#define IGP02E1000_PM_SPD                         0x0001  /* Smart Power Down */
+#define IGP02E1000_PM_D3_LPLU                     0x0004  /* Enable LPLU in non-D0a modes */
+#define IGP02E1000_PM_D0_LPLU                     0x0002  /* Enable LPLU in D0a mode */
+
 /* IGP01E1000 DSP reset macros */
 #define DSP_RESET_ENABLE     0x0
 #define DSP_RESET_DISABLE    0x2
 #define E1000_MAX_DSP_RESETS 10
 
-/* IGP01E1000 AGC Registers */
+/* IGP01E1000 & IGP02E1000 AGC Registers */
 
 #define IGP01E1000_AGC_LENGTH_SHIFT 7         /* Coarse - 13:11, Fine - 10:7 */
+#define IGP02E1000_AGC_LENGTH_SHIFT 9         /* Coarse - 15:13, Fine - 12:9 */
+
+/* IGP02E1000 AGC Register Length 9-bit mask */
+#define IGP02E1000_AGC_LENGTH_MASK  0x7F
 
 /* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */
 #define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128
+#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 113
 
-/* The precision of the length is +/- 10 meters */
+/* The precision error of the cable length is +/- 10 meters */
 #define IGP01E1000_AGC_RANGE    10
+#define IGP02E1000_AGC_RANGE    15
 
 /* IGP01E1000 PCS Initialization register */
 /* bits 3:6 in the PCS registers stores the channels polarity */
@@ -2096,7 +2703,11 @@ struct em_hw {
 #define IGP01E1000_ANALOG_FUSE_FINE_1               0x0080
 #define IGP01E1000_ANALOG_FUSE_FINE_10              0x0500
 
+
 /* Bit definitions for valid PHY IDs. */
+/* I = Integrated
+ * E = External
+ */
 #define M88E1000_E_PHY_ID  0x01410C50
 #define M88E1000_I_PHY_ID  0x01410C30
 #define M88E1011_I_PHY_ID  0x01410C20
@@ -2104,6 +2715,8 @@ struct em_hw {
 #define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
 #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
 #define M88E1011_I_REV_4   0x04
+#define M88E1111_I_PHY_ID  0x01410CC0
+#define L1LXT971A_PHY_ID   0x001378E0
 
 /* Miscellaneous PHY bit definitions. */
 #define PHY_PREAMBLE        0xFFFFFFFF
@@ -2128,7 +2741,7 @@ struct em_hw {
 #define ADVERTISE_100_FULL  0x0008
 #define ADVERTISE_1000_HALF 0x0010
 #define ADVERTISE_1000_FULL 0x0020
-#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F  /* Everything but 1000-Half */
 #define AUTONEG_ADVERTISE_10_100_ALL    0x000F /* All 10/100 speeds*/
 #define AUTONEG_ADVERTISE_10_ALL        0x0003 /* 10Mbps Full & Half speeds*/
 
index 9ac067c..6c6ceb3 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
 
-Copyright (c) 2001-2003, Intel Corporation
+Copyright (c) 2001-2005, Intel Corporation
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
 ***************************************************************************/
 
 /*$FreeBSD: src/sys/dev/em/if_em_osdep.h,v 1.1.2.11 2003/06/09 21:43:41 pdeuskar Exp $*/
-/*$DragonFly: src/sys/dev/netif/em/if_em_osdep.h,v 1.4 2004/03/17 04:59:41 dillon Exp $*/
+/*$DragonFly: src/sys/dev/netif/em/if_em_osdep.h,v 1.5 2005/11/08 12:48:18 sephe Exp $*/
 
 #ifndef _FREEBSD_OS_H_
 #define _FREEBSD_OS_H_
@@ -61,6 +61,8 @@ POSSIBILITY OF SUCH DAMAGE.
 /* The happy-fun DELAY macro is defined in /usr/src/sys/i386/include/clock.h */
 #define usec_delay(x) DELAY(x)
 #define msec_delay(x) DELAY(1000*(x))
+/* TODO: Should we be paranoid about delaying in interrupt context? */
+#define msec_delay_irq(x) DELAY(1000*(x))
 
 #define MSGOUT(S, A, B)     printf(S "\n", A, B)
 #define DEBUGFUNC(F)        DEBUGOUT(F);
@@ -118,9 +120,25 @@ struct em_osdep
 #define E1000_READ_REG_ARRAY(hw, reg, index) \
     E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2))
 
+#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
+
 #define E1000_WRITE_REG_ARRAY(hw, reg, index, value) \
     E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value)
 
+#define E1000_WRITE_REG_ARRAY_BYTE(hw, reg, index, value) \
+    bus_space_write_1( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+                       ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \
+                       E1000_REG_OFFSET(hw, reg) + (index), \
+                       value)
+
+#define E1000_WRITE_REG_ARRAY_WORD(hw, reg, index, value) \
+    bus_space_write_2( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+                       ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \
+                       E1000_REG_OFFSET(hw, reg) + (index), \
+                       value)
+
+#define E1000_WRITE_REG_ARRAY_DWORD(hw, reg, index, value) \
+    E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value)
 
 #endif  /* _FREEBSD_OS_H_ */