em(4): Sync with Intel's em-6.9.6(FreeBSD)
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 15 Feb 2009 11:46:46 +0000 (19:46 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 24 Feb 2009 10:50:47 +0000 (18:50 +0800)
In addition to adding support for some chips (e.g. 82574L), this also gives
me the chance to rearrange and clean up if_em.[ch] :)

Noticable changes to the FreeBSD driver:
- The hardware abstraction layer is put into a seperate module (ig_hal)
- IP csum offloading is supported when hardware TX csum offloading is enabled
- mbufs on RX/TX ring are freed in em_stop(), i.e. during "ifconfig emX down"
- TX pattern is adjusted that we test number of avaiable TX descs before
  dequeuing mbuf from ifq.  We also reserve double spare TX descs for 82544
  cards on PCI-X bus, so we will not need to unload the loaded mbuf in the
  mid way due to short of TX descs; this at least makes the logic a little
  bit simpler.

43 files changed:
sys/conf/files
sys/config/GENERIC
sys/config/JG64
sys/config/LINT
sys/dev/netif/Makefile
sys/dev/netif/em/Makefile
sys/dev/netif/em/README [deleted file]
sys/dev/netif/em/if_em.c
sys/dev/netif/em/if_em.h
sys/dev/netif/em/if_em_hw.c [deleted file]
sys/dev/netif/em/if_em_hw.h [deleted file]
sys/dev/netif/em/if_em_osdep.h [deleted file]
sys/dev/netif/ig_hal/LICENSE [new file with mode: 0644]
sys/dev/netif/ig_hal/Makefile [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_80003es2lan.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_80003es2lan.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_82540.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_82541.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_82541.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_82542.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_82543.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_82543.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_82571.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_82571.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_82575.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_82575.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_api.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_api.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_defines.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_hw.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_ich8lan.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_ich8lan.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_mac.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_mac.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_manage.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_manage.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_nvm.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_nvm.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_osdep.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_osdep.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_phy.c [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_phy.h [new file with mode: 0644]
sys/dev/netif/ig_hal/e1000_regs.h [new file with mode: 0644]

index 605e4fe..d374e1c 100644 (file)
@@ -220,7 +220,20 @@ dev/netif/ep/if_ep_isa.c   optional ep isa
 dev/netif/ep/if_ep_eisa.c      optional ep eisa
 dev/netif/ep/if_ep_pccard.c    optional ep pccard
 dev/netif/em/if_em.c           optional em
-dev/netif/em/if_em_hw.c                optional em
+dev/netif/ig_hal/e1000_80003es2lan.c   optional ig_hal
+dev/netif/ig_hal/e1000_82540.c optional ig_hal
+dev/netif/ig_hal/e1000_82541.c optional ig_hal
+dev/netif/ig_hal/e1000_82542.c optional ig_hal
+dev/netif/ig_hal/e1000_82543.c optional ig_hal
+dev/netif/ig_hal/e1000_82571.c optional ig_hal
+dev/netif/ig_hal/e1000_82575.c optional ig_hal
+dev/netif/ig_hal/e1000_api.c   optional ig_hal
+dev/netif/ig_hal/e1000_ich8lan.c       optional ig_hal
+dev/netif/ig_hal/e1000_mac.c   optional ig_hal
+dev/netif/ig_hal/e1000_manage.c        optional ig_hal
+dev/netif/ig_hal/e1000_nvm.c   optional ig_hal
+dev/netif/ig_hal/e1000_osdep.c optional ig_hal
+dev/netif/ig_hal/e1000_phy.c   optional ig_hal
 dev/atm/en/midway.c            optional en
 dev/netif/et/if_et.c           optional et
 dev/netif/ex/if_ex.c           optional ex
index 2747cd9..b6d503f 100644 (file)
@@ -205,10 +205,13 @@ device            ppi             # Parallel port interface device
 
 # PCI Ethernet NICs.
 device         de              # DEC/Intel DC21x4x (``Tulip'')
-device         em              # Intel PRO/1000 adapter Gigabit Ethernet Card (``Wiseman'')
 device         txp             # 3Com 3cR990 (``Typhoon'')
 device         vx              # 3Com 3c590, 3c595 (``Vortex'')
 
+device         em              # Intel PRO/1000 adapter Gigabit Ethernet Card (``Wiseman'')
+                               # Requires ig_hal
+device         ig_hal          # Intel PRO/1000 hardware abstraction layer
+
 # PCI Ethernet NICs that use the common MII bus controller code.
 # NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
 device         miibus          # MII bus support
index 76dd061..a23df8c 100644 (file)
@@ -204,10 +204,13 @@ device            sio3    at isa? disable port IO_COM4 irq 9
 
 # PCI Ethernet NICs.
 device         de              # DEC/Intel DC21x4x (``Tulip'')
-device         em              # Intel PRO/1000 adapter Gigabit Ethernet Card (``Wiseman'')
 device         txp             # 3Com 3cR990 (``Typhoon'')
 device         vx              # 3Com 3c590, 3c595 (``Vortex'')
 
+device         em              # Intel PRO/1000 adapter Gigabit Ethernet Card (``Wiseman'')
+                               # Requires ig_hal
+device         ig_hal          # Intel PRO/1000 hardware abstraction layer
+
 # PCI Ethernet NICs that use the common MII bus controller code.
 # NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
 device         miibus          # MII bus support
index bc3e8ee..5026f98 100644 (file)
@@ -1969,6 +1969,7 @@ device            vx              # 3Com 3c590, 3c595 (``Vortex'')
 # Gigabit Ethernet NICs.
 device         bge             # Broadcom BCM570x (``Tigon III'')
 device         em              # Intel Pro/1000 (82542,82543,82544,82540)
+device         ig_hal          # Intel Pro/1000 hardware abstraction layer
 device         et              # Agere ET1310 10/100/1000 Ethernet
 device         lge             # Level 1 LXT1001 (``Mercury'')
 device         nfe             # nVidia nForce2/3 MCP04/51/55 CK804
index 8221da3..918bd2d 100644 (file)
@@ -4,6 +4,6 @@
 SUBDIR= an acx age ale ar ath aue axe bce bfe bge bwi cue dc ed em ep et fwe \
        fxp iwi iwl jme kue lge lnc mii_layer my msk nfe nge pcn ral re rl \
        rtw rue rum sbni sbsh sf sis sk sln sr ste stge ti tl tx txp ural vge \
-       vr vx wb wi xe xl
+       vr vx wb wi xe xl ig_hal
 
 .include <bsd.subdir.mk>
index b9922d1..821a180 100644 (file)
@@ -2,17 +2,16 @@
 #$DragonFly: src/sys/dev/netif/em/Makefile,v 1.10 2008/09/17 08:51:29 sephe Exp $
 
 KMOD=  if_em
-SRCS=  if_em.c if_em_hw.c
+SRCS=  if_em.c
 SRCS+= device_if.h bus_if.h pci_if.h
-SRCS+= opt_polling.h opt_inet.h opt_ktr.h opt_serializer.h
+SRCS+= opt_polling.h opt_ktr.h opt_serializer.h
+
+KMODDEPS = ig_hal
 
 .ifndef BUILDING_WITH_KERNEL
 opt_polling.h:
        echo '#define DEVICE_POLLING 1' > ${.OBJDIR}/${.TARGET}
 
-opt_inet.h:
-       echo "#define INET 1" > ${.OBJDIR}/${.TARGET}
-
 opt_serializer.h:
        touch ${.OBJDIR}/${.TARGET}
 .endif
diff --git a/sys/dev/netif/em/README b/sys/dev/netif/em/README
deleted file mode 100644 (file)
index 615d078..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-$DragonFly: src/sys/dev/netif/em/README,v 1.8 2008/03/16 15:50:22 hasso Exp $
-FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters
-============================================================
-
-September 25, 2006
-
-
-Contents
-========
-
-- Overview
-- Identifying Your Adapter
-- Building and Installation
-- Speed and Duplex Configuration
-- Additional Configurations
-- Known Limitations
-- Support
-- License
-
-
-Overview
-========
-
-This file describes the FreeBSD* driver for the Intel(R) PRO/1000 Family of
-Adapters. This driver has been developed for use with FreeBSD, Release 6.x.
-
-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.
-
-
-Identifying Your Adapter
-========================
-
-For information on how to identify your adapter, go to the Adapter &
-Driver ID Guide at:
-
-http://support.intel.com/support/network/sb/cs-012904.htm
-
-
-For the latest Intel network drivers for FreeBSD, see:
-
-http://downloadfinder.intel.com/scripts-df-external/support_intel.aspx
-
-
-NOTE: Mobile adapters are not fully supported.
-NOTE: The Intel(R) 82562v 10/100 Network Connection only provides 10/100
-support.
-
-
-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
-      order to compile the driver module.
-
-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
-   example, use /home/username/em or /usr/local/src/em.
-
-2. Untar/unzip the archive:
-
-        tar xvfz em-x.x.x.tar.gz
-
-   This will create an em-x.x.x directory.
-
-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
-
-                  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:
-
-              1. Edit /boot/loader.conf, and add the following line:
-
-                  if_em_load="YES"
-
-4. To compile the driver into the kernel:
-
-        cd em-x.x.x/src
-
-        cp if_em* /usr/src/sys/dev/em
-
-        cp Makefile.kernel /usr/src/sys/modules/em/Makefile
-
-   Edit the /usr/src/sys/conf/files 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
-
-   Remove the following lines from the /usr/src/sys/conf/files 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
-   /usr/src/sys/config, 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
-   kernel, consult the FreeBSD operating system documentation.
-
-5. To assign an IP address to the interface, enter the following:
-
-        ifconfig em<interface_num> <IP_address>
-
-6. Verify that the interface works. Enter the following, where <IP_address>
-   is the IP address for another machine on the same subnet as the interface
-   that is being tested:
-
-        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:
-
-        ifconfig_em<interface_num>="<ifconfig_settings>"
-
-   Example usage:
-
-        ifconfig_em0="inet 192.168.10.1 netmask 255.255.255.0"
-
-   NOTE: For assistance, see the ifconfig man page.
-
-
-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
-configure the speed and duplex settings on the adapter. Example usage:
-
-        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
-         defaults to half-duplex.
-
-
-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
-                      option to select full-duplex mode.
-
-   100baseTX       -  Sets speed to 100 Mbps. Use the ifconfig mediaopt
-                      option to select full-duplex mode.
-
-   1000baseT       -  Sets speed to 1000 Mbps. In this case, the driver
-                      supports only full-duplex mode.
-
-   1000baseSX      -  Sets speed to 1000 Mbps. In this case, the driver
-                      supports only full-duplex mode.
-
-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
-Identifying Your Adapter section.
-
-  Jumbo Frames
-  ------------
-  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 16110. To modify
-  the setting, enter the following:
-
-        ifconfig em<interface_num> <hostname or IP address> mtu 9000
-
-  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.
-
-  - To enable Jumbo Frames, increase the MTU size on the interface beyond
-    1500.
-
-  - 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 for Jumbo Frames is 16110.  This value coincides
-    with the 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(R) 82571EB,
-    82572EI, 82573L and 80003ES2LAN controller.  These correspond to the
-    following product names:
-     Intel(R) PRO/1000 PT Server Adapter
-     Intel(R) PRO/1000 PT Desktop Adapter
-     Intel(R) PRO/1000 PT Network Connection
-     Intel(R) PRO/1000 PT Dual Port Server Adapter
-     Intel(R) PRO/1000 PT Dual Port Network Connection
-     Intel(R) PRO/1000 PF Server Adapter
-     Intel(R) PRO/1000 PF Network Connection
-     Intel(R) PRO/1000 PF Dual Port Server Adapter
-     Intel(R) PRO/1000 PB Server Connection
-     Intel(R) PRO/1000 PL Network Connection
-     Intel(R) PRO/1000 EB Network Connection with I/O Acceleration
-     Intel(R) PRO/1000 EB Backplane Connection with I/O Acceleration
-
-  - Adapters based on the Intel(R) 82542 and 82573V/E controller do not
-    support Jumbo Frames. These correspond to the following product names:
-     Intel(R) PRO/1000 Gigabit Server Adapter
-     Intel(R) PRO/1000 PM Network Connection
-
-  - Using Jumbo Frames at 10 or 100 Mbps may result in poor performance or
-    loss of link.
-
-  - The following adapters to not support Jumbo Frames:
-    Intel(R) 82562V 10/100 Network Connection
-    Intel(R) 82566DM Gigabit Network Connection
-    Intel(R) 82566DC Gigabit Network Connection
-    Intel(R) 82566MM Gigabit Network Connection
-    Intel(R) 82566MC Gigabit Network Connection
-
-
-  VLANs
-  -----
-  To create a new VLAN interface:
-
-        ifconfig <vlan_name> create
-
-  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
-           <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
-  tags, specifying a VLAN ID of 10.
-
-  To remove a VLAN interface:
-
-        ifconfig <vlan_name> destroy
-
-  Polling
-  -------
-  NOTES: DEVICE POLLING is only valid for non-SMP (Symmetric MultiProcessing)
-  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
-
-  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
-
-  Checksum Offload
-  ----------------
-  Checksum offloading is not supported on 82542 Gigabit adapters.
-
-  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.
-
-  To enable checksum offloading:
-
-         ifconfig <interface_num> rxcsum
-
-  To disable checksum offloading:
-
-         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
-=================
-
-  In FreeBSD version 4.x with Symmetric MultiProcessing (SMP), there is a known
-  issue on some newer hardware.  The problem is generic kernel and only in SMP
-  mode.  The workaround is to either use FreeBSD version 4.x in single processor
-  mode, or use FreeBSD 5.4 or later.
-
-  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
-
-  The driver can be compiled with the following changes:
-
-  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 */
-  to:
-      #define EM_MASTER_SLAVE  2
-
-  Use one of the following options:
-      1 = Master mode
-      2 = Slave mode
-      3 = Auto master/slave
-  Setting 2 is recommended.
-
-  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
-
-
-Support
-=======
-
-For general information and support, go to the Intel support website at:
-
-        http://support.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
-install or use the Software.
-
-* Other names and brands may be claimed as the property of others.
index f170c7a..f0db375 100644 (file)
@@ -1,24 +1,23 @@
 /*
- *
  * Copyright (c) 2004 Joerg Sonnenberger <joerg@bec.de>.  All rights reserved.
  *
- * Copyright (c) 2001-2006, Intel Corporation
+ * Copyright (c) 2001-2008, Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
- * 
+ *
  *  1. Redistributions of source code must retain the above copyright notice,
  *     this list of conditions and the following disclaimer.
- * 
+ *
  *  2. Redistributions in binary form must reproduce the above copyright
  *     notice, this list of conditions and the following disclaimer in the
  *     documentation and/or other materials provided with the distribution.
- * 
+ *
  *  3. Neither the name of the Intel Corporation nor the names of its
  *     contributors may be used to endorse or promote products derived from
  *     this software without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  *
  *
  * Copyright (c) 2005 The DragonFly Project.  All rights reserved.
- * 
+ *
  * This code is derived from software contributed to The DragonFly Project
  * by Matthew Dillon <dillon@backplane.com>
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
@@ -50,7 +49,7 @@
  * 3. Neither the name of The DragonFly Project nor the names of its
  *    contributors may be used to endorse or promote products derived
  *    from this software without specific, prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- * 
+ *
  * $DragonFly: src/sys/dev/netif/em/if_em.c,v 1.80 2008/09/17 08:51:29 sephe Exp $
- * $FreeBSD$
  */
 /*
  * SERIALIZATION API RULES:
  *
  * - If the driver uses the same serializer for the interrupt as for the
  *   ifnet, most of the serialization will be done automatically for the
- *   driver.  
+ *   driver.
  *
  * - ifmedia entry points will be serialized by the ifmedia code using the
  *   ifnet serializer.
  *   installed by the device driver.
  *
  * - The device driver typically holds the serializer at the time it wishes
- *   to call if_input.  If so, it should pass the serializer to if_input and
- *   note that the serializer might be dropped temporarily by if_input 
- *   (e.g. in case it has to bridge the packet to another interface).
+ *   to call if_input.
+ *
+ * - We must call lwkt_serialize_handler_enable() prior to enabling the
+ *   hardware interrupt and lwkt_serialize_handler_disable() after disabling
+ *   the hardware interrupt in order to avoid handler execution races from
+ *   scheduled interrupt threads.
  *
  *   NOTE!  Since callers into the device driver hold the ifnet serializer,
  *   the device driver may be holding a serializer at the time it calls
@@ -94,7 +95,6 @@
  */
 
 #include "opt_polling.h"
-#include "opt_inet.h"
 #include "opt_serializer.h"
 
 #include <sys/param.h>
 #include <sys/ktr.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
-#include <sys/module.h>
+#include <sys/proc.h>
 #include <sys/rman.h>
 #include <sys/serialize.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/sysctl.h>
+#include <sys/systm.h>
 
 #include <net/bpf.h>
 #include <net/ethernet.h>
 #include <net/if_arp.h>
 #include <net/if_dl.h>
 #include <net/if_media.h>
-#include <net/if_types.h>
 #include <net/ifq_var.h>
 #include <net/vlan/if_vlan_var.h>
 #include <net/vlan/if_vlan_ether.h>
 
-#ifdef INET
-#include <netinet/in.h>
 #include <netinet/in_systm.h>
-#include <netinet/in_var.h>
+#include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <netinet/tcp.h>
 #include <netinet/udp.h>
-#endif
-
-#include <dev/netif/em/if_em_hw.h>
-#include <dev/netif/em/if_em.h>
 
-#define EM_X60_WORKAROUND
-
-/*********************************************************************
- *  Set this to one to display debug statistics
- *********************************************************************/
-int    em_display_debug_stats = 0;
-
-/*********************************************************************
- *  Driver version
- *********************************************************************/
-
-char em_driver_version[] = "6.2.9";
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcireg.h>
 
+#include <dev/netif/ig_hal/e1000_api.h>
+#include <dev/netif/ig_hal/e1000_82571.h>
+#include <dev/netif/em/if_em.h>
 
-/*********************************************************************
- *  PCI Device ID Table
- *
- *  Used by probe to select devices to load on
- *  Last field stores an index into em_strings
- *  Last entry must be all 0s
- *
- *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
- *********************************************************************/
+#define EM_NAME        "Intel(R) PRO/1000 Network Connection "
+#define EM_VER " 6.9.6"
+
+#define EM_DEVICE(id)  \
+       { EM_VENDOR_ID, E1000_DEV_ID_##id, EM_NAME #id EM_VER }
+#define EM_DEVICE_NULL { 0, 0, NULL }
+
+static const struct em_vendor_info em_vendor_info_array[] = {
+       EM_DEVICE(82540EM),
+       EM_DEVICE(82540EM_LOM),
+       EM_DEVICE(82540EP),
+       EM_DEVICE(82540EP_LOM),
+       EM_DEVICE(82540EP_LP),
+
+       EM_DEVICE(82541EI),
+       EM_DEVICE(82541ER),
+       EM_DEVICE(82541ER_LOM),
+       EM_DEVICE(82541EI_MOBILE),
+       EM_DEVICE(82541GI),
+       EM_DEVICE(82541GI_LF),
+       EM_DEVICE(82541GI_MOBILE),
+
+       EM_DEVICE(82542),
+
+       EM_DEVICE(82543GC_FIBER),
+       EM_DEVICE(82543GC_COPPER),
+
+       EM_DEVICE(82544EI_COPPER),
+       EM_DEVICE(82544EI_FIBER),
+       EM_DEVICE(82544GC_COPPER),
+       EM_DEVICE(82544GC_LOM),
+
+       EM_DEVICE(82545EM_COPPER),
+       EM_DEVICE(82545EM_FIBER),
+       EM_DEVICE(82545GM_COPPER),
+       EM_DEVICE(82545GM_FIBER),
+       EM_DEVICE(82545GM_SERDES),
+
+       EM_DEVICE(82546EB_COPPER),
+       EM_DEVICE(82546EB_FIBER),
+       EM_DEVICE(82546EB_QUAD_COPPER),
+       EM_DEVICE(82546GB_COPPER),
+       EM_DEVICE(82546GB_FIBER),
+       EM_DEVICE(82546GB_SERDES),
+       EM_DEVICE(82546GB_PCIE),
+       EM_DEVICE(82546GB_QUAD_COPPER),
+       EM_DEVICE(82546GB_QUAD_COPPER_KSP3),
+
+       EM_DEVICE(82547EI),
+       EM_DEVICE(82547EI_MOBILE),
+       EM_DEVICE(82547GI),
+
+       EM_DEVICE(82571EB_COPPER),
+       EM_DEVICE(82571EB_FIBER),
+       EM_DEVICE(82571EB_SERDES),
+       EM_DEVICE(82571EB_SERDES_DUAL),
+       EM_DEVICE(82571EB_SERDES_QUAD),
+       EM_DEVICE(82571EB_QUAD_COPPER),
+       EM_DEVICE(82571EB_QUAD_COPPER_LP),
+       EM_DEVICE(82571EB_QUAD_FIBER),
+       EM_DEVICE(82571PT_QUAD_COPPER),
+
+       EM_DEVICE(82572EI_COPPER),
+       EM_DEVICE(82572EI_FIBER),
+       EM_DEVICE(82572EI_SERDES),
+       EM_DEVICE(82572EI),
+
+       EM_DEVICE(82573E),
+       EM_DEVICE(82573E_IAMT),
+       EM_DEVICE(82573L),
+
+       EM_DEVICE(80003ES2LAN_COPPER_SPT),
+       EM_DEVICE(80003ES2LAN_SERDES_SPT),
+       EM_DEVICE(80003ES2LAN_COPPER_DPT),
+       EM_DEVICE(80003ES2LAN_SERDES_DPT),
+
+       EM_DEVICE(ICH8_IGP_M_AMT),
+       EM_DEVICE(ICH8_IGP_AMT),
+       EM_DEVICE(ICH8_IGP_C),
+       EM_DEVICE(ICH8_IFE),
+       EM_DEVICE(ICH8_IFE_GT),
+       EM_DEVICE(ICH8_IFE_G),
+       EM_DEVICE(ICH8_IGP_M),
+
+       EM_DEVICE(ICH9_IGP_M_AMT),
+       EM_DEVICE(ICH9_IGP_AMT),
+       EM_DEVICE(ICH9_IGP_C),
+       EM_DEVICE(ICH9_IGP_M),
+       EM_DEVICE(ICH9_IGP_M_V),
+       EM_DEVICE(ICH9_IFE),
+       EM_DEVICE(ICH9_IFE_GT),
+       EM_DEVICE(ICH9_IFE_G),
+       EM_DEVICE(ICH9_BM),
+
+       EM_DEVICE(82574L),
+
+       EM_DEVICE(ICH10_R_BM_LM),
+       EM_DEVICE(ICH10_R_BM_LF),
+       EM_DEVICE(ICH10_R_BM_V),
+       EM_DEVICE(ICH10_D_BM_LM),
+       EM_DEVICE(ICH10_D_BM_LF),
 
-static em_vendor_info_t em_vendor_info_array[] =
-{
-       /* Intel(R) PRO/1000 Network Connection */
-       { 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_82541ER_LOM,     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},
-       { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3,
-                                               PCI_ANY_ID, PCI_ANY_ID, 0},
-
-       { 0x8086, E1000_DEV_ID_82547EI,         PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_82547EI_MOBILE,  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_82571EB_QUAD_COPPER,
-                                               PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE,
-                                               PCI_ANY_ID, PCI_ANY_ID, 0},
-
-       { 0x8086, E1000_DEV_ID_82571EB_QUAD_FIBER,
-                                               PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_82571PT_QUAD_COPPER,
-                                               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_82572EI,         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, E1000_DEV_ID_80003ES2LAN_COPPER_SPT,
-                                               PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_80003ES2LAN_SERDES_SPT,
-                                               PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_80003ES2LAN_COPPER_DPT,
-                                               PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_80003ES2LAN_SERDES_DPT,
-                                               PCI_ANY_ID, PCI_ANY_ID, 0},
-
-       { 0x8086, E1000_DEV_ID_ICH8_IGP_M_AMT,  PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_ICH8_IGP_AMT,    PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_ICH8_IGP_C,      PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_ICH8_IFE,        PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_ICH8_IFE_GT,     PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_ICH8_IFE_G,      PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_ICH8_IGP_M,      PCI_ANY_ID, PCI_ANY_ID, 0},
-
-       { 0x8086, E1000_DEV_ID_ICH9_IGP_AMT,    PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_ICH9_IGP_C,      PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_ICH9_IFE,        PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_ICH9_IFE_GT,     PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_ICH9_IFE_G,      PCI_ANY_ID, PCI_ANY_ID, 0},
-
-       { 0x8086, E1000_DEV_ID_82575EB_COPPER,  PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_82575EB_FIBER_SERDES,
-                                               PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, E1000_DEV_ID_82575GB_QUAD_COPPER,
-                                               PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x101A, PCI_ANY_ID, PCI_ANY_ID, 0},
-       { 0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0},
        /* required last entry */
-       { 0, 0, 0, 0, 0}
-};
-
-/*********************************************************************
- *  Table of branding strings for all supported NICs.
- *********************************************************************/
-
-static const char *em_strings[] = {
-       "Intel(R) PRO/1000 Network Connection"
+       EM_DEVICE_NULL
 };
 
-/*********************************************************************
- *  Function prototypes
- *********************************************************************/
 static int     em_probe(device_t);
 static int     em_attach(device_t);
 static int     em_detach(device_t);
 static int     em_shutdown(device_t);
-static void    em_intr(void *);
 static int     em_suspend(device_t);
 static int     em_resume(device_t);
-static void    em_start(struct ifnet *);
+
+static void    em_init(void *);
+static void    em_stop(struct adapter *);
 static int     em_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
+static void    em_start(struct ifnet *);
+#ifdef DEVICE_POLLING
+static void    em_poll(struct ifnet *, enum poll_cmd, int);
+#endif
 static void    em_watchdog(struct ifnet *);
-static void    em_init(void *);
-static void    em_stop(void *);
 static void    em_media_status(struct ifnet *, struct ifmediareq *);
 static int     em_media_change(struct ifnet *);
-static void    em_identify_hardware(struct adapter *);
-static int     em_allocate_pci_resources(device_t);
-static void    em_free_pci_resources(device_t);
-static void    em_local_timer(void *);
-static int     em_hardware_init(struct adapter *);
-static void    em_setup_interface(device_t, struct adapter *);
-static int     em_setup_transmit_structures(struct adapter *);
-static void    em_initialize_transmit_unit(struct adapter *);
-static int     em_setup_receive_structures(struct adapter *);
-static void    em_initialize_receive_unit(struct adapter *);
+static void    em_timer(void *);
+
+static void    em_intr(void *);
+static void    em_rxeof(struct adapter *, int);
+static void    em_txeof(struct adapter *);
+static void    em_tx_purge(struct adapter *);
 static void    em_enable_intr(struct adapter *);
 static void    em_disable_intr(struct adapter *);
-static void    em_free_transmit_structures(struct adapter *);
-static void    em_free_receive_structures(struct adapter *);
-static void    em_update_stats_counters(struct adapter *);
-static void    em_txeof(struct adapter *);
-static int     em_allocate_receive_structures(struct adapter *);
-static void    em_rxeof(struct adapter *, int);
-static void    em_receive_checksum(struct adapter *, struct em_rx_desc *,
-                                   struct mbuf *);
-static void    em_transmit_checksum_setup(struct adapter *, struct mbuf *,
-                                          uint32_t *, uint32_t *);
+
+static int     em_dma_malloc(struct adapter *, bus_size_t,
+                   struct em_dma_alloc *);
+static void    em_dma_free(struct adapter *, struct em_dma_alloc *);
+static void    em_init_tx_ring(struct adapter *);
+static int     em_init_rx_ring(struct adapter *);
+static int     em_create_tx_ring(struct adapter *);
+static int     em_create_rx_ring(struct adapter *);
+static void    em_destroy_tx_ring(struct adapter *, int);
+static void    em_destroy_rx_ring(struct adapter *, int);
+static int     em_newbuf(struct adapter *, int, int);
+static int     em_encap(struct adapter *, struct mbuf **);
+static void    em_rxcsum(struct adapter *, struct e1000_rx_desc *,
+                   struct mbuf *);
+static void    em_txcsum(struct adapter *, struct mbuf *,
+                   uint32_t *, uint32_t *);
+
+static int     em_get_hw_info(struct adapter *);
+static int     em_is_valid_eaddr(const uint8_t *);
+static int     em_alloc_pci_res(struct adapter *);
+static void    em_free_pci_res(struct adapter *);
+static int     em_hw_init(struct adapter *);
+static void    em_setup_ifp(struct adapter *);
+static void    em_init_tx_unit(struct adapter *);
+static void    em_init_rx_unit(struct adapter *);
+static void    em_update_stats(struct adapter *);
 static void    em_set_promisc(struct adapter *);
 static void    em_disable_promisc(struct adapter *);
 static void    em_set_multi(struct adapter *);
-static void    em_print_hw_stats(struct adapter *);
 static void    em_update_link_status(struct adapter *);
-static int     em_get_buf(int i, struct adapter *, struct mbuf *, int how);
-static void    em_enable_vlans(struct adapter *);
-static void    em_disable_vlans(struct adapter *) __unused;
-static int     em_encap(struct adapter *, struct mbuf *);
 static void    em_smartspeed(struct adapter *);
+
+/* Hardware workarounds */
 static int     em_82547_fifo_workaround(struct adapter *, int);
 static void    em_82547_update_fifo_head(struct adapter *, int);
 static int     em_82547_tx_fifo_reset(struct adapter *);
 static void    em_82547_move_tail(void *);
 static void    em_82547_move_tail_serialized(struct adapter *);
-static int     em_dma_malloc(struct adapter *, bus_size_t,
-                             struct em_dma_alloc *);
-static void    em_dma_free(struct adapter *, struct em_dma_alloc *);
+static uint32_t        em_82544_fill_desc(bus_addr_t, uint32_t, PDESC_ARRAY);
+
 static void    em_print_debug_info(struct adapter *);
-static int     em_is_valid_ether_addr(uint8_t *);
+static void    em_print_nvm_info(struct adapter *);
+static void    em_print_hw_stats(struct adapter *);
+
 static int     em_sysctl_stats(SYSCTL_HANDLER_ARGS);
 static int     em_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
-static uint32_t        em_fill_descriptors(bus_addr_t address, uint32_t length, 
-                                  PDESC_ARRAY desc_array);
 static int     em_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
 static int     em_sysctl_int_throttle(SYSCTL_HANDLER_ARGS);
+static void    em_add_sysctl(struct adapter *adapter);
 static void    em_add_int_delay_sysctl(struct adapter *, const char *,
-                                       const char *,
-                                       struct em_int_delay_info *, int, int);
+                   const char *, struct em_int_delay_info *, int, int);
 
-/*********************************************************************
- *  FreeBSD Device Interface Entry Points
- *********************************************************************/
+/* Management and WOL Support */
+static void    em_get_mgmt(struct adapter *);
+static void    em_rel_mgmt(struct adapter *);
+static void    em_get_hw_control(struct adapter *);
+static void    em_rel_hw_control(struct adapter *);
+static void    em_enable_wol(device_t);
 
 static device_method_t em_methods[] = {
        /* Device interface */
-       DEVMETHOD(device_probe, em_probe),
-       DEVMETHOD(device_attach, em_attach),
-       DEVMETHOD(device_detach, em_detach),
-       DEVMETHOD(device_shutdown, em_shutdown),
-       DEVMETHOD(device_suspend, em_suspend),
-       DEVMETHOD(device_resume, em_resume),
-       {0, 0}
+       DEVMETHOD(device_probe,         em_probe),
+       DEVMETHOD(device_attach,        em_attach),
+       DEVMETHOD(device_detach,        em_detach),
+       DEVMETHOD(device_shutdown,      em_shutdown),
+       DEVMETHOD(device_suspend,       em_suspend),
+       DEVMETHOD(device_resume,        em_resume),
+       { 0, 0 }
 };
 
 static driver_t em_driver = {
-       "em", em_methods, sizeof(struct adapter),
+       "em",
+       em_methods,
+       sizeof(struct adapter),
 };
 
 static devclass_t em_devclass;
 
 DECLARE_DUMMY_MODULE(if_em);
+MODULE_DEPEND(em, ig_hal, 1, 1, 1);
 DRIVER_MODULE(if_em, pci, em_driver, em_devclass, 0, 0);
 
 /*********************************************************************
  *  Tunable default values.
  *********************************************************************/
 
-#define E1000_TICKS_TO_USECS(ticks)    ((1024 * (ticks) + 500) / 1000)
-#define E1000_USECS_TO_TICKS(usecs)    ((1000 * (usecs) + 512) / 1024)
+#define EM_TICKS_TO_USECS(ticks)       ((1024 * (ticks) + 500) / 1000)
+#define EM_USECS_TO_TICKS(usecs)       ((1000 * (usecs) + 512) / 1024)
+
+static int     em_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV);
+static int     em_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR);
+static int     em_tx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_TADV);
+static int     em_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV);
+static int     em_int_throttle_ceil = EM_DEFAULT_ITR;
+static int     em_rxd = EM_DEFAULT_RXD;
+static int     em_txd = EM_DEFAULT_TXD;
+static int     em_smart_pwr_down = FALSE;
 
-static int em_tx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TIDV);
-static int em_rx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RDTR);
-static int em_tx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TADV);
-static int em_rx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RADV);
-static int em_int_throttle_ceil = 10000;
-static int em_rxd = EM_DEFAULT_RXD;
-static int em_txd = EM_DEFAULT_TXD;
-static int em_smart_pwr_down = FALSE;
+/* Controls whether promiscuous also shows bad packets */
+static int     em_debug_sbp = FALSE;
 
 TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt);
 TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt);
@@ -387,10 +377,14 @@ TUNABLE_INT("hw.em.int_throttle_ceil", &em_int_throttle_ceil);
 TUNABLE_INT("hw.em.rxd", &em_rxd);
 TUNABLE_INT("hw.em.txd", &em_txd);
 TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down);
+TUNABLE_INT("hw.em.sbp", &em_debug_sbp);
+
+/* Global used in WOL setup with multiport cards */
+static int     em_global_quad_port_a = 0;
+
+/* Set this to one to display debug statistics */
+static int     em_display_debug_stats = 0;
 
-/*
- * Kernel trace for characterization of operations
- */
 #if !defined(KTR_IF_EM)
 #define KTR_IF_EM      KTR_ALL
 #endif
@@ -402,439 +396,529 @@ KTR_INFO(KTR_IF_EM, if_em, pkt_txqueue, 5, "tx packet", 0);
 KTR_INFO(KTR_IF_EM, if_em, pkt_txclean, 6, "tx clean", 0);
 #define logif(name)    KTR_LOG(if_em_ ## name)
 
-/*********************************************************************
- *  Device identification routine
- *
- *  em_probe determines if the driver should be loaded on
- *  adapter based on PCI vendor/device id of the adapter.
- *
- *  return 0 on success, positive on failure
- *********************************************************************/
-
 static int
 em_probe(device_t dev)
 {
-       em_vendor_info_t *ent;
-
-       uint16_t pci_vendor_id = 0;
-       uint16_t pci_device_id = 0;
-       uint16_t pci_subvendor_id = 0;
-       uint16_t pci_subdevice_id = 0;
-       char adapter_name[60];
+       const struct em_vendor_info *ent;
+       uint16_t vid, did;
 
-       INIT_DEBUGOUT("em_probe: begin");
+       vid = pci_get_vendor(dev);
+       did = pci_get_device(dev);
 
-       pci_vendor_id = pci_get_vendor(dev);
-       if (pci_vendor_id != EM_VENDOR_ID)
-               return (ENXIO);
-
-       pci_device_id = pci_get_device(dev);
-       pci_subvendor_id = pci_get_subvendor(dev);
-       pci_subdevice_id = pci_get_subdevice(dev);
-
-       ent = em_vendor_info_array;
-       while (ent->vendor_id != 0) {
-               if ((pci_vendor_id == ent->vendor_id) &&
-                   (pci_device_id == ent->device_id) &&
-
-                   ((pci_subvendor_id == ent->subvendor_id) ||
-                    (ent->subvendor_id == PCI_ANY_ID)) &&
-
-                   ((pci_subdevice_id == ent->subdevice_id) ||
-                    (ent->subdevice_id == PCI_ANY_ID))) {
-                       ksnprintf(adapter_name, sizeof(adapter_name),
-                                "%s, Version - %s",  em_strings[ent->index], 
-                                em_driver_version);
-                       device_set_desc_copy(dev, adapter_name);
+       for (ent = em_vendor_info_array; ent->desc != NULL; ++ent) {
+               if (vid == ent->vendor_id && did == ent->device_id) {
+                       device_set_desc(dev, ent->desc);
                        device_set_async_attach(dev, TRUE);
                        return (0);
                }
-               ent++;
        }
-
        return (ENXIO);
 }
 
-/*********************************************************************
- *  Device initialization routine
- *
- *  The attach entry point is called when the driver is being loaded.
- *  This routine identifies the type of hardware, allocates all resources
- *  and initializes the hardware.
- *
- *  return 0 on success, positive on failure
- *********************************************************************/
-
 static int
 em_attach(device_t dev)
 {
-       struct adapter *adapter;
-       struct ifnet *ifp;
+       struct adapter *adapter = device_get_softc(dev);
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
        int tsize, rsize;
        int error = 0;
+       uint16_t eeprom_data, device_id;
 
-       INIT_DEBUGOUT("em_attach: begin");
-
-       adapter = device_get_softc(dev);
-       ifp = &adapter->interface_data.ac_if;
+       adapter->dev = adapter->osdep.dev = dev;
 
        callout_init(&adapter->timer);
        callout_init(&adapter->tx_fifo_timer);
 
-       adapter->dev = dev;
-       adapter->osdep.dev = dev;
-
-       /* SYSCTL stuff */
-       sysctl_ctx_init(&adapter->sysctl_ctx);
-       adapter->sysctl_tree = SYSCTL_ADD_NODE(&adapter->sysctl_ctx,
-                                              SYSCTL_STATIC_CHILDREN(_hw),
-                                              OID_AUTO, 
-                                              device_get_nameunit(dev),
-                                              CTLFLAG_RD,
-                                              0, "");
-
-       if (adapter->sysctl_tree == NULL) {
-               device_printf(dev, "Unable to create sysctl tree\n");
-               return EIO;
+       /* Determine hardware and mac info */
+       error = em_get_hw_info(adapter);
+       if (error) {
+               device_printf(dev, "Identify hardware failed\n");
+               goto fail;
        }
 
-       SYSCTL_ADD_PROC(&adapter->sysctl_ctx,  
-                       SYSCTL_CHILDREN(adapter->sysctl_tree),
-                       OID_AUTO, "debug_info", CTLTYPE_INT|CTLFLAG_RW, 
-                       (void *)adapter, 0,
-                       em_sysctl_debug_info, "I", "Debug Information");
+       /* Setup PCI resources */
+       error = em_alloc_pci_res(adapter);
+       if (error) {
+               device_printf(dev, "Allocation of PCI resources failed\n");
+               goto fail;
+       }
 
-       SYSCTL_ADD_PROC(&adapter->sysctl_ctx,  
-                       SYSCTL_CHILDREN(adapter->sysctl_tree),
-                       OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW, 
-                       (void *)adapter, 0,
-                       em_sysctl_stats, "I", "Statistics");
+       /*
+        * For ICH8 and family we need to map the flash memory,
+        * and this must happen after the MAC is identified.
+        */
+       if (adapter->hw.mac.type == e1000_ich8lan ||
+           adapter->hw.mac.type == e1000_ich10lan ||
+           adapter->hw.mac.type == e1000_ich9lan) {
+               adapter->flash_rid = EM_BAR_FLASH;
+
+               adapter->flash = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+                                       &adapter->flash_rid, RF_ACTIVE);
+               if (adapter->flash == NULL) {
+                       device_printf(dev, "Mapping of Flash failed\n");
+                       error = ENXIO;
+                       goto fail;
+               }
+               adapter->osdep.flash_bus_space_tag =
+                   rman_get_bustag(adapter->flash);
+               adapter->osdep.flash_bus_space_handle =
+                   rman_get_bushandle(adapter->flash);
 
-       /* Determine hardware revision */
-       em_identify_hardware(adapter);
+               /*
+                * This is used in the shared code
+                * XXX this goof is actually not used.
+                */
+               adapter->hw.flash_address = (uint8_t *)adapter->flash;
+       }
 
-       /* Set up some sysctls for the tunable interrupt delays */
-       em_add_int_delay_sysctl(adapter, "rx_int_delay",
-                               "receive interrupt delay in usecs",
-                               &adapter->rx_int_delay,
-                               E1000_REG_OFFSET(&adapter->hw, RDTR),
-                               em_rx_int_delay_dflt);
-       em_add_int_delay_sysctl(adapter, "tx_int_delay",
-                               "transmit interrupt delay in usecs",
-                               &adapter->tx_int_delay,
-                               E1000_REG_OFFSET(&adapter->hw, TIDV),
-                               em_tx_int_delay_dflt);
-       if (adapter->hw.mac_type >= em_82540) {
-               em_add_int_delay_sysctl(adapter, "rx_abs_int_delay",
-                                       "receive interrupt delay limit in usecs",
-                                       &adapter->rx_abs_int_delay,
-                                       E1000_REG_OFFSET(&adapter->hw, RADV),
-                                       em_rx_abs_int_delay_dflt);
-               em_add_int_delay_sysctl(adapter, "tx_abs_int_delay",
-                                       "transmit interrupt delay limit in usecs",
-                                       &adapter->tx_abs_int_delay,
-                                       E1000_REG_OFFSET(&adapter->hw, TADV),
-                                       em_tx_abs_int_delay_dflt);
-               SYSCTL_ADD_PROC(&adapter->sysctl_ctx,
-                       SYSCTL_CHILDREN(adapter->sysctl_tree),
-                       OID_AUTO, "int_throttle_ceil", CTLTYPE_INT|CTLFLAG_RW,
-                       adapter, 0, em_sysctl_int_throttle, "I", NULL);
+       /* Do Shared Code initialization */
+       if (e1000_setup_init_funcs(&adapter->hw, TRUE)) {
+               device_printf(dev, "Setup of Shared code failed\n");
+               error = ENXIO;
+               goto fail;
        }
 
+       e1000_get_bus_info(&adapter->hw);
+
        /*
-        * Validate number of transmit and receive descriptors. It
+        * Validate number of transmit and receive descriptors.  It
         * must not exceed hardware maximum, and must be multiple
-        * of EM_DBA_ALIGN.
+        * of E1000_DBA_ALIGN.
         */
-       if (((em_txd * sizeof(struct em_tx_desc)) % EM_DBA_ALIGN) != 0 ||
-           (adapter->hw.mac_type >= em_82544 && em_txd > EM_MAX_TXD) ||
-           (adapter->hw.mac_type < em_82544 && em_txd > EM_MAX_TXD_82543) ||
-           (em_txd < EM_MIN_TXD)) {
+       if ((em_txd * sizeof(struct e1000_tx_desc)) % EM_DBA_ALIGN != 0 ||
+           (adapter->hw.mac.type >= e1000_82544 && em_txd > EM_MAX_TXD) ||
+           (adapter->hw.mac.type < e1000_82544 && em_txd > EM_MAX_TXD_82543) ||
+           em_txd < EM_MIN_TXD) {
                device_printf(dev, "Using %d TX descriptors instead of %d!\n",
-                             EM_DEFAULT_TXD, em_txd);
+                   EM_DEFAULT_TXD, em_txd);
                adapter->num_tx_desc = EM_DEFAULT_TXD;
        } else {
                adapter->num_tx_desc = em_txd;
        }
-       if (((em_rxd * sizeof(struct em_rx_desc)) % EM_DBA_ALIGN) != 0 ||
-           (adapter->hw.mac_type >= em_82544 && em_rxd > EM_MAX_RXD) ||
-           (adapter->hw.mac_type < em_82544 && em_rxd > EM_MAX_RXD_82543) ||
-           (em_rxd < EM_MIN_RXD)) {
+       if ((em_rxd * sizeof(struct e1000_rx_desc)) % EM_DBA_ALIGN != 0 ||
+           (adapter->hw.mac.type >= e1000_82544 && em_rxd > EM_MAX_RXD) ||
+           (adapter->hw.mac.type < e1000_82544 && em_rxd > EM_MAX_RXD_82543) ||
+           em_rxd < EM_MIN_RXD) {
                device_printf(dev, "Using %d RX descriptors instead of %d!\n",
-                             EM_DEFAULT_RXD, em_rxd);
+                   EM_DEFAULT_RXD, em_rxd);
                adapter->num_rx_desc = EM_DEFAULT_RXD;
        } else {
                adapter->num_rx_desc = em_rxd;
        }
 
-       SYSCTL_ADD_INT(&adapter->sysctl_ctx,
-                      SYSCTL_CHILDREN(adapter->sysctl_tree), OID_AUTO, "rxd",
-                      CTLFLAG_RD, &adapter->num_rx_desc, 0, NULL);
-       SYSCTL_ADD_INT(&adapter->sysctl_ctx,
-                      SYSCTL_CHILDREN(adapter->sysctl_tree), OID_AUTO, "txd",
-                      CTLFLAG_RD, &adapter->num_tx_desc, 0, NULL);
+       adapter->hw.mac.autoneg = DO_AUTO_NEG;
+       adapter->hw.phy.autoneg_wait_to_complete = FALSE;
+       adapter->hw.phy.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+       adapter->rx_buffer_len = MCLBYTES;
 
-       adapter->hw.autoneg = DO_AUTO_NEG;
-       adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT;
-       adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
-       adapter->hw.tbi_compatibility_en = TRUE;
-       adapter->rx_buffer_len = EM_RXBUFFER_2048;
+       /*
+        * Interrupt throttle rate
+        */
+       if (em_int_throttle_ceil == 0) {
+               adapter->int_throttle_ceil = 0;
+       } else {
+               int throttle = em_int_throttle_ceil;
 
-       adapter->hw.phy_init_script = 1;
-       adapter->hw.phy_reset_disable = FALSE;
+               if (throttle < 0)
+                       throttle = EM_DEFAULT_ITR;
 
-#ifndef EM_MASTER_SLAVE
-       adapter->hw.master_slave = em_ms_hw_default;
-#else
-       adapter->hw.master_slave = EM_MASTER_SLAVE;
-#endif
+               /* Recalculate the tunable value to get the exact frequency. */
+               throttle = 1000000000 / 256 / throttle;
+               adapter->int_throttle_ceil = 1000000000 / 256 / throttle;
+       }
 
-       /*
-        * Set the max frame size assuming standard ethernet
-        * sized frames.
-        */   
-       adapter->hw.max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN;
+       e1000_init_script_state_82541(&adapter->hw, TRUE);
+       e1000_set_tbi_compatibility_82543(&adapter->hw, TRUE);
+
+       /* Copper options */
+       if (adapter->hw.phy.media_type == e1000_media_type_copper) {
+               adapter->hw.phy.mdix = AUTO_ALL_MODES;
+               adapter->hw.phy.disable_polarity_correction = FALSE;
+               adapter->hw.phy.ms_type = EM_MASTER_SLAVE;
+       }
+
+       /* Set the frame limits assuming standard ethernet sized frames. */
+       adapter->max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN;
+       adapter->min_frame_size = ETH_ZLEN + ETHER_CRC_LEN;
 
-       adapter->hw.min_frame_size =
-           MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN;
+       /* This controls when hardware reports transmit completion status. */
+       adapter->hw.mac.report_tx_early = 1;
 
        /*
-        * This controls when hardware reports transmit completion
-        * status.
+        * Create top level busdma tag
         */
-       adapter->hw.report_tx_early = 1;
-
-       error = em_allocate_pci_resources(dev);
-       if (error)
+       error = bus_dma_tag_create(NULL, 1, 0,
+                       BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
+                       NULL, NULL,
+                       BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT,
+                       0, &adapter->parent_dtag);
+       if (error) {
+               device_printf(dev, "could not create top level DMA tag\n");
                goto fail;
+       }
 
-       /* Initialize eeprom parameters */
-       em_init_eeprom_params(&adapter->hw);
-
-       tsize = roundup2(adapter->num_tx_desc * sizeof(struct em_tx_desc),
+       /*
+        * Allocate Transmit Descriptor ring
+        */
+       tsize = roundup2(adapter->num_tx_desc * sizeof(struct e1000_tx_desc),
                         EM_DBA_ALIGN);
-
-       /* Allocate Transmit Descriptor ring */
        error = em_dma_malloc(adapter, tsize, &adapter->txdma);
        if (error) {
-               device_printf(dev, "Unable to allocate TxDescriptor memory\n");
+               device_printf(dev, "Unable to allocate tx_desc memory\n");
                goto fail;
        }
-       adapter->tx_desc_base = (struct em_tx_desc *)adapter->txdma.dma_vaddr;
+       adapter->tx_desc_base = adapter->txdma.dma_vaddr;
 
-       rsize = roundup2(adapter->num_rx_desc * sizeof(struct em_rx_desc),
+       /*
+        * Allocate Receive Descriptor ring
+        */
+       rsize = roundup2(adapter->num_rx_desc * sizeof(struct e1000_rx_desc),
                         EM_DBA_ALIGN);
-
-       /* Allocate Receive Descriptor ring */
        error = em_dma_malloc(adapter, rsize, &adapter->rxdma);
        if (error) {
                device_printf(dev, "Unable to allocate rx_desc memory\n");
                goto fail;
        }
-       adapter->rx_desc_base = (struct em_rx_desc *)adapter->rxdma.dma_vaddr;
+       adapter->rx_desc_base = adapter->rxdma.dma_vaddr;
+
+       /* Make sure we have a good EEPROM before we read from it */
+       if (e1000_validate_nvm_checksum(&adapter->hw) < 0) {
+               /*
+                * Some PCI-E parts fail the first check due to
+                * the link being in sleep state, call it again,
+                * if it fails a second time its a real issue.
+                */
+               if (e1000_validate_nvm_checksum(&adapter->hw) < 0) {
+                       device_printf(dev,
+                           "The EEPROM Checksum Is Not Valid\n");
+                       error = EIO;
+                       goto fail;
+               }
+       }
 
        /* Initialize the hardware */
-       if (em_hardware_init(adapter)) {
+       error = em_hw_init(adapter);
+       if (error) {
                device_printf(dev, "Unable to initialize the hardware\n");
-               error = EIO;
                goto fail;
        }
 
        /* Copy the permanent MAC address out of the EEPROM */
-       if (em_read_mac_addr(&adapter->hw) < 0) {
-               device_printf(dev,
-                             "EEPROM read error while reading MAC address\n");
+       if (e1000_read_mac_addr(&adapter->hw) < 0) {
+               device_printf(dev, "EEPROM read error while reading MAC"
+                   " address\n");
                error = EIO;
                goto fail;
        }
-
-       if (!em_is_valid_ether_addr(adapter->hw.mac_addr)) {
+       if (!em_is_valid_eaddr(adapter->hw.mac.addr)) {
                device_printf(dev, "Invalid MAC address\n");
                error = EIO;
                goto fail;
        }
 
+       /* Allocate transmit descriptors and buffers */
+       error = em_create_tx_ring(adapter);
+       if (error) {
+               device_printf(dev, "Could not setup transmit structures\n");
+               goto fail;
+       }
+
+       /* Allocate receive descriptors and buffers */
+       error = em_create_rx_ring(adapter);
+       if (error) {
+               device_printf(dev, "Could not setup receive structures\n");
+               goto fail;
+       }
+
+       /* Manually turn off all interrupts */
+       E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff);
+
        /* Setup OS specific network interface */
-       em_setup_interface(dev, adapter);
+       em_setup_ifp(adapter);
+
+       /* Add sysctl tree, must after em_setup_ifp() */
+       em_add_sysctl(adapter);
 
        /* Initialize statistics */
-       em_clear_hw_cntrs(&adapter->hw);
-       em_update_stats_counters(adapter);
-       adapter->hw.get_link_status = 1;
+       em_update_stats(adapter);
+
+       adapter->hw.mac.get_link_status = 1;
        em_update_link_status(adapter);
 
        /* Indicate SOL/IDER usage */
-       if (em_check_phy_reset_block(&adapter->hw)) {
-               device_printf(dev, "PHY reset is blocked due to "
-                             "SOL/IDER session.\n");
-       }
-       /* Identify 82544 on PCIX */
-       em_get_bus_info(&adapter->hw);
-       if (adapter->hw.bus_type == em_bus_type_pcix &&
-           adapter->hw.mac_type == em_82544)
+       if (e1000_check_reset_block(&adapter->hw)) {
+               device_printf(dev,
+                   "PHY reset is blocked due to SOL/IDER session.\n");
+       }
+
+       /* Determine if we have to control management hardware */
+       adapter->has_manage = e1000_enable_mng_pass_thru(&adapter->hw);
+
+       /*
+        * Setup Wake-on-Lan
+        */
+       switch (adapter->hw.mac.type) {
+       case e1000_82542:
+       case e1000_82543:
+               break;
+
+       case e1000_82546:
+       case e1000_82546_rev_3:
+       case e1000_82571:
+       case e1000_80003es2lan:
+               if (adapter->hw.bus.func == 1) {
+                       e1000_read_nvm(&adapter->hw,
+                           NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
+               } else {
+                       e1000_read_nvm(&adapter->hw,
+                           NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+               }
+               eeprom_data &= EM_EEPROM_APME;
+               break;
+
+       default:
+               /* APME bit in EEPROM is mapped to WUC.APME */
+               eeprom_data =
+                   E1000_READ_REG(&adapter->hw, E1000_WUC) & E1000_WUC_APME;
+               break;
+       }
+       if (eeprom_data)
+               adapter->wol = E1000_WUFC_MAG;
+       /*
+         * We have the eeprom settings, now apply the special cases
+         * where the eeprom may be wrong or the board won't support
+         * wake on lan on a particular port
+        */
+       device_id = pci_get_device(dev);
+        switch (device_id) {
+       case E1000_DEV_ID_82546GB_PCIE:
+               adapter->wol = 0;
+               break;
+
+       case E1000_DEV_ID_82546EB_FIBER:
+       case E1000_DEV_ID_82546GB_FIBER:
+       case E1000_DEV_ID_82571EB_FIBER:
+               /*
+                * Wake events only supported on port A for dual fiber
+                * regardless of eeprom setting
+                */
+               if (E1000_READ_REG(&adapter->hw, E1000_STATUS) &
+                   E1000_STATUS_FUNC_1)
+                       adapter->wol = 0;
+               break;
+
+       case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+       case E1000_DEV_ID_82571EB_QUAD_COPPER:
+       case E1000_DEV_ID_82571EB_QUAD_FIBER:
+       case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+                /* if quad port adapter, disable WoL on all but port A */
+               if (em_global_quad_port_a != 0)
+                       adapter->wol = 0;
+               /* Reset for multiple quad port adapters */
+               if (++em_global_quad_port_a == 4)
+                       em_global_quad_port_a = 0;
+                break;
+       }
+
+       /* XXX disable wol */
+       adapter->wol = 0;
+
+       /* Do we need workaround for 82544 PCI-X adapter? */
+       if (adapter->hw.bus.type == e1000_bus_type_pcix &&
+           adapter->hw.mac.type == e1000_82544)
                adapter->pcix_82544 = TRUE;
        else
                adapter->pcix_82544 = FALSE;
 
-       error = bus_setup_intr(dev, adapter->res_interrupt, INTR_MPSAFE,
-                          em_intr, adapter,
-                          &adapter->int_handler_tag, ifp->if_serializer);
+       if (adapter->pcix_82544) {
+               /*
+                * 82544 on PCI-X may split one TX segment
+                * into two TX descs, so we double its number
+                * of spare TX desc here.
+                */
+               adapter->spare_tx_desc = 2 * EM_TX_SPARE;
+       } else {
+               adapter->spare_tx_desc = EM_TX_SPARE;
+       }
+
+       error = bus_setup_intr(dev, adapter->intr_res, INTR_MPSAFE,
+                              em_intr, adapter, &adapter->intr_tag,
+                              ifp->if_serializer);
        if (error) {
-               device_printf(dev, "Error registering interrupt handler!\n");
-               ether_ifdetach(ifp);
+               device_printf(dev, "Failed to register interrupt handler");
+               ether_ifdetach(&adapter->arpcom.ac_if);
                goto fail;
        }
 
-       ifp->if_cpuid = ithread_cpuid(rman_get_start(adapter->res_interrupt));
+       ifp->if_cpuid = ithread_cpuid(rman_get_start(adapter->intr_res));
        KKASSERT(ifp->if_cpuid >= 0 && ifp->if_cpuid < ncpus);
-       INIT_DEBUGOUT("em_attach: end");
-       return(0);
-
+       return (0);
 fail:
        em_detach(dev);
-       return(error);
+       return (error);
 }
 
-/*********************************************************************
- *  Device removal routine
- *
- *  The detach entry point is called when the driver is being removed.
- *  This routine stops the adapter and deallocates all the resources
- *  that were allocated for driver operation.
- *
- *  return 0 on success, positive on failure
- *********************************************************************/
-
 static int
 em_detach(device_t dev)
 {
        struct adapter *adapter = device_get_softc(dev);
 
-       INIT_DEBUGOUT("em_detach: begin");
-
        if (device_is_attached(dev)) {
-               struct ifnet *ifp = &adapter->interface_data.ac_if;
+               struct ifnet *ifp = &adapter->arpcom.ac_if;
 
                lwkt_serialize_enter(ifp->if_serializer);
+
                adapter->in_detach = 1;
                em_stop(adapter);
-               em_phy_hw_reset(&adapter->hw);
-               bus_teardown_intr(dev, adapter->res_interrupt, 
-                                 adapter->int_handler_tag);
+
+               e1000_phy_hw_reset(&adapter->hw);
+
+               em_rel_mgmt(adapter);
+
+               if ((adapter->hw.mac.type == e1000_82573 ||
+                    adapter->hw.mac.type == e1000_ich8lan ||
+                    adapter->hw.mac.type == e1000_ich10lan ||
+                    adapter->hw.mac.type == e1000_ich9lan) &&
+                   e1000_check_mng_mode(&adapter->hw))
+                       em_rel_hw_control(adapter);
+
+               if (adapter->wol) {
+                       E1000_WRITE_REG(&adapter->hw, E1000_WUC,
+                                       E1000_WUC_PME_EN);
+                       E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol);
+                       em_enable_wol(dev);
+               }
+
+               bus_teardown_intr(dev, adapter->intr_res, adapter->intr_tag);
+
                lwkt_serialize_exit(ifp->if_serializer);
 
                ether_ifdetach(ifp);
        }
        bus_generic_detach(dev);
 
-       em_free_pci_resources(dev);
+       em_free_pci_res(adapter);
+
+       em_destroy_tx_ring(adapter, adapter->num_tx_desc);
+       em_destroy_rx_ring(adapter, adapter->num_rx_desc);
 
        /* Free Transmit Descriptor ring */
-       if (adapter->tx_desc_base != NULL) {
+       if (adapter->tx_desc_base)
                em_dma_free(adapter, &adapter->txdma);
-               adapter->tx_desc_base = NULL;
-       }
 
        /* Free Receive Descriptor ring */
-       if (adapter->rx_desc_base != NULL) {
+       if (adapter->rx_desc_base)
                em_dma_free(adapter, &adapter->rxdma);
-               adapter->rx_desc_base = NULL;
-       }
+
+       /* Free top level busdma tag */
+       if (adapter->parent_dtag != NULL)
+               bus_dma_tag_destroy(adapter->parent_dtag);
 
        /* Free sysctl tree */
-       if (adapter->sysctl_tree != NULL) {
-               adapter->sysctl_tree = NULL;
+       if (adapter->sysctl_tree != NULL)
                sysctl_ctx_free(&adapter->sysctl_ctx);
-       }
 
        return (0);
 }
 
-/*********************************************************************
- *
- *  Shutdown entry point
- *
- **********************************************************************/
-
 static int
 em_shutdown(device_t dev)
 {
-       struct adapter *adapter = device_get_softc(dev);
-       struct ifnet *ifp = &adapter->interface_data.ac_if;
-
-       lwkt_serialize_enter(ifp->if_serializer);
-       em_stop(adapter);
-       lwkt_serialize_exit(ifp->if_serializer);
-
-       return (0);
+       return em_suspend(dev);
 }
 
-/*
- * Suspend/resume device methods.
- */
 static int
 em_suspend(device_t dev)
 {
        struct adapter *adapter = device_get_softc(dev);
-       struct ifnet *ifp = &adapter->interface_data.ac_if;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
 
        lwkt_serialize_enter(ifp->if_serializer);
+
        em_stop(adapter);
+
+       em_rel_mgmt(adapter);
+
+        if ((adapter->hw.mac.type == e1000_82573 ||
+             adapter->hw.mac.type == e1000_ich8lan ||
+             adapter->hw.mac.type == e1000_ich10lan ||
+             adapter->hw.mac.type == e1000_ich9lan) &&
+            e1000_check_mng_mode(&adapter->hw))
+                em_rel_hw_control(adapter);
+
+        if (adapter->wol) {
+               E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN);
+               E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol);
+               em_enable_wol(dev);
+        }
+
        lwkt_serialize_exit(ifp->if_serializer);
-       return (0);
+
+       return bus_generic_suspend(dev);
 }
 
 static int
 em_resume(device_t dev)
 {
        struct adapter *adapter = device_get_softc(dev);
-       struct ifnet *ifp = &adapter->interface_data.ac_if;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
 
        lwkt_serialize_enter(ifp->if_serializer);
-       ifp->if_flags &= ~IFF_RUNNING;
+
        em_init(adapter);
+       em_get_mgmt(adapter);
        if_devstart(ifp);
+
        lwkt_serialize_exit(ifp->if_serializer);
 
        return bus_generic_resume(dev);
 }
 
-/*********************************************************************
- *  Transmit entry point
- *
- *  em_start is called by the stack to initiate a transmit.
- *  The driver will remain in this routine as long as there are
- *  packets to transmit and transmit resources are available.
- *  In case resources are not available stack is notified and
- *  the packet is requeued.
- **********************************************************************/
-
 static void
 em_start(struct ifnet *ifp)
 {
-       struct mbuf *m_head;
        struct adapter *adapter = ifp->if_softc;
+       struct mbuf *m_head;
 
        ASSERT_SERIALIZED(ifp->if_serializer);
 
        if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
                return;
+
        if (!adapter->link_active) {
                ifq_purge(&ifp->if_snd);
                return;
        }
+
        while (!ifq_is_empty(&ifp->if_snd)) {
+               /*
+                * Force a cleanup if number of TX descriptors
+                * available hits the threshold
+                */
+               if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
+                       em_txeof(adapter);
+
+                       /* Now do we at least have a minimal? */
+                       if (EM_IS_OACTIVE(adapter)) {
+                               adapter->no_tx_desc_avail1++;
+                               ifp->if_flags |= IFF_OACTIVE;
+                               break;
+                       }
+               }
+
+               logif(pkt_txqueue);
                m_head = ifq_dequeue(&ifp->if_snd, NULL);
                if (m_head == NULL)
                        break;
 
-               logif(pkt_txqueue);
-               if (em_encap(adapter, m_head)) {
-                       ifp->if_flags |= IFF_OACTIVE;
-                       ifq_prepend(&ifp->if_snd, m_head);
-                       break;
+               if (em_encap(adapter, &m_head)) {
+                       if (adapter->num_tx_desc_avail ==
+                           adapter->num_tx_desc) {
+                               continue;
+                       } else {
+                               ifp->if_flags |= IFF_OACTIVE;
+                               break;
+                       }
                }
 
                /* Send a copy of the frame to the BPF listener */
@@ -845,194 +929,184 @@ em_start(struct ifnet *ifp)
        }
 }
 
-/*********************************************************************
- *  Ioctl entry point
- *
- *  em_ioctl is called when the user wants to configure the
- *  interface.
- *
- *  return 0 on success, positive on failure
- **********************************************************************/
-
 static int
 em_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
 {
-       int max_frame_size, mask, error = 0, reinit = 0;
-       struct ifreq *ifr = (struct ifreq *) data;
        struct adapter *adapter = ifp->if_softc;
+       struct ifreq *ifr = (struct ifreq *)data;
        uint16_t eeprom_data = 0;
-
-       ASSERT_SERIALIZED(ifp->if_serializer);
+       int max_frame_size, mask, reinit;
+       int error = 0;
 
        if (adapter->in_detach)
-               return 0;
+               return (error);
+
+       ASSERT_SERIALIZED(ifp->if_serializer);
 
        switch (command) {
        case SIOCSIFMTU:
-               IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)");
-               switch (adapter->hw.mac_type) {
-               case em_82573:
+               switch (adapter->hw.mac.type) {
+               case e1000_82573:
                        /*
                         * 82573 only supports jumbo frames
                         * if ASPM is disabled.
                         */
-                       em_read_eeprom(&adapter->hw, EEPROM_INIT_3GIO_3,
-                           1, &eeprom_data);
-                       if (eeprom_data & EEPROM_WORD1A_ASPM_MASK) {
+                       e1000_read_nvm(&adapter->hw,
+                           NVM_INIT_3GIO_3, 1, &eeprom_data);
+                       if (eeprom_data & NVM_WORD1A_ASPM_MASK) {
                                max_frame_size = ETHER_MAX_LEN;
                                break;
                        }
-                       /* Allow Jumbo frames */
-                       /* FALLTHROUGH */
-               case em_82571:
-               case em_82572:
-               case em_ich9lan:
-               case em_80003es2lan:    /* Limit Jumbo Frame size */
+                       /* FALL THROUGH */
+
+               /* Limit Jumbo Frame size */
+               case e1000_82571:
+               case e1000_82572:
+               case e1000_ich9lan:
+               case e1000_ich10lan:
+               case e1000_82574:
+               case e1000_80003es2lan:
                        max_frame_size = 9234;
                        break;
-               case em_ich8lan:
-                       /* ICH8 does not support jumbo frames */
+
+               /* Adapters that do not support jumbo frames */
+               case e1000_82542:
+               case e1000_ich8lan:
                        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) {
+               if (ifr->ifr_mtu > max_frame_size - ETHER_HDR_LEN -
+                   ETHER_CRC_LEN) {
                        error = EINVAL;
-               } else {
-                       ifp->if_mtu = ifr->ifr_mtu;
-                       adapter->hw.max_frame_size = 
-                       ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
-                       ifp->if_flags &= ~IFF_RUNNING;
-                       em_init(adapter);
+                       break;
                }
+
+               ifp->if_mtu = ifr->ifr_mtu;
+               adapter->max_frame_size =
+                   ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
+
+               if (ifp->if_flags & IFF_RUNNING)
+                       em_init(adapter);
                break;
+
        case SIOCSIFFLAGS:
-               IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS "
-                              "(Set Interface Flags)");
                if (ifp->if_flags & IFF_UP) {
-                       if (!(ifp->if_flags & IFF_RUNNING)) {
+                       if ((ifp->if_flags & IFF_RUNNING)) {
+                               if ((ifp->if_flags ^ adapter->if_flags) &
+                                   (IFF_PROMISC | IFF_ALLMULTI)) {
+                                       em_disable_promisc(adapter);
+                                       em_set_promisc(adapter);
+                               }
+                       } else {
                                em_init(adapter);
-                       } else if ((ifp->if_flags ^ adapter->if_flags) &
-                                  (IFF_PROMISC | IFF_ALLMULTI)) {
-                               em_disable_promisc(adapter);
-                               em_set_promisc(adapter);
                        }
-               } else {
-                       if (ifp->if_flags & IFF_RUNNING)
-                               em_stop(adapter);
+               } else if (ifp->if_flags & IFF_RUNNING) {
+                       em_stop(adapter);
                }
                adapter->if_flags = ifp->if_flags;
                break;
+
        case SIOCADDMULTI:
        case SIOCDELMULTI:
-               IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI");
                if (ifp->if_flags & IFF_RUNNING) {
                        em_disable_intr(adapter);
                        em_set_multi(adapter);
-                       if (adapter->hw.mac_type == em_82542_rev2_0)
-                               em_initialize_receive_unit(adapter);
+                       if (adapter->hw.mac.type == e1000_82542 &&
+                           adapter->hw.revision_id == E1000_REVISION_2)
+                               em_init_rx_unit(adapter);
 #ifdef DEVICE_POLLING
-                       /* Do not enable interrupt if polling(4) is enabled */
-                       if ((ifp->if_flags & IFF_POLLING) == 0)
+                       if (!(ifp->if_flags & IFF_POLLING))
 #endif
-                       em_enable_intr(adapter);
+                               em_enable_intr(adapter);
                }
                break;
+
        case SIOCSIFMEDIA:
                /* Check SOL/IDER usage */
-               if (em_check_phy_reset_block(&adapter->hw)) {
-                       if_printf(ifp, "Media change is blocked due to "
-                                 "SOL/IDER session.\n");
+               if (e1000_check_reset_block(&adapter->hw)) {
+                       device_printf(adapter->dev, "Media change is"
+                           " blocked due to SOL/IDER session.\n");
                        break;
                }
-               /* FALLTHROUGH */
+               /* FALL THROUGH */
+
        case SIOCGIFMEDIA:
-               IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA "
-                              "(Get/Set Interface Media)");
                error = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
                break;
+
        case SIOCSIFCAP:
-               IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)");
+               reinit = 0;
                mask = ifr->ifr_reqcap ^ ifp->if_capenable;
                if (mask & IFCAP_HWCSUM) {
-                       ifp->if_capenable ^= IFCAP_HWCSUM;
+                       ifp->if_capenable ^= (mask & IFCAP_HWCSUM);
                        reinit = 1;
                }
                if (mask & IFCAP_VLAN_HWTAGGING) {
                        ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
                        reinit = 1;
                }
-               if (reinit && (ifp->if_flags & IFF_RUNNING)) {
-                       ifp->if_flags &= ~IFF_RUNNING;
+               if (reinit && (ifp->if_flags & IFF_RUNNING))
                        em_init(adapter);
-               }
                break;
+
        default:
                error = ether_ioctl(ifp, command, data);
                break;
        }
-
        return (error);
 }
 
-/*********************************************************************
- *  Watchdog entry point
- *
- *  This routine is called whenever hardware quits transmitting.
- *
- **********************************************************************/
-
 static void
 em_watchdog(struct ifnet *ifp)
 {
        struct adapter *adapter = ifp->if_softc;
 
+       ASSERT_SERIALIZED(ifp->if_serializer);
+
+       /*
+        * The timer is set to 5 every time start queues a packet.
+        * Then txeof keeps resetting it as long as it cleans at
+        * least one descriptor.
+        * Finally, anytime all descriptors are clean the timer is
+        * set to 0.
+        */
+
        /*
         * If we are in this routine because of pause frames, then
         * don't reset the hardware.
         */
-       if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF) {
+       if (E1000_READ_REG(&adapter->hw, E1000_STATUS) &
+           E1000_STATUS_TXOFF) {
                ifp->if_timer = EM_TX_TIMEOUT;
                return;
        }
 
-       if (em_check_for_link(&adapter->hw) == 0)
+       if (e1000_check_for_link(&adapter->hw) == 0)
                if_printf(ifp, "watchdog timeout -- resetting\n");
 
-       ifp->if_flags &= ~IFF_RUNNING;
+       ifp->if_oerrors++;
+       adapter->watchdog_events++;
+
        em_init(adapter);
 
-       adapter->watchdog_timeouts++;
+       if (!ifq_is_empty(&ifp->if_snd))
+               if_devstart(ifp);
 }
 
-/*********************************************************************
- *  Init entry point
- *
- *  This routine is used in two ways. It is used by the stack as
- *  init entry point in network interface structure. It is also used
- *  by the driver as a hw/sw initialization routine to get to a
- *  consistent state.
- *
- *  return 0 on success, positive on failure
- **********************************************************************/
-
 static void
-em_init(void *arg)
+em_init(void *xsc)
 {
-       struct adapter *adapter = arg;
+       struct adapter *adapter = xsc;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
+       device_t dev = adapter->dev;
        uint32_t pba;
-       struct ifnet *ifp = &adapter->interface_data.ac_if;
 
        ASSERT_SERIALIZED(ifp->if_serializer);
 
-       INIT_DEBUGOUT("em_init: begin");
-
-       if (ifp->if_flags & IFF_RUNNING)
-               return;
-
        em_stop(adapter);
 
        /*
@@ -1046,86 +1120,114 @@ em_init(void *arg)
         *   Default allocation: PBA=30K for Rx, leaving 10K for Tx.
         *   Note: default does not leave enough room for Jumbo Frame >10k.
         */
-       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)
+       switch (adapter->hw.mac.type) {
+       case e1000_82547:
+       case e1000_82547_rev_2: /* 82547: Total Packet Buffer is 40K */
+               if (adapter->max_frame_size > 8192)
                        pba = E1000_PBA_22K; /* 22K for Rx, 18K 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;
+                   (E1000_PBA_40K - pba) << EM_PBA_BYTES_SHIFT;
                break;
+
        /* Total Packet Buffer on these is 48K */
-       case em_82571:
-       case em_82572:
-       case em_80003es2lan:
+       case e1000_82571:
+       case e1000_82572:
+       case e1000_80003es2lan:
                pba = E1000_PBA_32K; /* 32K for Rx, 16K for Tx */
                break;
-       case em_82573: /* 82573: Total Packet Buffer is 32K */
+
+       case e1000_82573: /* 82573: Total Packet Buffer is 32K */
                pba = E1000_PBA_12K; /* 12K for Rx, 20K for Tx */
                break;
-       case em_ich8lan:
-               pba = E1000_PBA_8K;
+
+       case e1000_82574:
+               pba = E1000_PBA_20K; /* 20K for Rx, 20K for Tx */
                break;
-       case em_ich9lan:
-#define E1000_PBA_10K   0x000A
+
+       case e1000_ich9lan:
+       case e1000_ich10lan:
+#define E1000_PBA_10K  0x000A
                pba = E1000_PBA_10K;
                break;
+
+       case e1000_ich8lan:
+               pba = E1000_PBA_8K;
+               break;
+
        default:
                /* Devices before 82547 had a Packet Buffer of 64K.   */
-               if(adapter->hw.max_frame_size > EM_RXBUFFER_8192)
+               if (adapter->max_frame_size > 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);
-
+       E1000_WRITE_REG(&adapter->hw, E1000_PBA, pba);
+       
        /* Get the latest mac address, User can use a LAA */
-       bcopy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr,
-             ETHER_ADDR_LEN);
+        bcopy(IF_LLADDR(ifp), adapter->hw.mac.addr, ETHER_ADDR_LEN);
+
+       /* Put the address into the Receive Address Array */
+       e1000_rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+
+       /*
+        * With the 82571 adapter, RAR[0] may be overwritten
+        * when the other port is reset, we make a duplicate
+        * in RAR[14] for that eventuality, this assures
+        * the interface continues to function.
+        */
+       if (adapter->hw.mac.type == e1000_82571) {
+               e1000_set_laa_state_82571(&adapter->hw, TRUE);
+               e1000_rar_set(&adapter->hw, adapter->hw.mac.addr,
+                   E1000_RAR_ENTRIES - 1);
+       }
 
        /* Initialize the hardware */
-       if (em_hardware_init(adapter)) {
-               if_printf(ifp, "Unable to initialize the hardware\n");
+       if (em_hw_init(adapter)) {
+               device_printf(dev, "Unable to initialize the hardware\n");
+               /* XXX em_stop()? */
                return;
        }
        em_update_link_status(adapter);
 
-       if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
-               em_enable_vlans(adapter);
+       /* Setup VLAN support, basic and offload if available */
+       E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN);
 
-       /* Set hardware offload abilities */
-       if (adapter->hw.mac_type >= em_82543) {
-               if (ifp->if_capenable & IFCAP_TXCSUM)
-                       ifp->if_hwassist = EM_CHECKSUM_FEATURES;
-               else
-                       ifp->if_hwassist = 0;
+       if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
+               uint32_t ctrl;
+
+               ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
+               ctrl |= E1000_CTRL_VME;
+               E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
        }
 
+       /* Set hardware offload abilities */
+       if (ifp->if_capenable & IFCAP_TXCSUM)
+               ifp->if_hwassist = EM_CSUM_FEATURES;
+       else
+               ifp->if_hwassist = 0;
+
+       /* Configure for OS presence */
+       em_get_mgmt(adapter);
+
        /* Prepare transmit descriptors and buffers */
-       if (em_setup_transmit_structures(adapter)) {
-               if_printf(ifp, "Could not setup transmit structures\n");
-               em_stop(adapter);
-               return;
-       }
-       em_initialize_transmit_unit(adapter);
+       em_init_tx_ring(adapter);
+       em_init_tx_unit(adapter);
 
        /* Setup Multicast table */
        em_set_multi(adapter);
 
        /* Prepare receive descriptors and buffers */
-       if (em_setup_receive_structures(adapter)) {
-               if_printf(ifp, "Could not setup receive structures\n");
+       if (em_init_rx_ring(adapter)) {
+               device_printf(dev, "Could not setup receive structures\n");
                em_stop(adapter);
                return;
        }
-       em_initialize_receive_unit(adapter);
+       em_init_rx_unit(adapter);
 
        /* Don't lose promiscuous settings */
        em_set_promisc(adapter);
@@ -1133,19 +1235,39 @@ em_init(void *arg)
        ifp->if_flags |= IFF_RUNNING;
        ifp->if_flags &= ~IFF_OACTIVE;
 
-       callout_reset(&adapter->timer, hz, em_local_timer, adapter);
-       em_clear_hw_cntrs(&adapter->hw);
+       callout_reset(&adapter->timer, hz, em_timer, adapter);
+       e1000_clear_hw_cntrs_base_generic(&adapter->hw);
+
+       /* MSI/X configuration for 82574 */
+       if (adapter->hw.mac.type == e1000_82574) {
+               int tmp;
+
+               tmp = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
+               tmp |= E1000_CTRL_EXT_PBA_CLR;
+               E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, tmp);
+               /*
+                * Set the IVAR - interrupt vector routing.
+                * Each nibble represents a vector, high bit
+                * is enable, other 3 bits are the MSIX table
+                * entry, we map RXQ0 to 0, TXQ0 to 1, and
+                * Link (other) to 2, hence the magic number.
+                */
+               E1000_WRITE_REG(&adapter->hw, E1000_IVAR, 0x800A0908);
+       }
 
 #ifdef DEVICE_POLLING
-       /* Do not enable interrupt if polling(4) is enabled */
+       /*
+        * Only enable interrupts if we are not polling, make sure
+        * they are off otherwise.
+        */
        if (ifp->if_flags & IFF_POLLING)
                em_disable_intr(adapter);
        else
-#endif
-       em_enable_intr(adapter);
+#endif /* DEVICE_POLLING */
+               em_enable_intr(adapter);
 
        /* Don't reset the phy next time init gets called */
-       adapter->hw.phy_reset_disable = TRUE;
+       adapter->hw.phy.reset_disable = TRUE;
 }
 
 #ifdef DEVICE_POLLING
@@ -1158,24 +1280,24 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
 
        ASSERT_SERIALIZED(ifp->if_serializer);
 
-       switch(cmd) {
+       switch (cmd) {
        case POLL_REGISTER:
                em_disable_intr(adapter);
                break;
+
        case POLL_DEREGISTER:
                em_enable_intr(adapter);
                break;
+
        case POLL_AND_CHECK_STATUS:
-               reg_icr = E1000_READ_REG(&adapter->hw, ICR);
+               reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
                if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
                        callout_stop(&adapter->timer);
-                       adapter->hw.get_link_status = 1;
-                       em_check_for_link(&adapter->hw);
+                       adapter->hw.mac.get_link_status = 1;
                        em_update_link_status(adapter);
-                       callout_reset(&adapter->timer, hz, em_local_timer,
-                                     adapter);
+                       callout_reset(&adapter->timer, hz, em_timer, adapter);
                }
-               /* fall through */
+               /* FALL THROUGH */
        case POLL_ONLY:
                if (ifp->if_flags & IFF_RUNNING) {
                        em_rxeof(adapter, count);
@@ -1190,25 +1312,19 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
 
 #endif /* DEVICE_POLLING */
 
-/*********************************************************************
- *
- *  Interrupt Service routine
- *
- *********************************************************************/
 static void
-em_intr(void *arg)
+em_intr(void *xsc)
 {
+       struct adapter *adapter = xsc;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
        uint32_t reg_icr;
-       struct ifnet *ifp;
-       struct adapter *adapter = arg;
-
-       ifp = &adapter->interface_data.ac_if;  
 
        logif(intr_beg);
        ASSERT_SERIALIZED(ifp->if_serializer);
 
-       reg_icr = E1000_READ_REG(&adapter->hw, ICR);
-       if ((adapter->hw.mac_type >= em_82571 &&
+       reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
+
+       if ((adapter->hw.mac.type >= e1000_82571 &&
             (reg_icr & E1000_ICR_INT_ASSERTED) == 0) ||
            reg_icr == 0) {
                logif(intr_end);
@@ -1216,21 +1332,16 @@ em_intr(void *arg)
        }
 
        /*
-        * XXX: some laptops trigger several spurious interrupts on em(4)
-        * when in the resume cycle. The ICR register reports all-ones
-        * value in this case. Processing such interrupts would lead to
-        * a freeze. I don't know why.
+        * XXX: some laptops trigger several spurious interrupts
+        * on em(4) when in the resume cycle. The ICR register
+        * reports all-ones value in this case. Processing such
+        * interrupts would lead to a freeze. I don't know why.
         */
        if (reg_icr == 0xffffffff) {
                logif(intr_end);
                return;
        }
 
-       /*
-        * note: do not attempt to improve efficiency by looping.  This 
-        * only results in unnecessary piecemeal collection of received
-        * packets and unnecessary piecemeal cleanups of the transmit ring.
-        */
        if (ifp->if_flags & IFF_RUNNING) {
                em_rxeof(adapter, -1);
                em_txeof(adapter);
@@ -1239,10 +1350,13 @@ em_intr(void *arg)
        /* Link status change */
        if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
                callout_stop(&adapter->timer);
-               adapter->hw.get_link_status = 1;
-               em_check_for_link(&adapter->hw);
+               adapter->hw.mac.get_link_status = 1;
                em_update_link_status(adapter);
-               callout_reset(&adapter->timer, hz, em_local_timer, adapter);
+
+               /* Deal with TX cruft when link lost */
+               em_tx_purge(adapter);
+
+               callout_reset(&adapter->timer, hz, em_timer, adapter);
        }
 
        if (reg_icr & E1000_ICR_RXO)
@@ -1254,25 +1368,14 @@ em_intr(void *arg)
        logif(intr_end);
 }
 
-/*********************************************************************
- *
- *  Media Ioctl callback
- *
- *  This routine is called whenever the user queries the status of
- *  the interface using ifconfig.
- *
- **********************************************************************/
 static void
 em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
        struct adapter *adapter = ifp->if_softc;
        u_char fiber_type = IFM_1000_SX;
 
-       INIT_DEBUGOUT("em_media_status: begin");
-
        ASSERT_SERIALIZED(ifp->if_serializer);
 
-       em_check_for_link(&adapter->hw);
        em_update_link_status(adapter);
 
        ifmr->ifm_status = IFM_AVALID;
@@ -1283,9 +1386,9 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
 
        ifmr->ifm_status |= IFM_ACTIVE;
 
-       if (adapter->hw.media_type == em_media_type_fiber ||
-           adapter->hw.media_type == em_media_type_internal_serdes) {
-               if (adapter->hw.mac_type == em_82545)
+       if (adapter->hw.phy.media_type == e1000_media_type_fiber ||
+           adapter->hw.phy.media_type == e1000_media_type_internal_serdes) {
+               if (adapter->hw.mac.type == e1000_82545)
                        fiber_type = IFM_1000_LX;
                ifmr->ifm_active |= fiber_type | IFM_FDX;
        } else {
@@ -1296,6 +1399,7 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
                case 100:
                        ifmr->ifm_active |= IFM_100_TX;
                        break;
+
                case 1000:
                        ifmr->ifm_active |= IFM_1000_T;
                        break;
@@ -1307,22 +1411,12 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
        }
 }
 
-/*********************************************************************
- *
- *  Media Ioctl callback
- *
- *  This routine is called when the user changes speed/duplex using
- *  media/mediopt option with ifconfig.
- *
- **********************************************************************/
 static int
 em_media_change(struct ifnet *ifp)
 {
        struct adapter *adapter = ifp->if_softc;
        struct ifmedia *ifm = &adapter->media;
 
-       INIT_DEBUGOUT("em_media_change: begin");
-
        ASSERT_SERIALIZED(ifp->if_serializer);
 
        if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
@@ -1330,152 +1424,132 @@ em_media_change(struct ifnet *ifp)
 
        switch (IFM_SUBTYPE(ifm->ifm_media)) {
        case IFM_AUTO:
-               adapter->hw.autoneg = DO_AUTO_NEG;
-               adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+               adapter->hw.mac.autoneg = DO_AUTO_NEG;
+               adapter->hw.phy.autoneg_advertised = AUTONEG_ADV_DEFAULT;
                break;
+
        case IFM_1000_LX:
        case IFM_1000_SX:
        case IFM_1000_T:
-               adapter->hw.autoneg = DO_AUTO_NEG;
-               adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+               adapter->hw.mac.autoneg = DO_AUTO_NEG;
+               adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL;
                break;
+
        case IFM_100_TX:
-               adapter->hw.autoneg = FALSE;
-               adapter->hw.autoneg_advertised = 0;
+               adapter->hw.mac.autoneg = FALSE;
+               adapter->hw.phy.autoneg_advertised = 0;
                if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
-                       adapter->hw.forced_speed_duplex = em_100_full;
+                       adapter->hw.mac.forced_speed_duplex = ADVERTISE_100_FULL;
                else
-                       adapter->hw.forced_speed_duplex = em_100_half;
+                       adapter->hw.mac.forced_speed_duplex = ADVERTISE_100_HALF;
                break;
+
        case IFM_10_T:
-               adapter->hw.autoneg = FALSE;
-               adapter->hw.autoneg_advertised = 0;
+               adapter->hw.mac.autoneg = FALSE;
+               adapter->hw.phy.autoneg_advertised = 0;
                if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
-                       adapter->hw.forced_speed_duplex = em_10_full;
+                       adapter->hw.mac.forced_speed_duplex = ADVERTISE_10_FULL;
                else
-                       adapter->hw.forced_speed_duplex = em_10_half;
+                       adapter->hw.mac.forced_speed_duplex = ADVERTISE_10_HALF;
                break;
+
        default:
                if_printf(ifp, "Unsupported media type\n");
+               break;
        }
+
        /*
-        * As the speed/duplex settings may have changed we need to
+        * As the speed/duplex settings my have changed we need to
         * reset the PHY.
         */
-       adapter->hw.phy_reset_disable = FALSE;
+       adapter->hw.phy.reset_disable = FALSE;
 
-       ifp->if_flags &= ~IFF_RUNNING;
        em_init(adapter);
 
-       return(0);
-}
-
-static void
-em_tx_cb(void *arg, bus_dma_segment_t *seg, int nsegs, bus_size_t mapsize,
-        int error)
-{
-       struct em_q *q = arg;
-
-       if (error)
-               return;
-       KASSERT(nsegs <= EM_MAX_SCATTER,
-               ("Too many DMA segments returned when mapping tx packet"));
-       q->nsegs = nsegs;
-       bcopy(seg, q->segs, nsegs * sizeof(seg[0]));
+       return (0);
 }
 
-/*********************************************************************
- *
- *  This routine maps the mbufs to tx descriptors.
- *
- *  return 0 on success, positive on failure
- **********************************************************************/
 static int
-em_encap(struct adapter *adapter, struct mbuf *m_head)
+em_encap(struct adapter *adapter, struct mbuf **m_headp)
 {
-       uint32_t txd_upper = 0, txd_lower = 0, txd_used = 0, txd_saved = 0;
-       int i, j, error, last = 0;
-
-       struct em_q q;
-       struct em_buffer *tx_buffer = NULL, *tx_buffer_first;
+       bus_dma_segment_t segs[EM_MAX_SCATTER];
        bus_dmamap_t map;
-       struct em_tx_desc *current_tx_desc = NULL;
-       struct ifnet *ifp = &adapter->interface_data.ac_if;
+       struct em_buffer *tx_buffer, *tx_buffer_mapped;
+       struct e1000_tx_desc *ctxd = NULL;
+       struct mbuf *m_head;
+       uint32_t txd_upper, txd_lower, txd_used;
+       int maxsegs, nsegs, i, j, first, last = 0, error;
 
-       /*
-        * Force a cleanup if number of TX descriptors
-        * available hits the threshold
-        */
-       if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
-               em_txeof(adapter);
-               if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
-                       adapter->no_tx_desc_avail1++;
-                       return (ENOBUFS);
-               }
-       }
+       txd_upper = txd_lower = 0;
+       txd_used = 0;
 
        /*
-        * Capture the first descriptor index, this descriptor will have
-        * the index of the EOP which is the only one that now gets a
-        * DONE bit writeback.
+        * Capture the first descriptor index, this descriptor
+        * will have the index of the EOP which is the only one
+        * that now gets a DONE bit writeback.
         */
-       tx_buffer_first = &adapter->tx_buffer_area[adapter->next_avail_tx_desc];
+       first = adapter->next_avail_tx_desc;
+       tx_buffer = &adapter->tx_buffer_area[first];
+       tx_buffer_mapped = tx_buffer;
+       map = tx_buffer->map;
 
-       /*
-        * Map the packet for DMA.
-        */
-       map = tx_buffer_first->map;
-       error = bus_dmamap_load_mbuf(adapter->txtag, map, m_head, em_tx_cb,
-                                    &q, BUS_DMA_NOWAIT);
-       if (error != 0) {
-               adapter->no_tx_dma_setup++;
-               return (error);
+       maxsegs = adapter->num_tx_desc_avail - EM_TX_RESERVED;
+       KASSERT(maxsegs >= adapter->spare_tx_desc,
+               ("not enough spare TX desc\n"));
+       if (adapter->pcix_82544) {
+               /* Half it; see the comment in em_attach() */
+               maxsegs >>= 1;
        }
-       KASSERT(q.nsegs != 0, ("em_encap: empty packet"));
+       if (maxsegs > EM_MAX_SCATTER)
+               maxsegs = EM_MAX_SCATTER;
 
-       if (q.nsegs > (adapter->num_tx_desc_avail - 2)) {
-               adapter->no_tx_desc_avail2++;
-               error = ENOBUFS;
-               goto fail;
-       }
+       error = bus_dmamap_load_mbuf_defrag(adapter->txtag, map, m_headp,
+                       segs, maxsegs, &nsegs, BUS_DMA_NOWAIT);
+       if (error) {
+               if (error == ENOBUFS)
+                       adapter->mbuf_alloc_failed++;
+               else
+                       adapter->no_tx_dma_setup++;
 
-       if (ifp->if_hwassist > 0) {
-               em_transmit_checksum_setup(adapter,  m_head,
-                                          &txd_upper, &txd_lower);
+               m_freem(*m_headp);
+               *m_headp = NULL;
+               return error;
        }
+        bus_dmamap_sync(adapter->txtag, map, BUS_DMASYNC_PREWRITE);
 
+       m_head = *m_headp;
+
+       if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) {
+               /* TX csum offloading will consume one TX desc */
+               em_txcsum(adapter, m_head, &txd_upper, &txd_lower);
+       }
        i = adapter->next_avail_tx_desc;
-       if (adapter->pcix_82544)
-               txd_saved = i;
 
        /* Set up our transmit descriptors */
-       for (j = 0; j < q.nsegs; j++) {
+       for (j = 0; j < nsegs; j++) {
                /* If adapter is 82544 and on PCIX bus */
                if(adapter->pcix_82544) {
                        DESC_ARRAY desc_array;
                        uint32_t array_elements, counter;
 
-                       /* 
+                       /*
                         * Check the Address and Length combination and
                         * split the data accordingly
                         */
-                       array_elements = em_fill_descriptors(q.segs[j].ds_addr,
-                                               q.segs[j].ds_len, &desc_array);
+                       array_elements = em_82544_fill_desc(segs[j].ds_addr,
+                                               segs[j].ds_len, &desc_array);
                        for (counter = 0; counter < array_elements; counter++) {
-                               if (txd_used == adapter->num_tx_desc_avail) {
-                                       adapter->next_avail_tx_desc = txd_saved;
-                                       adapter->no_tx_desc_avail2++;
-                                       error = ENOBUFS;
-                                       goto fail;
-                               }
+                               KKASSERT(txd_used < adapter->num_tx_desc_avail);
+
                                tx_buffer = &adapter->tx_buffer_area[i];
-                               current_tx_desc = &adapter->tx_desc_base[i];
-                               current_tx_desc->buffer_addr = htole64(
-                                       desc_array.descriptor[counter].address);
-                               current_tx_desc->lower.data = htole32(
-                                       adapter->txd_cmd | txd_lower |
-                                       (uint16_t)desc_array.descriptor[counter].length);
-                               current_tx_desc->upper.data = htole32(txd_upper);
+                               ctxd = &adapter->tx_desc_base[i];
+
+                               ctxd->buffer_addr = htole64(
+                                   desc_array.descriptor[counter].address);
+                               ctxd->lower.data = htole32(
+                                   adapter->txd_cmd | txd_lower |
+                                   desc_array.descriptor[counter].length);
+                               ctxd->upper.data = htole32(txd_upper);
 
                                last = i;
                                if (++i == adapter->num_tx_desc)
@@ -1484,15 +1558,15 @@ em_encap(struct adapter *adapter, struct mbuf *m_head)
                                tx_buffer->m_head = NULL;
                                tx_buffer->next_eop = -1;
                                txd_used++;
-                       }
+                        }
                } else {
                        tx_buffer = &adapter->tx_buffer_area[i];
-                       current_tx_desc = &adapter->tx_desc_base[i];
+                       ctxd = &adapter->tx_desc_base[i];
 
-                       current_tx_desc->buffer_addr = htole64(q.segs[j].ds_addr);
-                       current_tx_desc->lower.data = htole32(
-                               adapter->txd_cmd | txd_lower | q.segs[j].ds_len);
-                       current_tx_desc->upper.data = htole32(txd_upper);
+                       ctxd->buffer_addr = htole64(segs[j].ds_addr);
+                       ctxd->lower.data = htole32(adapter->txd_cmd |
+                                                  txd_lower | segs[j].ds_len);
+                       ctxd->upper.data = htole32(txd_upper);
 
                        last = i;
                        if (++i == adapter->num_tx_desc)
@@ -1504,92 +1578,74 @@ em_encap(struct adapter *adapter, struct mbuf *m_head)
        }
 
        adapter->next_avail_tx_desc = i;
-       if (adapter->pcix_82544)
+       if (adapter->pcix_82544) {
+               KKASSERT(adapter->num_tx_desc_avail > txd_used);
                adapter->num_tx_desc_avail -= txd_used;
-       else
-               adapter->num_tx_desc_avail -= q.nsegs;
+       } else {
+               KKASSERT(adapter->num_tx_desc_avail > nsegs);
+               adapter->num_tx_desc_avail -= nsegs;
+       }
 
-       /* Find out if we are in vlan mode */
+        /* Handle VLAN tag */
        if (m_head->m_flags & M_VLANTAG) {
-               /* Set the vlan id */
-               current_tx_desc->upper.fields.special =
-                       htole16(m_head->m_pkthdr.ether_vlantag);
+               /* Set the vlan id. */
+               ctxd->upper.fields.special =
+                   htole16(m_head->m_pkthdr.ether_vlantag);
 
                /* Tell hardware to add tag */
-               current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_VLE);
+               ctxd->lower.data |= htole32(E1000_TXD_CMD_VLE);
        }
 
        tx_buffer->m_head = m_head;
-       tx_buffer_first->map = tx_buffer->map;
+       tx_buffer_mapped->map = tx_buffer->map;
        tx_buffer->map = map;
-       bus_dmamap_sync(adapter->txtag, map, BUS_DMASYNC_PREWRITE);
 
        /*
         * Last Descriptor of Packet needs End Of Packet (EOP)
         * and Report Status (RS)
         */
-       current_tx_desc->lower.data |=
-               htole32(E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS);
+       ctxd->lower.data |= htole32(E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS);
 
        /*
         * Keep track in the first buffer which descriptor will be
-        * written back.
+        * written back
         */
-       tx_buffer_first->next_eop = last;
-
-       bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
-                       BUS_DMASYNC_PREWRITE);
+       tx_buffer = &adapter->tx_buffer_area[first];
+       tx_buffer->next_eop = last;
 
-       /* 
-        * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000
+       /*
+        * Advance the Transmit Descriptor Tail (TDT), this tells the E1000
         * that this frame is available to transmit.
         */
-       if (adapter->hw.mac_type == em_82547 &&
+       if (adapter->hw.mac.type == e1000_82547 &&
            adapter->link_duplex == HALF_DUPLEX) {
                em_82547_move_tail_serialized(adapter);
        } else {
-               E1000_WRITE_REG(&adapter->hw, TDT, i);
-               if (adapter->hw.mac_type == em_82547) {
+               E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), i);
+               if (adapter->hw.mac.type == e1000_82547) {
                        em_82547_update_fifo_head(adapter,
-                                                 m_head->m_pkthdr.len);
+                           m_head->m_pkthdr.len);
                }
        }
-
        return (0);
-fail:
-       bus_dmamap_unload(adapter->txtag, map);
-       return error;
 }
 
-/*********************************************************************
- *
+/*
  * 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.
- *
- **********************************************************************/
-static void
-em_82547_move_tail(void *arg)
-{
-       struct adapter *adapter = arg;
-       struct ifnet *ifp = &adapter->interface_data.ac_if;
-
-       lwkt_serialize_enter(ifp->if_serializer);
-       em_82547_move_tail_serialized(adapter);
-       lwkt_serialize_exit(ifp->if_serializer);
-}
-
+ * the internal Tx FIFO ring boundary.  We need to reset the FIFO pointers
+ * in this case.  We do that only when FIFO is quiescent.
+ */
 static void
 em_82547_move_tail_serialized(struct adapter *adapter)
 {
-       uint16_t hw_tdt;
-       uint16_t sw_tdt;
-       struct em_tx_desc *tx_desc;
-       uint16_t length = 0;
-       boolean_t eop = 0;
+       struct e1000_tx_desc *tx_desc;
+       uint16_t hw_tdt, sw_tdt, length = 0;
+       bool eop = 0;
 
-       hw_tdt = E1000_READ_REG(&adapter->hw, TDT);
+       ASSERT_SERIALIZED(adapter->arpcom.ac_if.if_serializer);
+
+       hw_tdt = E1000_READ_REG(&adapter->hw, E1000_TDT(0));
        sw_tdt = adapter->next_avail_tx_desc;
 
        while (hw_tdt != sw_tdt) {
@@ -1606,11 +1662,22 @@ em_82547_move_tail_serialized(struct adapter *adapter)
                                        em_82547_move_tail, adapter);
                                break;
                        }
-                       E1000_WRITE_REG(&adapter->hw, TDT, hw_tdt);
+                       E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), hw_tdt);
                        em_82547_update_fifo_head(adapter, length);
                        length = 0;
                }
-       }       
+       }
+}
+
+static void
+em_82547_move_tail(void *xsc)
+{
+       struct adapter *adapter = xsc;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
+
+       lwkt_serialize_enter(ifp->if_serializer);
+       em_82547_move_tail_serialized(adapter);
+       lwkt_serialize_exit(ifp->if_serializer);
 }
 
 static int
@@ -1630,7 +1697,6 @@ em_82547_fifo_workaround(struct adapter *adapter, int len)
                                return (1);
                }
        }
-
        return (0);
 }
 
@@ -1650,22 +1716,30 @@ em_82547_tx_fifo_reset(struct adapter *adapter)
 {
        uint32_t tctl;
 
-       if (E1000_READ_REG(&adapter->hw, TDT) == E1000_READ_REG(&adapter->hw, TDH) &&
-           E1000_READ_REG(&adapter->hw, TDFT) == E1000_READ_REG(&adapter->hw, TDFH) &&
-           E1000_READ_REG(&adapter->hw, TDFTS) == E1000_READ_REG(&adapter->hw, TDFHS) &&
-           E1000_READ_REG(&adapter->hw, TDFPC) == 0) {
+       if ((E1000_READ_REG(&adapter->hw, E1000_TDT(0)) ==
+            E1000_READ_REG(&adapter->hw, E1000_TDH(0))) &&
+           (E1000_READ_REG(&adapter->hw, E1000_TDFT) == 
+            E1000_READ_REG(&adapter->hw, E1000_TDFH)) &&
+           (E1000_READ_REG(&adapter->hw, E1000_TDFTS) ==
+            E1000_READ_REG(&adapter->hw, E1000_TDFHS)) &&
+           (E1000_READ_REG(&adapter->hw, E1000_TDFPC) == 0)) {
                /* Disable TX unit */
-               tctl = E1000_READ_REG(&adapter->hw, TCTL);
-               E1000_WRITE_REG(&adapter->hw, TCTL, tctl & ~E1000_TCTL_EN);
+               tctl = E1000_READ_REG(&adapter->hw, E1000_TCTL);
+               E1000_WRITE_REG(&adapter->hw, E1000_TCTL,
+                   tctl & ~E1000_TCTL_EN);
 
                /* Reset FIFO pointers */
-               E1000_WRITE_REG(&adapter->hw, TDFT,  adapter->tx_head_addr);
-               E1000_WRITE_REG(&adapter->hw, TDFH,  adapter->tx_head_addr);
-               E1000_WRITE_REG(&adapter->hw, TDFTS, adapter->tx_head_addr);
-               E1000_WRITE_REG(&adapter->hw, TDFHS, adapter->tx_head_addr);
+               E1000_WRITE_REG(&adapter->hw, E1000_TDFT,
+                   adapter->tx_head_addr);
+               E1000_WRITE_REG(&adapter->hw, E1000_TDFH,
+                   adapter->tx_head_addr);
+               E1000_WRITE_REG(&adapter->hw, E1000_TDFTS,
+                   adapter->tx_head_addr);
+               E1000_WRITE_REG(&adapter->hw, E1000_TDFHS,
+                   adapter->tx_head_addr);
 
                /* Re-enable TX unit */
-               E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+               E1000_WRITE_REG(&adapter->hw, E1000_TCTL, tctl);
                E1000_WRITE_FLUSH(&adapter->hw);
 
                adapter->tx_fifo_head = 0;
@@ -1680,18 +1754,21 @@ em_82547_tx_fifo_reset(struct adapter *adapter)
 static void
 em_set_promisc(struct adapter *adapter)
 {
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
        uint32_t reg_rctl;
-       struct ifnet *ifp = &adapter->interface_data.ac_if;
 
-       reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+       reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
 
        if (ifp->if_flags & IFF_PROMISC) {
                reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
-               E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+               /* Turn this on if you want to see bad packets */
+               if (em_debug_sbp)
+                       reg_rctl |= E1000_RCTL_SBP;
+               E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
        } else if (ifp->if_flags & IFF_ALLMULTI) {
                reg_rctl |= E1000_RCTL_MPE;
                reg_rctl &= ~E1000_RCTL_UPE;
-               E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+               E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
        }
 }
 
@@ -1700,37 +1777,30 @@ em_disable_promisc(struct adapter *adapter)
 {
        uint32_t reg_rctl;
 
-       reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+       reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
 
-       reg_rctl &= (~E1000_RCTL_UPE);
-       reg_rctl &= (~E1000_RCTL_MPE);
-       E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+       reg_rctl &= ~E1000_RCTL_UPE;
+       reg_rctl &= ~E1000_RCTL_MPE;
+       reg_rctl &= ~E1000_RCTL_SBP;
+       E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
 }
 
-/*********************************************************************
- *  Multicast Update
- *
- *  This routine is called whenever multicast address list is updated.
- *
- **********************************************************************/
-
 static void
 em_set_multi(struct adapter *adapter)
 {
-       uint32_t reg_rctl = 0;
-       uint8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
        struct ifmultiaddr *ifma;
+       uint32_t reg_rctl = 0;
+       uint8_t  mta[512]; /* Largest MTS is 4096 bits */
        int mcnt = 0;
-       struct ifnet *ifp = &adapter->interface_data.ac_if;
-
-       IOCTL_DEBUGOUT("em_set_multi: begin");
 
-       if (adapter->hw.mac_type == em_82542_rev2_0) {
-               reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
-               if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
-                       em_pci_clear_mwi(&adapter->hw);
+       if (adapter->hw.mac.type == e1000_82542 && 
+           adapter->hw.revision_id == E1000_REVISION_2) {
+               reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
+               if (adapter->hw.bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+                       e1000_pci_clear_mwi(&adapter->hw);
                reg_rctl |= E1000_RCTL_RST;
-               E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+               E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
                msec_delay(5);
        }
 
@@ -1742,52 +1812,54 @@ em_set_multi(struct adapter *adapter)
                        break;
 
                bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
-                     &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
+                   &mta[mcnt * ETHER_ADDR_LEN], ETHER_ADDR_LEN);
                mcnt++;
        }
 
        if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) {
-               reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+               reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
                reg_rctl |= E1000_RCTL_MPE;
-               E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+               E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
        } else {
-               em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0, 1);
+               e1000_update_mc_addr_list(&adapter->hw, mta,
+                   mcnt, 1, adapter->hw.mac.rar_entry_count);
        }
 
-       if (adapter->hw.mac_type == em_82542_rev2_0) {
-               reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+       if (adapter->hw.mac.type == e1000_82542 && 
+           adapter->hw.revision_id == E1000_REVISION_2) {
+               reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
                reg_rctl &= ~E1000_RCTL_RST;
-               E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+               E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
                msec_delay(5);
-               if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
-                        em_pci_set_mwi(&adapter->hw);
+               if (adapter->hw.bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+                       e1000_pci_set_mwi(&adapter->hw);
        }
 }
 
-/*********************************************************************
- *  Timer routine
- *
- *  This routine checks for link status and updates statistics.
- *
- **********************************************************************/
-
+/*
+ * This routine checks for link status and updates statistics.
+ */
 static void
-em_local_timer(void *arg)
+em_timer(void *xsc)
 {
-       struct ifnet *ifp;
-       struct adapter *adapter = arg;
-       ifp = &adapter->interface_data.ac_if;
+       struct adapter *adapter = xsc;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
 
        lwkt_serialize_enter(ifp->if_serializer);
 
-       em_check_for_link(&adapter->hw);
        em_update_link_status(adapter);
-       em_update_stats_counters(adapter);
-       if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING)
+       em_update_stats(adapter);
+
+       /* Reset LAA into RAR[0] on 82571 */
+       if (e1000_get_laa_state_82571(&adapter->hw) == TRUE)
+               e1000_rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+
+       if (em_display_debug_stats && (ifp->if_flags & IFF_RUNNING))
                em_print_hw_stats(adapter);
+
        em_smartspeed(adapter);
 
-       callout_reset(&adapter->timer, hz, em_local_timer, adapter);
+       callout_reset(&adapter->timer, hz, em_timer, adapter);
 
        lwkt_serialize_exit(ifp->if_serializer);
 }
@@ -1795,146 +1867,170 @@ em_local_timer(void *arg)
 static void
 em_update_link_status(struct adapter *adapter)
 {
-       struct ifnet *ifp;
-       ifp = &adapter->interface_data.ac_if;
-
-       if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
-               if (adapter->link_active == 0) {
-                       em_get_speed_and_duplex(&adapter->hw, 
-                                               &adapter->link_speed, 
-                                               &adapter->link_duplex);
-                       /* Check if we may set SPEED_MODE bit on PCI-E */
-                       if (adapter->link_speed == SPEED_1000 &&
-                           (adapter->hw.mac_type == em_82571 ||
-                            adapter->hw.mac_type == em_82572)) {
-                               int tarc0;
-
-                               tarc0 = E1000_READ_REG(&adapter->hw, TARC0);
-                               tarc0 |= SPEED_MODE_BIT;
-                               E1000_WRITE_REG(&adapter->hw, TARC0, tarc0);
-                       }
-                       if (bootverbose) {
-                               if_printf(&adapter->interface_data.ac_if,
-                                         "Link is up %d Mbps %s\n",
-                                         adapter->link_speed,
-                                         adapter->link_duplex == FULL_DUPLEX ?
-                                               "Full Duplex" : "Half Duplex");
-                       }
-                       adapter->link_active = 1;
-                       adapter->smartspeed = 0;
-                       ifp->if_baudrate = adapter->link_speed * 1000000;
-                       ifp->if_link_state = LINK_STATE_UP;
-                       if_link_state_change(ifp);
+       struct e1000_hw *hw = &adapter->hw;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
+       device_t dev = adapter->dev;
+       uint32_t link_check = 0;
+
+       /* Get the cached link value or read phy for real */
+       switch (hw->phy.media_type) {
+       case e1000_media_type_copper:
+               if (hw->mac.get_link_status) {
+                       /* Do the work to read phy */
+                       e1000_check_for_link(hw);
+                       link_check = !hw->mac.get_link_status;
+                       if (link_check) /* ESB2 fix */
+                               e1000_cfg_on_link_up(hw);
+               } else {
+                       link_check = TRUE;
                }
-       } else {
-               if (adapter->link_active == 1) {
-                       ifp->if_baudrate = 0;
-                       adapter->link_speed = 0;
-                       adapter->link_duplex = 0;
-                       if (bootverbose) {
-                               if_printf(&adapter->interface_data.ac_if,
-                                         "Link is Down\n");
-                       }
-                       adapter->link_active = 0;
-                       ifp->if_link_state = LINK_STATE_DOWN;
-                       if_link_state_change(ifp);
+               break;
+
+       case e1000_media_type_fiber:
+               e1000_check_for_link(hw);
+               link_check =
+                       E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU;
+               break;
+
+       case e1000_media_type_internal_serdes:
+               e1000_check_for_link(hw);
+               link_check = adapter->hw.mac.serdes_has_link;
+               break;
+
+       case e1000_media_type_unknown:
+       default:
+               break;
+       }
+
+       /* Now check for a transition */
+       if (link_check && adapter->link_active == 0) {
+               e1000_get_speed_and_duplex(hw, &adapter->link_speed,
+                   &adapter->link_duplex);
+               /* Check if we must disable SPEED_MODE bit on PCI-E */
+               if (adapter->link_speed != SPEED_1000 &&
+                   (hw->mac.type == e1000_82571 ||
+                    hw->mac.type == e1000_82572)) {
+                       int tarc0;
+
+                       tarc0 = E1000_READ_REG(hw, E1000_TARC(0));
+                       tarc0 &= ~SPEED_MODE_BIT;
+                       E1000_WRITE_REG(hw, E1000_TARC(0), tarc0);
                }
+               if (bootverbose) {
+                       device_printf(dev, "Link is up %d Mbps %s\n",
+                           adapter->link_speed,
+                           ((adapter->link_duplex == FULL_DUPLEX) ?
+                           "Full Duplex" : "Half Duplex"));
+               }
+               adapter->link_active = 1;
+               adapter->smartspeed = 0;
+               ifp->if_baudrate = adapter->link_speed * 1000000;
+               ifp->if_link_state = LINK_STATE_UP;
+               if_link_state_change(ifp);
+       } else if (!link_check && adapter->link_active == 1) {
+               ifp->if_baudrate = adapter->link_speed = 0;
+               adapter->link_duplex = 0;
+               if (bootverbose)
+                       device_printf(dev, "Link is Down\n");
+               adapter->link_active = 0;
+#if 0
+               /* Link down, disable watchdog */
+               if->if_timer = 0;
+#endif
+               ifp->if_link_state = LINK_STATE_DOWN;
+               if_link_state_change(ifp);
        }
 }
 
-/*********************************************************************
- *
- *  This routine disables all traffic on the adapter by issuing a
- *  global reset on the MAC and deallocates TX/RX buffers.
- *
- **********************************************************************/
-
 static void
-em_stop(void *arg)
+em_stop(struct adapter *adapter)
 {
-       struct ifnet   *ifp;
-       struct adapter * adapter = arg;
-       ifp = &adapter->interface_data.ac_if;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
+       int i;
 
        ASSERT_SERIALIZED(ifp->if_serializer);
 
-       INIT_DEBUGOUT("em_stop: begin");
        em_disable_intr(adapter);
-       em_reset_hw(&adapter->hw);
+
        callout_stop(&adapter->timer);
        callout_stop(&adapter->tx_fifo_timer);
-       em_free_transmit_structures(adapter);
-       em_free_receive_structures(adapter);
 
-       /* Tell the stack that the interface is no longer active */
        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
        ifp->if_timer = 0;
+
+       e1000_reset_hw(&adapter->hw);
+       if (adapter->hw.mac.type >= e1000_82544)
+               E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0);
+
+       for (i = 0; i < adapter->num_tx_desc; i++) {
+               struct em_buffer *tx_buffer = &adapter->tx_buffer_area[i];
+
+               if (tx_buffer->m_head != NULL) {
+                       bus_dmamap_unload(adapter->txtag, tx_buffer->map);
+                       m_freem(tx_buffer->m_head);
+                       tx_buffer->m_head = NULL;
+               }
+               tx_buffer->next_eop = -1;
+       }
+
+       for (i = 0; i < adapter->num_rx_desc; i++) {
+               struct em_buffer *rx_buffer = &adapter->rx_buffer_area[i];
+
+               if (rx_buffer->m_head != NULL) {
+                       bus_dmamap_unload(adapter->rxtag, rx_buffer->map);
+                       m_freem(rx_buffer->m_head);
+                       rx_buffer->m_head = NULL;
+               }
+       }
 }
 
-/*********************************************************************
- *
- *  Determine hardware revision.
- *
- **********************************************************************/
-static void
-em_identify_hardware(struct adapter *adapter)
+static int
+em_get_hw_info(struct adapter *adapter)
 {
        device_t dev = adapter->dev;
 
-       /* Make sure our PCI config space has the necessary stuff set */
-       adapter->hw.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
-       if (!((adapter->hw.pci_cmd_word & PCIM_CMD_BUSMASTEREN) &&
-             (adapter->hw.pci_cmd_word & PCIM_CMD_MEMEN))) {
-               device_printf(dev, "Memory Access and/or Bus Master bits "
-                             "were not set!\n");
-               adapter->hw.pci_cmd_word |= PCIM_CMD_BUSMASTEREN |
-                                           PCIM_CMD_MEMEN;
-               pci_write_config(dev, PCIR_COMMAND,
-                                adapter->hw.pci_cmd_word, 2);
-       }
-
        /* Save off the information about this board */
        adapter->hw.vendor_id = pci_get_vendor(dev);
        adapter->hw.device_id = pci_get_device(dev);
        adapter->hw.revision_id = pci_get_revid(dev);
        adapter->hw.subsystem_vendor_id = pci_get_subvendor(dev);
-       adapter->hw.subsystem_id = pci_get_subdevice(dev);
+       adapter->hw.subsystem_device_id = pci_get_subdevice(dev);
 
-       /* Identify the MAC */
-       if (em_set_mac_type(&adapter->hw))
-               device_printf(dev, "Unknown MAC Type\n");
-
-       if (adapter->hw.mac_type == em_82541 ||
-           adapter->hw.mac_type == em_82541_rev_2 ||
-           adapter->hw.mac_type == em_82547 ||
-           adapter->hw.mac_type == em_82547_rev_2)
-               adapter->hw.phy_init_script = TRUE;
+       /* Do Shared Code Init and Setup */
+       if (e1000_set_mac_type(&adapter->hw))
+               return ENXIO;
+       return 0;
 }
 
 static int
-em_allocate_pci_resources(device_t dev)
+em_alloc_pci_res(struct adapter *adapter)
 {
-       struct adapter *adapter = device_get_softc(dev);
-       int rid;
+       device_t dev = adapter->dev;
+       int val, rid, error = E1000_SUCCESS;
+
+       /* Enable bus mastering */
+       pci_enable_busmaster(dev);
 
-       rid = PCIR_BAR(0);
-       adapter->res_memory = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
-                                                    &rid, RF_ACTIVE);
-       if (adapter->res_memory == NULL) {
+       adapter->memory_rid = EM_BAR_MEM;
+       adapter->memory = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+                               &adapter->memory_rid, RF_ACTIVE);
+       if (adapter->memory == NULL) {
                device_printf(dev, "Unable to allocate bus resource: memory\n");
-               return ENXIO;
+               return (ENXIO);
        }
        adapter->osdep.mem_bus_space_tag =
-               rman_get_bustag(adapter->res_memory);
+           rman_get_bustag(adapter->memory);
        adapter->osdep.mem_bus_space_handle =
-           rman_get_bushandle(adapter->res_memory);
+           rman_get_bushandle(adapter->memory);
+
+       /* XXX This is quite goofy, it is not actually used */
        adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.mem_bus_space_handle;
 
-       if (adapter->hw.mac_type > em_82543) {
+       /* Only older adapters use IO mapping */
+       if (adapter->hw.mac.type > e1000_82543 &&
+           adapter->hw.mac.type < e1000_82571) {
                /* Figure our where our IO BAR is ? */
-               for (rid = PCIR_BAR(0); rid < PCIR_CIS;) {
-                       uint32_t val;
-
+               for (rid = PCIR_BAR(0); rid < PCIR_CARDBUSCIS;) {
                        val = pci_read_config(dev, rid, 4);
                        if (EM_BAR_TYPE(val) == EM_BAR_TYPE_IO) {
                                adapter->io_rid = rid;
@@ -1945,128 +2041,97 @@ em_allocate_pci_resources(device_t dev)
                        if (EM_BAR_MEM_TYPE(val) == EM_BAR_MEM_TYPE_64BIT)
                                rid += 4;
                }
-               if (rid >= PCIR_CIS) {
+               if (rid >= PCIR_CARDBUSCIS) {
                        device_printf(dev, "Unable to locate IO BAR\n");
                        return (ENXIO);
-               }
-
-               adapter->res_ioport = bus_alloc_resource_any(dev,
-                   SYS_RES_IOPORT, &adapter->io_rid, RF_ACTIVE);
-               if (!(adapter->res_ioport)) {
+               }
+               adapter->ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
+                                       &adapter->io_rid, RF_ACTIVE);
+               if (adapter->ioport == NULL) {
                        device_printf(dev, "Unable to allocate bus resource: "
-                                     "ioport\n");
-                       return ENXIO;
+                           "ioport\n");
+                       return (ENXIO);
                }
                adapter->hw.io_base = 0;
                adapter->osdep.io_bus_space_tag =
-                       rman_get_bustag(adapter->res_ioport);
+                   rman_get_bustag(adapter->ioport);
                adapter->osdep.io_bus_space_handle =
-                       rman_get_bushandle(adapter->res_ioport);
+                   rman_get_bushandle(adapter->ioport);
        }
 
-       /* For ICH8 we need to find the flash memory. */
-       if ((adapter->hw.mac_type == em_ich8lan) ||
-           (adapter->hw.mac_type == em_ich9lan)) {
-               rid = EM_FLASH;
-               adapter->flash_mem = bus_alloc_resource_any(dev,
-                   SYS_RES_MEMORY, &rid, RF_ACTIVE);
-               if (adapter->flash_mem == NULL) {
-                       device_printf(dev, "Unable to allocate bus resource: "
-                                     "flash memory\n");
-                       return ENXIO;
-               }
-               adapter->osdep.flash_bus_space_tag =
-                   rman_get_bustag(adapter->flash_mem);
-               adapter->osdep.flash_bus_space_handle =
-                   rman_get_bushandle(adapter->flash_mem);
-       }
-
-       rid = 0x0;
-       adapter->res_interrupt = bus_alloc_resource_any(dev, SYS_RES_IRQ,
-           &rid, RF_SHAREABLE | RF_ACTIVE);
-       if (adapter->res_interrupt == NULL) {
+       adapter->intr_rid = 0;
+       adapter->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+                               &adapter->intr_rid,
+                               RF_SHAREABLE | RF_ACTIVE);
+       if (adapter->intr_res == NULL) {
                device_printf(dev, "Unable to allocate bus resource: "
-                             "interrupt\n");
-               return ENXIO;
+                   "interrupt\n");
+               return (ENXIO);
        }
 
+       adapter->hw.bus.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
        adapter->hw.back = &adapter->osdep;
-
-       return 0;
+       return (error);
 }
 
 static void
-em_free_pci_resources(device_t dev)
+em_free_pci_res(struct adapter *adapter)
 {
-       struct adapter *adapter = device_get_softc(dev);
+       device_t dev = adapter->dev;
 
-       if (adapter->res_interrupt != NULL) {
-               bus_release_resource(dev, SYS_RES_IRQ, 0, 
-                                    adapter->res_interrupt);
+       if (adapter->intr_res != NULL) {
+               bus_release_resource(dev, SYS_RES_IRQ,
+                   adapter->intr_rid, adapter->intr_res);
        }
-       if (adapter->res_memory != NULL) {
-               bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), 
-                                    adapter->res_memory);
+
+       if (adapter->memory != NULL) {
+               bus_release_resource(dev, SYS_RES_MEMORY,
+                   adapter->memory_rid, adapter->memory);
        }
 
-       if (adapter->res_ioport != NULL) {
-               bus_release_resource(dev, SYS_RES_IOPORT, adapter->io_rid, 
-                                    adapter->res_ioport);
+       if (adapter->flash != NULL) {
+               bus_release_resource(dev, SYS_RES_MEMORY,
+                   adapter->flash_rid, adapter->flash);
        }
 
-       if (adapter->flash_mem != NULL) {
-               bus_release_resource(dev, SYS_RES_MEMORY, EM_FLASH,
-                                    adapter->flash_mem);
+       if (adapter->ioport != NULL) {
+               bus_release_resource(dev, SYS_RES_IOPORT,
+                   adapter->io_rid, adapter->ioport);
        }
 }
 
-/*********************************************************************
- *
- *  Initialize the hardware to a configuration as specified by the
- *  adapter structure. The controller is reset, the EEPROM is
- *  verified, the MAC address is set, then the shared initialization
- *  routines are called.
- *
- **********************************************************************/
 static int
-em_hardware_init(struct adapter *adapter)
+em_hw_init(struct adapter *adapter)
 {
-       uint16_t        rx_buffer_size;
+       device_t dev = adapter->dev;
+       uint16_t rx_buffer_size;
 
-       INIT_DEBUGOUT("em_hardware_init: begin");
        /* Issue a global reset */
-       em_reset_hw(&adapter->hw);
+       e1000_reset_hw(&adapter->hw);
+
+       /* Get control from any management/hw control */
+       if ((adapter->hw.mac.type == e1000_82573 ||
+            adapter->hw.mac.type == e1000_ich8lan ||
+            adapter->hw.mac.type == e1000_ich10lan ||
+            adapter->hw.mac.type == e1000_ich9lan) &&
+           e1000_check_mng_mode(&adapter->hw))
+               em_get_hw_control(adapter);
 
        /* When hardware is reset, fifo_head is also reset */
        adapter->tx_fifo_head = 0;
 
-       /* Make sure we have a good EEPROM before we read from it */
-       if (em_validate_eeprom_checksum(&adapter->hw) < 0) {
-               if (em_validate_eeprom_checksum(&adapter->hw) < 0) {
-                       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");
-               return (EIO);
-       }
-
        /* Set up smart power down as default off on newer adapters. */
        if (!em_smart_pwr_down &&
-           (adapter->hw.mac_type == em_82571 ||
-            adapter->hw.mac_type == em_82572)) {
+           (adapter->hw.mac.type == e1000_82571 ||
+            adapter->hw.mac.type == e1000_82572)) {
                uint16_t phy_tmp = 0;
 
                /* Speed up time to link by disabling smart power down. */
-               em_read_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT,
-                               &phy_tmp);
+               e1000_read_phy_reg(&adapter->hw,
+                   IGP02E1000_PHY_POWER_MGMT, &phy_tmp);
                phy_tmp &= ~IGP02E1000_PM_SPD;
-               em_write_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT,
-                                phy_tmp);
+               e1000_write_phy_reg(&adapter->hw,
+                   IGP02E1000_PHY_POWER_MGMT, phy_tmp);
        }
 
        /*
@@ -2076,54 +2141,47 @@ em_hardware_init(struct adapter *adapter)
         *   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
+        *   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);
+       rx_buffer_size =
+               (E1000_READ_REG(&adapter->hw, E1000_PBA) & 0xffff) << 10;
 
-       adapter->hw.fc_high_water =
-           rx_buffer_size - roundup2(adapter->hw.max_frame_size, 1024); 
-       adapter->hw.fc_low_water = adapter->hw.fc_high_water - 1500;
-       if (adapter->hw.mac_type == em_80003es2lan)
-               adapter->hw.fc_pause_time = 0xFFFF;
+       adapter->hw.fc.high_water = rx_buffer_size -
+                                   roundup2(adapter->max_frame_size, 1024);
+       adapter->hw.fc.low_water = adapter->hw.fc.high_water - 1500;
+
+       if (adapter->hw.mac.type == e1000_80003es2lan)
+               adapter->hw.fc.pause_time = 0xFFFF;
        else
-               adapter->hw.fc_pause_time = 1000;
-       adapter->hw.fc_send_xon = TRUE;
-       adapter->hw.fc = E1000_FC_FULL;
+               adapter->hw.fc.pause_time = EM_FC_PAUSE_TIME;
+       adapter->hw.fc.send_xon = TRUE;
+       adapter->hw.fc.requested_mode = e1000_fc_full;
 
-       if (em_init_hw(&adapter->hw) < 0) {
-               device_printf(adapter->dev, "Hardware Initialization Failed");
+       if (e1000_init_hw(&adapter->hw) < 0) {
+               device_printf(dev, "Hardware Initialization Failed\n");
                return (EIO);
        }
 
-       em_check_for_link(&adapter->hw);
+       e1000_check_for_link(&adapter->hw);
 
        return (0);
 }
 
-/*********************************************************************
- *
- *  Setup networking device structure and register an interface.
- *
- **********************************************************************/
 static void
-em_setup_interface(device_t dev, struct adapter *adapter)
+em_setup_ifp(struct adapter *adapter)
 {
-       struct ifnet *ifp;
-       u_char fiber_type = IFM_1000_SX;        /* default type */
-       INIT_DEBUGOUT("em_setup_interface: begin");
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
 
-       ifp = &adapter->interface_data.ac_if;
-       if_initname(ifp, device_get_name(dev), device_get_unit(dev));
-       ifp->if_mtu = ETHERMTU;
-       ifp->if_baudrate = 1000000000;
-       ifp->if_init =  em_init;
+       if_initname(ifp, device_get_name(adapter->dev),
+                   device_get_unit(adapter->dev));
        ifp->if_softc = adapter;
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_init =  em_init;
        ifp->if_ioctl = em_ioctl;
        ifp->if_start = em_start;
 #ifdef DEVICE_POLLING
@@ -2133,48 +2191,33 @@ em_setup_interface(device_t dev, struct adapter *adapter)
        ifq_set_maxlen(&ifp->if_snd, adapter->num_tx_desc - 1);
        ifq_set_ready(&ifp->if_snd);
 
-       if (adapter->hw.mac_type >= em_82543)
-               ifp->if_capabilities |= IFCAP_HWCSUM;
+       ether_ifattach(ifp, adapter->hw.mac.addr, NULL);
 
-       ifp->if_capenable = ifp->if_capabilities;
+       if (adapter->hw.mac.type >= e1000_82543)
+               ifp->if_capabilities = IFCAP_HWCSUM;
 
-       ether_ifattach(ifp, adapter->hw.mac_addr, NULL);
+       ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
+       ifp->if_capenable = ifp->if_capabilities;
 
-#ifdef PROFILE_SERIALIZER
-       SYSCTL_ADD_UINT(&adapter->sysctl_ctx,
-                       SYSCTL_CHILDREN(adapter->sysctl_tree), OID_AUTO,
-                       "serializer_sleep", CTLFLAG_RW,
-                       &ifp->if_serializer->sleep_cnt, 0, NULL);
-       SYSCTL_ADD_UINT(&adapter->sysctl_ctx,
-                       SYSCTL_CHILDREN(adapter->sysctl_tree), OID_AUTO,
-                       "serializer_tryfail", CTLFLAG_RW,
-                       &ifp->if_serializer->tryfail_cnt, 0, NULL);
-       SYSCTL_ADD_UINT(&adapter->sysctl_ctx,
-                       SYSCTL_CHILDREN(adapter->sysctl_tree), OID_AUTO,
-                       "serializer_enter", CTLFLAG_RW,
-                       &ifp->if_serializer->enter_cnt, 0, NULL);
-       SYSCTL_ADD_UINT(&adapter->sysctl_ctx,
-                       SYSCTL_CHILDREN(adapter->sysctl_tree), OID_AUTO,
-                       "serializer_try", CTLFLAG_RW,
-                       &ifp->if_serializer->try_cnt, 0, NULL);
-#endif
+       if (ifp->if_capenable & IFCAP_TXCSUM)
+               ifp->if_hwassist = EM_CSUM_FEATURES;
 
        /*
         * Tell the upper layer(s) we support long frames.
         */
        ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
-       ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
-       ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
 
        /*
         * Specify the media types supported by this adapter and register
         * callbacks to update media and link information
         */
-       ifmedia_init(&adapter->media, IFM_IMASK, em_media_change,
-                    em_media_status);
-       if (adapter->hw.media_type == em_media_type_fiber ||
-           adapter->hw.media_type == em_media_type_internal_serdes) {
-               if (adapter->hw.mac_type == em_82545)
+       ifmedia_init(&adapter->media, IFM_IMASK,
+                    em_media_change, em_media_status);
+       if (adapter->hw.phy.media_type == e1000_media_type_fiber ||
+           adapter->hw.phy.media_type == e1000_media_type_internal_serdes) {
+               u_char fiber_type = IFM_1000_SX; /* default type */
+
+               if (adapter->hw.mac.type == e1000_82545)
                        fiber_type = IFM_1000_LX;
                ifmedia_add(&adapter->media, IFM_ETHER | fiber_type | IFM_FDX, 
                            0, NULL);
@@ -2187,466 +2230,462 @@ em_setup_interface(device_t dev, struct adapter *adapter)
                            0, NULL);
                ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
                            0, NULL);
-               ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
-                           0, NULL);
-               ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL);
+               if (adapter->hw.phy.type != e1000_phy_ife) {
+                       ifmedia_add(&adapter->media,
+                               IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
+                       ifmedia_add(&adapter->media,
+                               IFM_ETHER | IFM_1000_T, 0, NULL);
+               }
        }
        ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL);
        ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
 }
 
-/*********************************************************************
- *
- *  Workaround for SmartSpeed on 82541 and 82547 controllers
- *
- **********************************************************************/
+
+/*
+ * Workaround for SmartSpeed on 82541 and 82547 controllers
+ */
 static void
 em_smartspeed(struct adapter *adapter)
 {
        uint16_t phy_tmp;
 
-       if (adapter->link_active || (adapter->hw.phy_type != em_phy_igp) ||
-           !adapter->hw.autoneg ||
-           !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL))
+       if (adapter->link_active || adapter->hw.phy.type != e1000_phy_igp ||
+           adapter->hw.mac.autoneg == 0 ||
+           (adapter->hw.phy.autoneg_advertised & ADVERTISE_1000_FULL) == 0)
                return;
 
        if (adapter->smartspeed == 0) {
                /*
                 * If Master/Slave config fault is asserted twice,
-                * we assume back-to-back.
+                * we assume back-to-back
                 */
-               em_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp);
+               e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp);
                if (!(phy_tmp & SR_1000T_MS_CONFIG_FAULT))
                        return;
-               em_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp);
+               e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp);
                if (phy_tmp & SR_1000T_MS_CONFIG_FAULT) {
-                       em_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_tmp);
+                       e1000_read_phy_reg(&adapter->hw,
+                           PHY_1000T_CTRL, &phy_tmp);
                        if (phy_tmp & CR_1000T_MS_ENABLE) {
                                phy_tmp &= ~CR_1000T_MS_ENABLE;
-                               em_write_phy_reg(&adapter->hw,
-                                                PHY_1000T_CTRL, phy_tmp);
+                               e1000_write_phy_reg(&adapter->hw,
+                                   PHY_1000T_CTRL, phy_tmp);
                                adapter->smartspeed++;
-                               if (adapter->hw.autoneg &&
-                                   !em_phy_setup_autoneg(&adapter->hw) &&
-                                   !em_read_phy_reg(&adapter->hw, PHY_CTRL,
-                                                    &phy_tmp)) {
-                                       phy_tmp |= (MII_CR_AUTO_NEG_EN |
-                                                   MII_CR_RESTART_AUTO_NEG);
-                                       em_write_phy_reg(&adapter->hw,
-                                                        PHY_CTRL, phy_tmp);
+                               if (adapter->hw.mac.autoneg &&
+                                   !e1000_phy_setup_autoneg(&adapter->hw) &&
+                                   !e1000_read_phy_reg(&adapter->hw,
+                                    PHY_CONTROL, &phy_tmp)) {
+                                       phy_tmp |= MII_CR_AUTO_NEG_EN |
+                                                  MII_CR_RESTART_AUTO_NEG;
+                                       e1000_write_phy_reg(&adapter->hw,
+                                           PHY_CONTROL, phy_tmp);
                                }
                        }
                }
                return;
        } else if (adapter->smartspeed == EM_SMARTSPEED_DOWNSHIFT) {
                /* If still no link, perhaps using 2/3 pair cable */
-               em_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_tmp);
+               e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_tmp);
                phy_tmp |= CR_1000T_MS_ENABLE;
-               em_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_tmp);
-               if (adapter->hw.autoneg &&
-                   !em_phy_setup_autoneg(&adapter->hw) &&
-                   !em_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_tmp)) {
-                       phy_tmp |= (MII_CR_AUTO_NEG_EN |
-                                   MII_CR_RESTART_AUTO_NEG);
-                       em_write_phy_reg(&adapter->hw, PHY_CTRL, phy_tmp);
+               e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_tmp);
+               if (adapter->hw.mac.autoneg &&
+                   !e1000_phy_setup_autoneg(&adapter->hw) &&
+                   !e1000_read_phy_reg(&adapter->hw, PHY_CONTROL, &phy_tmp)) {
+                       phy_tmp |= MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG;
+                       e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, phy_tmp);
                }
        }
+
        /* Restart process after EM_SMARTSPEED_MAX iterations */
        if (adapter->smartspeed++ == EM_SMARTSPEED_MAX)
                adapter->smartspeed = 0;
 }
 
-/*
- * Manage DMA'able memory.
- */
-static void
-em_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
-{
-       if (error)
-               return;
-       *(bus_addr_t *)arg = segs->ds_addr;
-}
-
 static int
 em_dma_malloc(struct adapter *adapter, bus_size_t size,
              struct em_dma_alloc *dma)
 {
-       device_t dev = adapter->dev;
-       int error;
-
-       error = bus_dma_tag_create(NULL,                /* parent */
-                                  EM_DBA_ALIGN, 0,     /* alignment, bounds */
-                                  BUS_SPACE_MAXADDR,   /* lowaddr */
-                                  BUS_SPACE_MAXADDR,   /* highaddr */
-                                  NULL, NULL,          /* filter, filterarg */
-                                  size,                /* maxsize */
-                                  1,                   /* nsegments */
-                                  size,                /* maxsegsize */
-                                  0,                   /* flags */
-                                  &dma->dma_tag);
-       if (error) {
-               device_printf(dev, "%s: bus_dma_tag_create failed; error %d\n",
-                             __func__, error);
-               return error;
-       }
-
-       error = bus_dmamem_alloc(dma->dma_tag, (void**)&dma->dma_vaddr,
-                                BUS_DMA_WAITOK, &dma->dma_map);
-       if (error) {
-               device_printf(dev, "%s: bus_dmammem_alloc failed; "
-                             "size %llu, error %d\n",
-                             __func__, (uintmax_t)size, error);
-               goto fail;
-       }
-
-       error = bus_dmamap_load(dma->dma_tag, dma->dma_map,
-                               dma->dma_vaddr, size,
-                               em_dmamap_cb, &dma->dma_paddr,
-                               BUS_DMA_WAITOK);
-       if (error) {
-               device_printf(dev, "%s: bus_dmamap_load failed; error %u\n",
-                             __func__, error);
-               bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
-               goto fail;
-       }
-
-       return 0;
-fail:
-       bus_dma_tag_destroy(dma->dma_tag);
-       dma->dma_tag = NULL;
-       return error;
+       dma->dma_vaddr = bus_dmamem_coherent_any(adapter->parent_dtag,
+                               EM_DBA_ALIGN, size, BUS_DMA_WAITOK,
+                               &dma->dma_tag, &dma->dma_map,
+                               &dma->dma_paddr);
+       if (dma->dma_vaddr == NULL)
+               return ENOMEM;
+       else
+               return 0;
 }
 
 static void
 em_dma_free(struct adapter *adapter, struct em_dma_alloc *dma)
 {
-       if (dma->dma_tag != NULL) {
-               bus_dmamap_unload(dma->dma_tag, dma->dma_map);
-               bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
-               bus_dma_tag_destroy(dma->dma_tag);
-               dma->dma_tag = NULL;
-       }
+       if (dma->dma_tag == NULL)
+               return;
+       bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+       bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
+       bus_dma_tag_destroy(dma->dma_tag);
 }
 
-/*********************************************************************
- *
- *  Allocate and initialize transmit structures.
- *
- **********************************************************************/
 static int
-em_setup_transmit_structures(struct adapter *adapter)
+em_create_tx_ring(struct adapter *adapter)
 {
+       device_t dev = adapter->dev;
        struct em_buffer *tx_buffer;
-       bus_size_t size;
        int error, i;
 
-       /*
-        * Setup DMA descriptor areas.
-        */
-       size = roundup2(adapter->hw.max_frame_size, MCLBYTES);
-       if (bus_dma_tag_create(NULL,                    /* parent */
-                              1, 0,                    /* alignment, bounds */
-                              BUS_SPACE_MAXADDR,       /* lowaddr */ 
-                              BUS_SPACE_MAXADDR,       /* highaddr */
-                              NULL, NULL,              /* filter, filterarg */
-                              size,                    /* maxsize */
-                              EM_MAX_SCATTER,          /* nsegments */
-                              size,                    /* maxsegsize */
-                              0,                       /* flags */ 
-                              &adapter->txtag)) {
-               device_printf(adapter->dev, "Unable to allocate TX DMA tag\n");
-               return(ENOMEM);
-       }
-
        adapter->tx_buffer_area =
                kmalloc(sizeof(struct em_buffer) * adapter->num_tx_desc,
                        M_DEVBUF, M_WAITOK | M_ZERO);
 
-       bzero(adapter->tx_desc_base,
-             sizeof(struct em_tx_desc) * adapter->num_tx_desc);
-       tx_buffer = adapter->tx_buffer_area;
+       /*
+        * Create DMA tags for tx buffers
+        */
+       error = bus_dma_tag_create(adapter->parent_dtag, /* parent */
+                       1, 0,                   /* alignment, bounds */
+                       BUS_SPACE_MAXADDR,      /* lowaddr */
+                       BUS_SPACE_MAXADDR,      /* highaddr */
+                       NULL, NULL,             /* filter, filterarg */
+                       EM_TSO_SIZE,            /* maxsize */
+                       EM_MAX_SCATTER,         /* nsegments */
+                       EM_MAX_SEGSIZE,         /* maxsegsize */
+                       BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW |
+                       BUS_DMA_ONEBPAGE,       /* flags */
+                       &adapter->txtag);
+       if (error) {
+               device_printf(dev, "Unable to allocate TX DMA tag\n");
+               kfree(adapter->tx_buffer_area, M_DEVBUF);
+               adapter->tx_buffer_area = NULL;
+               return error;
+       }
+
+       /*
+        * Create DMA maps for tx buffers
+        */
        for (i = 0; i < adapter->num_tx_desc; i++) {
-               error = bus_dmamap_create(adapter->txtag, 0, &tx_buffer->map);
+               tx_buffer = &adapter->tx_buffer_area[i];
+
+               error = bus_dmamap_create(adapter->txtag,
+                                         BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE,
+                                         &tx_buffer->map);
                if (error) {
-                       device_printf(adapter->dev,
-                                     "Unable to create TX DMA map\n");
-                       goto fail;
+                       device_printf(dev, "Unable to create TX DMA map\n");
+                       em_destroy_tx_ring(adapter, i);
+                       return error;
                }
-               tx_buffer++;
+               tx_buffer->next_eop = -1;
        }
+       return (0);
+}
 
+static void
+em_init_tx_ring(struct adapter *adapter)
+{
+       /* Clear the old ring contents */
+       bzero(adapter->tx_desc_base,
+           (sizeof(struct e1000_tx_desc)) * adapter->num_tx_desc);
+
+       /* Reset state */
        adapter->next_avail_tx_desc = 0;
        adapter->next_tx_to_clean = 0;
-
-       /* Set number of descriptors available */
        adapter->num_tx_desc_avail = adapter->num_tx_desc;
-
-       /* Set checksum context */
-       adapter->active_checksum_context = OFFLOAD_NONE;
-
-       bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
-                       BUS_DMASYNC_PREWRITE);
-
-       return (0);
-fail:
-       em_free_transmit_structures(adapter);
-       return (error);
 }
 
-/*********************************************************************
- *
- *  Enable transmit unit.
- *
- **********************************************************************/
 static void
-em_initialize_transmit_unit(struct adapter *adapter)
+em_init_tx_unit(struct adapter *adapter)
 {
-       uint32_t reg_tctl;
-       uint32_t reg_tipg = 0;
+       uint32_t tctl, tarc, tipg = 0;
        uint64_t bus_addr;
 
-       INIT_DEBUGOUT("em_initialize_transmit_unit: begin");
-
        /* Setup the Base and Length of the Tx Descriptor Ring */
        bus_addr = adapter->txdma.dma_paddr;
-       E1000_WRITE_REG(&adapter->hw, TDLEN,
-                       adapter->num_tx_desc * sizeof(struct em_tx_desc));
-       E1000_WRITE_REG(&adapter->hw, TDBAH, (uint32_t)(bus_addr >> 32));
-       E1000_WRITE_REG(&adapter->hw, TDBAL, (uint32_t)bus_addr);
-
+       E1000_WRITE_REG(&adapter->hw, E1000_TDLEN(0),
+           adapter->num_tx_desc * sizeof(struct e1000_tx_desc));
+       E1000_WRITE_REG(&adapter->hw, E1000_TDBAH(0),
+           (uint32_t)(bus_addr >> 32));
+       E1000_WRITE_REG(&adapter->hw, E1000_TDBAL(0),
+           (uint32_t)bus_addr);
        /* Setup the HW Tx Head and Tail descriptor pointers */
-       E1000_WRITE_REG(&adapter->hw, TDT, 0);
-       E1000_WRITE_REG(&adapter->hw, TDH, 0);
-
-       HW_DEBUGOUT2("Base = %x, Length = %x\n",
-                    E1000_READ_REG(&adapter->hw, TDBAL),
-                    E1000_READ_REG(&adapter->hw, TDLEN));
+       E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), 0);
+       E1000_WRITE_REG(&adapter->hw, E1000_TDH(0), 0);
 
        /* Set the default values for the Tx Inter Packet Gap timer */
-       switch (adapter->hw.mac_type) {
-       case em_82542_rev2_0:
-       case em_82542_rev2_1:
-               reg_tipg = DEFAULT_82542_TIPG_IPGT;
-               reg_tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
-               reg_tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+       switch (adapter->hw.mac.type) {
+       case e1000_82542:
+               tipg = DEFAULT_82542_TIPG_IPGT;
+               tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+               tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
                break;
-       case em_80003es2lan:
-               reg_tipg = DEFAULT_82543_TIPG_IPGR1;
-               reg_tipg |=
-                   DEFAULT_80003ES2LAN_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+
+       case e1000_80003es2lan:
+               tipg = DEFAULT_82543_TIPG_IPGR1;
+               tipg |= DEFAULT_80003ES2LAN_TIPG_IPGR2 <<
+                   E1000_TIPG_IPGR2_SHIFT;
                break;
+
        default:
-               if (adapter->hw.media_type == em_media_type_fiber ||
-                   adapter->hw.media_type == em_media_type_internal_serdes)
-                       reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
+               if (adapter->hw.phy.media_type == e1000_media_type_fiber ||
+                   adapter->hw.phy.media_type ==
+                   e1000_media_type_internal_serdes)
+                       tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
                else
-                       reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
-               reg_tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
-               reg_tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+                       tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
+               tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+               tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+               break;
+       }
+
+       E1000_WRITE_REG(&adapter->hw, E1000_TIPG, tipg);
+       E1000_WRITE_REG(&adapter->hw, E1000_TIDV, adapter->tx_int_delay.value);
+       if(adapter->hw.mac.type >= e1000_82540) {
+               E1000_WRITE_REG(&adapter->hw, E1000_TADV,
+                   adapter->tx_abs_int_delay.value);
        }
 
-       E1000_WRITE_REG(&adapter->hw, TIPG, reg_tipg);
-       E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay.value);
-       if (adapter->hw.mac_type >= em_82540) {
-               E1000_WRITE_REG(&adapter->hw, TADV,
-                               adapter->tx_abs_int_delay.value);
+       if (adapter->hw.mac.type == e1000_82571 ||
+           adapter->hw.mac.type == e1000_82572) {
+               tarc = E1000_READ_REG(&adapter->hw, E1000_TARC(0));
+               tarc |= SPEED_MODE_BIT;
+               E1000_WRITE_REG(&adapter->hw, E1000_TARC(0), tarc);
+       } else if (adapter->hw.mac.type == e1000_80003es2lan) {
+               tarc = E1000_READ_REG(&adapter->hw, E1000_TARC(0));
+               tarc |= 1;
+               E1000_WRITE_REG(&adapter->hw, E1000_TARC(0), tarc);
+               tarc = E1000_READ_REG(&adapter->hw, E1000_TARC(1));
+               tarc |= 1;
+               E1000_WRITE_REG(&adapter->hw, E1000_TARC(1), tarc);
        }
 
        /* 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
-               reg_tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+       tctl = E1000_READ_REG(&adapter->hw, E1000_TCTL);
+       tctl &= ~E1000_TCTL_CT;
+       tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | E1000_TCTL_EN |
+               (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+       if (adapter->hw.mac.type >= e1000_82571)
+               tctl |= E1000_TCTL_MULR;
 
        /* This write will effectively turn on the transmit unit. */
-       E1000_WRITE_REG(&adapter->hw, TCTL, reg_tctl);
+       E1000_WRITE_REG(&adapter->hw, E1000_TCTL, tctl);
 
-       /* Setup Transmit Descriptor Base Settings */
+       /* Setup Transmit Descriptor Base Settings */   
        adapter->txd_cmd = E1000_TXD_CMD_IFCS;
 
        if (adapter->tx_int_delay.value > 0)
                adapter->txd_cmd |= E1000_TXD_CMD_IDE;
 }
 
-/*********************************************************************
- *
- *  Free all transmit related data structures.
- *
- **********************************************************************/
 static void
-em_free_transmit_structures(struct adapter *adapter)
+em_destroy_tx_ring(struct adapter *adapter, int ndesc)
 {
        struct em_buffer *tx_buffer;
        int i;
 
-       INIT_DEBUGOUT("free_transmit_structures: begin");
+       if (adapter->tx_buffer_area == NULL)
+               return;
 
-       if (adapter->tx_buffer_area != NULL) {
-               tx_buffer = adapter->tx_buffer_area;
-               for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) {
-                       if (tx_buffer->m_head != NULL) {
-                               bus_dmamap_unload(adapter->txtag,
-                                                 tx_buffer->map);
-                               m_freem(tx_buffer->m_head);
-                       }
+       for (i = 0; i < ndesc; i++) {
+               tx_buffer = &adapter->tx_buffer_area[i];
 
-                       if (tx_buffer->map != NULL) {
-                               bus_dmamap_destroy(adapter->txtag, tx_buffer->map);
-                               tx_buffer->map = NULL;
-                       }
-                       tx_buffer->m_head = NULL;
-               }
-       }
-       if (adapter->tx_buffer_area != NULL) {
-               kfree(adapter->tx_buffer_area, M_DEVBUF);
-               adapter->tx_buffer_area = NULL;
-       }
-       if (adapter->txtag != NULL) {
-               bus_dma_tag_destroy(adapter->txtag);
-               adapter->txtag = NULL;
+               KKASSERT(tx_buffer->m_head == NULL);
+               bus_dmamap_destroy(adapter->txtag, tx_buffer->map);
        }
+       bus_dma_tag_destroy(adapter->txtag);
+
+       kfree(adapter->tx_buffer_area, M_DEVBUF);
+       adapter->tx_buffer_area = NULL;
 }
 
-/*********************************************************************
- *
- *  The offload context needs to be set when we transfer the first
- *  packet of a particular protocol (TCP/UDP). We change the
- *  context only if the protocol type changes.
- *
- **********************************************************************/
+/*
+ * The offload context needs to be set when we transfer the first
+ * packet of a particular protocol (TCP/UDP).  This routine has been
+ * enhanced to deal with inserted VLAN headers, and IPV6 (not complete)
+ */
 static void
-em_transmit_checksum_setup(struct adapter *adapter,
-                          struct mbuf *mp,
-                          uint32_t *txd_upper,
-                          uint32_t *txd_lower) 
+em_txcsum(struct adapter *adapter, struct mbuf *mp,
+         uint32_t *txd_upper, uint32_t *txd_lower)
 {
-       struct em_context_desc *TXD;
+       struct e1000_context_desc *TXD;
        struct em_buffer *tx_buffer;
-       int curr_txd;
+       struct ether_vlan_header *eh;
+       struct ip *ip = NULL;
+       struct ip6_hdr *ip6;
+       struct tcp_hdr *th;
+       int curr_txd, ehdrlen;
+       uint32_t cmd, hdr_len, ip_hlen;
+       uint16_t etype;
+       uint8_t ipproto;
+
+       cmd = hdr_len = ipproto = 0;
+
+       /* Setup checksum offload context. */
+       curr_txd = adapter->next_avail_tx_desc;
+       tx_buffer = &adapter->tx_buffer_area[curr_txd];
+       TXD = (struct e1000_context_desc *)&adapter->tx_desc_base[curr_txd];
 
-       if (mp->m_pkthdr.csum_flags) {
-               if (mp->m_pkthdr.csum_flags & CSUM_TCP) {
-                       *txd_upper = E1000_TXD_POPTS_TXSM << 8;
-                       *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
-                       if (adapter->active_checksum_context == OFFLOAD_TCP_IP)
-                               return;
-                       else
-                               adapter->active_checksum_context = OFFLOAD_TCP_IP;
-               } else if (mp->m_pkthdr.csum_flags & CSUM_UDP) {
-                       *txd_upper = E1000_TXD_POPTS_TXSM << 8;
-                       *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
-                       if (adapter->active_checksum_context == OFFLOAD_UDP_IP)
-                               return;
-                       else
-                               adapter->active_checksum_context = OFFLOAD_UDP_IP;
-               } else {
-                       *txd_upper = 0;
-                       *txd_lower = 0;
-                       return;
-               }
+       /*
+        * Determine where frame payload starts.
+        * Jump over vlan headers if already present,
+        * helpful for QinQ too.
+        */
+       eh = mtod(mp, struct ether_vlan_header *);
+       if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
+               etype = ntohs(eh->evl_proto);
+               ehdrlen = ETHER_HDR_LEN + EVL_ENCAPLEN;
        } else {
-               *txd_upper = 0;
-               *txd_lower = 0;
-               return;
+               etype = ntohs(eh->evl_encap_proto);
+               ehdrlen = ETHER_HDR_LEN;
        }
 
        /*
-        * If we reach this point, the checksum offload context
-        * needs to be reset.
+        * We only support TCP/UDP for IPv4 and IPv6 for the moment.
+        * TODO: Support SCTP too when it hits the tree.
         */
-       curr_txd = adapter->next_avail_tx_desc;
-       tx_buffer = &adapter->tx_buffer_area[curr_txd];
-       TXD = (struct em_context_desc *) &adapter->tx_desc_base[curr_txd];
+       switch (etype) {
+       case ETHERTYPE_IP:
+               ip = (struct ip *)(mp->m_data + ehdrlen);
+               ip_hlen = ip->ip_hl << 2;
+
+               /* Setup of IP header checksum. */
+               if (mp->m_pkthdr.csum_flags & CSUM_IP) {
+                       /*
+                        * Start offset for header checksum calculation.
+                        * End offset for header checksum calculation.
+                        * Offset of place to put the checksum.
+                        */
+                       TXD->lower_setup.ip_fields.ipcss = ehdrlen;
+                       TXD->lower_setup.ip_fields.ipcse =
+                           htole16(ehdrlen + ip_hlen - 1);
+                       TXD->lower_setup.ip_fields.ipcso =
+                           ehdrlen + offsetof(struct ip, ip_sum);
+                       cmd |= E1000_TXD_CMD_IP;
+                       *txd_upper |= E1000_TXD_POPTS_IXSM << 8;
+               }
+
+               if (mp->m_len < ehdrlen + ip_hlen)
+                       return; /* failure */
+
+               hdr_len = ehdrlen + ip_hlen;
+               ipproto = ip->ip_p;
+
+               break;
+
+       case ETHERTYPE_IPV6:
+               ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
+               ip_hlen = sizeof(struct ip6_hdr); /* XXX: No header stacking. */
+
+               if (mp->m_len < ehdrlen + ip_hlen)
+                       return; /* failure */
 
-       TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN;
-       TXD->lower_setup.ip_fields.ipcso =
-           ETHER_HDR_LEN + offsetof(struct ip, ip_sum);
-       TXD->lower_setup.ip_fields.ipcse =
-           htole16(ETHER_HDR_LEN + sizeof(struct ip) - 1);
+               /* IPv6 doesn't have a header checksum. */
 
-       TXD->upper_setup.tcp_fields.tucss =
-           ETHER_HDR_LEN + sizeof(struct ip);
-       TXD->upper_setup.tcp_fields.tucse = htole16(0);
+               hdr_len = ehdrlen + ip_hlen;
+               ipproto = ip6->ip6_nxt;
+
+               break;
 
-       if (adapter->active_checksum_context == OFFLOAD_TCP_IP) {
-               TXD->upper_setup.tcp_fields.tucso =
-                       ETHER_HDR_LEN + sizeof(struct ip) +
-                       offsetof(struct tcphdr, th_sum);
-       } else if (adapter->active_checksum_context == OFFLOAD_UDP_IP) {
-               TXD->upper_setup.tcp_fields.tucso =
-                       ETHER_HDR_LEN + sizeof(struct ip) +
-                       offsetof(struct udphdr, uh_sum);
+       default:
+               *txd_upper = 0;
+               *txd_lower = 0;
+               return;
        }
 
-       TXD->tcp_seg_setup.data = htole32(0);
-       TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
+       switch (ipproto) {
+       case IPPROTO_TCP:
+               if (mp->m_pkthdr.csum_flags & CSUM_TCP) {
+                       /*
+                        * Start offset for payload checksum calculation.
+                        * End offset for payload checksum calculation.
+                        * Offset of place to put the checksum.
+                        */
+                       th = (struct tcp_hdr *)(mp->m_data + hdr_len);
+                       TXD->upper_setup.tcp_fields.tucss = hdr_len;
+                       TXD->upper_setup.tcp_fields.tucse = htole16(0);
+                       TXD->upper_setup.tcp_fields.tucso =
+                           hdr_len + offsetof(struct tcphdr, th_sum);
+                       cmd |= E1000_TXD_CMD_TCP;
+                       *txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+               }
+               break;
 
+       case IPPROTO_UDP:
+               if (mp->m_pkthdr.csum_flags & CSUM_UDP) {
+                       /*
+                        * Start offset for header checksum calculation.
+                        * End offset for header checksum calculation.
+                        * Offset of place to put the checksum.
+                        */
+                       TXD->upper_setup.tcp_fields.tucss = hdr_len;
+                       TXD->upper_setup.tcp_fields.tucse = htole16(0);
+                       TXD->upper_setup.tcp_fields.tucso =
+                           hdr_len + offsetof(struct udphdr, uh_sum);
+                       *txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       *txd_lower = E1000_TXD_CMD_DEXT |       /* Extended descr type */
+                    E1000_TXD_DTYP_D;          /* Data descr */
+       TXD->tcp_seg_setup.data = htole32(0);
+       TXD->cmd_and_length =
+           htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | cmd);
        tx_buffer->m_head = NULL;
        tx_buffer->next_eop = -1;
 
        if (++curr_txd == adapter->num_tx_desc)
                curr_txd = 0;
 
+       KKASSERT(adapter->num_tx_desc_avail > 0);
        adapter->num_tx_desc_avail--;
+
        adapter->next_avail_tx_desc = curr_txd;
 }
 
-/**********************************************************************
- *
- *  Examine each tx_buffer in the used queue. If the hardware is done
- *  processing the packet then free associated resources. The
- *  tx_buffer is put back on the free queue.
- *
- **********************************************************************/
-
 static void
 em_txeof(struct adapter *adapter)
 {
        int first, last, done, num_avail;
        struct em_buffer *tx_buffer;
-       struct em_tx_desc *tx_desc, *eop_desc;
-       struct ifnet *ifp = &adapter->interface_data.ac_if;
+       struct e1000_tx_desc *tx_desc, *eop_desc;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
 
        if (adapter->num_tx_desc_avail == adapter->num_tx_desc)
                return;
 
-       num_avail = adapter->num_tx_desc_avail; 
+       num_avail = adapter->num_tx_desc_avail;
        first = adapter->next_tx_to_clean;
+
        tx_desc = &adapter->tx_desc_base[first];
        tx_buffer = &adapter->tx_buffer_area[first];
        last = tx_buffer->next_eop;
-       KKASSERT(last >= 0 && last < adapter->num_tx_desc);
        eop_desc = &adapter->tx_desc_base[last];
 
        /*
-        * Now caculate the terminating index for the cleanup loop below
+        * What this does is get the index of the
+        * first descriptor AFTER the EOP of the
+        * first packet, that way we can do the
+        * simple comparison on the inner while loop.
         */
        if (++last == adapter->num_tx_desc)
                last = 0;
        done = last;
 
-       bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
-                       BUS_DMASYNC_POSTREAD);
-
-       while (eop_desc->upper.fields.status & E1000_TXD_STAT_DD) {
+        while (eop_desc->upper.fields.status & E1000_TXD_STAT_DD) {
+               /* We clean the range of the packet */
                while (first != done) {
+                       logif(pkt_txclean);
+
                        tx_desc->upper.data = 0;
                        tx_desc->lower.data = 0;
+                       tx_desc->buffer_addr = 0;
                        num_avail++;
 
-                       logif(pkt_txclean);
-
                        if (tx_buffer->m_head) {
                                ifp->if_opackets++;
-                               bus_dmamap_sync(adapter->txtag, tx_buffer->map,
-                                               BUS_DMASYNC_POSTWRITE);
                                bus_dmamap_unload(adapter->txtag,
                                                  tx_buffer->map);
-
                                m_freem(tx_buffer->m_head);
                                tx_buffer->m_head = NULL;
                        }
@@ -2658,11 +2697,13 @@ em_txeof(struct adapter *adapter)
                        tx_buffer = &adapter->tx_buffer_area[first];
                        tx_desc = &adapter->tx_desc_base[first];
                }
+
                /* See if we can continue to the next packet */
                last = tx_buffer->next_eop;
                if (last != -1) {
-                       KKASSERT(last >= 0 && last < adapter->num_tx_desc);
                        eop_desc = &adapter->tx_desc_base[last];
+
+                       /* Get new done point */
                        if (++last == adapter->num_tx_desc)
                                last = 0;
                        done = last;
@@ -2670,156 +2711,164 @@ em_txeof(struct adapter *adapter)
                        break;
                }
        }
+        adapter->next_tx_to_clean = first;
+       adapter->num_tx_desc_avail = num_avail;
 
-       bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
-                       BUS_DMASYNC_PREWRITE);
+       if (adapter->num_tx_desc_avail > EM_TX_CLEANUP_THRESHOLD) {
+               ifp->if_flags &= ~IFF_OACTIVE;
 
-       adapter->next_tx_to_clean = first;
+               /* All clean, turn off the timer */
+               if (adapter->num_tx_desc_avail == adapter->num_tx_desc)
+                       ifp->if_timer = 0;
+       }
+}
 
-       /*
-        * If we have enough room, clear IFF_OACTIVE to tell the stack
-        * that it is OK to send packets.
-        * If there are no pending descriptors, clear the timeout. Otherwise,
-        * if some descriptors have been freed, restart the timeout.
-        */
-       if (num_avail > EM_TX_CLEANUP_THRESHOLD) {
-               ifp->if_flags &= ~IFF_OACTIVE;
-               if (num_avail == adapter->num_tx_desc)
+/*
+ * When Link is lost sometimes there is work still in the TX ring
+ * which will result in a watchdog, rather than allow that do an
+ * attempted cleanup and then reinit here.  Note that this has been
+ * seens mostly with fiber adapters.
+ */
+static void
+em_tx_purge(struct adapter *adapter)
+{
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
+
+       if (!adapter->link_active && ifp->if_timer) {
+               em_txeof(adapter);
+               if (ifp->if_timer) {
+                       if_printf(ifp, "Link lost, TX pending, reinit\n");
                        ifp->if_timer = 0;
-               else if (num_avail == adapter->num_tx_desc_avail)
-                       ifp->if_timer = EM_TX_TIMEOUT;
+                       em_init(adapter);
+               }
        }
-       adapter->num_tx_desc_avail = num_avail;
 }
 
-/*********************************************************************
- *
- *  Get a buffer from system mbuf buffer pool.
- *
- **********************************************************************/
 static int
-em_get_buf(int i, struct adapter *adapter, struct mbuf *nmp, int how)
+em_newbuf(struct adapter *adapter, int i, int init)
 {
-       struct mbuf *mp = nmp;
+       struct mbuf *m;
+       bus_dma_segment_t seg;
+       bus_dmamap_t map;
        struct em_buffer *rx_buffer;
-       struct ifnet *ifp;
-       bus_addr_t paddr;
-       int error;
-
-       ifp = &adapter->interface_data.ac_if;
-
-       if (mp == NULL) {
-               mp = m_getcl(how, MT_DATA, M_PKTHDR);
-               if (mp == NULL) {
-                       adapter->mbuf_cluster_failed++;
-                       return (ENOBUFS);
+       int error, nseg;
+
+       m = m_getcl(init ? MB_WAIT : MB_DONTWAIT, MT_DATA, M_PKTHDR);
+       if (m == NULL) {
+               adapter->mbuf_cluster_failed++;
+               if (init) {
+                       if_printf(&adapter->arpcom.ac_if,
+                                 "Unable to allocate RX mbuf\n");
                }
-               mp->m_len = mp->m_pkthdr.len = MCLBYTES;
-       } else {
-               mp->m_len = mp->m_pkthdr.len = MCLBYTES;
-               mp->m_data = mp->m_ext.ext_buf;
-               mp->m_next = NULL;
+               return (ENOBUFS);
        }
+       m->m_len = m->m_pkthdr.len = MCLBYTES;
 
-       if (ifp->if_mtu <= ETHERMTU)
-               m_adj(mp, ETHER_ALIGN);
-
-       rx_buffer = &adapter->rx_buffer_area[i];
+       if (adapter->max_frame_size <= MCLBYTES - ETHER_ALIGN)
+               m_adj(m, ETHER_ALIGN);
 
-       /*
-        * Using memory from the mbuf cluster pool, invoke the
-        * bus_dma machinery to arrange the memory mapping.
-        */
-       error = bus_dmamap_load(adapter->rxtag, rx_buffer->map,
-                               mtod(mp, void *), mp->m_len,
-                               em_dmamap_cb, &paddr, 0);
+       error = bus_dmamap_load_mbuf_segment(adapter->rxtag,
+                       adapter->rx_sparemap, m,
+                       &seg, 1, &nseg, BUS_DMA_NOWAIT);
        if (error) {
-               m_freem(mp);
+               m_freem(m);
+               if (init) {
+                       if_printf(&adapter->arpcom.ac_if,
+                                 "Unable to load RX mbuf\n");
+               }
                return (error);
        }
-       rx_buffer->m_head = mp;
-       adapter->rx_desc_base[i].buffer_addr = htole64(paddr);
-       bus_dmamap_sync(adapter->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD);
 
+       rx_buffer = &adapter->rx_buffer_area[i];
+       if (rx_buffer->m_head != NULL)
+               bus_dmamap_unload(adapter->rxtag, rx_buffer->map);
+
+       map = rx_buffer->map;
+       rx_buffer->map = adapter->rx_sparemap;
+       adapter->rx_sparemap = map;
+
+       rx_buffer->m_head = m;
+
+       adapter->rx_desc_base[i].buffer_addr = htole64(seg.ds_addr);
        return (0);
 }
 
-/*********************************************************************
- *
- *  Allocate memory for rx_buffer structures. Since we use one
- *  rx_buffer per received packet, the maximum number of rx_buffer's
- *  that we'll need is equal to the number of receive descriptors
- *  that we've allocated.
- *
- **********************************************************************/
 static int
-em_allocate_receive_structures(struct adapter *adapter)
+em_create_rx_ring(struct adapter *adapter)
 {
-       int i, error, size;
+       device_t dev = adapter->dev;
        struct em_buffer *rx_buffer;
+       int i, error;
+
+       adapter->rx_buffer_area =
+               kmalloc(sizeof(struct em_buffer) * adapter->num_rx_desc,
+                       M_DEVBUF, M_WAITOK | M_ZERO);
 
-       size = adapter->num_rx_desc * sizeof(struct em_buffer);
-       adapter->rx_buffer_area = kmalloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
-
-       error = bus_dma_tag_create(NULL,                /* parent */
-                                  1, 0,                /* alignment, bounds */
-                                  BUS_SPACE_MAXADDR,   /* lowaddr */
-                                  BUS_SPACE_MAXADDR,   /* highaddr */
-                                  NULL, NULL,          /* filter, filterarg */
-                                  MCLBYTES,            /* maxsize */
-                                  1,                   /* nsegments */
-                                  MCLBYTES,            /* maxsegsize */
-                                  0,                   /* flags */
-                                  &adapter->rxtag);
+       /*
+        * Create DMA tag for rx buffers
+        */
+       error = bus_dma_tag_create(adapter->parent_dtag, /* parent */
+                       1, 0,                   /* alignment, bounds */
+                       BUS_SPACE_MAXADDR,      /* lowaddr */
+                       BUS_SPACE_MAXADDR,      /* highaddr */
+                       NULL, NULL,             /* filter, filterarg */
+                       MCLBYTES,               /* maxsize */
+                       1,                      /* nsegments */
+                       MCLBYTES,               /* maxsegsize */
+                       BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, /* flags */
+                       &adapter->rxtag);
        if (error) {
-               device_printf(adapter->dev, "%s: bus_dma_tag_create failed; "
-                             "error %u\n", __func__, error);
-               goto fail;
+               device_printf(dev, "Unable to allocate RX DMA tag\n");
+               kfree(adapter->rx_buffer_area, M_DEVBUF);
+               adapter->rx_buffer_area = NULL;
+               return error;
+       }
+
+       /*
+        * Create spare DMA map for rx buffers
+        */
+       error = bus_dmamap_create(adapter->rxtag, BUS_DMA_WAITOK,
+                                 &adapter->rx_sparemap);
+       if (error) {
+               device_printf(dev, "Unable to create spare RX DMA map\n");
+               bus_dma_tag_destroy(adapter->rxtag);
+               kfree(adapter->rx_buffer_area, M_DEVBUF);
+               adapter->rx_buffer_area = NULL;
+               return error;
        }
-       rx_buffer = adapter->rx_buffer_area;
-       for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) {
-               error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT,
+
+       /*
+        * Create DMA maps for rx buffers
+        */
+       for (i = 0; i < adapter->num_rx_desc; i++) {
+               rx_buffer = &adapter->rx_buffer_area[i];
+
+               error = bus_dmamap_create(adapter->rxtag, BUS_DMA_WAITOK,
                                          &rx_buffer->map);
                if (error) {
-                       device_printf(adapter->dev,
-                                     "%s: bus_dmamap_create failed; "
-                                     "error %u\n", __func__, error);
-                       goto fail;
+                       device_printf(dev, "Unable to create RX DMA map\n");
+                       em_destroy_rx_ring(adapter, i);
+                       return error;
                }
        }
-
-       for (i = 0; i < adapter->num_rx_desc; i++) {
-               error = em_get_buf(i, adapter, NULL, MB_DONTWAIT);
-               if (error)
-                       goto fail;
-       }
-
-       bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
-                       BUS_DMASYNC_PREWRITE);
-
        return (0);
-fail:
-       em_free_receive_structures(adapter);
-       return (error);
 }
 
-/*********************************************************************
- *
- *  Allocate and initialize receive structures.
- *
- **********************************************************************/
 static int
-em_setup_receive_structures(struct adapter *adapter)
+em_init_rx_ring(struct adapter *adapter)
 {
-       int error;
+       int i, error;
 
+       /* Reset descriptor ring */
        bzero(adapter->rx_desc_base,
-             sizeof(struct em_rx_desc) * adapter->num_rx_desc);
+           (sizeof(struct e1000_rx_desc)) * adapter->num_rx_desc);
 
-       error = em_allocate_receive_structures(adapter);
-       if (error)
-               return (error);
+       /* Allocate new ones. */
+       for (i = 0; i < adapter->num_rx_desc; i++) {
+               error = em_newbuf(adapter, i, 1);
+               if (error)
+                       return (error);
+       }
 
        /* Setup our descriptor pointers */
        adapter->next_rx_desc_to_check = 0;
@@ -2827,191 +2876,179 @@ em_setup_receive_structures(struct adapter *adapter)
        return (0);
 }
 
-/*********************************************************************
- *
- *  Enable receive unit.
- *
- **********************************************************************/
 static void
-em_initialize_receive_unit(struct adapter *adapter)
+em_init_rx_unit(struct adapter *adapter)
 {
-       uint32_t reg_rctl;
-       uint32_t reg_rxcsum;
-       struct ifnet *ifp;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
        uint64_t bus_addr;
-       INIT_DEBUGOUT("em_initialize_receive_unit: begin");
-
-       ifp = &adapter->interface_data.ac_if;
+       uint32_t rctl, rxcsum;
 
        /*
         * Make sure receives are disabled while setting
         * up the descriptor ring
         */
-       E1000_WRITE_REG(&adapter->hw, RCTL, 0);
-
-       /* Set the Receive Delay Timer Register */
-       E1000_WRITE_REG(&adapter->hw, RDTR, 
-                       adapter->rx_int_delay.value | E1000_RDT_FPDB);
+       rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
+       E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
 
-       if(adapter->hw.mac_type >= em_82540) {
-               E1000_WRITE_REG(&adapter->hw, RADV,
-                               adapter->rx_abs_int_delay.value);
+       if (adapter->hw.mac.type >= e1000_82540) {
+               E1000_WRITE_REG(&adapter->hw, E1000_RADV,
+                   adapter->rx_abs_int_delay.value);
 
-               /* Set the interrupt throttling rate in 256ns increments */  
-               if (em_int_throttle_ceil) {
-                       E1000_WRITE_REG(&adapter->hw, ITR,
-                               1000000000 / 256 / em_int_throttle_ceil);
+               /*
+                * Set the interrupt throttling rate. Value is calculated
+                * as ITR = 1 / (INT_THROTTLE_CEIL * 256ns)
+                */
+               if (adapter->int_throttle_ceil) {
+                       E1000_WRITE_REG(&adapter->hw, E1000_ITR,
+                               1000000000 / 256 / adapter->int_throttle_ceil);
                } else {
-                       E1000_WRITE_REG(&adapter->hw, ITR, 0);
+                       E1000_WRITE_REG(&adapter->hw, E1000_ITR, 0);
                }
        }
 
+       /* Disable accelerated ackknowledge */
+       if (adapter->hw.mac.type == e1000_82574) {
+               E1000_WRITE_REG(&adapter->hw,
+                   E1000_RFCTL, E1000_RFCTL_ACK_DIS);
+       }
+
        /* Setup the Base and Length of the Rx Descriptor Ring */
        bus_addr = adapter->rxdma.dma_paddr;
-       E1000_WRITE_REG(&adapter->hw, RDLEN, adapter->num_rx_desc *
-                       sizeof(struct em_rx_desc));
-       E1000_WRITE_REG(&adapter->hw, RDBAH, (uint32_t)(bus_addr >> 32));
-       E1000_WRITE_REG(&adapter->hw, RDBAL, (uint32_t)bus_addr);
+       E1000_WRITE_REG(&adapter->hw, E1000_RDLEN(0),
+           adapter->num_rx_desc * sizeof(struct e1000_rx_desc));
+       E1000_WRITE_REG(&adapter->hw, E1000_RDBAH(0),
+           (uint32_t)(bus_addr >> 32));
+       E1000_WRITE_REG(&adapter->hw, E1000_RDBAL(0),
+           (uint32_t)bus_addr);
 
        /* Setup the Receive Control Register */
-       reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
-                  E1000_RCTL_RDMTS_HALF |
-                  (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+       rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+       rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
+               E1000_RCTL_RDMTS_HALF |
+               (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
 
-       if (adapter->hw.tbi_compatibility_on == TRUE)
-               reg_rctl |= E1000_RCTL_SBP;
+       /* Make sure VLAN Filters are off */
+       rctl &= ~E1000_RCTL_VFE;
+
+       if (e1000_tbi_sbp_enabled_82543(&adapter->hw))
+               rctl |= E1000_RCTL_SBP;
+       else
+               rctl &= ~E1000_RCTL_SBP;
 
        switch (adapter->rx_buffer_len) {
        default:
-       case EM_RXBUFFER_2048:
-               reg_rctl |= E1000_RCTL_SZ_2048;
+       case 2048:
+               rctl |= E1000_RCTL_SZ_2048;
+               break;
+
+       case 4096:
+               rctl |= E1000_RCTL_SZ_4096 |
+                   E1000_RCTL_BSEX | E1000_RCTL_LPE;
                break;
-       case EM_RXBUFFER_4096:
-               reg_rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX |
-                           E1000_RCTL_LPE;
-               break;            
-       case EM_RXBUFFER_8192:
-               reg_rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX |
-                           E1000_RCTL_LPE;
+
+       case 8192:
+               rctl |= E1000_RCTL_SZ_8192 |
+                   E1000_RCTL_BSEX | E1000_RCTL_LPE;
                break;
-       case EM_RXBUFFER_16384:
-               reg_rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX |
-                           E1000_RCTL_LPE;
+
+       case 16384:
+               rctl |= E1000_RCTL_SZ_16384 |
+                   E1000_RCTL_BSEX | E1000_RCTL_LPE;
                break;
        }
 
        if (ifp->if_mtu > ETHERMTU)
-               reg_rctl |= E1000_RCTL_LPE;
+               rctl |= E1000_RCTL_LPE;
+       else
+               rctl &= ~E1000_RCTL_LPE;
 
-       /* Enable 82543 Receive Checksum Offload for TCP and UDP */
-       if ((adapter->hw.mac_type >= em_82543) &&
-           (ifp->if_capenable & IFCAP_RXCSUM)) {
-               reg_rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
-               reg_rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
-               E1000_WRITE_REG(&adapter->hw, RXCSUM, reg_rxcsum);
+       /* Receive Checksum Offload for TCP and UDP */
+       if (ifp->if_capenable & IFCAP_RXCSUM) {
+               rxcsum = E1000_READ_REG(&adapter->hw, E1000_RXCSUM);
+               rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
+               E1000_WRITE_REG(&adapter->hw, E1000_RXCSUM, rxcsum);
        }
 
-#ifdef EM_X60_WORKAROUND
-       if (adapter->hw.mac_type == em_82573)
-               E1000_WRITE_REG(&adapter->hw, RDTR, 32);
-#endif
+       /*
+        * XXX TEMPORARY WORKAROUND: on some systems with 82573
+        * long latencies are observed, like Lenovo X60. This
+        * change eliminates the problem, but since having positive
+        * values in RDTR is a known source of problems on other
+        * platforms another solution is being sought.
+        */
+       if (adapter->hw.mac.type == e1000_82573)
+               E1000_WRITE_REG(&adapter->hw, E1000_RDTR, 0x20);
 
        /* Enable Receives */
-       E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+       E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl);
 
-       /* Setup the HW Rx Head and Tail Descriptor Pointers */
-       E1000_WRITE_REG(&adapter->hw, RDH, 0);
-       E1000_WRITE_REG(&adapter->hw, RDT, adapter->num_rx_desc - 1);
+       /*
+        * Setup the HW Rx Head and Tail Descriptor Pointers
+        */
+       E1000_WRITE_REG(&adapter->hw, E1000_RDH(0), 0);
+       E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), adapter->num_rx_desc - 1);
 }
 
-/*********************************************************************
- *
- *  Free receive related data structures.
- *
- **********************************************************************/
 static void
-em_free_receive_structures(struct adapter *adapter)
+em_destroy_rx_ring(struct adapter *adapter, int ndesc)
 {
        struct em_buffer *rx_buffer;
        int i;
 
-       INIT_DEBUGOUT("free_receive_structures: begin");
+       if (adapter->rx_buffer_area == NULL)
+               return;
 
-       if (adapter->rx_buffer_area != NULL) {
-               rx_buffer = adapter->rx_buffer_area;
-               for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) {
-                       if (rx_buffer->m_head != NULL) {
-                               bus_dmamap_unload(adapter->rxtag,
-                                                 rx_buffer->map);
-                               m_freem(rx_buffer->m_head);
-                               rx_buffer->m_head = NULL;
-                       }
-                       if (rx_buffer->map != NULL) {
-                               bus_dmamap_destroy(adapter->rxtag,
-                                                  rx_buffer->map);
-                               rx_buffer->map = NULL;
-                       }
-               }
-       }
-       if (adapter->rx_buffer_area != NULL) {
-               kfree(adapter->rx_buffer_area, M_DEVBUF);
-               adapter->rx_buffer_area = NULL;
-       }
-       if (adapter->rxtag != NULL) {
-               bus_dma_tag_destroy(adapter->rxtag);
-               adapter->rxtag = NULL;
+       for (i = 0; i < ndesc; i++) {
+               rx_buffer = &adapter->rx_buffer_area[i];
+
+               KKASSERT(rx_buffer->m_head == NULL);
+               bus_dmamap_destroy(adapter->rxtag, rx_buffer->map);
        }
+       bus_dmamap_destroy(adapter->rxtag, adapter->rx_sparemap);
+       bus_dma_tag_destroy(adapter->rxtag);
+
+       kfree(adapter->rx_buffer_area, M_DEVBUF);
+       adapter->rx_buffer_area = NULL;
 }
 
-/*********************************************************************
- *
- *  This routine executes in interrupt context. It replenishes
- *  the mbufs in the descriptor and sends data which has been
- *  dma'ed into host memory to upper layer.
- *
- *  We loop at most count times if count is > 0, or until done if
- *  count < 0.
- *
- *********************************************************************/
 static void
 em_rxeof(struct adapter *adapter, int count)
 {
-       struct ifnet *ifp;
-       struct mbuf *mp;
-       uint8_t accept_frame = 0;
-       uint8_t eop = 0;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
+       uint8_t status, accept_frame = 0, eop = 0;
        uint16_t len, desc_len, prev_len_adj;
+       struct e1000_rx_desc *current_desc;
+       struct mbuf *mp;
        int i;
        struct mbuf_chain chain[MAXCPU];
 
-       /* Pointer to the receive descriptor being examined. */
-       struct em_rx_desc *current_desc;
-
-       ifp = &adapter->interface_data.ac_if;
        i = adapter->next_rx_desc_to_check;
        current_desc = &adapter->rx_desc_base[i];
 
-       bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
-                       BUS_DMASYNC_POSTREAD);
-
        if (!(current_desc->status & E1000_RXD_STAT_DD))
                return;
 
        ether_input_chain_init(chain);
 
        while ((current_desc->status & E1000_RXD_STAT_DD) && count != 0) {
+               struct mbuf *m = NULL;
+
                logif(pkt_receive);
+
                mp = adapter->rx_buffer_area[i].m_head;
+
+               /*
+                * Can't defer bus_dmamap_sync(9) because TBI_ACCEPT
+                * needs to access the last received byte in the mbuf.
+                */
                bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map,
                                BUS_DMASYNC_POSTREAD);
-               bus_dmamap_unload(adapter->rxtag,
-                                 adapter->rx_buffer_area[i].map);
 
                accept_frame = 1;
                prev_len_adj = 0;
                desc_len = le16toh(current_desc->length);
-               if (current_desc->status & E1000_RXD_STAT_EOP) {
+               status = current_desc->status;
+               if (status & E1000_RXD_STAT_EOP) {
                        count--;
                        eop = 1;
                        if (desc_len < ETHER_CRC_LEN) {
@@ -3026,21 +3063,20 @@ em_rxeof(struct adapter *adapter, int count)
                }
 
                if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
-                       uint8_t last_byte;
+                       uint8_t last_byte;
                        uint32_t pkt_len = desc_len;
 
                        if (adapter->fmp != NULL)
-                               pkt_len += adapter->fmp->m_pkthdr.len; 
+                               pkt_len += adapter->fmp->m_pkthdr.len;
 
                        last_byte = *(mtod(mp, caddr_t) + desc_len - 1);
-
-                       if (TBI_ACCEPT(&adapter->hw, current_desc->status, 
-                                      current_desc->errors, 
-                                      pkt_len, last_byte)) {
-                               em_tbi_adjust_stats(&adapter->hw, 
-                                                   &adapter->stats, 
-                                                   pkt_len, 
-                                                   adapter->hw.mac_addr);
+                       if (TBI_ACCEPT(&adapter->hw, status,
+                           current_desc->errors, pkt_len, last_byte,
+                           adapter->min_frame_size, adapter->max_frame_size)) {
+                               e1000_tbi_adjust_stats_82543(&adapter->hw,
+                                   &adapter->stats, pkt_len,
+                                   adapter->hw.mac.addr,
+                                   adapter->max_frame_size);
                                if (len > 0)
                                        len--;
                        } else {
@@ -3049,14 +3085,9 @@ em_rxeof(struct adapter *adapter, int count)
                }
 
                if (accept_frame) {
-                       if (em_get_buf(i, adapter, NULL, MB_DONTWAIT) == ENOBUFS) {
-                               adapter->dropped_pkts++;
-                               em_get_buf(i, adapter, mp, MB_DONTWAIT);
-                               if (adapter->fmp != NULL)
-                                       m_freem(adapter->fmp);
-                               adapter->fmp = NULL;
-                               adapter->lmp = NULL;
-                               goto skip;
+                       if (em_newbuf(adapter, i, 0) != 0) {
+                               ifp->if_iqdrops++;
+                               goto discard;
                        }
 
                        /* Assign correct length to the current fragment */
@@ -3064,18 +3095,22 @@ em_rxeof(struct adapter *adapter, int count)
 
                        if (adapter->fmp == NULL) {
                                mp->m_pkthdr.len = len;
-                               adapter->fmp = mp;       /* Store the first mbuf */
+                               adapter->fmp = mp; /* Store the first mbuf */
                                adapter->lmp = mp;
                        } else {
-                               /* Chain mbuf's together */
-                               /* 
+                               /*
+                                * Chain mbuf's together
+                                */
+
+                               /*
                                 * Adjust length of previous mbuf in chain if
                                 * we received less than 4 bytes in the last
                                 * descriptor.
                                 */
                                if (prev_len_adj > 0) {
                                        adapter->lmp->m_len -= prev_len_adj;
-                                       adapter->fmp->m_pkthdr.len -= prev_len_adj;
+                                       adapter->fmp->m_pkthdr.len -=
+                                           prev_len_adj;
                                }
                                adapter->lmp->m_next = mp;
                                adapter->lmp = adapter->lmp->m_next;
@@ -3086,258 +3121,298 @@ em_rxeof(struct adapter *adapter, int count)
                                adapter->fmp->m_pkthdr.rcvif = ifp;
                                ifp->if_ipackets++;
 
-                               em_receive_checksum(adapter, current_desc,
-                                                   adapter->fmp);
-                               if (current_desc->status & E1000_RXD_STAT_VP) {
-                                       adapter->fmp->m_flags |= M_VLANTAG;
+                               if (ifp->if_capenable & IFCAP_RXCSUM) {
+                                       em_rxcsum(adapter, current_desc,
+                                                 adapter->fmp);
+                               }
+
+                               if (status & E1000_RXD_STAT_VP) {
                                        adapter->fmp->m_pkthdr.ether_vlantag =
-                                               (current_desc->special &
-                                                E1000_RXD_SPC_VLAN_MASK);
+                                           (le16toh(current_desc->special) &
+                                           E1000_RXD_SPC_VLAN_MASK);
+                                       adapter->fmp->m_flags |= M_VLANTAG;
                                }
-                               ether_input_chain(ifp, adapter->fmp, chain);
+                               m = adapter->fmp;
                                adapter->fmp = NULL;
                                adapter->lmp = NULL;
                        }
                } else {
-                       adapter->dropped_pkts++;
-                       em_get_buf(i, adapter, mp, MB_DONTWAIT);
-                       if (adapter->fmp != NULL) 
+                       ifp->if_ierrors++;
+discard:
+#ifdef foo
+                       /* Reuse loaded DMA map and just update mbuf chain */
+                       mp = adapter->rx_buffer_area[i].m_head;
+                       mp->m_len = mp->m_pkthdr.len = MCLBYTES;
+                       mp->m_data = mp->m_ext.ext_buf;
+                       mp->m_next = NULL;
+                       if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN))
+                               m_adj(mp, ETHER_ALIGN);
+#endif
+                       if (adapter->fmp != NULL) {
                                m_freem(adapter->fmp);
-                       adapter->fmp = NULL;
-                       adapter->lmp = NULL;
+                               adapter->fmp = NULL;
+                               adapter->lmp = NULL;
+                       }
+                       m = NULL;
                }
 
-skip:
                /* Zero out the receive descriptors status. */
                current_desc->status = 0;
 
+               if (m != NULL)
+                       ether_input_chain(ifp, m, chain);
+
                /* Advance our pointers to the next descriptor. */
-               if (++i == adapter->num_rx_desc) {
+               if (++i == adapter->num_rx_desc)
                        i = 0;
-                       current_desc = adapter->rx_desc_base;
-               } else {
-                       current_desc++;
-               }
+               current_desc = &adapter->rx_desc_base[i];
        }
+       adapter->next_rx_desc_to_check = i;
 
        ether_input_dispatch(chain);
 
-       bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
-                       BUS_DMASYNC_PREWRITE);
-
-       adapter->next_rx_desc_to_check = i;
-
        /* Advance the E1000's Receive Queue #0  "Tail Pointer". */
        if (--i < 0)
                i = adapter->num_rx_desc - 1;
-
-       E1000_WRITE_REG(&adapter->hw, RDT, i);
+       E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i);
 }
 
-/*********************************************************************
- *
- *  Verify that the hardware indicated that the checksum is valid.
- *  Inform the stack about the status of checksum so that stack
- *  doesn't spend time verifying the checksum.
- *
- *********************************************************************/
 static void
-em_receive_checksum(struct adapter *adapter,
-                   struct em_rx_desc *rx_desc,
-                   struct mbuf *mp)
+em_rxcsum(struct adapter *adapter, struct e1000_rx_desc *rx_desc,
+         struct mbuf *mp)
 {
        /* 82543 or newer only */
-       if ((adapter->hw.mac_type < em_82543) ||
+       if (adapter->hw.mac.type < e1000_82543 ||
            /* Ignore Checksum bit is set */
-           (rx_desc->status & E1000_RXD_STAT_IXSM)) {
-               mp->m_pkthdr.csum_flags = 0;
+           (rx_desc->status & E1000_RXD_STAT_IXSM))
                return;
-       }
 
-       if (rx_desc->status & E1000_RXD_STAT_IPCS) {
-               /* Did it pass? */
-               if (!(rx_desc->errors & E1000_RXD_ERR_IPE)) {
-                       /* IP Checksum Good */
-                       mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
-                       mp->m_pkthdr.csum_flags |= CSUM_IP_VALID;
-               } else {
-                       mp->m_pkthdr.csum_flags = 0;
-               }
+       if ((rx_desc->status & E1000_RXD_STAT_IPCS) &&
+           !(rx_desc->errors & E1000_RXD_ERR_IPE)) {
+               /* IP Checksum Good */
+               mp->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID;
        }
 
-       if (rx_desc->status & E1000_RXD_STAT_TCPCS) {
-               /* Did it pass? */
-               if (!(rx_desc->errors & E1000_RXD_ERR_TCPE)) {
-                       mp->m_pkthdr.csum_flags |=
-                       (CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
-                        CSUM_FRAG_NOT_CHECKED);
-                       mp->m_pkthdr.csum_data = htons(0xffff);
-               }
+       if ((rx_desc->status & E1000_RXD_STAT_TCPCS) &&
+           !(rx_desc->errors & E1000_RXD_ERR_TCPE)) {
+               mp->m_pkthdr.csum_flags |= CSUM_DATA_VALID |
+                                          CSUM_PSEUDO_HDR |
+                                          CSUM_FRAG_NOT_CHECKED;
+               mp->m_pkthdr.csum_data = htons(0xffff);
        }
 }
 
-
-static void 
-em_enable_vlans(struct adapter *adapter)
+static void
+em_enable_intr(struct adapter *adapter)
 {
-       uint32_t ctrl;
-
-       E1000_WRITE_REG(&adapter->hw, VET, ETHERTYPE_VLAN);
-
-       ctrl = E1000_READ_REG(&adapter->hw, CTRL);
-       ctrl |= E1000_CTRL_VME;
-       E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+       lwkt_serialize_handler_enable(adapter->arpcom.ac_if.if_serializer);
+       E1000_WRITE_REG(&adapter->hw, E1000_IMS, IMS_ENABLE_MASK);
 }
 
 static void
-em_disable_vlans(struct adapter *adapter)
+em_disable_intr(struct adapter *adapter)
 {
-       uint32_t ctrl;
-
-       ctrl = E1000_READ_REG(&adapter->hw, CTRL);
-       ctrl &= ~E1000_CTRL_VME;
-       E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+       E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff);
+       lwkt_serialize_handler_disable(adapter->arpcom.ac_if.if_serializer);
 }
 
 /*
- * note: we must call bus_enable_intr() prior to enabling the hardware
- * interrupt and bus_disable_intr() after disabling the hardware interrupt
- * in order to avoid handler execution races from scheduled interrupt
- * threads.
+ * Bit of a misnomer, what this really means is
+ * to enable OS management of the system... aka
+ * to disable special hardware management features 
  */
 static void
-em_enable_intr(struct adapter *adapter)
-{
-       struct ifnet *ifp = &adapter->interface_data.ac_if;
-       
-       if ((ifp->if_flags & IFF_POLLING) == 0) {
-               lwkt_serialize_handler_enable(ifp->if_serializer);
-               E1000_WRITE_REG(&adapter->hw, IMS, (IMS_ENABLE_MASK));
+em_get_mgmt(struct adapter *adapter)
+{
+       /* A shared code workaround */
+#define E1000_82542_MANC2H E1000_MANC2H
+       if (adapter->has_manage) {
+               int manc2h = E1000_READ_REG(&adapter->hw, E1000_MANC2H);
+               int manc = E1000_READ_REG(&adapter->hw, E1000_MANC);
+
+               /* disable hardware interception of ARP */
+               manc &= ~(E1000_MANC_ARP_EN);
+
+                /* enable receiving management packets to the host */
+                if (adapter->hw.mac.type >= e1000_82571) {
+                       manc |= E1000_MANC_EN_MNG2HOST;
+#define E1000_MNG2HOST_PORT_623 (1 << 5)
+#define E1000_MNG2HOST_PORT_664 (1 << 6)
+                       manc2h |= E1000_MNG2HOST_PORT_623;
+                       manc2h |= E1000_MNG2HOST_PORT_664;
+                       E1000_WRITE_REG(&adapter->hw, E1000_MANC2H, manc2h);
+               }
+
+               E1000_WRITE_REG(&adapter->hw, E1000_MANC, manc);
        }
 }
 
+/*
+ * Give control back to hardware management
+ * controller if there is one.
+ */
 static void
-em_disable_intr(struct adapter *adapter)
+em_rel_mgmt(struct adapter *adapter)
 {
-       /*
-        * The first version of 82542 had an errata where when link was forced
-        * it would stay up even up even if the cable was disconnected.
-        * Sequence errors were used to detect the disconnect and then the
-        * driver would unforce the link.  This code in the in the ISR.  For
-        * this to work correctly the Sequence error interrupt had to be
-        * enabled all the time.
-        */
-       if (adapter->hw.mac_type == em_82542_rev2_0) {
-               E1000_WRITE_REG(&adapter->hw, IMC,
-                               (0xffffffff & ~E1000_IMC_RXSEQ));
-       } else {
-               E1000_WRITE_REG(&adapter->hw, IMC, 0xffffffff);
-       }
+       if (adapter->has_manage) {
+               int manc = E1000_READ_REG(&adapter->hw, E1000_MANC);
 
-       lwkt_serialize_handler_disable(adapter->interface_data.ac_if.if_serializer);
-}
+               /* re-enable hardware interception of ARP */
+               manc |= E1000_MANC_ARP_EN;
 
-static int
-em_is_valid_ether_addr(uint8_t *addr)
-{
-       static const char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
+               if (adapter->hw.mac.type >= e1000_82571)
+                       manc &= ~E1000_MANC_EN_MNG2HOST;
 
-       if ((addr[0] & 1) || !bcmp(addr, zero_addr, ETHER_ADDR_LEN))
-               return (FALSE);
-       else
-               return (TRUE);
+               E1000_WRITE_REG(&adapter->hw, E1000_MANC, manc);
+       }
 }
 
-void
-em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t *value)
+/*
+ * em_get_hw_control() sets {CTRL_EXT|FWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded.  For AMT version (only with 82573)
+ * of the f/w this means that the network i/f is open.
+ */
+static void
+em_get_hw_control(struct adapter *adapter)
 {
-       pci_write_config(((struct em_osdep *)hw->back)->dev, reg, *value, 2);
-}
+       uint32_t ctrl_ext, swsm;
 
-void
-em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t *value)
-{
-       *value = pci_read_config(((struct em_osdep *)hw->back)->dev, reg, 2);
+       /* Let firmware know the driver has taken over */
+       switch (adapter->hw.mac.type) {
+       case e1000_82573:
+               swsm = E1000_READ_REG(&adapter->hw, E1000_SWSM);
+               E1000_WRITE_REG(&adapter->hw, E1000_SWSM,
+                   swsm | E1000_SWSM_DRV_LOAD);
+               break;
+       case e1000_82571:
+       case e1000_82572:
+       case e1000_80003es2lan:
+       case e1000_ich8lan:
+       case e1000_ich9lan:
+       case e1000_ich10lan:
+               ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
+               E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
+                   ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+               break;
+       default:
+               break;
+       }
 }
 
-void
-em_pci_set_mwi(struct em_hw *hw)
+/*
+ * em_rel_hw_control() resets {CTRL_EXT|FWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that the
+ * driver is no longer loaded.  For AMT version (only with 82573)
+ * of the f/w this means that the network i/f is closed.
+ */
+static void
+em_rel_hw_control(struct adapter *adapter)
 {
-       pci_write_config(((struct em_osdep *)hw->back)->dev, PCIR_COMMAND,
-                        (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2);
-}
+       uint32_t ctrl_ext, swsm;
 
-void
-em_pci_clear_mwi(struct em_hw *hw)
-{
-       pci_write_config(((struct em_osdep *)hw->back)->dev, PCIR_COMMAND,
-                        (hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2);
-}
+       /* Let firmware taken over control of h/w */
+       switch (adapter->hw.mac.type) {
+       case e1000_82573:
+               swsm = E1000_READ_REG(&adapter->hw, E1000_SWSM);
+               E1000_WRITE_REG(&adapter->hw, E1000_SWSM,
+                   swsm & ~E1000_SWSM_DRV_LOAD);
+               break;
 
-uint32_t
-em_io_read(struct em_hw *hw, unsigned long port)
-{
-       struct em_osdep *io = hw->back;
+       case e1000_82571:
+       case e1000_82572:
+       case e1000_80003es2lan:
+       case e1000_ich8lan:
+       case e1000_ich9lan:
+       case e1000_ich10lan:
+               ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
+               E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
+                   ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+               break;
 
-       return bus_space_read_4(io->io_bus_space_tag,
-                               io->io_bus_space_handle, port);
+       default:
+               break;
+       }
 }
 
-void
-em_io_write(struct em_hw *hw, unsigned long port, uint32_t value)
+static int
+em_is_valid_eaddr(const uint8_t *addr)
 {
-       struct em_osdep *io = hw->back;
+       char zero_addr[ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 };
+
+       if ((addr[0] & 1) || !bcmp(addr, zero_addr, ETHER_ADDR_LEN))
+               return (FALSE);
 
-       bus_space_write_4(io->io_bus_space_tag,
-                         io->io_bus_space_handle, port, value);
+       return (TRUE);
 }
 
 /*
- * We may eventually really do this, but its unnecessary 
- * for now so we just return unsupported.
+ * Enable PCI Wake On Lan capability
  */
-int32_t
-em_read_pcie_cap_reg(struct em_hw *hw, uint32_t reg, uint16_t *value)
+void
+em_enable_wol(device_t dev)
 {
-       return (0);
+       uint16_t cap, status;
+       uint8_t id;
+
+       /* First find the capabilities pointer*/
+       cap = pci_read_config(dev, PCIR_CAP_PTR, 2);
+
+       /* Read the PM Capabilities */
+       id = pci_read_config(dev, cap, 1);
+       if (id != PCIY_PMG)     /* Something wrong */
+               return;
+
+       /*
+        * OK, we have the power capabilities,
+        * so now get the status register
+        */
+       cap += PCIR_POWER_STATUS;
+       status = pci_read_config(dev, cap, 2);
+       status |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
+       pci_write_config(dev, cap, status, 2);
 }
 
 
-/*********************************************************************
+/*
  * 82544 Coexistence issue workaround.
  *    There are 2 issues.
- *     1. Transmit Hang issue.
+ *       1. Transmit Hang issue.
  *    To detect this issue, following equation can be used...
- *          SIZE[3:0] + ADDR[2:0] = SUM[3:0].
- *          If SUM[3:0] is in between 1 to 4, we will have this issue.
+ *       SIZE[3:0] + ADDR[2:0] = SUM[3:0].
+ *       If SUM[3:0] is in between 1 to 4, we will have this issue.
  *
- *     2. DAC issue.
+ *       2. DAC issue.
  *    To detect this issue, following equation can be used...
- *          SIZE[3:0] + ADDR[2:0] = SUM[3:0].
- *          If SUM[3:0] is in between 9 to c, we will have this issue.
- *
+ *       SIZE[3:0] + ADDR[2:0] = SUM[3:0].
+ *       If SUM[3:0] is in between 9 to c, we will have this issue.
  *
  *    WORKAROUND:
- *          Make sure we do not have ending address as 1,2,3,4(Hang) or
- *          9,a,b,c (DAC)
- *
-*************************************************************************/
+ *       Make sure we do not have ending address
+ *       as 1,2,3,4(Hang) or 9,a,b,c (DAC)
+ */
 static uint32_t
-em_fill_descriptors(bus_addr_t address, uint32_t length, PDESC_ARRAY desc_array)
+em_82544_fill_desc(bus_addr_t address, uint32_t length, PDESC_ARRAY desc_array)
 {
-       /* Since issue is sensitive to length and address.*/
-       /* Let us first check the address...*/
        uint32_t safe_terminator;
+
+       /*
+        * Since issue is sensitive to length and address.
+        * Let us first check the address...
+        */
        if (length <= 4) {
                desc_array->descriptor[0].address = address;
                desc_array->descriptor[0].length = length;
                desc_array->elements = 1;
                return (desc_array->elements);
        }
-       safe_terminator = (uint32_t)((((uint32_t)address & 0x7) + (length & 0xF)) & 0xF);
-       /* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */ 
+
+       safe_terminator =
+       (uint32_t)((((uint32_t)address & 0x7) + (length & 0xF)) & 0xF);
+
+       /* If it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */
        if (safe_terminator == 0 ||
-           (safe_terminator > 4 && safe_terminator < 9) || 
+           (safe_terminator > 4 && safe_terminator < 9) ||
            (safe_terminator > 0xC && safe_terminator <= 0xF)) {
                desc_array->descriptor[0].address = address;
                desc_array->descriptor[0].length = length;
@@ -3353,226 +3428,242 @@ em_fill_descriptors(bus_addr_t address, uint32_t length, PDESC_ARRAY desc_array)
        return (desc_array->elements);
 }
 
-/**********************************************************************
- *
- *  Update the board statistics counters.
- *
- **********************************************************************/
 static void
-em_update_stats_counters(struct adapter *adapter)
-{
-       struct ifnet   *ifp;
-
-       if (adapter->hw.media_type == em_media_type_copper ||
-           (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
-               adapter->stats.symerrs += E1000_READ_REG(&adapter->hw, SYMERRS);
-               adapter->stats.sec += E1000_READ_REG(&adapter->hw, SEC);
-       }
-       adapter->stats.crcerrs += E1000_READ_REG(&adapter->hw, CRCERRS);
-       adapter->stats.mpc += E1000_READ_REG(&adapter->hw, MPC);
-       adapter->stats.scc += E1000_READ_REG(&adapter->hw, SCC);
-       adapter->stats.ecol += E1000_READ_REG(&adapter->hw, ECOL);
-
-       adapter->stats.mcc += E1000_READ_REG(&adapter->hw, MCC);
-       adapter->stats.latecol += E1000_READ_REG(&adapter->hw, LATECOL);
-       adapter->stats.colc += E1000_READ_REG(&adapter->hw, COLC);
-       adapter->stats.dc += E1000_READ_REG(&adapter->hw, DC);
-       adapter->stats.rlec += E1000_READ_REG(&adapter->hw, RLEC);
-       adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, XONRXC);
-       adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, XONTXC);
-       adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, XOFFRXC);
-       adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, XOFFTXC);
-       adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, FCRUC);
-       adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, PRC64);
-       adapter->stats.prc127 += E1000_READ_REG(&adapter->hw, PRC127);
-       adapter->stats.prc255 += E1000_READ_REG(&adapter->hw, PRC255);
-       adapter->stats.prc511 += E1000_READ_REG(&adapter->hw, PRC511);
-       adapter->stats.prc1023 += E1000_READ_REG(&adapter->hw, PRC1023);
-       adapter->stats.prc1522 += E1000_READ_REG(&adapter->hw, PRC1522);
-       adapter->stats.gprc += E1000_READ_REG(&adapter->hw, GPRC);
-       adapter->stats.bprc += E1000_READ_REG(&adapter->hw, BPRC);
-       adapter->stats.mprc += E1000_READ_REG(&adapter->hw, MPRC);
-       adapter->stats.gptc += E1000_READ_REG(&adapter->hw, GPTC);
+em_update_stats(struct adapter *adapter)
+{
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
+
+       if (adapter->hw.phy.media_type == e1000_media_type_copper ||
+           (E1000_READ_REG(&adapter->hw, E1000_STATUS) & E1000_STATUS_LU)) {
+               adapter->stats.symerrs +=
+                       E1000_READ_REG(&adapter->hw, E1000_SYMERRS);
+               adapter->stats.sec += E1000_READ_REG(&adapter->hw, E1000_SEC);
+       }
+       adapter->stats.crcerrs += E1000_READ_REG(&adapter->hw, E1000_CRCERRS);
+       adapter->stats.mpc += E1000_READ_REG(&adapter->hw, E1000_MPC);
+       adapter->stats.scc += E1000_READ_REG(&adapter->hw, E1000_SCC);
+       adapter->stats.ecol += E1000_READ_REG(&adapter->hw, E1000_ECOL);
+
+       adapter->stats.mcc += E1000_READ_REG(&adapter->hw, E1000_MCC);
+       adapter->stats.latecol += E1000_READ_REG(&adapter->hw, E1000_LATECOL);
+       adapter->stats.colc += E1000_READ_REG(&adapter->hw, E1000_COLC);
+       adapter->stats.dc += E1000_READ_REG(&adapter->hw, E1000_DC);
+       adapter->stats.rlec += E1000_READ_REG(&adapter->hw, E1000_RLEC);
+       adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, E1000_XONRXC);
+       adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, E1000_XONTXC);
+       adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, E1000_XOFFRXC);
+       adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, E1000_XOFFTXC);
+       adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, E1000_FCRUC);
+       adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, E1000_PRC64);
+       adapter->stats.prc127 += E1000_READ_REG(&adapter->hw, E1000_PRC127);
+       adapter->stats.prc255 += E1000_READ_REG(&adapter->hw, E1000_PRC255);
+       adapter->stats.prc511 += E1000_READ_REG(&adapter->hw, E1000_PRC511);
+       adapter->stats.prc1023 += E1000_READ_REG(&adapter->hw, E1000_PRC1023);
+       adapter->stats.prc1522 += E1000_READ_REG(&adapter->hw, E1000_PRC1522);
+       adapter->stats.gprc += E1000_READ_REG(&adapter->hw, E1000_GPRC);
+       adapter->stats.bprc += E1000_READ_REG(&adapter->hw, E1000_BPRC);
+       adapter->stats.mprc += E1000_READ_REG(&adapter->hw, E1000_MPRC);
+       adapter->stats.gptc += E1000_READ_REG(&adapter->hw, E1000_GPTC);
 
        /* For the 64-bit byte counters the low dword must be read first. */
        /* Both registers clear on the read of the high dword */
 
-       adapter->stats.gorcl += E1000_READ_REG(&adapter->hw, GORCL);
-       adapter->stats.gorch += E1000_READ_REG(&adapter->hw, GORCH);
-       adapter->stats.gotcl += E1000_READ_REG(&adapter->hw, GOTCL);
-       adapter->stats.gotch += E1000_READ_REG(&adapter->hw, GOTCH);
-
-       adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, RNBC);
-       adapter->stats.ruc += E1000_READ_REG(&adapter->hw, RUC);
-       adapter->stats.rfc += E1000_READ_REG(&adapter->hw, RFC);
-       adapter->stats.roc += E1000_READ_REG(&adapter->hw, ROC);
-       adapter->stats.rjc += E1000_READ_REG(&adapter->hw, RJC);
-
-       adapter->stats.torl += E1000_READ_REG(&adapter->hw, TORL);
-       adapter->stats.torh += E1000_READ_REG(&adapter->hw, TORH);
-       adapter->stats.totl += E1000_READ_REG(&adapter->hw, TOTL);
-       adapter->stats.toth += E1000_READ_REG(&adapter->hw, TOTH);
-
-       adapter->stats.tpr += E1000_READ_REG(&adapter->hw, TPR);
-       adapter->stats.tpt += E1000_READ_REG(&adapter->hw, TPT);
-       adapter->stats.ptc64 += E1000_READ_REG(&adapter->hw, PTC64);
-       adapter->stats.ptc127 += E1000_READ_REG(&adapter->hw, PTC127);
-       adapter->stats.ptc255 += E1000_READ_REG(&adapter->hw, PTC255);
-       adapter->stats.ptc511 += E1000_READ_REG(&adapter->hw, PTC511);
-       adapter->stats.ptc1023 += E1000_READ_REG(&adapter->hw, PTC1023);
-       adapter->stats.ptc1522 += E1000_READ_REG(&adapter->hw, PTC1522);
-       adapter->stats.mptc += E1000_READ_REG(&adapter->hw, MPTC);
-       adapter->stats.bptc += E1000_READ_REG(&adapter->hw, BPTC);
-
-       if (adapter->hw.mac_type >= em_82543) {
+       adapter->stats.gorc += E1000_READ_REG(&adapter->hw, E1000_GORCH);
+       adapter->stats.gotc += E1000_READ_REG(&adapter->hw, E1000_GOTCH);
+
+       adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, E1000_RNBC);
+       adapter->stats.ruc += E1000_READ_REG(&adapter->hw, E1000_RUC);
+       adapter->stats.rfc += E1000_READ_REG(&adapter->hw, E1000_RFC);
+       adapter->stats.roc += E1000_READ_REG(&adapter->hw, E1000_ROC);
+       adapter->stats.rjc += E1000_READ_REG(&adapter->hw, E1000_RJC);
+
+       adapter->stats.tor += E1000_READ_REG(&adapter->hw, E1000_TORH);
+       adapter->stats.tot += E1000_READ_REG(&adapter->hw, E1000_TOTH);
+
+       adapter->stats.tpr += E1000_READ_REG(&adapter->hw, E1000_TPR);
+       adapter->stats.tpt += E1000_READ_REG(&adapter->hw, E1000_TPT);
+       adapter->stats.ptc64 += E1000_READ_REG(&adapter->hw, E1000_PTC64);
+       adapter->stats.ptc127 += E1000_READ_REG(&adapter->hw, E1000_PTC127);
+       adapter->stats.ptc255 += E1000_READ_REG(&adapter->hw, E1000_PTC255);
+       adapter->stats.ptc511 += E1000_READ_REG(&adapter->hw, E1000_PTC511);
+       adapter->stats.ptc1023 += E1000_READ_REG(&adapter->hw, E1000_PTC1023);
+       adapter->stats.ptc1522 += E1000_READ_REG(&adapter->hw, E1000_PTC1522);
+       adapter->stats.mptc += E1000_READ_REG(&adapter->hw, E1000_MPTC);
+       adapter->stats.bptc += E1000_READ_REG(&adapter->hw, E1000_BPTC);
+
+       if (adapter->hw.mac.type >= e1000_82543) {
                adapter->stats.algnerrc += 
-                   E1000_READ_REG(&adapter->hw, ALGNERRC);
+               E1000_READ_REG(&adapter->hw, E1000_ALGNERRC);
                adapter->stats.rxerrc += 
-                   E1000_READ_REG(&adapter->hw, RXERRC);
+               E1000_READ_REG(&adapter->hw, E1000_RXERRC);
                adapter->stats.tncrs += 
-                   E1000_READ_REG(&adapter->hw, TNCRS);
+               E1000_READ_REG(&adapter->hw, E1000_TNCRS);
                adapter->stats.cexterr += 
-                   E1000_READ_REG(&adapter->hw, CEXTERR);
+               E1000_READ_REG(&adapter->hw, E1000_CEXTERR);
                adapter->stats.tsctc += 
-                   E1000_READ_REG(&adapter->hw, TSCTC);
+               E1000_READ_REG(&adapter->hw, E1000_TSCTC);
                adapter->stats.tsctfc += 
-                   E1000_READ_REG(&adapter->hw, TSCTFC);
+               E1000_READ_REG(&adapter->hw, E1000_TSCTFC);
        }
-       ifp = &adapter->interface_data.ac_if;
 
-       /* Fill out the OS statistics structure */
        ifp->if_collisions = adapter->stats.colc;
 
        /* Rx Errors */
        ifp->if_ierrors =
-               adapter->dropped_pkts +
-               adapter->stats.rxerrc +
-               adapter->stats.crcerrs +
-               adapter->stats.algnerrc +
-               adapter->stats.ruc + adapter->stats.roc +
-               adapter->stats.mpc + adapter->stats.cexterr +
-               adapter->rx_overruns;
+           adapter->dropped_pkts + adapter->stats.rxerrc +
+           adapter->stats.crcerrs + adapter->stats.algnerrc +
+           adapter->stats.ruc + adapter->stats.roc +
+           adapter->stats.mpc + adapter->stats.cexterr;
 
        /* Tx Errors */
-       ifp->if_oerrors = adapter->stats.ecol + adapter->stats.latecol +
-                         adapter->watchdog_timeouts;
+       ifp->if_oerrors =
+           adapter->stats.ecol + adapter->stats.latecol +
+           adapter->watchdog_events;
 }
 
-
-/**********************************************************************
- *
- *  This routine is called only when em_display_debug_stats is enabled.
- *  This routine provides a way to take a look at important statistics
- *  maintained by the driver and hardware.
- *
- **********************************************************************/
 static void
 em_print_debug_info(struct adapter *adapter)
 {
-       device_t dev= adapter->dev;
+       device_t dev = adapter->dev;
        uint8_t *hw_addr = adapter->hw.hw_addr;
 
        device_printf(dev, "Adapter hardware address = %p \n", hw_addr);
-       device_printf(dev, "CTRL  = 0x%x RCTL = 0x%x\n",
-                     E1000_READ_REG(&adapter->hw, CTRL),
-                     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, "CTRL = 0x%x RCTL = 0x%x \n",
+           E1000_READ_REG(&adapter->hw, E1000_CTRL),
+           E1000_READ_REG(&adapter->hw, E1000_RCTL));
+       device_printf(dev, "Packet buffer = Tx=%dk Rx=%dk \n",
+           ((E1000_READ_REG(&adapter->hw, E1000_PBA) & 0xffff0000) >> 16),\
+           (E1000_READ_REG(&adapter->hw, E1000_PBA) & 0xffff) );
        device_printf(dev, "Flow control watermarks high = %d low = %d\n",
-                     adapter->hw.fc_high_water, adapter->hw.fc_low_water);
+           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));
+           E1000_READ_REG(&adapter->hw, E1000_TIDV),
+           E1000_READ_REG(&adapter->hw, E1000_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));
+           E1000_READ_REG(&adapter->hw, E1000_RDTR),
+           E1000_READ_REG(&adapter->hw, E1000_RADV));
        device_printf(dev, "fifo workaround = %lld, fifo_reset_count = %lld\n",
-                     (long long)adapter->tx_fifo_wrk_cnt,
-                     (long long)adapter->tx_fifo_reset_cnt);
+           (long long)adapter->tx_fifo_wrk_cnt,
+           (long long)adapter->tx_fifo_reset_cnt);
        device_printf(dev, "hw tdh = %d, hw tdt = %d\n",
-                     E1000_READ_REG(&adapter->hw, TDH),
-                     E1000_READ_REG(&adapter->hw, TDT));
+           E1000_READ_REG(&adapter->hw, E1000_TDH(0)),
+           E1000_READ_REG(&adapter->hw, E1000_TDT(0)));
+       device_printf(dev, "hw rdh = %d, hw rdt = %d\n",
+           E1000_READ_REG(&adapter->hw, E1000_RDH(0)),
+           E1000_READ_REG(&adapter->hw, E1000_RDT(0)));
        device_printf(dev, "Num Tx descriptors avail = %d\n",
-                     adapter->num_tx_desc_avail);
+           adapter->num_tx_desc_avail);
        device_printf(dev, "Tx Descriptors not avail1 = %ld\n",
-                     adapter->no_tx_desc_avail1);
+           adapter->no_tx_desc_avail1);
        device_printf(dev, "Tx Descriptors not avail2 = %ld\n",
-                     adapter->no_tx_desc_avail2);
+           adapter->no_tx_desc_avail2);
        device_printf(dev, "Std mbuf failed = %ld\n",
-                     adapter->mbuf_alloc_failed);
+           adapter->mbuf_alloc_failed);
        device_printf(dev, "Std mbuf cluster failed = %ld\n",
-                     adapter->mbuf_cluster_failed);
+           adapter->mbuf_cluster_failed);
        device_printf(dev, "Driver dropped packets = %ld\n",
-                     adapter->dropped_pkts);
+           adapter->dropped_pkts);
+       device_printf(dev, "Driver tx dma failure in encap = %ld\n",
+               adapter->no_tx_dma_setup);
 }
 
 static void
 em_print_hw_stats(struct adapter *adapter)
 {
-       device_t dev= adapter->dev;
+       device_t dev = adapter->dev;
 
        device_printf(dev, "Excessive collisions = %lld\n",
-                     (long long)adapter->stats.ecol);
+           (long long)adapter->stats.ecol);
+#if (DEBUG_HW > 0)  /* Dont output these errors normally */
        device_printf(dev, "Symbol errors = %lld\n",
-                     (long long)adapter->stats.symerrs);
+           (long long)adapter->stats.symerrs);
+#endif
        device_printf(dev, "Sequence errors = %lld\n",
-                     (long long)adapter->stats.sec);
+           (long long)adapter->stats.sec);
        device_printf(dev, "Defer count = %lld\n",
-                     (long long)adapter->stats.dc);
-
+           (long long)adapter->stats.dc);
        device_printf(dev, "Missed Packets = %lld\n",
-                     (long long)adapter->stats.mpc);
+           (long long)adapter->stats.mpc);
        device_printf(dev, "Receive No Buffers = %lld\n",
-                     (long long)adapter->stats.rnbc);
+           (long long)adapter->stats.rnbc);
        /* RLEC is inaccurate on some hardware, calculate our own. */
-       device_printf(dev, "Receive Length errors = %lld\n",
-                     (long long)adapter->stats.roc +
-                     (long long)adapter->stats.ruc);
+       device_printf(dev, "Receive Length Errors = %lld\n",
+           ((long long)adapter->stats.roc + (long long)adapter->stats.ruc));
        device_printf(dev, "Receive errors = %lld\n",
-                     (long long)adapter->stats.rxerrc);
+           (long long)adapter->stats.rxerrc);
        device_printf(dev, "Crc errors = %lld\n",
-                     (long long)adapter->stats.crcerrs);
+           (long long)adapter->stats.crcerrs);
        device_printf(dev, "Alignment errors = %lld\n",
-                     (long long)adapter->stats.algnerrc);
-       device_printf(dev, "Carrier extension errors = %lld\n",
-                     (long long)adapter->stats.cexterr);
-       device_printf(dev, "RX overruns = %lu\n", adapter->rx_overruns);
-       device_printf(dev, "Watchdog timeouts = %lu\n",
-                     adapter->watchdog_timeouts);
-
+           (long long)adapter->stats.algnerrc);
+       device_printf(dev, "Collision/Carrier extension errors = %lld\n",
+           (long long)adapter->stats.cexterr);
+       device_printf(dev, "RX overruns = %ld\n", adapter->rx_overruns);
+       device_printf(dev, "watchdog timeouts = %ld\n",
+           adapter->watchdog_events);
        device_printf(dev, "XON Rcvd = %lld\n",
-                     (long long)adapter->stats.xonrxc);
+           (long long)adapter->stats.xonrxc);
        device_printf(dev, "XON Xmtd = %lld\n",
-                     (long long)adapter->stats.xontxc);
+           (long long)adapter->stats.xontxc);
        device_printf(dev, "XOFF Rcvd = %lld\n",
-                     (long long)adapter->stats.xoffrxc);
+           (long long)adapter->stats.xoffrxc);
        device_printf(dev, "XOFF Xmtd = %lld\n",
-                     (long long)adapter->stats.xofftxc);
-
+           (long long)adapter->stats.xofftxc);
        device_printf(dev, "Good Packets Rcvd = %lld\n",
-                     (long long)adapter->stats.gprc);
+           (long long)adapter->stats.gprc);
        device_printf(dev, "Good Packets Xmtd = %lld\n",
-                     (long long)adapter->stats.gptc);
+           (long long)adapter->stats.gptc);
+}
+
+static void
+em_print_nvm_info(struct adapter *adapter)
+{
+       uint16_t        eeprom_data;
+       int     i, j, row = 0;
+
+       /* Its a bit crude, but it gets the job done */
+       kprintf("\nInterface EEPROM Dump:\n");
+       kprintf("Offset\n0x0000  ");
+       for (i = 0, j = 0; i < 32; i++, j++) {
+               if (j == 8) { /* Make the offset block */
+                       j = 0; ++row;
+                       kprintf("\n0x00%x0  ",row);
+               }
+               e1000_read_nvm(&adapter->hw, i, 1, &eeprom_data);
+               kprintf("%04x ", eeprom_data);
+       }
+       kprintf("\n");
 }
 
 static int
 em_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
 {
-       int error;
-       int result;
        struct adapter *adapter;
+       struct ifnet *ifp;
+       int error, result;
 
        result = -1;
        error = sysctl_handle_int(oidp, &result, 0, req);
-
        if (error || !req->newptr)
                return (error);
 
-       if (result == 1) {
-               adapter = (struct adapter *)arg1;
+       adapter = (struct adapter *)arg1;
+       ifp = &adapter->arpcom.ac_if;
+
+       lwkt_serialize_enter(ifp->if_serializer);
+
+       if (result == 1)
                em_print_debug_info(adapter);
-       }
+
+       /*
+        * This value will cause a hex dump of the
+        * first 32 16-bit words of the EEPROM to
+        * the screen.
+        */
+       if (result == 2)
+               em_print_nvm_info(adapter);
+
+       lwkt_serialize_exit(ifp->if_serializer);
 
        return (error);
 }
@@ -3580,21 +3671,21 @@ em_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
 static int
 em_sysctl_stats(SYSCTL_HANDLER_ARGS)
 {
-       int error;
-       int result;
-       struct adapter *adapter;
+       int error, result;
 
        result = -1;
        error = sysctl_handle_int(oidp, &result, 0, req);
-
        if (error || !req->newptr)
                return (error);
 
        if (result == 1) {
-               adapter = (struct adapter *)arg1;
+               struct adapter *adapter = (struct adapter *)arg1;
+               struct ifnet *ifp = &adapter->arpcom.ac_if;
+
+               lwkt_serialize_enter(ifp->if_serializer);
                em_print_hw_stats(adapter);
+               lwkt_serialize_exit(ifp->if_serializer);
        }
-
        return (error);
 }
 
@@ -3603,90 +3694,181 @@ em_sysctl_int_delay(SYSCTL_HANDLER_ARGS)
 {
        struct em_int_delay_info *info;
        struct adapter *adapter;
+       struct ifnet *ifp;
        uint32_t regval;
-       int error;
-       int usecs;
-       int ticks;
+       int error, usecs, ticks;
 
        info = (struct em_int_delay_info *)arg1;
-       adapter = info->adapter;
        usecs = info->value;
        error = sysctl_handle_int(oidp, &usecs, 0, req);
        if (error != 0 || req->newptr == NULL)
                return (error);
-       if (usecs < 0 || usecs > E1000_TICKS_TO_USECS(65535))
+       if (usecs < 0 || usecs > EM_TICKS_TO_USECS(65535))
                return (EINVAL);
        info->value = usecs;
-       ticks = E1000_USECS_TO_TICKS(usecs);
+       ticks = EM_USECS_TO_TICKS(usecs);
+
+       adapter = info->adapter;
+       ifp = &adapter->arpcom.ac_if;
+
+       lwkt_serialize_enter(ifp->if_serializer);
 
-       lwkt_serialize_enter(adapter->interface_data.ac_if.if_serializer);
        regval = E1000_READ_OFFSET(&adapter->hw, info->offset);
        regval = (regval & ~0xffff) | (ticks & 0xffff);
        /* Handle a few special cases. */
        switch (info->offset) {
        case E1000_RDTR:
-       case E1000_82542_RDTR:
-               regval |= E1000_RDT_FPDB;
                break;
+
        case E1000_TIDV:
-       case E1000_82542_TIDV:
                if (ticks == 0) {
                        adapter->txd_cmd &= ~E1000_TXD_CMD_IDE;
                        /* Don't write 0 into the TIDV register. */
                        regval++;
-               } else
+               } else {
                        adapter->txd_cmd |= E1000_TXD_CMD_IDE;
+               }
                break;
        }
        E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval);
-       lwkt_serialize_exit(adapter->interface_data.ac_if.if_serializer);
+
+       lwkt_serialize_exit(ifp->if_serializer);
        return (0);
 }
 
 static void
 em_add_int_delay_sysctl(struct adapter *adapter, const char *name,
-                       const char *description, struct em_int_delay_info *info,
-                       int offset, int value)
+       const char *description, struct em_int_delay_info *info,
+       int offset, int value)
 {
        info->adapter = adapter;
        info->offset = offset;
        info->value = value;
-       SYSCTL_ADD_PROC(&adapter->sysctl_ctx,
-                       SYSCTL_CHILDREN(adapter->sysctl_tree),
-                       OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW,
-                       info, 0, em_sysctl_int_delay, "I", description);
+
+       if (adapter->sysctl_tree != NULL) {
+               SYSCTL_ADD_PROC(&adapter->sysctl_ctx,
+                   SYSCTL_CHILDREN(adapter->sysctl_tree),
+                   OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW,
+                   info, 0, em_sysctl_int_delay, "I", description);
+       }
+}
+
+static void
+em_add_sysctl(struct adapter *adapter)
+{
+#ifdef PROFILE_SERIALIZER
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
+#endif
+
+       sysctl_ctx_init(&adapter->sysctl_ctx);
+       adapter->sysctl_tree = SYSCTL_ADD_NODE(&adapter->sysctl_ctx,
+                                       SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
+                                       device_get_nameunit(adapter->dev),
+                                       CTLFLAG_RD, 0, "");
+       if (adapter->sysctl_tree == NULL) {
+               device_printf(adapter->dev, "can't add sysctl node\n");
+       } else {
+               SYSCTL_ADD_PROC(&adapter->sysctl_ctx,
+                   SYSCTL_CHILDREN(adapter->sysctl_tree),
+                   OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, adapter, 0,
+                   em_sysctl_debug_info, "I", "Debug Information");
+
+               SYSCTL_ADD_PROC(&adapter->sysctl_ctx,
+                   SYSCTL_CHILDREN(adapter->sysctl_tree),
+                   OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW, adapter, 0,
+                   em_sysctl_stats, "I", "Statistics");
+
+               SYSCTL_ADD_INT(&adapter->sysctl_ctx,
+                   SYSCTL_CHILDREN(adapter->sysctl_tree),
+                   OID_AUTO, "rxd", CTLFLAG_RD,
+                   &adapter->num_rx_desc, 0, NULL);
+               SYSCTL_ADD_INT(&adapter->sysctl_ctx,
+                   SYSCTL_CHILDREN(adapter->sysctl_tree),
+                   OID_AUTO, "txd", CTLFLAG_RD,
+                   &adapter->num_tx_desc, 0, NULL);
+
+#ifdef PROFILE_SERIALIZER
+               SYSCTL_ADD_UINT(&adapter->sysctl_ctx,
+                   SYSCTL_CHILDREN(adapter->sysctl_tree),
+                   OID_AUTO, "serializer_sleep", CTLFLAG_RW,
+                   &ifp->if_serializer->sleep_cnt, 0, NULL);
+               SYSCTL_ADD_UINT(&adapter->sysctl_ctx,
+                   SYSCTL_CHILDREN(adapter->sysctl_tree),
+                   OID_AUTO, "serializer_tryfail", CTLFLAG_RW,
+                   &ifp->if_serializer->tryfail_cnt, 0, NULL);
+               SYSCTL_ADD_UINT(&adapter->sysctl_ctx,
+                   SYSCTL_CHILDREN(adapter->sysctl_tree),
+                   OID_AUTO, "serializer_enter", CTLFLAG_RW,
+                   &ifp->if_serializer->enter_cnt, 0, NULL);
+               SYSCTL_ADD_UINT(&adapter->sysctl_ctx,
+                   SYSCTL_CHILDREN(adapter->sysctl_tree),
+                   OID_AUTO, "serializer_try", CTLFLAG_RW,
+                   &ifp->if_serializer->try_cnt, 0, NULL);
+#endif
+               if (adapter->hw.mac.type >= e1000_82540) {
+                       SYSCTL_ADD_PROC(&adapter->sysctl_ctx,
+                           SYSCTL_CHILDREN(adapter->sysctl_tree),
+                           OID_AUTO, "int_throttle_ceil",
+                           CTLTYPE_INT|CTLFLAG_RW, adapter, 0,
+                           em_sysctl_int_throttle, "I",
+                           "interrupt throttling rate");
+               }
+       }
+
+       /* Set up some sysctls for the tunable interrupt delays */
+       em_add_int_delay_sysctl(adapter, "rx_int_delay",
+           "receive interrupt delay in usecs", &adapter->rx_int_delay,
+           E1000_REGISTER(&adapter->hw, E1000_RDTR), em_rx_int_delay_dflt);
+       em_add_int_delay_sysctl(adapter, "tx_int_delay",
+           "transmit interrupt delay in usecs", &adapter->tx_int_delay,
+           E1000_REGISTER(&adapter->hw, E1000_TIDV), em_tx_int_delay_dflt);
+       if (adapter->hw.mac.type >= e1000_82540) {
+               em_add_int_delay_sysctl(adapter, "rx_abs_int_delay",
+                   "receive interrupt delay limit in usecs",
+                   &adapter->rx_abs_int_delay,
+                   E1000_REGISTER(&adapter->hw, E1000_RADV),
+                   em_rx_abs_int_delay_dflt);
+               em_add_int_delay_sysctl(adapter, "tx_abs_int_delay",
+                   "transmit interrupt delay limit in usecs",
+                   &adapter->tx_abs_int_delay,
+                   E1000_REGISTER(&adapter->hw, E1000_TADV),
+                   em_tx_abs_int_delay_dflt);
+       }
 }
 
 static int
 em_sysctl_int_throttle(SYSCTL_HANDLER_ARGS)
 {
        struct adapter *adapter = (void *)arg1;
-       int error;
-       int throttle;
+       struct ifnet *ifp = &adapter->arpcom.ac_if;
+       int error, throttle;
 
-       throttle = em_int_throttle_ceil;
+       throttle = adapter->int_throttle_ceil;
        error = sysctl_handle_int(oidp, &throttle, 0, req);
        if (error || req->newptr == NULL)
                return error;
        if (throttle < 0 || throttle > 1000000000 / 256)
                return EINVAL;
+
+       lwkt_serialize_enter(ifp->if_serializer);
+
        if (throttle) {
                /*
                 * Set the interrupt throttling rate in 256ns increments,
                 * recalculate sysctl value assignment to get exact frequency.
                 */
                throttle = 1000000000 / 256 / throttle;
-               lwkt_serialize_enter(adapter->interface_data.ac_if.if_serializer);
-               em_int_throttle_ceil = 1000000000 / 256 / throttle;
-               E1000_WRITE_REG(&adapter->hw, ITR, throttle);
-               lwkt_serialize_exit(adapter->interface_data.ac_if.if_serializer);
+               adapter->int_throttle_ceil = 1000000000 / 256 / throttle;
        } else {
-               lwkt_serialize_enter(adapter->interface_data.ac_if.if_serializer);
-               em_int_throttle_ceil = 0;
-               E1000_WRITE_REG(&adapter->hw, ITR, 0);
-               lwkt_serialize_exit(adapter->interface_data.ac_if.if_serializer);
+               adapter->int_throttle_ceil = 0;
+       }
+       E1000_WRITE_REG(&adapter->hw, E1000_ITR, throttle);
+
+       lwkt_serialize_exit(ifp->if_serializer);
+
+       if (bootverbose) {
+               if_printf(ifp, "Interrupt moderation set to %d/sec\n",
+                         adapter->int_throttle_ceil);
        }
-       device_printf(adapter->dev, "Interrupt moderation set to %d/sec\n", 
-                       em_int_throttle_ceil);
        return 0;
 }
index 808de75..3ac30a8 100644 (file)
@@ -1,41 +1,36 @@
-/**************************************************************************
-
-Copyright (c) 2001-2006, Intel Corporation
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
-    this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
-    notice, this list of conditions and the following disclaimer in the
-    documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the Intel Corporation nor the names of its
-    contributors may be used to endorse or promote products derived from
-    this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-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.20 2008/07/22 12:08:41 sephe Exp $*/
+/*
+ * Copyright (c) 2001-2008, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *  3. Neither the name of the Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived from
+ *     this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
 
-#ifndef _EM_H_DEFINED_
-#define _EM_H_DEFINED_
+#ifndef _IF_EM_H_
+#define _IF_EM_H_
 
 /* Tunables */
 
@@ -49,12 +44,12 @@ POSSIBILITY OF SUCH DAMAGE.
  *   descriptor is 16 bytes.
  *   Since TDLEN should be multiple of 128bytes, the number of transmit
  *   desscriptors should meet the following condition.
- *      (num_tx_desc * sizeof(struct em_tx_desc)) % 128 == 0
+ *      (num_tx_desc * sizeof(struct e1000_tx_desc)) % 128 == 0
  */
-#define EM_MIN_TXD             80
-#define EM_MAX_TXD_82543       256
-#define EM_MAX_TXD             4096
-#define EM_DEFAULT_TXD         EM_MAX_TXD_82543
+#define EM_MIN_TXD                     80
+#define EM_MAX_TXD_82543               256
+#define EM_MAX_TXD                     4096
+#define EM_DEFAULT_TXD                 EM_MAX_TXD_82543
 
 /*
  * EM_RXD - Maximum number of receive Descriptors
@@ -67,12 +62,12 @@ POSSIBILITY OF SUCH DAMAGE.
  *   descriptor. The maximum MTU size is 16110.
  *   Since TDLEN should be multiple of 128bytes, the number of transmit
  *   desscriptors should meet the following condition.
- *      (num_tx_desc * sizeof(struct em_tx_desc)) % 128 == 0
+ *      (num_tx_desc * sizeof(struct e1000_tx_desc)) % 128 == 0
  */
-#define EM_MIN_RXD             80
-#define EM_MAX_RXD_82543       256
-#define EM_MAX_RXD             4096
-#define EM_DEFAULT_RXD         EM_MAX_RXD_82543
+#define EM_MIN_RXD                     80
+#define EM_MAX_RXD_82543               256
+#define EM_MAX_RXD                     4096
+#define EM_DEFAULT_RXD                 EM_MAX_RXD_82543
 
 /*
  * EM_TIDV - Transmit Interrupt Delay Value
@@ -84,7 +79,7 @@ POSSIBILITY OF SUCH DAMAGE.
  *   system is reporting dropped transmits, this value may be set too high
  *   causing the driver to run out of available transmit descriptors.
  */
-#define EM_TIDV                         64
+#define EM_TIDV                                64
 
 /*
  * EM_TADV - Transmit Absolute Interrupt Delay Value
@@ -98,7 +93,7 @@ POSSIBILITY OF SUCH DAMAGE.
  *   along with EM_TIDV, may improve traffic throughput in specific
  *   network conditions.
  */
-#define EM_TADV                         64
+#define EM_TADV                                64
 
 /*
  * EM_RDTR - Receive Interrupt Delay Timer (Packet Timer)
@@ -119,7 +114,7 @@ POSSIBILITY OF SUCH DAMAGE.
  *            restoring the network connection. To eliminate the potential
  *            for the hang ensure that EM_RDTR is set to 0.
  */
-#define EM_RDTR                         0
+#define EM_RDTR                                0
 
 /*
  * Receive Interrupt Absolute Delay Timer (Not valid for 82542/82543/82544)
@@ -132,30 +127,35 @@ POSSIBILITY OF SUCH DAMAGE.
  *   along with EM_RDTR, may improve traffic throughput in specific network
  *   conditions.
  */
-#define EM_RADV                         64
-
-/*
- * Inform the stack about transmit checksum offload capabilities.
- */
-#define EM_CHECKSUM_FEATURES            (CSUM_TCP | CSUM_UDP)
+#define EM_RADV                                64
 
 /*
  * This parameter controls the duration of transmit watchdog timer.
  */
-#define EM_TX_TIMEOUT                   5    /* set to 5 seconds */
+#define EM_TX_TIMEOUT                  5
+
+/* One for TX csum offloading desc, the other is reserved */
+#define EM_TX_RESERVED                 2
+
+/* Large enough for 16K jumbo frame */
+#define EM_TX_SPARE                    8
+
+/* Interrupt throttle rate */
+#define EM_DEFAULT_ITR                 10000
 
 /*
  * This parameter controls when the driver calls the routine to reclaim
  * transmit descriptors.
  */
 #define EM_TX_CLEANUP_THRESHOLD                (adapter->num_tx_desc / 8)
+#define EM_TX_OP_THRESHOLD             (adapter->num_tx_desc / 32)
 
 /*
  * This parameter controls whether or not autonegotation is enabled.
  *              0 - Disable autonegotiation
  *              1 - Enable  autonegotiation
  */
-#define DO_AUTO_NEG                     1
+#define DO_AUTO_NEG                    1
 
 /*
  * This parameter control whether or not the driver will wait for
@@ -163,38 +163,39 @@ POSSIBILITY OF SUCH DAMAGE.
  *              1 - Wait for autonegotiation to complete
  *              0 - Don't wait for autonegotiation to complete
  */
-#define WAIT_FOR_AUTO_NEG_DEFAULT       0
-
-/*
- * EM_MASTER_SLAVE is only defined to enable a workaround for a known
- * compatibility issue with 82541/82547 devices and some switches.
- * See the "Known Limitations" section of the README file for a complete
- * description and a list of affected switches.
- *     
- *              0 = Hardware default
- *              1 = Master mode
- *              2 = Slave mode
- *              3 = Auto master/slave
- */
-/* #define EM_MASTER_SLAVE     2 */
+#define WAIT_FOR_AUTO_NEG_DEFAULT      0
 
 /* Tunables -- End */
 
-#define AUTONEG_ADV_DEFAULT             (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
-                                         ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
-                                         ADVERTISE_1000_FULL)
+#define AUTONEG_ADV_DEFAULT            (ADVERTISE_10_HALF | \
+                                        ADVERTISE_10_FULL | \
+                                        ADVERTISE_100_HALF | \
+                                        ADVERTISE_100_FULL | \
+                                        ADVERTISE_1000_FULL)
 
-#define EM_VENDOR_ID                    0x8086
-#define EM_FLASH                        0x0014 /* Flash memory on ICH8 */
+#define AUTO_ALL_MODES                 0
 
-#define EM_JUMBO_PBA                    0x00000028
-#define EM_DEFAULT_PBA                  0x00000030
-#define EM_SMARTSPEED_DOWNSHIFT         3
-#define EM_SMARTSPEED_MAX               15
+/* PHY master/slave setting */
+#define EM_MASTER_SLAVE                        e1000_ms_hw_default
 
-#define MAX_NUM_MULTICAST_ADDRESSES     128
-#define PCI_ANY_ID                      (~0U)
+/*
+ * Micellaneous constants
+ */
+#define EM_VENDOR_ID                   0x8086
 
+#define EM_BAR_MEM                     PCIR_BAR(0)
+#define EM_BAR_FLASH                   PCIR_BAR(1)
+
+#define EM_JUMBO_PBA                   0x00000028
+#define EM_DEFAULT_PBA                 0x00000030
+#define EM_SMARTSPEED_DOWNSHIFT                3
+#define EM_SMARTSPEED_MAX              15
+#define EM_MAX_INTR                    10
+
+#define MAX_NUM_MULTICAST_ADDRESSES    128
+#define PCI_ANY_ID                     (~0U)
+#define EM_FC_PAUSE_TIME               1000
+#define EM_EEPROM_APME                 0x400;
 
 /*
  * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
@@ -203,7 +204,7 @@ POSSIBILITY OF SUCH DAMAGE.
  */
 #define EM_DBA_ALIGN                   128
 
-#define SPEED_MODE_BIT                 (1 << 21)       /* On PCI-E MACs only */
+#define SPEED_MODE_BIT                 (1 << 21) /* On PCI-E MACs only */
 
 /* PCI Config defines */
 #define EM_BAR_TYPE(v)                 ((v) & EM_BAR_TYPE_MASK)
@@ -215,135 +216,94 @@ POSSIBILITY OF SUCH DAMAGE.
 #define EM_BAR_MEM_TYPE_32BIT          0x00000000
 #define EM_BAR_MEM_TYPE_64BIT          0x00000004
 
+#define EM_MAX_SCATTER                 64
+#define EM_TSO_SIZE                    (65535 + \
+                                        sizeof(struct ether_vlan_header))
+#define EM_MAX_SEGSIZE                 4096
+#define EM_MSIX_MASK                   0x01F00000 /* For 82574 use */
+#define ETH_ZLEN                       60
+
+#define EM_CSUM_FEATURES               (CSUM_IP | CSUM_TCP | CSUM_UDP)
+#define CSUM_OFFLOAD                   (CSUM_IP | CSUM_TCP | CSUM_UDP)
+
 /*
- * Community introduced backward
- * compatibility issue.
+ * 82574 has a nonstandard address for EIAC
+ * and since its only used in MSIX, and in
+ * the em driver only 82574 uses MSIX we can
+ * solve it just using this define.
  */
-#if !defined(PCIR_CIS)
-#define PCIR_CIS       PCIR_CARDBUSCIS
-#endif
-
-/* Defines for printing debug information */
-#define DEBUG_INIT  0
-#define DEBUG_IOCTL 0
-#define DEBUG_HW    0
-
-#define INIT_DEBUGOUT(S)            if (DEBUG_INIT)  kprintf(S "\n")
-#define INIT_DEBUGOUT1(S, A)        if (DEBUG_INIT)  kprintf(S "\n", A)
-#define INIT_DEBUGOUT2(S, A, B)     if (DEBUG_INIT)  kprintf(S "\n", A, B)
-#define IOCTL_DEBUGOUT(S)           if (DEBUG_IOCTL) kprintf(S "\n")
-#define IOCTL_DEBUGOUT1(S, A)       if (DEBUG_IOCTL) kprintf(S "\n", A)
-#define IOCTL_DEBUGOUT2(S, A, B)    if (DEBUG_IOCTL) kprintf(S "\n", A, B)
-#define HW_DEBUGOUT(S)              if (DEBUG_HW) kprintf(S "\n")
-#define HW_DEBUGOUT1(S, A)          if (DEBUG_HW) kprintf(S "\n", A)
-#define HW_DEBUGOUT2(S, A, B)       if (DEBUG_HW) kprintf(S "\n", A, B)
-
-
-/* Supported RX Buffer Sizes */
-#define EM_RXBUFFER_2048        2048
-#define EM_RXBUFFER_4096        4096
-#define EM_RXBUFFER_8192        8192
-#define EM_RXBUFFER_16384      16384
-
-#define        EM_MAX_SCATTER          64
-
-/* ******************************************************************************
- * vendor_info_array
- *
- * This array contains the list of Subvendor/Subdevice IDs on which the driver
- * should load.
- *
- * ******************************************************************************/
-typedef struct _em_vendor_info_t {
-       unsigned int vendor_id;
-       unsigned int device_id;
-       unsigned int subvendor_id;
-       unsigned int subdevice_id;
-       unsigned int index;
-} em_vendor_info_t;
+#define EM_EIAC                                0x000DC
 
+/* Used in for 82547 10Mb Half workaround */
+#define EM_PBA_BYTES_SHIFT             0xA
+#define EM_TX_HEAD_ADDR_SHIFT          7
+#define EM_PBA_TX_MASK                 0xFFFF0000
+#define EM_FIFO_HDR                    0x10
+#define EM_82547_PKT_THRESH            0x3e0
 
-struct em_buffer {
-       int                     next_eop;       /* Index of the desc to watch */
-       struct mbuf             *m_head;
-       bus_dmamap_t            map;            /* bus_dma map for packet */
-};
+struct adapter;
 
-struct em_q {
-       int                     nsegs;          /* # of segments/descriptors */
-       bus_dma_segment_t       segs[EM_MAX_SCATTER];
+struct em_int_delay_info {
+       struct adapter  *adapter;       /* Back-pointer to the adapter struct */
+       int             offset;         /* Register offset to read/write */
+       int             value;          /* Current value in usecs */
 };
 
 /*
  * Bus dma allocation structure used by
- * em_dma_malloc and em_dma_free.
+ * e1000_dma_malloc and e1000_dma_free.
  */
 struct em_dma_alloc {
        bus_addr_t              dma_paddr;
-       caddr_t                 dma_vaddr;
+       void                    *dma_vaddr;
        bus_dma_tag_t           dma_tag;
        bus_dmamap_t            dma_map;
-       bus_dma_segment_t       dma_seg;
-       int                     dma_nseg;
 };
 
-typedef enum _XSUM_CONTEXT_T {
-       OFFLOAD_NONE,
-       OFFLOAD_TCP_IP,
-       OFFLOAD_UDP_IP
-} XSUM_CONTEXT_T;
+/* Our adapter structure */
+struct adapter {
+       struct arpcom           arpcom;
+       struct e1000_hw         hw;
 
-struct adapter;
-struct em_int_delay_info {
-       struct adapter *adapter;        /* Back-pointer to the adapter struct */
-       int offset;                     /* Register offset to read/write */
-       int value;                      /* Current value in usecs */
-};
+       /* DragonFly operating-system-specific structures. */
+       struct e1000_osdep      osdep;
+       device_t                dev;
 
-/* For 82544 PCIX  Workaround */
-typedef struct _ADDRESS_LENGTH_PAIR
-{
-       uint64_t   address;
-       uint32_t   length;
-} ADDRESS_LENGTH_PAIR, *PADDRESS_LENGTH_PAIR;
+       bus_dma_tag_t           parent_dtag;
 
-typedef struct _DESCRIPTOR_PAIR
-{
-       ADDRESS_LENGTH_PAIR descriptor[4];
-       uint32_t   elements;
-} DESC_ARRAY, *PDESC_ARRAY;
+       struct resource         *memory;
+       int                     memory_rid;
+       struct resource         *flash;
+       int                     flash_rid;
 
-/* Our adapter structure */
-struct adapter {
-       struct arpcom   interface_data;
-       struct em_hw    hw;
-
-       /* Operating-system-specific structures */
-       struct em_osdep osdep;
-       struct device   *dev;
-       struct resource *res_memory;
-       struct resource *flash_mem;
-       struct resource *res_ioport;
-       struct resource *res_interrupt;
-       void            *int_handler_tag;
-       struct ifmedia  media;
-       struct callout  timer;
-       struct callout  tx_fifo_timer;
-       int             if_flags;
-       int             io_rid;
+       struct resource         *ioport;
+       int                     io_rid;
+
+       struct resource         *intr_res;
+       void                    *intr_tag;
+       int                     intr_rid;
+
+       struct ifmedia          media;
+       struct callout          timer;
+       struct callout          tx_fifo_timer;
+       int                     if_flags;
+       int                     max_frame_size;
+       int                     min_frame_size;
+
+       /* Management and WOL features */
+       int                     wol;
+       int                     has_manage;
 
        /* Info about the board itself */
-       uint32_t        part_num;
-       uint8_t         link_active;
-       uint16_t        link_speed;
-       uint16_t        link_duplex;
-       uint32_t        smartspeed;
+       uint8_t                 link_active;
+       uint16_t                link_speed;
+       uint16_t                link_duplex;
+       uint32_t                smartspeed;
        struct em_int_delay_info tx_int_delay;
        struct em_int_delay_info tx_abs_int_delay;
        struct em_int_delay_info rx_int_delay;
        struct em_int_delay_info rx_abs_int_delay;
-
-       XSUM_CONTEXT_T  active_checksum_context;
+       int                     int_throttle_ceil;
 
        /*
         * Transmit definitions
@@ -355,14 +315,15 @@ struct adapter {
         * The number of remaining tx_desc is num_tx_desc_avail.
         */
        struct em_dma_alloc     txdma;          /* bus_dma glue for tx desc */
-       struct em_tx_desc       *tx_desc_base;
+       struct e1000_tx_desc    *tx_desc_base;
        uint32_t                next_avail_tx_desc;
        uint32_t                next_tx_to_clean;
-       volatile uint16_t       num_tx_desc_avail;
-       uint16_t                num_tx_desc;
+       int                     num_tx_desc_avail;
+       int                     num_tx_desc;
        uint32_t                txd_cmd;
        struct em_buffer        *tx_buffer_area;
        bus_dma_tag_t           txtag;          /* dma tag for tx */
+       int                     spare_tx_desc;
 
        /* 
         * Receive definitions
@@ -373,12 +334,13 @@ struct adapter {
         * The next pair to check on receive is at offset next_rx_desc_to_check
         */
        struct em_dma_alloc     rxdma;          /* bus_dma glue for rx desc */
-       struct em_rx_desc       *rx_desc_base;
+       struct e1000_rx_desc    *rx_desc_base;
        uint32_t                next_rx_desc_to_check;
-       uint16_t                num_rx_desc;
        uint32_t                rx_buffer_len;
+       int                     num_rx_desc;
        struct em_buffer        *rx_buffer_area;
        bus_dma_tag_t           rxtag;
+       bus_dmamap_t            rx_sparemap;
 
        /*
         * First/last mbuf pointers, for
@@ -387,40 +349,64 @@ struct adapter {
        struct mbuf             *fmp;
        struct mbuf             *lmp;
 
+       /* Misc stats maintained by the driver */
+       unsigned long           dropped_pkts;
+       unsigned long           mbuf_alloc_failed;
+       unsigned long           mbuf_cluster_failed;
+       unsigned long           no_tx_desc_avail1;
+       unsigned long           no_tx_desc_avail2;
+       unsigned long           no_tx_map_avail;
+       unsigned long           no_tx_dma_setup;
+       unsigned long           watchdog_events;
+       unsigned long           rx_overruns;
+       unsigned long           rx_irq;
+       unsigned long           tx_irq;
+       unsigned long           link_irq;
+
+       /* sysctl tree glue */
        struct sysctl_ctx_list  sysctl_ctx;
        struct sysctl_oid       *sysctl_tree;
 
-       /* Misc stats maintained by the driver */
-       unsigned long   dropped_pkts;
-       unsigned long   mbuf_alloc_failed;
-       unsigned long   mbuf_cluster_failed;
-       unsigned long   no_tx_desc_avail1;
-       unsigned long   no_tx_desc_avail2;
-       unsigned long   no_tx_map_avail;
-       unsigned long   no_tx_dma_setup;
-       unsigned long   rx_overruns;
-       unsigned long   watchdog_timeouts;
-
-       /* Used in for 82547 10Mb Half workaround */
-       uint32_t        tx_fifo_size;
-       uint32_t        tx_fifo_head;
-       uint32_t        tx_fifo_head_addr;
-       uint64_t        tx_fifo_reset_cnt;
-       uint64_t        tx_fifo_wrk_cnt;
-       uint32_t        tx_head_addr;
-
-#define EM_PBA_BYTES_SHIFT     0xA
-#define EM_TX_HEAD_ADDR_SHIFT  7
-#define EM_PBA_TX_MASK         0xFFFF0000
-#define EM_FIFO_HDR            0x10
-
-#define EM_82547_PKT_THRESH    0x3e0
-       /* For 82544 PCIX Workaround */
-       boolean_t       pcix_82544;
-       boolean_t       in_detach;
-
-       struct em_hw_stats stats;
+       /* 82547 workaround */
+       uint32_t                tx_fifo_size;
+       uint32_t                tx_fifo_head;
+       uint32_t                tx_fifo_head_addr;
+       uint64_t                tx_fifo_reset_cnt;
+       uint64_t                tx_fifo_wrk_cnt;
+       uint32_t                tx_head_addr;
+
+        /* For 82544 PCIX Workaround */
+       boolean_t               pcix_82544;
+       boolean_t               in_detach;
+
+       struct e1000_hw_stats   stats;
+};
+
+struct em_vendor_info {
+       uint16_t        vendor_id;
+       uint16_t        device_id;
+       const char      *desc;
+};
+
+struct em_buffer {
+       int             next_eop;       /* Index of the desc to watch */
+       struct mbuf     *m_head;
+       bus_dmamap_t    map;            /* bus_dma map for packet */
 };
 
-#endif /* !_EM_H_DEFINED_ */
+/* For 82544 PCIX  Workaround */
+typedef struct _ADDRESS_LENGTH_PAIR {
+       uint64_t        address;
+       uint32_t        length;
+} ADDRESS_LENGTH_PAIR, *PADDRESS_LENGTH_PAIR;
+
+typedef struct _DESCRIPTOR_PAIR {
+       ADDRESS_LENGTH_PAIR descriptor[4];
+       uint32_t        elements;
+} DESC_ARRAY, *PDESC_ARRAY;
+
+#define EM_IS_OACTIVE(adapter) \
+       ((adapter)->num_tx_desc_avail < \
+        (adapter)->spare_tx_desc + EM_TX_RESERVED)
+
+#endif /* _IF_EM_H_ */
diff --git a/sys/dev/netif/em/if_em_hw.c b/sys/dev/netif/em/if_em_hw.c
deleted file mode 100644 (file)
index 6d78d30..0000000
+++ /dev/null
@@ -1,9197 +0,0 @@
-/*******************************************************************************
-Copyright (c) 2001-2005, Intel Corporation 
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without 
-modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice, 
-    this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright 
-    notice, this list of conditions and the following disclaimer in the 
-    documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the Intel Corporation nor the names of its 
-    contributors may be used to endorse or promote products derived from 
-    this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-*******************************************************************************/
-
-/*$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.13 2008/01/11 10:34:15 sephe Exp $*/
-
-/* if_em_hw.c
- * Shared functions for accessing and configuring the MAC
- */
-
-#define STATIC static
-
-#ifdef LM
-#include "if_em_hw.h"
-#else
-#include <dev/netif/em/if_em_hw.h>
-#endif
-
-static int32_t em_swfw_sync_acquire(struct em_hw *hw, uint16_t mask);
-static void em_swfw_sync_release(struct em_hw *hw, uint16_t mask);
-static int32_t em_read_kmrn_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *data);
-static int32_t em_write_kmrn_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t data);
-static int32_t em_get_software_semaphore(struct em_hw *hw);
-static void em_release_software_semaphore(struct em_hw *hw);
-
-static uint8_t em_arc_subsystem_valid(struct em_hw *hw);
-static int32_t em_check_downshift(struct em_hw *hw);
-static int32_t em_check_polarity(struct em_hw *hw, em_rev_polarity *polarity);
-static void em_clear_vfta(struct em_hw *hw);
-static int32_t em_commit_shadow_ram(struct em_hw *hw);
-static int32_t em_config_dsp_after_link_change(struct em_hw *hw, boolean_t link_up);
-static int32_t em_config_fc_after_link_up(struct em_hw *hw);
-static int32_t em_detect_gig_phy(struct em_hw *hw);
-static int32_t em_erase_ich8_4k_segment(struct em_hw *hw, uint32_t bank);
-static int32_t em_get_auto_rd_done(struct em_hw *hw);
-static int32_t em_get_cable_length(struct em_hw *hw, uint16_t *min_length, uint16_t *max_length);
-static int32_t em_get_hw_eeprom_semaphore(struct em_hw *hw);
-static int32_t em_get_phy_cfg_done(struct em_hw *hw);
-static int32_t em_get_software_flag(struct em_hw *hw);
-static int32_t em_ich8_cycle_init(struct em_hw *hw);
-static int32_t em_ich8_flash_cycle(struct em_hw *hw, uint32_t timeout);
-static int32_t em_id_led_init(struct em_hw *hw);
-static int32_t em_init_lcd_from_nvm_config_region(struct em_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size);
-static int32_t em_init_lcd_from_nvm(struct em_hw *hw);
-static void em_init_rx_addrs(struct em_hw *hw);
-static void em_initialize_hardware_bits(struct em_hw *hw);
-static boolean_t em_is_onboard_nvm_eeprom(struct em_hw *hw);
-static int32_t em_kumeran_lock_loss_workaround(struct em_hw *hw);
-static int32_t em_mng_enable_host_if(struct em_hw *hw);
-static int32_t em_mng_host_if_write(struct em_hw *hw, uint8_t *buffer, uint16_t length, uint16_t offset, uint8_t *sum);
-static int32_t em_mng_write_cmd_header(struct em_hw* hw, struct em_host_mng_command_header* hdr);
-static int32_t em_mng_write_commit(struct em_hw *hw);
-static int32_t em_phy_ife_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
-static int32_t em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
-static int32_t em_read_eeprom_eerd(struct em_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
-static int32_t em_write_eeprom_eewr(struct em_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
-static int32_t em_poll_eerd_eewr_done(struct em_hw *hw, int eerd);
-static int32_t em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
-static void em_put_hw_eeprom_semaphore(struct em_hw *hw);
-static int32_t em_read_ich8_byte(struct em_hw *hw, uint32_t index, uint8_t *data);
-static int32_t em_verify_write_ich8_byte(struct em_hw *hw, uint32_t index, uint8_t byte);
-static int32_t em_write_ich8_byte(struct em_hw *hw, uint32_t index, uint8_t byte);
-static int32_t em_read_ich8_word(struct em_hw *hw, uint32_t index, uint16_t *data);
-static int32_t em_read_ich8_data(struct em_hw *hw, uint32_t index, uint32_t size, uint16_t *data);
-static int32_t em_write_ich8_data(struct em_hw *hw, uint32_t index, uint32_t size, uint16_t data);
-static int32_t em_read_eeprom_ich8(struct em_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
-static int32_t em_write_eeprom_ich8(struct em_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
-static void em_release_software_flag(struct em_hw *hw);
-static int32_t em_set_d3_lplu_state(struct em_hw *hw, boolean_t active);
-static int32_t em_set_d0_lplu_state(struct em_hw *hw, boolean_t active);
-static int32_t em_set_pci_ex_no_snoop(struct em_hw *hw, uint32_t no_snoop);
-static void em_set_pci_express_master_disable(struct em_hw *hw);
-static int32_t em_wait_autoneg(struct em_hw *hw);
-static void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
-static int32_t em_set_phy_type(struct em_hw *hw);
-static void em_phy_init_script(struct em_hw *hw);
-static int32_t em_setup_copper_link(struct em_hw *hw);
-static int32_t em_setup_fiber_serdes_link(struct em_hw *hw);
-static int32_t em_adjust_serdes_amplitude(struct em_hw *hw);
-static int32_t em_phy_force_speed_duplex(struct em_hw *hw);
-static int32_t em_config_mac_to_phy(struct em_hw *hw);
-static void em_raise_mdi_clk(struct em_hw *hw, uint32_t *ctrl);
-static void em_lower_mdi_clk(struct em_hw *hw, uint32_t *ctrl);
-static void em_shift_out_mdi_bits(struct em_hw *hw, uint32_t data,
-                                     uint16_t count);
-static uint16_t em_shift_in_mdi_bits(struct em_hw *hw);
-static int32_t em_phy_reset_dsp(struct em_hw *hw);
-static int32_t em_write_eeprom_spi(struct em_hw *hw, uint16_t offset,
-                                      uint16_t words, uint16_t *data);
-static int32_t em_write_eeprom_microwire(struct em_hw *hw,
-                                            uint16_t offset, uint16_t words,
-                                            uint16_t *data);
-static int32_t em_spi_eeprom_ready(struct em_hw *hw);
-static void em_raise_ee_clk(struct em_hw *hw, uint32_t *eecd);
-static void em_lower_ee_clk(struct em_hw *hw, uint32_t *eecd);
-static void em_shift_out_ee_bits(struct em_hw *hw, uint16_t data,
-                                    uint16_t count);
-static int32_t em_write_phy_reg_ex(struct em_hw *hw, uint32_t reg_addr,
-                                      uint16_t phy_data);
-static int32_t em_read_phy_reg_ex(struct em_hw *hw,uint32_t reg_addr,
-                                     uint16_t *phy_data);
-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_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);
-static int32_t em_configure_kmrn_for_10_100(struct em_hw *hw,
-                                               uint16_t duplex);
-static int32_t em_configure_kmrn_for_1000(struct em_hw *hw);
-
-/* IGP cable length table */
-static const
-uint16_t em_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
-    { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-      5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
-      25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
-      40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
-      60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
-      90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
-      100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
-      110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
-
-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.
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-STATIC int32_t
-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:
-        if (hw->mac_type == em_82541 ||
-            hw->mac_type == em_82541_rev_2 ||
-            hw->mac_type == em_82547 ||
-            hw->mac_type == em_82547_rev_2) {
-            hw->phy_type = em_phy_igp;
-            break;
-        }
-    case IGP03E1000_E_PHY_ID:
-        hw->phy_type = em_phy_igp_3;
-        break;
-    case IFE_E_PHY_ID:
-    case IFE_PLUS_E_PHY_ID:
-    case IFE_C_E_PHY_ID:
-        hw->phy_type = em_phy_ife;
-        break;
-    case GG82563_E_PHY_ID:
-        if (hw->mac_type == em_80003es2lan) {
-            hw->phy_type = em_phy_gg82563;
-            break;
-        }
-        /* Fall Through */
-    default:
-        /* Should never have loaded on this device */
-        hw->phy_type = em_phy_undefined;
-        return -E1000_ERR_PHY_TYPE;
-    }
-
-    return E1000_SUCCESS;
-}
-
-/******************************************************************************
- * IGP phy init script - initializes the GbE PHY
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-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);
-
-        switch (hw->mac_type) {
-        case em_82541:
-        case em_82547:
-            em_write_phy_reg(hw, 0x1F95, 0x0001);
-
-            em_write_phy_reg(hw, 0x1F71, 0xBD21);
-
-            em_write_phy_reg(hw, 0x1F79, 0x0018);
-
-            em_write_phy_reg(hw, 0x1F30, 0x1600);
-
-            em_write_phy_reg(hw, 0x1F31, 0x0014);
-
-            em_write_phy_reg(hw, 0x1F32, 0x161C);
-
-            em_write_phy_reg(hw, 0x1F94, 0x0003);
-
-            em_write_phy_reg(hw, 0x1F96, 0x003F);
-
-            em_write_phy_reg(hw, 0x2010, 0x0008);
-            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;
-
-            /* Move to analog registers page */
-            em_read_phy_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused);
-
-            if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
-                em_read_phy_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS, &fused);
-
-                fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
-                coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
-
-                if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
-                    coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
-                    fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
-                } else if (coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
-                    fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
-
-                fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
-                        (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
-                        (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
-
-                em_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_CONTROL, fused);
-                em_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_BYPASS,
-                                    IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
-            }
-        }
-    }
-}
-
-/******************************************************************************
- * Set the mac type member in the hw struct.
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-int32_t
-em_set_mac_type(struct em_hw *hw)
-{
-    DEBUGFUNC("em_set_mac_type");
-
-    switch (hw->device_id) {
-    case E1000_DEV_ID_82542:
-        switch (hw->revision_id) {
-        case E1000_82542_2_0_REV_ID:
-            hw->mac_type = em_82542_rev2_0;
-            break;
-        case E1000_82542_2_1_REV_ID:
-            hw->mac_type = em_82542_rev2_1;
-            break;
-        default:
-            /* Invalid 82542 revision ID */
-            return -E1000_ERR_MAC_TYPE;
-        }
-        break;
-    case E1000_DEV_ID_82543GC_FIBER:
-    case E1000_DEV_ID_82543GC_COPPER:
-        hw->mac_type = em_82543;
-        break;
-    case E1000_DEV_ID_82544EI_COPPER:
-    case E1000_DEV_ID_82544EI_FIBER:
-    case E1000_DEV_ID_82544GC_COPPER:
-    case E1000_DEV_ID_82544GC_LOM:
-        hw->mac_type = em_82544;
-        break;
-    case E1000_DEV_ID_82540EM:
-    case E1000_DEV_ID_82540EM_LOM:
-    case E1000_DEV_ID_82540EP:
-    case E1000_DEV_ID_82540EP_LOM:
-    case E1000_DEV_ID_82540EP_LP:
-        hw->mac_type = em_82540;
-        break;
-    case E1000_DEV_ID_82545EM_COPPER:
-    case E1000_DEV_ID_82545EM_FIBER:
-        hw->mac_type = em_82545;
-        break;
-    case E1000_DEV_ID_82545GM_COPPER:
-    case E1000_DEV_ID_82545GM_FIBER:
-    case E1000_DEV_ID_82545GM_SERDES:
-        hw->mac_type = em_82545_rev_3;
-        break;
-    case E1000_DEV_ID_82546EB_COPPER:
-    case E1000_DEV_ID_82546EB_FIBER:
-    case E1000_DEV_ID_82546EB_QUAD_COPPER:
-        hw->mac_type = em_82546;
-        break;
-    case E1000_DEV_ID_82546GB_COPPER:
-    case E1000_DEV_ID_82546GB_FIBER:
-    case E1000_DEV_ID_82546GB_SERDES:
-    case E1000_DEV_ID_82546GB_PCIE:
-    case E1000_DEV_ID_82546GB_QUAD_COPPER:
-    case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
-        hw->mac_type = em_82546_rev_3;
-        break;
-    case E1000_DEV_ID_82541EI:
-    case E1000_DEV_ID_82541EI_MOBILE:
-    case E1000_DEV_ID_82541ER_LOM:
-        hw->mac_type = em_82541;
-        break;
-    case E1000_DEV_ID_82541ER:
-    case E1000_DEV_ID_82541GI:
-    case E1000_DEV_ID_82541GI_LF:
-    case E1000_DEV_ID_82541GI_MOBILE:
-        hw->mac_type = em_82541_rev_2;
-        break;
-    case E1000_DEV_ID_82547EI:
-    case E1000_DEV_ID_82547EI_MOBILE:
-        hw->mac_type = em_82547;
-        break;
-    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:
-    case E1000_DEV_ID_82571EB_QUAD_COPPER:
-    case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
-            hw->mac_type = em_82571;
-        break;
-    case E1000_DEV_ID_82572EI_COPPER:
-    case E1000_DEV_ID_82572EI_FIBER:
-    case E1000_DEV_ID_82572EI_SERDES:
-    case E1000_DEV_ID_82572EI:
-        hw->mac_type = 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;
-    case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
-    case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
-    case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
-    case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
-        hw->mac_type = em_80003es2lan;
-        break;
-    case E1000_DEV_ID_ICH8_IGP_M_AMT:
-    case E1000_DEV_ID_ICH8_IGP_AMT:
-    case E1000_DEV_ID_ICH8_IGP_C:
-    case E1000_DEV_ID_ICH8_IFE:
-    case E1000_DEV_ID_ICH8_IFE_GT:
-    case E1000_DEV_ID_ICH8_IFE_G:
-    case E1000_DEV_ID_ICH8_IGP_M:
-        hw->mac_type = em_ich8lan;
-        break;
-    case E1000_DEV_ID_ICH9_IGP_AMT:
-    case E1000_DEV_ID_ICH9_IGP_C:
-    case E1000_DEV_ID_ICH9_IFE:
-    case E1000_DEV_ID_ICH9_IFE_GT:
-    case E1000_DEV_ID_ICH9_IFE_G:
-        hw->mac_type = em_ich9lan;
-        break;
-    default:
-        /* Should never have loaded on this device */
-        return -E1000_ERR_MAC_TYPE;
-    }
-
-    switch (hw->mac_type) {
-    case em_ich8lan:
-    case em_ich9lan:
-        hw->swfwhw_semaphore_present = TRUE;
-        hw->asf_firmware_present = TRUE;
-        break;
-    case em_80003es2lan:
-        hw->swfw_sync_present = TRUE;
-        /* fall through */
-    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;
-}
-
-/*****************************************************************************
- * Set media type and TBI compatibility.
- *
- * hw - Struct containing variables accessed by shared code
- * **************************************************************************/
-void
-em_set_media_type(struct em_hw *hw)
-{
-    uint32_t status;
-
-    DEBUGFUNC("em_set_media_type");
-
-    if (hw->mac_type != em_82543) {
-        /* tbi_compatibility is only valid on 82543 */
-        hw->tbi_compatibility_en = FALSE;
-    }
-
-    switch (hw->device_id) {
-    case E1000_DEV_ID_82545GM_SERDES:
-    case E1000_DEV_ID_82546GB_SERDES:
-    case E1000_DEV_ID_82571EB_SERDES:
-    case E1000_DEV_ID_82572EI_SERDES:
-    case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
-        hw->media_type = em_media_type_internal_serdes;
-        break;
-    default:
-        switch (hw->mac_type) {
-        case em_82542_rev2_0:
-        case em_82542_rev2_1:
-            hw->media_type = em_media_type_fiber;
-            break;
-        case em_ich8lan:
-        case em_ich9lan:
-        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) {
-                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;
-            }
-            break;
-        }
-    }
-}
-
-/******************************************************************************
- * Reset the transmit and receive units; mask and clear all interrupts.
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-int32_t
-em_reset_hw(struct em_hw *hw)
-{
-    uint32_t ctrl;
-    uint32_t ctrl_ext;
-    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");
-
-    /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
-    if (hw->mac_type == em_82542_rev2_0) {
-        DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
-        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);
-
-    /* Disable the Transmit and Receive units.  Then delay to allow
-     * any pending transactions to complete before we hit the MAC with
-     * the global reset.
-     */
-    E1000_WRITE_REG(hw, RCTL, 0);
-    E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
-    E1000_WRITE_FLUSH(hw);
-
-    /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
-    hw->tbi_compatibility_on = FALSE;
-
-    /* Delay to allow any outstanding PCI transactions to complete before
-     * resetting the device
-     */
-    msec_delay(10);
-
-    ctrl = E1000_READ_REG(hw, CTRL);
-
-    /* Must reset the PHY before resetting the MAC */
-    if ((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
-        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);
-    }
-
-    /* Workaround for ICH8 bit corruption issue in FIFO memory */
-    if (hw->mac_type == em_ich8lan) {
-        /* Set Tx and Rx buffer allocation to 8k apiece. */
-        E1000_WRITE_REG(hw, PBA, E1000_PBA_8K);
-        /* Set Packet Buffer Size to 16k. */
-        E1000_WRITE_REG(hw, PBS, E1000_PBS_16K);
-    }
-
-    /* Issue a global reset to the MAC.  This will reset the chip's
-     * transmit, receive, DMA, and link units.  It will not effect
-     * the current PCI configuration.  The global reset bit is self-
-     * clearing, and should clear within a microsecond.
-     */
-    DEBUGOUT("Issuing a global reset to MAC\n");
-
-    switch (hw->mac_type) {
-        case em_82544:
-        case em_82540:
-        case em_82545:
-        case em_82546:
-        case em_82541:
-        case em_82541_rev_2:
-            /* These controllers can't ack the 64-bit write when issuing the
-             * reset, so use IO-mapping as a workaround to issue the reset */
-            E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
-            break;
-        case em_82545_rev_3:
-        case em_82546_rev_3:
-            /* Reset is performed on a shadow of the control register */
-            E1000_WRITE_REG(hw, CTRL_DUP, (ctrl | E1000_CTRL_RST));
-            break;
-        case em_ich8lan:
-        case em_ich9lan:
-            if (!hw->phy_reset_disable &&
-                em_check_phy_reset_block(hw) == E1000_SUCCESS) {
-                /* em_ich8lan PHY HW reset requires MAC CORE reset
-                 * at the same time to make sure the interface between
-                 * MAC and the external PHY is reset.
-                 */
-                ctrl |= E1000_CTRL_PHY_RST;
-            }
-
-            em_get_software_flag(hw);
-            E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
-            msec_delay(5);
-            break;
-        default:
-            E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
-            break;
-    }
-
-    /* After MAC reset, force reload of EEPROM to restore power-on settings to
-     * device.  Later controllers reload the EEPROM automatically, so just wait
-     * for reload to complete.
-     */
-    switch (hw->mac_type) {
-        case em_82542_rev2_0:
-        case em_82542_rev2_1:
-        case em_82543:
-        case em_82544:
-            /* Wait for reset to complete */
-            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);
-            /* Wait for EEPROM reload */
-            msec_delay(2);
-            break;
-        case em_82541:
-        case em_82541_rev_2:
-        case em_82547:
-        case em_82547_rev_2:
-            /* Wait for EEPROM reload */
-            msec_delay(20);
-            break;
-        case em_82573:
-            if (em_is_onboard_nvm_eeprom(hw) == FALSE) {
-                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 */
-        default:
-            /* Auto read done will delay 5ms or poll based on mac type */
-            ret_val = em_get_auto_rd_done(hw);
-            if (ret_val)
-                return ret_val;
-            break;
-    }
-
-    /* Disable HW ARPs on ASF enabled adapters */
-    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);
-    }
-
-    if ((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
-        em_phy_init_script(hw);
-
-        /* 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);
-    }
-
-    /* Clear interrupt mask to stop board from generating interrupts */
-    DEBUGOUT("Masking off all interrupts\n");
-    E1000_WRITE_REG(hw, IMC, 0xffffffff);
-
-    /* Clear any pending interrupt events. */
-    icr = E1000_READ_REG(hw, ICR);
-
-    /* If MWI was previously enabled, reenable it. */
-    if (hw->mac_type == em_82542_rev2_0) {
-        if (hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
-            em_pci_set_mwi(hw);
-    }
-
-    if (hw->mac_type == em_ich8lan || hw->mac_type == em_ich9lan) {
-        uint32_t kab = E1000_READ_REG(hw, KABGTXD);
-        kab |= E1000_KABGTXD_BGSQLBIAS;
-        E1000_WRITE_REG(hw, KABGTXD, kab);
-    }
-
-    return E1000_SUCCESS;
-}
-
-/******************************************************************************
- *
- * Initialize a number of hardware-dependent bits
- *
- * hw: Struct containing variables accessed by shared code
- *
- *****************************************************************************/
-STATIC void
-em_initialize_hardware_bits(struct em_hw *hw)
-{
-    if ((hw->mac_type >= em_82571) && (!hw->initialize_hw_bits_disable)) {
-        /* Settings common to all silicon */
-        uint32_t reg_ctrl, reg_ctrl_ext;
-        uint32_t reg_tarc0, reg_tarc1;
-        uint32_t reg_tctl;
-        uint32_t reg_txdctl, reg_txdctl1;
-
-        reg_tarc0 = E1000_READ_REG(hw, TARC0);
-        reg_tarc0 &= ~0x78000000;           /* Clear bits 30, 29, 28, and 27 */
-
-        reg_txdctl = E1000_READ_REG(hw, TXDCTL);
-        reg_txdctl |= E1000_TXDCTL_COUNT_DESC;       /* Set bit 22 */
-        E1000_WRITE_REG(hw, TXDCTL, reg_txdctl);
-
-        reg_txdctl1 = E1000_READ_REG(hw, TXDCTL1);
-        reg_txdctl1 |= E1000_TXDCTL_COUNT_DESC;      /* Set bit 22 */
-        E1000_WRITE_REG(hw, TXDCTL1, reg_txdctl1);
-
-        switch (hw->mac_type) {
-            case em_82571:
-            case em_82572:
-                reg_tarc1 = E1000_READ_REG(hw, TARC1);
-                reg_tctl = E1000_READ_REG(hw, TCTL);
-
-                /* Set the phy Tx compatible mode bits */
-                reg_tarc1 &= ~0x60000000;   /* Clear bits 30 and 29 */
-
-                reg_tarc0 |= 0x07800000;    /* Set TARC0 bits 23-26 */
-                reg_tarc1 |= 0x07000000;    /* Set TARC1 bits 24-26 */
-
-                if (reg_tctl & E1000_TCTL_MULR)
-                    reg_tarc1 &= ~0x10000000;   /* Clear bit 28 if MULR is 1b */
-                else
-                    reg_tarc1 |= 0x10000000;    /* Set bit 28 if MULR is 0b */
-
-      &n